from abc import abstractmethod
from typing import List, Optional, Pattern, Dict, Match
from datetime import datetime, timedelta
from collections import namedtuple
import regex

from recognizers_text.utilities import RegExpUtility, QueryProcessor
from recognizers_text.extractor import Extractor, ExtractResult, Metadata
from recognizers_date_time.date_time.base_time import BaseTimeExtractor, BaseTimeParser
from .constants import Constants, TimeTypeConstants
from .extractors import DateTimeExtractor
from .parsers import DateTimeParser, DateTimeParseResult
from .utilities import Token, merge_all_tokens, DateTimeResolutionResult, \
    DateTimeUtilityConfiguration, DateTimeFormatUtil, ResolutionStartEnd, DateTimeOptionsConfiguration, DateTimeOptions

MatchedIndex = namedtuple('MatchedIndex', ['matched', 'index'])

class TimePeriodExtractorConfiguration(DateTimeOptionsConfiguration):
    @property
    @abstractmethod
    def simple_cases_regex(self) -> List[Pattern]:
        raise NotImplementedError

    @property
    @abstractmethod
    def till_regex(self) -> Pattern:
        raise NotImplementedError

    @property
    @abstractmethod
    def time_of_day_regex(self) -> Pattern:
        raise NotImplementedError

    @property
    @abstractmethod
    def general_ending_regex(self) -> Pattern:
        raise NotImplementedError

    @property
    @abstractmethod
    def single_time_extractor(self) -> DateTimeExtractor:
        raise NotImplementedError

    @property
    @abstractmethod
    def integer_extractor(self) -> Extractor:
        raise NotImplementedError

    @abstractmethod
    def get_from_token_index(self, source: str) -> MatchedIndex:
        raise NotImplementedError

    @abstractmethod
    def get_between_token_index(self, source: str) -> MatchedIndex:
        raise NotImplementedError

    @property
    @abstractmethod
    def token_before_date(self) -> str:
        raise NotImplementedError

    @property
    @abstractmethod
    def pure_number_regex(self) -> List[Pattern]:
        raise NotImplementedError

    @property
    @abstractmethod
    def check_both_before_after(self) -> bool:
        raise NotImplementedError

    @property
    @abstractmethod
    def is_connector_token(self, middle):
        raise NotImplementedError

    @property
    @abstractmethod
    def time_zone_extractor(self) -> DateTimeExtractor:
        raise NotImplementedError

class BaseTimePeriodExtractor(DateTimeExtractor):
    @property
    def extractor_type_name(self) -> str:
        return Constants.SYS_DATETIME_TIMEPERIOD

    def __init__(self, config: TimePeriodExtractorConfiguration):
        self.config = config

    def extract(self, source: str, reference: datetime = None) -> List[ExtractResult]:
        if reference is None:
            reference = datetime.now()

        tokens = self.match_simple_cases(source)
        tokens.extend(self.merge_two_time_points(source, reference))
        tokens.extend(self.match_time_of_day(source))

        if (self.config.options & DateTimeOptions.CALENDAR) != 0:
            tokens.extend(self.match_pure_number_cases(source))

        result = merge_all_tokens(tokens, source, self.extractor_type_name)

        if (self.config.options & DateTimeOptions.ENABLE_PREVIEW) != 0:
            # When TimeZone be migrated enable it
            pass

        if source == 'morgen':
            result = []

        return result

    def match_pure_number_cases(self, text):
        ret = []

        for regexp in self.config.pure_number_regex:

            matches = regexp.search(text)
            for match in matches:
                after_str = text[text.index(match.group()) + (match.end() - match.start()):]
                ending_match = self.config.general_ending_regex.search(after_str)
                if ending_match:
                    ret.append(Token(text.index(match.group()),
                                     text.index(match.group()) + (match.end() - match.start())))
        return ret

    def match_simple_cases(self, source: str) -> List[Token]:
        result = []

        for regexp in self.config.simple_cases_regex:
            matches = regex.finditer(regexp, source)

            if matches:
                for match in matches:

                    # Cases like "from 10:30 to 11", don't necessarily need "am/pm"
                    if RegExpUtility.get_group(match, Constants.MINUTE_GROUP_NAME) or\
                            RegExpUtility.get_group(match, Constants.SECOND_GROUP_NAME):

                        # Cases like "from 3:30 to 4" should be supported
                        # Cases like "from 3:30 to 5 on 1/1/2015" should be supported
                        # Cases like "from 3:30 to 4 people" is considered not valid
                        end_with_valid_token = False

                        # "No extra tokens after the time period"
                        if (source.index(match.group()) + (match.end() - match.start())) == len(source):
                            end_with_valid_token = True

                        else:
                            after_str = source[source.index(match.group()) + (match.end() - match.start()):]

                            end_with_general_endings = self.config.general_ending_regex.match(after_str)
                            end_with_am_pm = RegExpUtility.get_group(match, Constants.RIGHT_AM_PM_GROUP_NAME)

                            if end_with_general_endings or end_with_am_pm or\
                                    after_str.lstrip().startswith(self.config.token_before_date):
                                end_with_valid_token = True
                            elif (self.config.options & DateTimeOptions.ENABLE_PREVIEW) != 0:
                                # When TimeZone be migrated enable it
                                end_with_valid_token = False

                        if end_with_valid_token:
                            result.append(Token(source.index(match.group()), source.index(match.group()) +
                                                (match.end() - match.start())))
                    else:
                        # Is there "pm" or "am"?
                        match_pm_str = RegExpUtility.get_group(match, Constants.PM_GROUP_NAME)
                        match_am_str = RegExpUtility.get_group(match, Constants.AM_GROUP_NAME)
                        desc_str = RegExpUtility.get_group(match, Constants.DESC_GROUP_NAME)

                        # Check "pm", "am"
                        if match_pm_str or match_am_str or desc_str:
                            result.append(Token(source.index(match.group()), source.index(match.group()) +
                                                (match.end() - match.start())))
                        else:
                            after_str = source[source.index(match.group()) + (match.end() - match.start()):]

                            # When TimeZone be migrated enable it
                            if (self.config.options & DateTimeOptions.ENABLE_PREVIEW) != 0:
                                result.append(Token(source.index(match.group()),
                                                    source.index(match.group()) + (match.end() - match.start())))

        return result

    def starts_with_time_zone(self, after_text: str):
        # it needs TimeZone
        starts_with_time_zone = False

        time_zone_extract_results = self.config.time

    def merge_two_time_points(self, source: str, reference: datetime) -> List[Token]:
        result: List[Token] = list()
        time_extract_results = self.config.single_time_extractor.extract(source, reference)
        num_extract_results = self.config.integer_extractor.extract(source)

        # Check if it is an ending number
        if num_extract_results:
            time_numbers: List[ExtractResult] = list()

            # check if it is a ending number
            ending_number = False
            num = num_extract_results[-1]
            if num.start + num.length == len(source):
                ending_number = True
            else:
                after = source[num.start + num.length:]
                if regex.search(self.config.general_ending_regex, after) is not None:
                    ending_number = True
            if ending_number:
                time_numbers.append(num)

            i = 0
            j = 0

            while i < len(num_extract_results):
                # find subsequent time point
                num_end = num_extract_results[i].start + num_extract_results[i].length

                while j < len(time_extract_results) and time_extract_results[j].start <= num_end:
                    j += 1

                if j >= len(time_extract_results):
                    break
                # check connector string
                middle = source[num_end:time_extract_results[j].start]
                if RegExpUtility.exact_match(self.config.till_regex, middle, True).success or\
                        self.config.is_connector_token(middle.strip()):
                    time_numbers.append(num_extract_results[i])
                i += 1

            # check overlap
            for time_num in time_numbers:
                overlap: bool = any(map(time_num.overlap, time_extract_results))
                if not overlap:
                    time_extract_results.append(time_num)

            time_extract_results = sorted(time_extract_results, key=lambda x: x.start)

        # merge "{TimePoint} to {TimePoint}", "between {TimePoint} and {TimePoint}"
        i = 0

        while i < len(time_extract_results)-1:
            middle_begin = time_extract_results[i].start + time_extract_results[i].length
            middle_end = time_extract_results[i + 1].start
            middle: str = source[middle_begin:middle_end].strip().lower()
            match = regex.search(self.config.till_regex, middle)

            # handle "{TimePoint} to {TimePoint}"
            if match is not None and match.start() == 0 and match.group() == middle:
                period_begin = time_extract_results[i].start
                period_end = time_extract_results[i + 1].start + time_extract_results[i + 1].length

                # handle "from"
                before = source[0:period_begin].strip().lower()
                after = source[period_end: len(source) - period_end].strip().lower()
                from_index: MatchedIndex = self.config.get_from_token_index(
                    before)
                if from_index.matched:
                    period_begin = from_index.index

                # handle "between"
                between_index: MatchedIndex = self.config.get_between_token_index(
                    before)
                if between_index.matched:
                    period_begin = between_index.index

                # handle "between" in afterStr
                after_index: MatchedIndex = self.config.get_between_token_index(
                    after)
                if after_index.matched:
                    period_end = after_index.index

                result.append(Token(period_begin, period_end))
                i += 2
                continue

            # handle "between {TimePoint} and {TimePoint}"
            if self.config.is_connector_token(middle):
                period_begin = time_extract_results[i].start
                period_end = time_extract_results[i + 1].start + time_extract_results[i + 1].length

                # handle "between"
                before = source[0:period_begin].strip().lower()
                between_index: MatchedIndex = self.config.get_between_token_index(
                    before)
                if between_index.matched:
                    period_begin = between_index.index
                    result.append(Token(period_begin, period_end))
                    i += 2
                    continue

                # handle "between...and..." case when "between" follows the datepoints
                after_str = source[period_end: + len(source) - period_end]
                after_index = self.config.get_between_token_index(after_str)
                if self.config.check_both_before_after and after_index.matched:
                    period_end += after_index.index
                    result.append(Token(period_begin, period_end))

                    # merge two tokens here, increase the index by two
                    i += 2
                    continue

            i += 1

        return result

    def match_time_of_day(self, source: str) -> List[Token]:
        result: List[Token] = list()
        matches = regex.finditer(self.config.time_of_day_regex, source)

        for match in matches:
            meta = None
            if RegExpUtility.get_group(match, Constants.MEALTIME_GROUP_NAME):
                meta = Metadata()
                meta.is_mealtime = True

            result.append(Token(start=source.index(match.group()),
                                end=source.index(match.group()) + (match.end() - match.start()),
                                metadata=meta))
        return result

MatchedTimeRegex = namedtuple(
    'MatchedTimeRegex', ['matched', 'timex', 'begin_hour', 'end_hour', 'end_min'])

class TimePeriodParserConfiguration:
    @property
    @abstractmethod
    def time_extractor(self) -> BaseTimeExtractor:
        raise NotImplementedError

    @property
    @abstractmethod
    def time_parser(self) -> BaseTimeParser:
        raise NotImplementedError

    @property
    @abstractmethod
    def integer_extractor(self) -> Extractor:
        raise NotImplementedError

    @property
    @abstractmethod
    def time_zone_parser(self) -> DateTimeParser:
        raise NotImplementedError

    @property
    @abstractmethod
    def pure_number_from_to_regex(self) -> Pattern:
        raise NotImplementedError

    @property
    @abstractmethod
    def pure_number_between_and_regex(self) -> Pattern:
        raise NotImplementedError

    @property
    @abstractmethod
    def specific_time_from_to_regex(self) -> Pattern:
        raise NotImplementedError

    @property
    @abstractmethod
    def specific_time_between_and_regex(self) -> Pattern:
        raise NotImplementedError

    @property
    @abstractmethod
    def time_of_day_regex(self) -> Pattern:
        raise NotImplementedError

    @property
    @abstractmethod
    def till_regex(self) -> Pattern:
        raise NotImplementedError

    @property
    @abstractmethod
    def numbers(self) -> Dict[str, int]:
        raise NotImplementedError

    @property
    @abstractmethod
    def utility_configuration(self) -> DateTimeUtilityConfiguration:
        raise NotImplementedError

    @abstractmethod
    def get_matched_timex_range(self, source: str) -> MatchedTimeRegex:
        raise NotImplementedError

class BaseTimePeriodParser(DateTimeParser):
    @property
    def parser_type_name(self) -> str:
        return Constants.SYS_DATETIME_TIMEPERIOD

    def __init__(self, config: TimePeriodParserConfiguration):
        self.config = config

    def parse(self, source: ExtractResult, reference: datetime = None) -> Optional[DateTimeParseResult]:
        if reference is None:
            reference = datetime.now()

        value = None
        if source.type is self.parser_type_name:
            source_text = source.text.lower()

            inner_result = self.parse_simple_cases(source_text, reference)

            if not inner_result.success:
                inner_result = self.merge_two_time_points(
                    source_text, reference)

            if not inner_result.success:
                inner_result = self.parse_time_of_day(source_text, reference)

            if inner_result.success:
                inner_result.future_resolution[TimeTypeConstants.START_TIME] = DateTimeFormatUtil.format_time(
                    inner_result.future_value.start)
                inner_result.future_resolution[TimeTypeConstants.END_TIME] = DateTimeFormatUtil.format_time(
                    inner_result.future_value.end)
                inner_result.past_resolution[TimeTypeConstants.START_TIME] = DateTimeFormatUtil.format_time(
                    inner_result.past_value.start)
                inner_result.past_resolution[TimeTypeConstants.END_TIME] = DateTimeFormatUtil.format_time(
                    inner_result.past_value.end)
                value = inner_result

        result = DateTimeParseResult(source)
        result.value = value
        result.timex_str = value.timex if value is not None else ''
        result.resolution_str = ''

        return result

    def parse_simple_cases(self, source: str, reference: datetime) -> DateTimeResolutionResult:
        result = DateTimeResolutionResult()

        result = self.parse_pure_numbers(source, reference)
        if not result.success:
            result = self.parse_specific_time(source, reference)

        return result

    def parse_pure_numbers(self, source: str, reference: datetime) -> DateTimeResolutionResult:
        result = DateTimeResolutionResult()
        year = reference.year
        month = reference.month
        day = reference.day

        source = source.strip().lower()

        match = regex.search(self.config.pure_number_from_to_regex, source)
        if not match:
            match = regex.search(
                self.config.pure_number_between_and_regex, source)

        if not match or match.start() != 0:
            return result

        # this "from .. to .." pattern is valid if followed by a Date OR "pm"
        valid = False

        # get hours
        hour_group_list = RegExpUtility.get_group_list(match, Constants.HOUR_GROUP_NAME)

        hour_str = hour_group_list[0]
        begin_hour = self.config.numbers.get(hour_str, None)
        if not begin_hour:
            begin_hour = int(hour_str)

        hour_str = hour_group_list[1]
        end_hour = self.config.numbers.get(hour_str, None)
        if not end_hour:
            end_hour = int(hour_str)

        # parse PM
        left_desc: str = RegExpUtility.get_group(match, Constants.LEFT_DESC_GROUP_NAME)
        right_desc: str = RegExpUtility.get_group(match, Constants.RIGHT_DESC_GROUP_NAME)
        pm_str: str = RegExpUtility.get_group(match, Constants.PM_GROUP_NAME)
        am_str: str = RegExpUtility.get_group(match, Constants.AM_GROUP_NAME)

        # The "am_pm" only occurs in time, don't have to consider it here

        if not left_desc:
            right_am_valid: bool = right_desc and regex.search(
                self.config.utility_configuration.am_desc_regex, right_desc.lower())
            right_pm_valid: bool = right_desc and regex.search(
                self.config.utility_configuration.pm_desc__regex, right_desc.lower())

            if am_str or right_am_valid:
                if end_hour >= 12:
                    end_hour -= 12

                if begin_hour >= 12 and begin_hour - 12 < end_hour:
                    begin_hour -= 12

                # Resolve case like "11 to 3am"
                if 12 > begin_hour > end_hour:
                    begin_hour += 12

                valid = True
            elif pm_str or right_pm_valid:
                if end_hour < 12:
                    end_hour += 12

                # Resolve case like "11 to 3pm"
                if begin_hour + 12 < end_hour:
                    begin_hour += 12

                valid = True
        if not valid:
            return result

        begin = f'T{begin_hour:02d}'
        end = f'T{end_hour:02d}'

        if begin_hour >= end_hour:
            end_hour += 24

        difference = end_hour - begin_hour
        result.timex = f'({begin},{end},PT{difference}H)'
        result.future_value = ResolutionStartEnd()
        result.past_value = ResolutionStartEnd()
        result.future_value.start = datetime(
            year, month, day) + timedelta(hours=begin_hour)
        result.future_value.end = datetime(
            year, month, day) + timedelta(hours=end_hour)
        result.past_value.start = result.future_value.start
        result.past_value.end = result.future_value.end
        result.success = True

        return result

    def parse_specific_time(self, source: str, reference: datetime) -> DateTimeResolutionResult:
        result = DateTimeResolutionResult()
        year = reference.year
        month = reference.month
        day = reference.day

        source = source.strip().lower()

        match = regex.search(self.config.specific_time_from_to_regex, source)
        if not match:
            match = regex.search(
                self.config.specific_time_between_and_regex, source)

        if not match or match.start() != 0:
            return result

        # this "from .. to .." pattern is valid if followed by a Date OR "pm"
        valid = False

        time1 = RegExpUtility.get_group(match, "time1")
        time2 = RegExpUtility.get_group(match, "time2")

        # get hours
        hour_group_list = RegExpUtility.get_group_list(match, Constants.HOUR_GROUP_NAME)

        hour_str = hour_group_list[0]
        begin_hour = self.config.numbers.get(hour_str, None)
        if not begin_hour:
            begin_hour = int(hour_str)

        hour_str = hour_group_list[1]
        end_hour = self.config.numbers.get(hour_str, None)
        if not end_hour:
            end_hour = int(hour_str)

        # get minutes
        minute_group_list = RegExpUtility.get_group_list(match, Constants.MINUTE_GROUP_NAME)

        begin_minute = end_minute = -1
        if len(minute_group_list) > 1:
            minute_str = minute_group_list[0]
            begin_minute = self.config.numbers.get(minute_str, None)
            if not begin_minute:
                begin_minute = int(minute_str)
            minute_str = minute_group_list[1]
            end_minute = self.config.numbers.get(minute_str, None)
            if not end_minute:
                end_minute = int(minute_str)
        elif len(minute_group_list) == 1:
            minute_str = minute_group_list[0]
            if minute_str in time1:
                begin_minute = self.config.numbers.get(minute_str, None)
                if not begin_minute:
                    begin_minute = int(minute_str)
            elif minute_str in time2:
                end_minute = self.config.numbers.get(minute_str, None)
                if not end_minute:
                    end_minute = int(minute_str)

        # parse AM/PM
        left_desc: str = RegExpUtility.get_group(match, Constants.LEFT_DESC_GROUP_NAME)
        right_desc: str = RegExpUtility.get_group(match, Constants.RIGHT_DESC_GROUP_NAME)

        desc_capture_list = RegExpUtility.get_group_list(match, Constants.DESC_GROUP_NAME)
        for desc_capture in desc_capture_list:
            if desc_capture in time1 and not left_desc:
                left_desc: str = desc_capture
            elif desc_capture in time2 and not right_desc:
                right_desc: str = desc_capture

        begin_date_time = datetime(year, month, day, hour=begin_hour, minute=begin_minute if begin_minute > 0 else 0)
        end_date_time = datetime(year, month, day, hour=end_hour, minute=end_minute if end_minute > 0 else 0)

        has_left_am = left_desc != '' and left_desc.startswith('a')
        has_left_pm = left_desc != '' and left_desc.startswith('p')
        has_right_am = right_desc != '' and right_desc.startswith('a')
        has_right_pm = right_desc != '' and right_desc.startswith('p')
        has_left = has_left_am or has_left_pm
        has_right = has_right_am or has_right_pm

        # both time point has description like 'am' or 'pm'
        if has_left and has_right:
            if has_left_am:
                if begin_hour >= 12:
                    begin_date_time -= timedelta(hours=12)
            else:
                if begin_hour < 12:
                    begin_date_time += timedelta(hours=12)
            if has_right_am:
                if end_hour > 12:
                    end_date_time -= timedelta(hours=12)
            else:
                if end_hour < 12:
                    end_date_time += timedelta(hours=12)
        # one of the time point has description like 'am' or 'pm'
        elif has_left or has_right:
            if has_left_am:
                if begin_hour >= 12:
                    begin_date_time -= timedelta(hours=12)
                if end_hour < 12:
                    if end_date_time < begin_date_time:
                        end_date_time += timedelta(hours=12)
            elif has_left_pm:
                if begin_hour < 12:
                    begin_date_time += timedelta(hours=12)
                if end_hour < 12:
                    if end_date_time < begin_date_time:
                        span: datetime = begin_date_time - end_date_time
                        end_date_time += timedelta(hours=24) if span >= timedelta(hours=12) else timedelta(hours=12)
            if has_right_am:
                if end_hour >= 12:
                    end_date_time -= timedelta(hours=12)
                if begin_hour < 12:
                    if end_date_time < begin_date_time:
                        begin_date_time -= timedelta(hours=12)
            elif has_right_pm:
                if end_hour < 12:
                    end_date_time += timedelta(hours=12)
                if begin_hour < 12:
                    if end_date_time < begin_date_time:
                        begin_date_time -= timedelta(hours=12)
                    else:
                        span = end_date_time - begin_date_time
                        if span >= timedelta(hours=12):
                            begin_date_time += timedelta(hours=12)
        # no 'am' or 'pm' indicator
        elif begin_hour <= 12 and end_hour <= 12:
            if begin_date_time > end_date_time:
                if begin_hour == 12:
                    begin_date_time -= timedelta(hours=12)
                else:
                    end_date_time += timedelta(hours=12)
            result.comment = Constants.AM_PM_GROUP_NAME

        if end_date_time < begin_date_time:
            end_date_time += timedelta(hours=24)

        if begin_minute >= 0:
            begin = f'T{begin_date_time.hour:02d}:{begin_date_time.minute:02d}'
        else:
            begin = f'T{begin_date_time.hour:02d}'
        if end_minute >= 0:
            end = f'T{end_date_time.hour:02d}:{end_date_time.minute:02d}'
        else:
            end = f'T{end_date_time.hour:02d}'

        difference = datetime(year, month, day) + (end_date_time - begin_date_time)
        if difference.minute != 0 and difference.hour != 0:
            result.timex = f'({begin},{end},PT{difference.hour}H{difference.minute}M)'
        elif difference.minute != 0 and difference.hour == 0:
            result.timex = f'({begin},{end},PT{difference.minute}M)'
        else:
            result.timex = f'({begin},{end},PT{difference.hour}H)'

        result.future_value = ResolutionStartEnd()
        result.past_value = ResolutionStartEnd()
        result.future_value.start = begin_date_time
        result.future_value.end = end_date_time
        result.past_value.start = result.future_value.start
        result.past_value.end = result.future_value.end
        result.success = True

        result.sub_date_time_entities = []

        # in SplitDateAndTime mode, time points will be get from these sub_date_time_entities
        # cases like "from 4 to 5pm", "4" should not be trated as sub_date_time_entities
        if has_left or begin_minute >= 0:
            er = ExtractResult()
            er.start = match.start("time1")
            er.length = match.end("time1") - match.start("time1")
            er.text = time1
            er.type = Constants.SYS_DATETIME_TIME
            pr = self.config.time_parser.parse(er, reference)
            result.sub_date_time_entities.append(pr)

        # cases like "from 4am to 5" "5" should not treated as sub_date_time_entities
        if has_right or end_minute >= 0:
            er = ExtractResult()
            er.start = match.start("time2")
            er.length = match.end("time2") - match.start("time2")
            er.text = time2
            er.type = Constants.SYS_DATETIME_TIME
            pr = self.config.time_parser.parse(er, reference)
            result.sub_date_time_entities.append(pr)

        return result

    def merge_two_time_points(self, source: str, reference: datetime) -> DateTimeResolutionResult:
        result = DateTimeResolutionResult()
        extract_results = self.config.time_extractor.extract(source, reference)
        valid_time_number = True

        if len(extract_results) != 2:
            if len(extract_results) == 1:
                time_extract_results = extract_results[0]
                num_extract_results = self.config.integer_extractor.extract(source)

                for num in num_extract_results:
                    middle_begin = 0
                    middle_end = 0

                    # ending number
                    if num.start > time_extract_results.start + time_extract_results.length:
                        middle_begin = time_extract_results.start + time_extract_results.length
                        middle_end = num.start - middle_begin
                    elif num.start + num.length < time_extract_results.start:
                        middle_begin = num.start + num.length
                        middle_end = time_extract_results.start - middle_begin

                    # check if the middle string between the time point and the valid number is a connect string.
                    middle_str = source[middle_begin:middle_begin + middle_end]
                    if regex.search(self.config.till_regex, middle_str) is not None:
                        num.type = Constants.SYS_DATETIME_TIME
                        extract_results.append(num)
                        valid_time_number = True
                        break

                extract_results = sorted(extract_results, key=lambda x: x.start)

            if not valid_time_number:
                return result

        if len(extract_results) != 2:
            return result

        pr1 = self.config.time_parser.parse(extract_results[0], reference)
        pr2 = self.config.time_parser.parse(extract_results[1], reference)

        if pr1.value is None or pr2.value is None:
            return result

        am_pm_str1: str = pr1.value.comment
        am_pm_str2: str = pr2.value.comment
        begin_time: datetime = pr1.value.future_value
        end_time: datetime = pr2.value.future_value

        if am_pm_str2 and am_pm_str2.endswith(Constants.AM_PM_GROUP_NAME) and\
                end_time <= begin_time < end_time + timedelta(hours=12):
            end_time: datetime = end_time + timedelta(hours=12)
            pr2.value.future_value = end_time
            pr2.timex_str = f'T{end_time.hour}'
            if end_time.minute > 0:
                pr2.timex_str = f'{pr2.timex_str}:{end_time.minute}'

        if am_pm_str1 and am_pm_str1.endswith(Constants.AM_PM_GROUP_NAME) and\
                end_time > begin_time + timedelta(hours=12):
            begin_time: datetime = begin_time + timedelta(hours=12)
            pr1.value.future_value = begin_time
            pr1.timex_str = f'T{begin_time.hour}'
            if begin_time.minute > 0:
                pr1.timex_str = f'{pr1.timex_str}:{begin_time.minute}'

        if end_time < begin_time:
            end_time = end_time + timedelta(days=1)

        hours = QueryProcessor.float_or_int(
            (end_time - begin_time).total_seconds() // 3600)
        minutes = QueryProcessor.float_or_int(
            (end_time - begin_time).total_seconds() / 60 % 60)

        hours_str = f'{hours}H' if hours > 0 else ''
        minutes_str = f'{minutes}M' if 0 < minutes < 60 else ''
        result.timex = f'({pr1.timex_str},{pr2.timex_str},PT{hours_str}{minutes_str})'
        result.future_value = ResolutionStartEnd(begin_time, end_time)
        result.past_value = ResolutionStartEnd(begin_time, end_time)
        result.success = True
        if am_pm_str1 and am_pm_str1.endswith(Constants.AM_PM_GROUP_NAME) and am_pm_str2 and\
                am_pm_str2.endswith(Constants.AM_PM_GROUP_NAME):
            result.comment = Constants.AM_PM_GROUP_NAME

        result.sub_date_time_entities = [pr1, pr2]
        return result

    # parse "morning", "afternoon", "night"
    def parse_time_of_day(self, source: str, reference: datetime) -> DateTimeResolutionResult:
        result = DateTimeResolutionResult()
        year = reference.year
        month = reference.month
        day = reference.day

        # extract early/late prefix from text
        has_early = False
        has_late = False
        match = regex.search(self.config.time_of_day_regex, source)
        if match is not None:
            early = RegExpUtility.get_group(match, Constants.COMMENT_EARLY)
            if early:
                has_early = True
                source = source.replace(early, '')
                result.comment = Constants.COMMENT_EARLY
                result.mod = TimeTypeConstants.EARLY_MOD
            late = RegExpUtility.get_group(match, Constants.COMMENT_LATE)
            if late:
                has_late = True
                source = source.replace(late, '')
                result.comment = Constants.COMMENT_LATE
                result.mod = TimeTypeConstants.LATE_MOD

        timex_range = self.config.get_matched_timex_range(source)
        if not timex_range.matched:
            return result

        # modify time period if "early" or "late" is existed
        if has_early:
            timex_range = MatchedTimeRegex(
                matched=timex_range.matched,
                timex=timex_range.timex,
                begin_hour=timex_range.begin_hour,
                end_hour=timex_range.begin_hour + 2,
                end_min=0 if timex_range.end_min == 59 else timex_range.end_min
            )
        elif has_late:
            timex_range = MatchedTimeRegex(
                matched=timex_range.matched,
                timex=timex_range.timex,
                begin_hour=timex_range.begin_hour + 2,
                end_hour=timex_range.end_hour,
                end_min=timex_range.end_min
            )

        result.timex = timex_range.timex
        result.future_value = ResolutionStartEnd()
        result.past_value = ResolutionStartEnd()
        result.future_value.start = datetime(
            year, month, day, timex_range.begin_hour, 0, 0)
        result.future_value.end = datetime(
            year, month, day, timex_range.end_hour, timex_range.end_min, timex_range.end_min)
        result.past_value.start = result.future_value.start
        result.past_value.end = result.future_value.end

        result.success = True
        return result


import requests
import datetime
from lxml import etree
from io import BytesIO
import sqlite3
import pprint

CBR_URI = 'http://www.cbr.ru/scripts/XML_daily.asp'

class CrawlerModel(object):
    def __init__(self):
        self.currencies = []

    def cbr(self, date=None):
        if date is None:
            date = datetime.datetime.now()
        r = requests.get(CBR_URI)
        c = r.content
        i = BytesIO(c)
        tree = etree.parse(i)

        cs = self.currencies = []
        root = tree.getroot()
        for i in range(len(root)):
            rec = root[i]
            print(etree.tostring(rec, pretty_print=True, encoding=str))

            cs.append(
                (int(rec[0].text),
                 float(rec[4].text.replace(",", "."))))
        # pprint.pprint(cs)
        return self.currencies

class CurrencyStorer(object):
    def __init__(self, filename):
        self.filename = filename
        self.conn = sqlite3.connect(filename)
        self.check_structures()

    def check_structures(self):
        cur = self.conn.cursor()
        cur.execute("""
           CREATE TABLE IF NOT EXISTS rate (
              cur_id int,
              date   date,
              rate   float
           )
        """)

    def store(self, cur_list, date=None):
        if date is None:
            date = datetime.datetime.now()
        cur = self.conn.cursor()
        new_cur_list = ((r[0], date, r[1]) for r in cur_list)
        cur.executemany("INSERT INTO rate VALUES (?, ?, ?)", new_cur_list)
        cur.execute("COMMIT")

    def length(self):
        cur = self.conn.cursor()
        answer = cur.execute("""
             SELECT count(*) as CNT FROM rate
        """)

        for row in answer:
            cnt = row[0]
            return cnt

    def _clean(self):
        cur = self.conn.cursor()
        cur.execute("DELETE FROM rate")
        cur.execute("COMMIT")

class Exporter(object):
    def __init__(self, filename):
        self.filename = filename

    def export(self, curs):
        root = etree.Element("root")
        for code, val in curs:
            c = etree.SubElement(root, "cur", {"id": str(code)})
            c.text = "{:.5f}".format(val)

        doc = etree.ElementTree(root)
        doc.write(self.filename,
                  pretty_print=True,
                  xml_declaration=True,
                  encoding="utf-8")

        return True


import json
from pathlib import Path
from subprocess import check_call
from datetime import datetime
import calendar

import numpy as np

import matplotlib.units as munits
import matplotlib.dates as mdates
import matplotlib.pyplot as plt

munits.registry[np.datetime64] = mdates.ConciseDateConverter()

data = json.loads(Path('processed_data.json').read_text('utf8'))

outdir = Path('plots_CI')
outdir.mkdir(exist_ok=True)

def get_decision_day(month):
    """Return the day of the first Tuesday of the month"""
    d = datetime.strptime(month, '%b-%y')
    return d.replace(day=(1 - d.weekday()) % 7 + 1)

def before_decision_day(date, month):
    """Return whether a date is before interest rate decision day in the given month"""
    d = datetime.strptime(date, '%Y-%m-%d')
    return d < get_decision_day(month)

def date2num(date):
    date = np.datetime64(date)
    # how many months since start of data?
    n_months = (date.astype('datetime64[M]') - np.datetime64('2022-04')).astype(int)
    # what fraction of the month are we through?
    dt = date.astype(datetime)
    n_days_in_month = calendar.monthrange(dt.year, dt.month)[1]
    fraction_of_month = dt.day / n_days_in_month
    return n_months + fraction_of_month

months = [
    'Apr-22',
    'May-22',
    'Jun-22',
    'Jul-22',
    'Aug-22',
    'Sep-22',
    'Oct-22',
    'Nov-22',
    'Dec-22',
    'Jan-23',
    'Feb-23',
    'Mar-23',
    'Apr-23',
    'May-23',
    'Jun-23',
    'Jul-23',
    'Aug-23',
    'Sep-23',
    'Oct-23',
    'Nov-23',
    'Dec-23',
    'Jan-24',
    'Feb-24',
    'Mar-24',
    'Apr-24',
    'May-24',
    'Jun-24',
    'Jul-24',
]

actual_cash_rate = {
    'Apr-22': 0.1,
    'May-22': 0.35,
    'Jun-22': 0.85,
    'Jul-22': 1.35,
    'Aug-22': 1.85,
    'Sep-22': 2.35,
    'Oct-22': 2.60,
    'Nov-22': 2.85,
    'Dec-22': 3.10,
    'Jan-23': 3.10,
    'Feb-23': 3.35,
    'Mar-23': 3.60,
    'Apr-23': 3.60,
}

# Pad data with NaNs:
padded_data = data.copy()
for k, v in data.items():
    padded_data[k] = {month: v.get(month, np.NaN) for month in months}

data = padded_data

plt.figure(figsize=(8, 6))
for i, date in enumerate(data):
    labels = [m.replace('-', '\n') for m in months]

    # Make confidence intervals
    all_predictions = [[] for _ in months]
    for d in list(data)[:i]:
        for j, r in enumerate(data[d].values()):
            if before_decision_day(d, months[j]) and not np.isnan(r):
                all_predictions[j].append(r)

    lower = [np.percentile(x, 25) if x else np.nan for x in all_predictions]
    median = [np.percentile(x, 50) if x else np.nan for x in all_predictions]
    upper = [np.percentile(x, 75) if x else np.nan for x in all_predictions]

    plt.plot(labels, median, 'ko-', label="Interbank futures median")
    plt.fill_between(
        labels,
        lower,
        upper,
        color='k',
        alpha=0.3,
        label=f"Interbank futures interquartile range as of {date}",
        linewidth=0,
    )
    plt.axvline(date2num(date), color='k', linestyle='--')

    y = list(data[date].values())

    plt.plot(
        [a.replace('-', '\n') for a in actual_cash_rate.keys()],
        list(actual_cash_rate.values()),
        'o-',
        label='Actual cash rate target',
        color='C1',
    )

    plt.gca().yaxis.set_major_locator(plt.MultipleLocator(0.2))
    plt.axis(ymin=0, ymax=4.5, xmin=labels[0], xmax=labels[-1])
    plt.grid(True, color='k', alpha=0.5, linestyle=":")
    plt.ylabel("cash rate (%)")
    plt.tight_layout()
    plt.legend(loc='lower right')
    plt.show()
    plt.savefig(outdir / f'{i:04d}.png')
    plt.clf()
    print(i)

# convert to gif
check_call(
    ['convert']
    + [outdir / f'{j:04d}.png' for j in range(1, len(data))]
    + [
        '-delay',
        '500',
        outdir / f'{len(data) - 1:04d}.png',
        'animated-CI.gif',
    ]
)


# coding: utf-8

# $Id: $

# Override lots of classes to prevent blocking on AMQP server connect.

from socket import SOL_TCP
import socket

from amqp import Connection
from amqp import transport
from amqp.utils import set_cloexec, get_errno

# noinspection PyUnresolvedReferences
class NonBlockingMixin(object):
    # noinspection PyMissingConstructor
    def __init__(self, host, connect_timeout):
        # Copy whole constructor from amqp.transport._AbstractTransport to
        # comment out one single line
        self.connected = True
        # noinspection PyUnusedLocal
        msg = None
        port = transport.AMQP_PORT

        m = transport.IPV6_LITERAL.match(host)
        if m:
            host = m.group(1)
            if m.group(2):
                port = int(m.group(2))
        else:
            if ':' in host:
                host, port = host.rsplit(':', 1)
                port = int(port)

        self.sock = None
        last_err = None
        for res in socket.getaddrinfo(host, port, 0,
                                      socket.SOCK_STREAM, SOL_TCP):
            af, socktype, proto, canonname, sa = res
            try:
                self.sock = socket.socket(af, socktype, proto)
                try:
                    set_cloexec(self.sock, True)
                except NotImplementedError:
                    pass
                self.sock.settimeout(connect_timeout)
                self.sock.connect(sa)
            except socket.error as exc:
                msg = exc
                self.sock.close()
                self.sock = None
                last_err = msg
                continue
            break

        if not self.sock:
            # Didn't connect, return the most recent error message
            raise socket.error(last_err)

        try:
            # Here is the magic: disable unlimited timeout while waiting
            # for amqp hello message

            # self.sock.settimeout(None)

            self.sock.setsockopt(SOL_TCP, socket.TCP_NODELAY, 1)
            self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)

            self._setup_transport()

            self._write(transport.AMQP_PROTOCOL_HEADER)
        except (OSError, IOError, socket.error) as exc:
            # noinspection PyProtectedMember
            if get_errno(exc) not in transport._UNAVAIL:
                self.connected = False
            raise

class NonBlockingTCPTransport(NonBlockingMixin, transport.TCPTransport):
    pass

class NonBlockingSSLTransport(NonBlockingMixin, transport.SSLTransport):
    def __init__(self, host, connect_timeout, ssl):
        if isinstance(ssl, dict):
            self.sslopts = ssl
        self._read_buffer = transport.EMPTY_BUFFER
        # Expect NonBlockingMixin.__init__ call
        super(NonBlockingSSLTransport, self).__init__(host, connect_timeout)

def create_transport(host, connect_timeout, ssl=False):
    """Given a few parameters from the Connection constructor,
    select and create a subclass of _AbstractTransport."""
    if ssl:
        return NonBlockingSSLTransport(host, connect_timeout, ssl)
    else:
        return NonBlockingTCPTransport(host, connect_timeout)

class NonBlockingConnection(Connection):
    def Transport(self, host, connect_timeout, ssl=False):
        return create_transport(host, connect_timeout, ssl)


from sqlalchemy import Column, Integer, String, Text

from backend.db.db_init import Base

class Banner(Base):
    """Banner model."""

    __tablename__ = 'banner'

    id = Column(Integer, primary_key=True, index=True)
    title = Column(String(200), index=True)
    description = Column(Text, nullable=True)
    banner_order = Column(Integer, default=0, index=True)
    image_file = Column(Text, nullable=False)

    def __str__(self) -> str:
        return self.title


MENU = {
    "espresso": {
        "ingredients": {
            "water": 50,
            "coffee": 18,
        },
        "cost": 1.5,
    },
    "latte": {
        "ingredients": {
            "water": 200,
            "milk": 150,
            "coffee": 24,
        },
        "cost": 2.5,
    },
    "cappuccino": {
        "ingredients": {
            "water": 250,
            "milk": 100,
            "coffee": 24,
        },
        "cost": 3.0,
    }
}

resources = {
    "water": 300,
    "milk": 200,
    "coffee": 100,
}

def coins():
    print("input money")
    money = int(input("how many quarters: ")) * 0.25
    money += int(input("how many dimes: ")) * 0.1
    money += int(input("how many nickels: ")) * 0.05
    money += int(input("how many pennies: ")) * 0.01
    return money

def check_resourses(sum_ingredients):
    for n in sum_ingredients:
        if sum_ingredients[n] >= resources[n]:
            print("cant make it")
            return 0
    return 1

income = 0
on = 1

while on:
    choice = input("what do you want? espresso, latte, cappucino: ")
    if choice == "off":
        on = 0
    elif choice == "report":
        print(f"water: {resources['water']}ml")
        print(f"milk: {resources['milk']}ml")
        print(f"coffe: {resources['coffee']}g")
        print(f"money: ${income}")
    else:
        drink = MENU[choice]
        if check_resourses(drink["ingredients"]):
            pay = coins()
            if pay < drink["cost"]:
                print("no money")
            else:
                income = drink["cost"]
                print(f"Here is change: {round(pay - drink['cost'], 2)} and you {choice}")
                for n in drink["ingredients"]:
                    resources[n] -= drink["ingredients"][n]


import commands2
from wpilib import SmartDashboard

class TurretInitialize(commands2.CommandBase):

    def __init__(self, container, turret, samples=25) -> None:
        super().__init__()
        self.setName('TurretInitialize')
        self.container = container
        self.turret = turret
        self.samples = samples
        self.data = [0] * self.samples
        self.counter = 0

        self.addRequirements(self.turret)  # commandsv2 version of requirements

    def runsWhenDisabled(self):  # ok to run when disabled - override the base method
        return True

    def initialize(self) -> None:
        """Called just before this Command runs the first time."""
        self.start_time = round(self.container.get_enabled_time(), 2)
        print("\n" + f"** Started {self.getName()} at {self.start_time} s **", flush=True)
        SmartDashboard.putString("alert",
                                 f"** Started {self.getName()} at {self.start_time - self.container.get_enabled_time():2.2f} s **")

        self.data = [0] * self.samples
        self.counter = 0
        SmartDashboard.putBoolean('turret_initialized', False)

    def execute(self) -> None:
        self.data[self.counter % self.samples] = self.turret.analog_abs_encoder.getDistance()
        self.counter += 1

    def isFinished(self) -> bool:
        return self.counter >= self.samples

    def end(self, interrupted: bool) -> None:

        average_encoder_value = sum(self.data) / self.samples
        print(f"Average encoder value is {average_encoder_value}")
        calibrated_angle = average_encoder_value + 57  # our absolute encoder's offset from our zero is 57
        if calibrated_angle > 270:  # keep us within -90 to 270
            calibrated_angle = calibrated_angle - 360
        self.turret.sparkmax_encoder.setPosition(calibrated_angle)
        print(f'set turret sparkmax encoder using {average_encoder_value} to {calibrated_angle}')

        end_time = self.container.get_enabled_time()
        message = 'Interrupted' if interrupted else 'Ended'
        print(f"** {message} {self.getName()} at {end_time:.1f} s after {end_time - self.start_time:.1f} s **")
        SmartDashboard.putString(f"alert", f"** {message} {self.getName()} at {end_time:.1f} s after {end_time - self.start_time:.1f} s **")
        SmartDashboard.putBoolean('turret_initialized', True)


import re
from plib.condition import Condition, ConditionType

class ParserException(Exception):
    pass

class Parser:
    def parse_numbers_from_key(self, text: str) -> list[float]:
        text = f" {text} "
        pattern = re.compile(r"[^\w](\d+)[^\w]")
        numbers = []
        for match in pattern.finditer(text):
            numbers.append(float(match.group(1)))
        return numbers

    def parse_condition(self, text: str) -> list[Condition]:
        pattern = re.compile(r"(<|>|<=|>=|<>|=)\s*(\d+)")
        conditions = []
        for match in pattern.finditer(text):
            condition_type = None
            if match.group(1) == "=":
                condition_type = ConditionType.EQUAL
            elif match.group(1) == ">":
                condition_type = ConditionType.MORE
            elif match.group(1) == "<":
                condition_type = ConditionType.LESS
            elif match.group(1) == ">=":
                condition_type = ConditionType.MORE_EQUAL
            elif match.group(1) == "<=":
                condition_type = ConditionType.LESS_EQUAL
            elif match.group(1) == "<>":
                condition_type = ConditionType.DIFFERENT
            if condition_type != None:
                conditions.append(Condition(condition_type, float(match.group(2))))
        if len(conditions) == 0:
            raise ParserException("bad condition")
        return conditions


"""
@software: PyCharm
@file: DataAnalyse.py
@time: 2020年10月16日22:05:23
@Desc：利用K-Means聚类算法对用户进行分类
"""
import pandas as pd
import numpy as np
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
import matplotlib as mpl
import seaborn as sns
# K-Means聚类算法
mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['font.serif'] = ['SimHei']
sns.set_style("darkgrid",{"font.sans-serif":['SimHei', 'Arial']})
mpl.rcParams['axes.unicode_minus'] = False

datafile = "C:\\Users\lyhoo\Desktop\\air_data.csv"
data = pd.read_csv(datafile, encoding="utf-8")
print(data.shape)
print(data.info())
print(data[0:5])
print(data.loc[2:4, ['GENDER']])

data = data[data["SUM_YR_1"].notnull() & data["SUM_YR_2"].notnull()]
index1 = data["SUM_YR_1"] != 0
index2 = data["SUM_YR_2"] != 0
index3 = (data["SEG_KM_SUM"] == 0) & (data["avg_discount"] == 0)
data = data[index1 | index2| index3]
print(data.shape)

filter_data = data[[ "FFP_DATE", "LOAD_TIME", "FLIGHT_COUNT", "SUM_YR_1", "SUM_YR_2", "SEG_KM_SUM", "AVG_INTERVAL" , "MAX_INTERVAL", "avg_discount"]]
filter_data[0:5]

data["LOAD_TIME"] = pd.to_datetime(data["LOAD_TIME"])
data["FFP_DATE"] = pd.to_datetime(data["FFP_DATE"])
data["入会时间"] = data["LOAD_TIME"] - data["FFP_DATE"]
data["平均每公里票价"] = (data["SUM_YR_1"] + data["SUM_YR_2"]) / data["SEG_KM_SUM"]
data["时间间隔差值"] = data["MAX_INTERVAL"] - data["AVG_INTERVAL"]
deal_data = data.rename(
    columns = {"FLIGHT_COUNT" : "飞行次数", "SEG_KM_SUM" : "总里程", "avg_discount" : "平均折扣率"},
    inplace = False
)
filter_data = deal_data[["入会时间", "飞行次数", "平均每公里票价", "总里程", "时间间隔差值", "平均折扣率"]]
print(filter_data[0:5])
filter_data['入会时间'] = filter_data['入会时间'].astype(np.int64)/(60*60*24*10**9)
print(filter_data[0:5])
print(filter_data.info())

print(filter_data[840:845])
flag1 = filter_data.std(axis=0)
flag2 = filter_data.mean(axis=0)
filter_zscore_data = (filter_data - filter_data.mean(axis=0))/(filter_data.std(axis=0))
print(filter_zscore_data[0:5])

#利用SSE分析K值的选取
def distEclud(vecA, vecB):
    """
    计算两个向量的欧式距离的平方，并返回
    """
    return np.sum(np.power(vecA - vecB, 2))

def test_Kmeans_nclusters(data_train):
    """
    计算不同的k值时，SSE的大小变化
    """
    data_train = data_train.values
    nums = range(2, 10)
    SSE = []
    for num in nums:
        sse = 0
        kmodel = KMeans(n_clusters=num, n_jobs=4)
        kmodel.fit(data_train)
        # 簇中心
        cluster_ceter_list = kmodel.cluster_centers_
        # 个样本属于的簇序号列表
        cluster_list = kmodel.labels_.tolist()
        for index in range(len(data)):
            cluster_num = cluster_list[index]
            sse += distEclud(data_train[index, :], cluster_ceter_list[cluster_num])
        print("簇数是", num, "时； SSE是", sse)
        SSE.append(sse)
    return nums, SSE

nums, SSE = test_Kmeans_nclusters(filter_zscore_data)

#画图，通过观察SSE与k的取值尝试找出合适的k值
# 中文和负号的正常显示
plt.rcParams['font.sans-serif'] = 'SimHei'
plt.rcParams['font.size'] = 12.0
plt.rcParams['axes.unicode_minus'] = False
# 使用ggplot的绘图风格
plt.style.use('ggplot')
## 绘图观测SSE与簇个数的关系
fig=plt.figure(figsize=(10, 8))
ax=fig.add_subplot(1,1,1)
ax.plot(nums,SSE,marker="+")
ax.set_xlabel("n_clusters", fontsize=18)
ax.set_ylabel("SSE", fontsize=18)
fig.suptitle("KMeans", fontsize=20)
plt.show()

kmodel = KMeans(n_clusters=5, n_jobs=4)
kmodel.fit(filter_zscore_data)

# 简单打印结果
r1 = pd.Series(kmodel.labels_).value_counts()  # 统计各个类别的数目
r2 = pd.DataFrame(kmodel.cluster_centers_)  # 找出聚类中心

res0Series = pd.Series(kmodel.labels_)
res0 = res0Series[res0Series.values == 0]
res1 = res0Series[res0Series.values == 1]
res2 = res0Series[res0Series.values == 2]
res3 = res0Series[res0Series.values == 3]
res4 = res0Series[res0Series.values == 4]
people_1 = filter_zscore_data.iloc[res0.index]
people_2 = filter_zscore_data.iloc[res1.index]
people_3 = filter_zscore_data.iloc[res2.index]
people_4 = filter_zscore_data.iloc[res3.index]
people_5 = filter_zscore_data.iloc[res4.index]
print(type(people_1))
outputpath = 'C:\\Users\\lyhoo\\Desktop\\people_1.csv'
people_1.to_csv(outputpath,sep=',',index=True,header=True)
outputpath = 'C:\\Users\\lyhoo\\Desktop\\people_2.csv'
people_2.to_csv(outputpath,sep=',',index=True,header=True)
outputpath = 'C:\\Users\\lyhoo\\Desktop\\people_3.csv'
people_3.to_csv(outputpath,sep=',',index=True,header=True)
outputpath = 'C:\\Users\\lyhoo\\Desktop\\people_4.csv'
people_4.to_csv(outputpath,sep=',',index=True,header=True)
outputpath = 'C:\\Users\\lyhoo\\Desktop\\people_5.csv'
people_5.to_csv(outputpath,sep=',',index=True,header=True)
people_1_1 = people_1*flag1+flag2
people_1_2 = people_2*flag1+flag2
people_1_3 = people_3*flag1+flag2
people_1_4 = people_4*flag1+flag2
people_1_5 = people_5*flag1+flag2
outputpath1 = 'C:\\Users\\lyhoo\\Desktop\\people_1_1.csv'
outputpath2 = 'C:\\Users\\lyhoo\\Desktop\\people_1_2.csv'
outputpath3 = 'C:\\Users\\lyhoo\\Desktop\\people_1_3.csv'
outputpath4 = 'C:\\Users\\lyhoo\\Desktop\\people_1_4.csv'
outputpath5 = 'C:\\Users\\lyhoo\\Desktop\\people_1_5.csv'
people_1_1.to_csv(outputpath1,sep=',',index=True,header=True)
people_1_2.to_csv(outputpath2,sep=',',index=True,header=True)
people_1_3.to_csv(outputpath3,sep=',',index=True,header=True)
people_1_4.to_csv(outputpath4,sep=',',index=True,header=True)
people_1_5.to_csv(outputpath5,sep=',',index=True,header=True)
print(people_1_1)
print(people_1)

print(people_2)
print(people_3)
print(people_4)
print(people_5)

# 聚类图
# 所有簇中心坐标值中最大值和最小值
max = r2.values.max()
min = r2.values.min()
r = pd.concat([r2, r1], axis=1)  # 横向连接（0是纵向），得到聚类中心对应的类别下的数目
r.columns = list(filter_zscore_data.columns) + [u'类别数目']  # 重命名表头

# 绘图
fig = plt.figure(figsize=(10, 8))
ax = fig.add_subplot(111, polar=True)
center_num = r.values
feature = ["入会时间", "飞行次数", "平均每公里票价", "总里程", "时间间隔差值", "平均折扣率"]
N = len(feature)
for i, v in enumerate(center_num):
    # 设置雷达图的角度，用于平分切开一个圆面
    angles = np.linspace(0, 2 * np.pi, N, endpoint=False)
    # 为了使雷达图一圈封闭起来，需要下面的步骤
    center = np.concatenate((v[:-1], [v[0]]))
    angles = np.concatenate((angles, [angles[0]]))
    # 绘制折线图
    ax.plot(angles, center, 'o-', linewidth=2, label="第%d簇人群,%d人" % (i + 1, v[-1]))
    # 填充颜色
    ax.fill(angles, center, alpha=0.25)
    # 添加每个特征的标签
    ax.set_thetagrids(angles * 180 / np.pi, feature, fontsize=15)
    # 设置雷达图的范围
    ax.set_ylim(min - 0.1, max + 0.1)
    # 添加标题
    plt.title('客户群特征分析图', fontsize=20)
    # 添加网格线
    ax.grid(True)
    # 设置图例
    plt.legend(loc='upper right', bbox_to_anchor=(1.3, 1.0), ncol=1, fancybox=True, shadow=True)

# 显示图形
plt.show()


import csv
import os
from dotenv import load_dotenv

def mgmt_level(mgmt_level):
    if ("쉬움" in mgmt_level):
        return 1

    elif ("보통" in mgmt_level):
        return 2

    else:
        return 3

col = ['id', 'kr_name', 'sci_name', 'grw_type', 'grw_speed',
       'min_grw_temp', 'max_grw_temp', 'winter_min_temp',
       'min_humidity', 'max_humidity', 'light_demand',
       'water_cycle', 'mgmt_level', 'mgmt_demand', 'place',
       'mgmt_tip', 'grw_season', 'characteristics',
       'insect_info', 'toxic_info', 'smell_degree', 'height', 'area',
       'description', 'img'
       ]

load_dotenv()

# load urls from list
filename = os.environ.get('OUTPUT_DIR') + 'dry_list.csv'
fr = open(filename, 'r', encoding='utf-8-sig')
reader = csv.reader(fr)

urls = []
for row in reader:
    if row[0] == 'id':
        continue

    urls.append(row[2].split("|")[0])

# load file
filename = os.environ.get('OUTPUT_DIR') + 'dry_preproc_v2.csv'
fr = open(filename, 'r', encoding='utf-8-sig')
reader = csv.reader(fr)

# output file
filename = os.environ.get('OUTPUT_DIR') + 'dry_preproc_v3.csv'
fw = open(filename, 'w', encoding='utf-8-sig', newline='')
writer = csv.writer(fw)

# output columns
writer.writerow(col)

# read line
cnt = 0
for row in reader:
    if row[0] == 'id':
        continue

    cnt += 1
    data = row

    # grw_type
    # data[3] = data[3].split(",")[0]

    if ("반그늘" in data[10]):
        data[10] = 2

    else:
        data[10] = 3

    if ("1 ~2" in data[11] or "두 번" in data[11]):
        data[11] = 53003

    else:
        data[11] = 53004

    data[12] = mgmt_level(data[12])

    data[15] = data[15].replace("\"", "\'")

    data[21] = 25
    data[22] = 30

    data[23] = data[17].replace("\"", "\'")
    data[17] = ""

    data.append(urls[cnt - 1])
    writer.writerow(data)
    print("[%3d] row done : " % (cnt))

print("DONE")


from django.contrib.auth import get_user_model
from django.db import models

User = get_user_model()

class Follow(models.Model):
    user = models.ForeignKey(
        User,
        related_name='follower',
        on_delete=models.CASCADE,
        verbose_name='Подписался кто'
    )
    author = models.ForeignKey(
        User,
        related_name='following',
        on_delete=models.CASCADE,
        verbose_name='Подписан на кого'
    )

    class Meta:
        ordering = ['-id']
        verbose_name = 'Подписка'
        verbose_name_plural = 'Подписки'
        constraints = [
            models.UniqueConstraint(fields=['user', 'author'],
                                    name='unique_follow')
        ]

    def __str__(self):
        return f'{self.user}_on_{self.author}'


# deseasonlize and normalize the wintertime daily mean PM2.5 from 2014 to 2021 in BTH, YRD and PRD regions

import numpy as np
from netCDF4 import Dataset

def moving_avg(data):

    data_avg = np.zeros((91))
    for m in range(0,len(data)-21):
        data_avg[m] = data[m+21]-np.nanmean(data[m:m+21])
    return data_avg

def main():

    file_pm = '/home/lss/data/O3_meteo/PM_process/vc_sta_std/CNEMC/CNEMC_PM25.nc'
    dataset = Dataset(file_pm)
    pm_bth = dataset.variables['PM_bth'][:]
    pm_yrd = dataset.variables['PM_yrd'][:]
    pm_prd = dataset.variables['PM_prd'][:]
    dataset.close()
    PM = np.append(pm_bth,pm_yrd,axis=1)
    PM = np.append(PM,pm_prd,axis=1)

    PM_avg = np.zeros((7,len(PM[0]),91))
    PM_de = np.zeros((7,len(PM[0]),91))
    for j in range(0,len(PM[0])):
        for i in range(0,len(PM)):
            PM_avg[i,j,:] = moving_avg(PM[i,j,:])
        PM_de[0:4,j] = PM_avg[0:4,j]/np.nanstd(PM_avg[0:4,j])
        index = np.where(PM_de[0:4,j]>np.nanpercentile(PM_de[0:4,j],90))
        PM_de[4:,j] = PM_avg[4:,j]/np.nanstd(PM_avg[4:,j])
        index = np.where(PM_de[4:,j]>np.nanpercentile(PM_de[4:,j],90))

    file_output = '/home/lss/data/O3_meteo/PM_process/vc_sta_std/CNEMC/CNEMC_ND_PM25.nc'
    f_w = Dataset(file_output,'w',format='NETCDF4')
    f_w.createDimension('year',7)
    f_w.createDimension('days',91)
    f_w.createDimension('BTH',len(pm_bth[0]))
    f_w.createDimension('YRD',len(pm_yrd[0]))
    f_w.createDimension('PRD',len(pm_prd[0]))
    f_w.createVariable('PM_bth',np.float32,('year','BTH','days'))
    f_w.createVariable('PM_yrd',np.float32,('year','YRD','days'))
    f_w.createVariable('PM_prd',np.float32,('year','PRD','days'))
    f_w.variables['PM_bth'][:] = PM_de[:,0:len(pm_bth[0]),:]
    f_w.variables['PM_yrd'][:] = PM_de[:,len(pm_bth[0]):len(pm_bth[0])+len(pm_yrd[0]),:]
    f_w.variables['PM_prd'][:] = PM_de[:,len(pm_bth[0])+len(pm_yrd[0]):len(pm_bth[0])+len(pm_yrd[0])+len(pm_prd[0]),:]
    f_w.close()

if __name__=='__main__':
    main()


from collections import Counter
from typing import List, Tuple

def major_and_minor_elem(inp: List) -> Tuple[int, int]:
    """Finds the most common and the least common elements in array"""
    c = Counter(inp).most_common()
    most = c[0][0]
    least = c[-1][0]
    return most, least

print(major_and_minor_elem([3, 2, 3, 4, 1, 1, 1, 2, 1, 1]))


#!/usr/bin/python3
def divisible_by_2(my_list=[]):
    """finds all multiples of 2 in a list"""
    length = len(my_list)
    new_cpy = []
    for i in range(length):
        if my_list[i] % 2 == 0:
            new_cpy.append(True)
        else:
            new_cpy.append(False)
    return new_cpy


import operator
import time

from TestCase import *
from Context import FEROL,RU,BU

class case_2x1_corruptedEvents(TestCase):

    def checkIt(self):
        self.checkAppParam('nbCorruptedEvents','unsignedLong',0,operator.eq,"BU")
        self.checkAppParam('nbEventsWithCRCerrors','unsignedLong',0,operator.eq,"BU")

    def runTest(self):
        testDir="/tmp/evb_test/ramdisk"
        self.prepareAppliance(testDir,runNumber=1)
        self.setAppParam('rawDataDir','string',testDir,'BU')
        self.setAppParam('metaDataDir','string',testDir,'BU')
        self.configureEvB()
        self.setAppParam('hltParameterSetURL','string','file://'+testDir,'BU')
        self.enableEvB(runNumber=1)
        self.checkEVM(8192)
        self.checkRU(8192)
        self.checkBU(16384)
        self.checkIt()

        sys.stdout.write("Corrupt an event on FED 2 - tolerating")
        sys.stdout.flush()
        self.setAppParam('corruptNbEvents','unsignedInt','1','FEROL',2)
        self.waitForAppState("MissingData","EVM")
        print(" done")
        self.checkAppState("Enabled","RU")
        self.checkAppState("Enabled","BU")
        self.checkEVM(6144)
        self.checkRU(8192)
        self.checkBU(14336)
        self.checkIt()
        dumps = self.getFiles("dump_run000001_event[0-9]+_fed0002.txt$",app="EVM")
        if len(dumps) != 1:
            raise ValueException("Expected one dump file from FED 2, but found: "+str(dumps))

        sys.stdout.write("Corrupt 2 events on FED 7 - not tolerating")
        sys.stdout.flush()
        self.setAppParam('corruptNbEvents','unsignedInt','2','FEROL',7)
        self.waitForAppState("Failed","RU")
        print(" done")
        self.checkAppState("MissingData","EVM")
        self.checkAppState("Enabled","BU")
        dumps = self.getFiles("dump_run000001_event[0-9]+_fed0007.txt$",app="EVM")
        if len(dumps) != 1:
            raise ValueException("Expected one dump file from FED 7, but found: "+str(dumps))

        self.haltEvB()
        self.checkBuDir(testDir,"000001")

        self.configureEvB()
        self.enableEvB(runNumber=2)
        self.checkEVM(8192)
        self.checkRU(8192)
        self.checkBU(16384)
        self.checkIt()
        sys.stdout.write("Corrupt an event on FED 1 - tolerating")
        sys.stdout.flush()
        self.setAppParam('corruptNbEvents','unsignedInt','1','FEROL',1)
        self.waitForAppState("MissingData","EVM")
        print(" done")
        self.checkAppState("Enabled","RU")
        self.checkAppState("Enabled","BU")
        self.checkEVM(6144)
        self.checkRU(8192)
        self.checkBU(14336)
        self.checkIt()
        dumps = self.getFiles("dump_run000001_event[0-9]+_fed0002.txt$",app="EVM")
        if len(dumps) != 1:
            raise ValueException("Expected one dump file from FED 2, but found: "+str(dumps))
        self.sendResync()
        self.checkAppState("Enabled","EVM")
        self.checkAppState("Enabled","RU")
        self.checkAppState("Enabled","BU")
        self.checkEVM(8192)
        self.checkRU(8192)
        self.checkBU(16384)
        self.checkIt()
        self.stopEvB()
        self.checkBuDir(testDir,"000002")

    def fillConfiguration(self,symbolMap):
        evm = RU(symbolMap,[
             ('inputSource','string','Socket'),
             ('checkCRC','unsignedInt','0'),
             ('tolerateCorruptedEvents','boolean','true'),
             ('fakeLumiSectionDuration','unsignedInt','5')
            ])
        for id in range(0,4):
            self._config.add( FEROL(symbolMap,evm,id) )

        ru = RU(symbolMap,[
             ('inputSource','string','Socket'),
             ('checkCRC','unsignedInt','0'),
             ('tolerateCorruptedEvents','boolean','false')
            ])
        for id in range(4,8):
            self._config.add( FEROL(symbolMap,ru,id) )

        self._config.add( evm )
        self._config.add( ru )

        self._config.add( BU(symbolMap,[
             ('checkCRC','unsignedInt','1'),
             ('staleResourceTime','unsignedInt','0'),
             ('lumiSectionTimeout','unsignedInt','6'),
             ('numberOfBuilders','unsignedInt','2')
            ]) )


import allure
import pytest
import requests
from jsonschema import validate
from urllib.parse import urljoin

@pytest.mark.parametrize('id_post, id_user', [(1, 1), (12, 2), (25, 3)], ids=['post 1 user 1',
                                                                              'post 12 user 2',
                                                                              'post 25 user 3'])
def test_positive_update_resource(request, base_url, id_post, id_user):
    allure.dynamic.title(f'Позитивный тест обновления ресурса [{request.node.callspec.id}]')
    headers = {'Content-type': 'application/json; charset=UTF-8'}
    json = {
        'id': id_post,
        'title': 'foo',
        'body': 'bar',
        'userId': id_user
    }

    response = requests.put(url=urljoin(base_url, str(id_post)), headers=headers, json=json)
    assert response.status_code == 200

    schema = {
        'type': 'object',
        'properties': {
            'userId': {'type': 'number'},
            'id': {'type': 'number'},
            'title': {'type': 'string'},
            'body': {'type': 'string'}
        },
        'required': ['userId', 'id', 'title', 'body']
    }

    validate(instance=response.json(), schema=schema)
    assert response.json().get('title') == json['title']
    assert response.json().get('body') == json['body']
    assert response.json().get('userId') == id_user
    assert response.json().get('id') == id_post

@pytest.mark.parametrize('id_post, id_user, expected_status_code', [(0, 1, 404),
                                                                    (101, 10, 404),
                                                                    ('id', 3, 400),
                                                                    ('', 1, 400)],
                         ids=['post 0 user 1',
                              'post 101 user 10',
                              'post string user 3',
                              'post empty user 1'])
def test_negative_update_resource(request, base_url, id_post, id_user, expected_status_code):
    allure.dynamic.title(f'Негативный тест обновления ресурса [{request.node.callspec.id}]')
    headers = {'Content-type': 'application/json; charset=UTF-8'}
    json = {
        'id': id_post,
        'title': 'foo',
        'body': 'bar',
        'userId': id_user
    }

    response = requests.put(url=urljoin(base_url, str(id_post)), headers=headers, json=json)
    assert response.status_code == expected_status_code


# -*- coding: utf-8 -*-
from .utils import (filter_out_result,
                    is_stream,
                    name_parser_factory,
                    no_return,
                    Param,
                    remove_subscribe,
                    type_info_factory)

class Method(object):
    """ Method """

    def __init__(
            self,
            plugin_name,
            package,
            is_server,
            method_description,
            pb_method,
            requests,
            responses):
        self._no_return = False
        self._has_result = False
        self._returns = False
        self._plugin_name = name_parser_factory.create(plugin_name)
        self._package = name_parser_factory.create(package)
        self._is_server = is_server
        self._method_description = method_description
        self._name = name_parser_factory.create(pb_method.name)
        self.extract_params(pb_method, requests)
        self.extract_return_type_and_name(pb_method, responses)
        self.extract_async_type(pb_method)
        self.extract_is_finite(pb_method)

    def extract_params(self, pb_method, requests):
        method_input = pb_method.input_type.split(".")[-1]
        request = requests[method_input]['struct']
        params_description = requests[method_input]['docs']['params']

        self._params = []

        field_id = 0
        for field in request.field:
            self._params.append(
                Param(
                    name=name_parser_factory.create(field.name),
                    type_info=type_info_factory.create(field),
                    description=params_description[field_id])
            )

            field_id += 1

    def extract_return_type_and_name(self, pb_method, responses):
        method_output = pb_method.output_type.split(".")[-1]
        response = responses[method_output]['struct']
        response_docs = responses[method_output]['docs']

        return_params = list(
            filter_out_result(
                response.field,
                response_docs['params']))

        if len(return_params) < len(response.field):
            self._has_result = True

        if len(return_params) > 1:
            raise Exception(
                "Responses cannot have more than 1 return parameter" +
                f" (and an optional '*Result')!\nError in {method_output}")

        if len(return_params) == 1:
            self._return_type = type_info_factory.create(
                return_params[0]['field'])
            self._return_name = name_parser_factory.create(
                return_params[0]['field'].json_name)
            self._return_description = return_params[0]['docs']
        elif len(return_params) == 0 and self.return_type_required:
            raise Exception(
                "This response must have 1 return parameter" +
                f" (and an optional '*Result')!\nError in {method_output}")

    def extract_async_type(self, pb_method):
        self._is_sync = True
        self._is_async = True

        for option_line in pb_method.options.__str__().splitlines():
            if "[mavsdk.options.async_type]" in option_line:
                async_type = option_line.split(':')[-1].strip()

                if async_type == "SYNC":
                    self._is_async = False
                elif async_type == "ASYNC":
                    self._is_sync = False

    def extract_is_finite(self, pb_method):
        self._is_finite = False

        for method_descriptor in pb_method.options.Extensions:
            if method_descriptor.name == "is_finite":
                self._is_finite = pb_method.options.Extensions[method_descriptor]

    @property
    def no_return(self):
        return self._no_return

    @property
    def returns(self):
        return self._returns

    @property
    def plugin_name(self):
        return self._plugin_name

    @property
    def package(self):
        return self._package

    @property
    def is_server(self):
        return self._is_server

    @property
    def name(self):
        return self._name

    @property
    def params(self):
        return self._params

    @property
    def return_type_required(self):
        return False

    @property
    def method_description(self):
        return self._method_description

    @staticmethod
    def collect_methods(
            plugin_name,
            package,
            is_server,
            docs,
            methods,
            structs,
            requests,
            responses,
            template_env):
        """ Collects all methods for the plugin """
        _methods = {}

        method_id = 0
        for method in methods:
            # Extract method description
            method_description = docs['methods'][method_id].strip()

            # Check if stream
            if (is_stream(method)):
                _methods[method.name] = Stream(plugin_name,
                                               package,
                                               is_server,
                                               method_description,
                                               template_env,
                                               method,
                                               requests,
                                               responses)

            # Check if method is just a call
            elif (no_return(method, responses)):
                _methods[method.name] = Call(plugin_name,
                                             package,
                                             is_server,
                                             method_description,
                                             template_env,
                                             method,
                                             requests,
                                             responses)

            else:
                _methods[method.name] = Request(plugin_name,
                                                package,
                                                is_server,
                                                method_description,
                                                template_env,
                                                method,
                                                requests,
                                                responses)

            method_id += 1

        return _methods

    def __repr__(self):
        return "method: {}".format(self._name)

class Call(Method):
    """ A call method doesn't return any value, but either succeeds or fails
    """

    def __init__(
            self,
            plugin_name,
            package,
            is_server,
            method_description,
            template_env,
            pb_method,
            requests,
            responses):
        super().__init__(
            plugin_name,
            package,
            is_server,
            method_description,
            pb_method,
            requests,
            responses)
        try:
            self._template = template_env.get_template("call.j2")
        except:
            self._template = None
        self._no_return = True

    @property
    def is_call(self):
        return True

    def __repr__(self):
        return self._template.render(name=self._name,
                                     params=self._params,
                                     plugin_name=self._plugin_name,
                                     package=self._package,
                                     is_server=self._is_server,
                                     method_description=self._method_description,
                                     has_result=self._has_result,
                                     is_async=self._is_async,
                                     is_sync=self._is_sync)

class Request(Method):
    """ Requests a value """

    def __init__(
            self,
            plugin_name,
            package,
            is_server,
            method_description,
            template_env,
            pb_method,
            requests,
            responses):
        super().__init__(
            plugin_name,
            package,
            is_server,
            method_description,
            pb_method,
            requests,
            responses)
        try:
            self._template = template_env.get_template("request.j2")
        except:
            self._template = None
        self._method_description = method_description
        self._returns = True

    @property
    def is_request(self):
        return True

    @property
    def return_name(self):
        return self._return_name

    @property
    def return_type(self):
        return self._return_type

    @property
    def return_description(self):
        return self._return_description

    def __repr__(self):
        return self._template.render(
            name=self._name,
            params=self._params,
            return_type=self._return_type,
            return_name=self._return_name,
            return_description=self._return_description,
            plugin_name=self._plugin_name,
            package=self._package,
            is_server=self.is_server,
            method_description=self._method_description,
            has_result=self._has_result,
            is_async=self._is_async,
            is_sync=self._is_sync)

class Stream(Method):
    """ A stream of values """

    def __init__(
            self,
            plugin_name,
            package,
            is_server,
            method_description,
            template_env,
            pb_method,
            requests,
            responses):
        super().__init__(
            plugin_name,
            package,
            is_server,
            method_description,
            pb_method,
            requests,
            responses)
        self._name = name_parser_factory.create(
            remove_subscribe(pb_method.name))
        try:
            self._template = template_env.get_template("stream.j2")
        except:
            self._template = None

    @property
    def return_type_required(self):
        return True

    @property
    def is_stream(self):
        return True

    @property
    def return_name(self):
        return self._return_name

    @property
    def return_type(self):
        return self._return_type

    @property
    def return_description(self):
        return self._return_description

    def __repr__(self):
        return self._template.render(
            name=self._name,
            params=self._params,
            return_type=self._return_type,
            return_name=self._return_name,
            return_description=self._return_description,
            plugin_name=self._plugin_name,
            package=self._package,
            is_server=self._is_server,
            method_description=self._method_description,
            has_result=self._has_result,
            is_async=self._is_async,
            is_sync=self._is_sync,
            is_finite=self._is_finite)


from PyQt5.QtWidgets import QComboBox

from view import AddThesisView
from protocols import AddModifyViewDelegate

class ModifyThesisView(AddThesisView):
    def __init__(self, parent, delegate: AddModifyViewDelegate = None):
        AddThesisView.__init__(self, parent, delegate=delegate, title_prefix="Modyfikacja")
        self._set_up_initial_values(
            line_edit_values=self._line_edit_values(),
            combo_box_values=self._combo_box_values(),
            list_view_values=self._list_view_values()
        )

    def _set_up_general(self):
        AddThesisView._set_up_general(self)
        self._fields = [("Praca Dyplomowa", QComboBox)] + self._fields
        self._combo_box_items = [self._theses] + self._combo_box_items

    @property
    def _theses(self):
        results = self._db_manager.query(f"""
                SELECT tytul FROM PraceDyplomowe
                """)
        return (result[0] for result in results)

    def _line_edit_values(self):
        results = self._db_manager.query(f"""
        SELECT tytul, STRING_AGG(slowoKluczowe, ', ') FROM PraceDyplomowe
            LEFT JOIN SlowaKluczowePracy SKP on PraceDyplomowe.id_praca = SKP.id_praca
            LEFT JOIN SlowaKluczowe SK on SKP.id_slowoKluczowe = SK.id_slowoKluczowe
        GROUP BY tytul
        HAVING tytul = '{self._editable_fields["Praca Dyplomowa"].currentText().split(" - ")[0]}'
        """)
        return [value for value in results[0]]

    def _combo_box_values(self):
        results = self._db_manager.query(f"""
                SELECT nazwaRodzaju, nazwaWydzialu, nazwaKierunku, CONCAT(imie, ' ', nazwisko)
                FROM RodzajStudiow
                    LEFT JOIN KierunekStudiow KS on RodzajStudiow.id_rodzajStudiow = KS.id_rodzajStudiow
                    LEFT JOIN PraceDyplomowe PD on KS.id_kierunek = PD.id_kierunekStudiow
                    LEFT JOIN PracownicyNaukowi PN on PD.id_promotor = PN.id_pracownikNaukowy
                    LEFT JOIN Katedra K on KS.id_katedra = K.id_Katedra
                    LEFT JOIN Wydzial W on K.id_Wydzial = W.id_Wydzial
                WHERE tytul = '{self._editable_fields["Praca Dyplomowa"].currentText()}'
                """)
        return [self._editable_fields["Praca Dyplomowa"].currentText()] + [value for value in results[0]]

    def _list_view_values(self):
        authors = [author[0] for author in self._db_manager.query(f"""
                SELECT CONCAT(imie, ' ', nazwisko) FROM Studenci
                LEFT JOIN AutorzyPracy AP on Studenci.id_student = AP.id_student
                LEFT JOIN PraceDyplomowe PD on AP.id_praca = PD.id_praca
                WHERE PD.tytul = '{self._editable_fields["Praca Dyplomowa"].currentText()}'
                """)]
        reviewers = [reviewer[0] for reviewer in self._db_manager.query(f"""
                SELECT CONCAT(imie, ' ', nazwisko) FROM PracownicyNaukowi
                    LEFT JOIN Recenzja R on PracownicyNaukowi.id_pracownikNaukowy = R.id_recenzujacy
                    LEFT JOIN PraceDyplomowe PD on PracownicyNaukowi.id_pracownikNaukowy = R.id_recenzujacy
                WHERE PD.tytul = '{self._editable_fields["Praca Dyplomowa"].currentText()}'
                """)]
        return [authors, reviewers]


# -*- coding: UTF-8 -*-
#
# Heap Sort Algorithm
# The All ▲lgorithms library for python
#
# Contributed by: DatHydroGuy
# Github: @DatHydroGuy
#

def build_heap(array_to_sort, array_length, index):
    """
    Build a heap, where each node has two child nodes, and a root node is greater than both child nodes.
    """
    largest = index         # Flag the largest element as the last (root) element
    left = 2 * index + 1    # Calculate index of left child node
    right = 2 * index + 2   # Calculate index of right child node

    # See if left child of root exists and is greater than root
    if left < array_length and array_to_sort[index] < array_to_sort[left]:
        largest = left

    # See if right child of root exists and is greater than root
    if right < array_length and array_to_sort[largest] < array_to_sort[right]:
        largest = right

    # If a larger element than root was found, swap with root so that root holds the new largest value
    if largest != index:
        array_to_sort[index], array_to_sort[largest] = array_to_sort[largest], array_to_sort[index]  # swap

        # Re-build the heap under the new largest root node
        build_heap(array_to_sort, array_length, largest)

def heap_sort(array_to_sort):
    """
    Builds a max-heap, then continuously removes the largest element and re-builds the heap until sorted
    """
    array_length = len(array_to_sort)

    # Build a max-heap to sort the elements into order
    for index in range(array_length // 2 - 1, -1, -1):
        build_heap(array_to_sort, array_length, index)

    # One by one extract elements
    for index in range(array_length - 1, 0, -1):
        array_to_sort[index], array_to_sort[0] = array_to_sort[0], array_to_sort[index]  # swap
        build_heap(array_to_sort, index, 0)


import html
import re
from datetime import datetime

import pdfminer.high_level
import requests
from requests import Response

import categories
from message_handler import MessageHandler
from utils import cd, temporary_locale

class BoltMessageHandler(MessageHandler):
    def get_type(self):
        return categories.TRANSPORT

    def get_query_params(self):
        return {
            self.SUBJECT: "Your Bolt Scooter ride",
        }

    def handle_html(self, html_str: str):
        """neither
        root = etree.fromstring(html_str)
        tree = etree.ElementTree(root)
        (https://bugs.launchpad.net/lxml/+bug/1902364)

        nor

        root = etree.HTML(html_str)
        tree = etree.ElementTree(root)
        (https://bugs.launchpad.net/lxml/+bug/1854057)

        worked. Falling back to regex.
        """
        purchase_date: str = re.search(r"\d{4}-\d\d-\d\d", html_str)[0]
        self.purchase_date = datetime.strptime(purchase_date, "%Y-%m-%d")
        url: str = re.search(
            r"(https://doclink.live.boltsvc.net/invoice/pdf[^\"]+)", html_str
        )[0]
        url: str = html.unescape(url)
        response: Response = requests.get(url)
        if response.status_code != 200:
            raise Exception(f"Could not download {url}")
        self.filename = (
            f"{self.get_category_key()}_{self.purchase_date.strftime('%Y%m%d')}_"
            f"{datetime.now().strftime('%H%M%S')}.pdf"
        )
        with cd(self.receipts_dir), open(self.filename, "wb") as f:
            f.write(response.content)
            self.extract_txt(self.filename)

    def extract_txt(self, pdffile: str):
        with temporary_locale("en_US"):
            text = pdfminer.high_level.extract_text(pdffile)
            purchase_date = re.findall(r"\n\nDate: (\d{4}-\d\d-\d\d)\n\n", text)[0]
            self.purchase_date = datetime.strptime(purchase_date, "%Y-%m-%d")
            self.amount = float(list(re.findall(r"\s\d+\.\d+\s", text))[-1])


from enum import Enum

class Juiz:
    @classmethod
    def julgar_vencedor(cls, input_jogador1, input_jogador2):
        if input_jogador1 == input_jogador2:
            return 0

        if input_jogador1 == "pedra":
            if input_jogador2 == "papel":
                return 2
            if input_jogador2 == "tesoura":
                return 1
        if input_jogador1 == "papel":
            if input_jogador2 == "pedra":
                return 1
            if input_jogador2 == "tesoura":
                return 2
        if input_jogador1 == "tesoura":
            if input_jogador2 == "papel":
                return 1
            if input_jogador2 == "pedra":
                return 2

class PedraPapelTesoura:
    input_tipos = ["pedra", "papel", "tesoura", "fim"]

    @classmethod
    def _get_input_jogador(cls, ):
        input_jogador = None
        while input_jogador not in cls.input_tipos:
            input_jogador = input().lower()
            if input_jogador not in cls.input_tipos:
                print(f"Input inválido. Tente: {cls.input_tipos}")
        return input_jogador

    @classmethod
    def jogar(cls, ):

        pararJogo = False
        while not pararJogo:
            print("===================")
            print("Input (Jogador 1):")
            input_jogador1 = cls._get_input_jogador()
            print("Input (Jogador 2):")
            input_jogador2 = cls._get_input_jogador()
            print("===================")
            if input_jogador1 == "fim" or input_jogador2 == "fim":
                print("Finalizando jogo")
                pararJogo = True
            else:
                vencedor = Juiz.julgar_vencedor(input_jogador1, input_jogador2)
                if vencedor == 0:
                    print("Empate")
                else:
                    print(f"Jogador {vencedor}")

if __name__ == "__main__":
    PedraPapelTesoura.jogar()


# -*- coding:utf-8 -*-
import tkinter
import threading
import pyaudio
import wave
import transcription
import summarization

start_flag = False
quitting_flag = False
count = 0

def recording():
    global label
    global start_flag
    global quitting_flag
    global count

    CHUNK = 2**10
    FORMAT = pyaudio.paInt16
    CHANNELS = 1
    RATE = 44100
    output_path = "./output.wav"

    p = pyaudio.PyAudio()
    stream = p.open(format=FORMAT,
                    channels=CHANNELS,
                    rate=RATE,
                    input=True,
                    frames_per_buffer=CHUNK)

    frames = []

    while not quitting_flag: #ボタン側で操作する
        if start_flag:
            data = stream.read(CHUNK)
            frames.append(data)
            label.config(text=count)
            count += 1

    print("Done.")

    stream.stop_stream()
    stream.close()
    p.terminate()

    # 録音データの保存
    wf = wave.open(output_path, 'wb')
    wf.setnchannels(CHANNELS)
    wf.setsampwidth(p.get_sample_size(FORMAT))
    wf.setframerate(RATE)
    wf.writeframes(b''.join(frames))
    wf.close()

    # whisperによる文字起こし
    sount2text = transcription.transcription()

    # 要約する
    summary = summarization.summarize(sount2text)
    sorted_summary = sorted(summary['scoring_data'], reverse=True, key=lambda x:x[1])
    # 重要度が高い順の5つの文を表示
    for x in range(5):
        index = sorted_summary[x][0]
        print(summary["summarize_result"][index])

# スタートボタンが押された時の処理
def start_button_click(event):
    global start_flag
    global count

    count = 0
    start_flag = True

# ストップボタンが押された時の処理
def stop_button_click(event):
    global start_flag
    global quitting_flag

    start_flag = False
    quitting_flag = True
    # thread1終了まで待つ
    # thread1.join()

# 終了ボタンが押された時の処理
def quit_app():
    global quitting_flag
    global app
    global thread1

    quitting_flag = True

    # thread1終了まで待つ
    thread1.join()

    # # thread1終了後にアプリ終了
    app.destroy()

# メインウィンドウを作成
app = tkinter.Tk()
app.state('zoomed') # フルスクリーン表示

# ボタンの作成と配置
start_button = tkinter.Button(
    app,
    text="録音開始",
)
start_button.pack()

stop_button = tkinter.Button(
    app,
    text="録音終了",
)
stop_button.pack()

# ラベルの作成と配置
label = tkinter.Label(
    app,
    width=5,
    height=1,
    text=0,
    font=("", 20)
)
label.pack()

# イベント処理の設定
start_button.bind("<ButtonPress>", start_button_click)
stop_button.bind("<ButtonPress>", stop_button_click)
app.protocol("WM_DELETE_WINDOW", quit_app)

#　スレッドの生成と開始
thread1 = threading.Thread(target=recording)
thread1.start()

# メインループ
app.mainloop()


import Ice, sys, glob, os, Tartarus

from Tartarus import logging

path = []
trace = 0

_orig_import = __import__
_loaded_modules = {}

# Trailing dot reqiured:
_MOD_PREFIX = "Tartarus.iface."
_MOD_PREFIX_LEN = len(_MOD_PREFIX)

def load(name):
    """Load Tartarus interface.

    Name is in form ModName.SubModName.SubModName ...

    This function finds directory ModName in n Tartarus.slices.path and loads
    all slice files from it in hope that it makes module Tartarus.iface.<name>
    avaliable.
    """
    global path

    # append default path if needed.
    if len(path) == 0:
        path = [os.path.join(sys.prefix, 'share', 'Tartarus', 'slice') ]

    period = name.find(".")
    if period > 0:
        modname = name[:period]
    else:
        modname = name

    if modname in _loaded_modules:
        logging.trace(__name__,
                "Found %s interface in cache" % modname, trace >= 4)
        return

    logging.trace(__name__, "Loading %s interface" % modname, trace)

    mpath = None
    for p in path:
        test = os.path.join(p, modname)
        if os.path.isdir(test):
            mpath = test
            break

    logging.trace(__name__,
            "In path %s found dir %s" % (path, mpath), trace >= 16)

    if mpath is None:
        raise RuntimeError(
                "Could not find module '%s' in path %s" %
                (modname, path))

    files = glob.glob(os.path.join(mpath, "*.ice"))
    logging.trace(__name__, "Loading slices: %s" % files, trace >= 16)
    Ice.loadSlice("--all -I%s"  % mpath, [ "-I%s" % d for d in path ] + files)
    _loaded_modules[ modname ] = sys.modules[_MOD_PREFIX + modname]

def tartarus_import(*args):
    """This function is used as import hook in Tartarus."""

    name = args[0]
    if len(args) > 3:
        fromlist = args[3]
    else:
        fromlist = None

    logging.trace(__name__,
            "Import hook invoked for name '%s', fromlist = %s"
                % (name, fromlist),
            trace >= 16)
    if name.startswith(_MOD_PREFIX):
        try:
            mname = name[_MOD_PREFIX_LEN:]
            load(mname)
        except Exception:
            pass

    elif name == _MOD_PREFIX[:-1] and fromlist is not None:
        # import in form "from $_MOD_PREFIX import ModuleName1, ModuleName2"
        for mname in fromlist:
            try:
                load(mname)
            except Exception:
                pass

    return _orig_import(*args)

def setup_import_hook():
    """Setup hook on __import__.

    This function installs hook on builtin __import__ function,
    which enables autoloading slice files from Tartarus.
    """
    import __builtin__
    __builtin__.__import__ = tartarus_import


#!/usr/bin/env python3
import numpy as np
import matplotlib.pyplot as plt

from scipy.constants import epsilon_0

epsilon = 1#epsilon_0
N = 1000
dr = 1
r = dr*np.linspace(0,N-1,N)
Er = np.zeros(N)

def rho(r):
	if r < 250:
		return epsilon
	else:
		return 0

for i in range(N-1):
	Er[i+1] = dr*rho(r[i+1])/epsilon+(1-2*dr/r[i+1])*Er[i]

fig = plt.figure()
ax = fig.add_subplot(111)
l1 = ax.plot(r, Er)
plt.show()