import operator
import time
from collections import defaultdict
from functools import reduce
from typing import Dict, List

from django.utils.translation import ugettext as _
from django.utils.translation import ugettext_lazy as _lazy
from elasticsearch_dsl import Q
from fta_web.alert.handlers.base import (
    AlertDimensionFormatter,
    BaseBizQueryHandler,
    BaseQueryTransformer,
    QueryField,
)
from fta_web.alert.handlers.translator import (
    AbstractTranslator,
    ActionPluginTypeTranslator,
    ActionSignalTranslator,
    BizTranslator,
)

from bkmonitor.documents import ActionInstanceDocument, AlertDocument
from bkmonitor.models import ActionPlugin, ConvergeRelation
from bkmonitor.utils.time_tools import hms_string
from constants.action import (
    ACTION_DISPLAY_STATUS_CHOICES,
    ACTION_DISPLAY_STATUS_DICT,
    ActionDisplayStatus,
    ActionSignal,
    ConvergeStatus,
)
from constants.alert import EVENT_SEVERITY

class ActionQueryTransformer(BaseQueryTransformer):
    VALUE_TRANSLATE_FIELDS = {
        "alert_level": EVENT_SEVERITY,
        "status": ACTION_DISPLAY_STATUS_CHOICES,
    }

    query_fields = [
        QueryField("id", _lazy("处理记录ID"), is_char=True),
        QueryField("converge_id", _lazy("收敛记录ID")),
        QueryField("is_converge_primary", _lazy("是否为收敛关键记录")),
        QueryField("status", _lazy("状态")),
        QueryField("failure_type", _lazy("失败类型")),
        QueryField("ex_data", _lazy("异常信息"), searchable=False),
        QueryField("strategy_id", _lazy("策略ID")),
        QueryField("strategy_name", _lazy("策略名称"), agg_field="strategy_name.raw", is_char=True),
        QueryField("signal", _lazy("触发信号")),
        QueryField("alert_id", _lazy("告警ID")),
        QueryField("alert_level", _lazy("告警级别")),
        QueryField("operator", _lazy("负责人")),
        QueryField("inputs", _lazy("动作输入"), searchable=False),
        QueryField("outputs", _lazy("动作输出"), searchable=False),
        QueryField("failure_type", _lazy("动作输入")),
        QueryField("execute_times", _lazy("执行次数")),
        QueryField("action_plugin_type", _lazy("套餐类型")),
        QueryField("action_plugin", _lazy("套餐插件快照"), searchable=False),
        QueryField("action_name", _lazy("套餐名称"), agg_field="action_name.raw", is_char=True),
        QueryField("action_config", _lazy("套餐配置"), searchable=False),
        QueryField("action_config_id", _lazy("套餐ID")),
        QueryField("is_parent_action", _lazy("是否为子任务")),
        QueryField("related_action_ids", _lazy("关联的任务ID")),
        QueryField("parent_action_id", _lazy("父记录ID")),
        QueryField("create_time", _lazy("创建时间")),
        QueryField("update_time", _lazy("更新时间")),
        QueryField("end_time", _lazy("结束时间")),
        QueryField("bk_target_display", _lazy("目标")),
        QueryField("bk_biz_id", _lazy("业务ID")),
        QueryField("bk_biz_name", _lazy("业务名称"), is_char=True),
        QueryField("bk_set_ids", _lazy("集群ID")),
        QueryField("bk_set_names", _lazy("集群名称")),
        QueryField("bk_module_ids", _lazy("模块ID")),
        QueryField("bk_module_names", _lazy("模块名称")),
        QueryField("raw_id", _lazy("原始ID")),
        QueryField("duration", _lazy("处理时长")),
        QueryField("operate_target_string", _lazy("执行对象")),
        QueryField("content", _lazy("处理内容"), searchable=False),
        QueryField("dimensions", _lazy("维度信息"), searchable=False),
    ]

class ActionQueryHandler(BaseBizQueryHandler):
    """
    动作查询
    """

    query_transformer = ActionQueryTransformer
    CONST_MINUTES = 60

    def __init__(
        self,
        bk_biz_ids: List[int] = None,
        alert_ids: List[str] = None,
        status: List[str] = None,
        parent_action_id=None,
        username: str = "",
        **kwargs,
    ):
        super(ActionQueryHandler, self).__init__(bk_biz_ids, username, **kwargs)
        self.alert_ids = alert_ids
        self.status = [status] if isinstance(status, str) else status
        self.search_parent_action_id = None
        self.raw_id = None
        self.search_collect_action = False
        self.start_time = self.start_time or 0
        self.end_time = self.end_time or 0

        if not self.ordering:
            # 默认排序
            self.ordering = ["-create_time"]

        if parent_action_id:
            parent_action = ActionInstanceDocument.get(id=parent_action_id)
            if not parent_action:
                return

            # 搜索范围内在当前任务创建的前后一分钟，保证所有的汇总任务能搜索到
            self.start_time = parent_action.create_time - self.CONST_MINUTES
            self.end_time = parent_action.end_time + self.CONST_MINUTES if parent_action.end_time else int(time.time())

            if parent_action.is_parent_action:
                if self.alert_ids:
                    self.alert_ids.extend(parent_action.alert_id)
                else:
                    self.alert_ids = parent_action.alert_id
                self.search_parent_action_id = parent_action.raw_id
                self.search_collect_action = True
            else:
                self.raw_id = parent_action.raw_id

        if self.alert_ids:
            # 如果给了 告警ID，则时间范围按 告警起止时间进行查询
            alerts = AlertDocument.mget(self.alert_ids, fields=["create_time", "update_time"])
            now_ts = int(time.time())
            start_time = 0
            end_time = now_ts
            for alert in alerts:
                start_time = max(start_time, alert.create_time)
                if alert.end_time:
                    end_time = min(end_time, alert.update_time)
            self.start_time = max(self.start_time, start_time)
            self.end_time = max(self.end_time, end_time)

    def get_exclude_parent_search_object(self, search_object):
        """
        根据条件判断是否需要排除
        :param search_object:
        :return:
        """
        for condition in self.conditions:
            if condition["key"] == "parent_action_id":
                values = [int(v) for v in condition["value"]]
                if 0 in values:
                    return search_object.exclude("term", signal="collect")
        return search_object.exclude("term", is_parent_action=True)

    def get_search_object(self, start_time: int = None, end_time: int = None):
        start_time = start_time or self.start_time
        end_time = end_time or self.end_time

        search_object = ActionInstanceDocument.search(start_time=self.start_time, end_time=self.end_time)
        search_object = self.get_exclude_parent_search_object(search_object)

        if self.search_parent_action_id and self.search_collect_action:
            search_object = search_object.filter(
                Q("term", parent_action_id=self.search_parent_action_id) | Q("term", signal=ActionSignal.COLLECT)
            )

        if self.raw_id:
            search_object = search_object.filter("term", raw_id=self.raw_id)

        search_object = self.add_biz_condition(search_object)

        if self.username:
            search_object = search_object.filter("term", operator=self.username)

        if start_time and end_time and not self.alert_ids:
            # 没有传告警ID才需要限定时间范围，否则会导致返回的处理记录不完整（有的记录是在告警结束后生成的）
            search_object = search_object.filter(
                (Q("range", end_time={"gte": start_time}) | ~Q("exists", field="end_time"))
                & Q("range", create_time={"lte": end_time})
            )

        if self.status:
            search_object = search_object.filter("terms", status=self.status)
        elif not self.alert_ids and not self.search_parent_action_id:
            # 是否显示“已收敛”，“已屏蔽”等未实际执行动作的记录
            search_object = search_object.filter(
                "terms", status=[ActionDisplayStatus.SUCCESS, ActionDisplayStatus.FAILURE, ActionDisplayStatus.RUNNING]
            )

        if self.alert_ids:
            search_object = search_object.filter("terms", alert_id=self.alert_ids)

        return search_object

    def search(self, show_overview=False, show_aggs=False, show_dsl=False):
        exc = None
        search_object = None
        try:
            search_object = self.get_search_object()
            search_object = self.add_conditions(search_object, self.conditions)
            search_object = self.add_query_string(search_object, self.query_string)
            search_object = self.add_ordering(search_object, self.ordering)
            search_object = self.add_pagination(search_object, self.page, self.page_size)

            if show_overview:
                search_object = self.add_overview(search_object)

            if show_aggs:
                search_object = self.add_aggs(search_object)

            search_result = search_object.params(track_total_hits=True).execute()
        except Exception as e:
            search_result = self.make_empty_response()
            exc = e

        actions = self.handle_hit_list(search_result)

        result = {
            "actions": actions,
            "total": min(search_result.hits.total.value, 10000),
        }

        if show_overview:
            result["overview"] = self.handle_overview(search_result)

        if show_aggs:
            result["aggs"] = self.handle_aggs(search_result)

        if show_dsl and search_object:
            result["dsl"] = search_object.to_dict()

        if exc:
            exc.data = result
            raise exc

        return result

    def add_biz_condition(self, search_object):
        queries = []
        if self.authorized_bizs is not None and self.bk_biz_ids:
            # 进行我有权限的告警过滤
            queries.append(Q("terms", **{"bk_biz_id": self.authorized_bizs}))

        if self.bk_biz_ids == []:
            # 如果不带任何业务信息，表示获取跟自己相关的告警
            queries.append(Q("term", operator=self.request_username))

        if self.unauthorized_bizs and self.request_username:
            queries.append(
                Q(Q("terms", **{"bk_biz_id": self.unauthorized_bizs}) & Q("term", operator=self.request_username))
            )
        if queries:
            return search_object.filter(reduce(operator.or_, queries))
        return search_object

    @classmethod
    def handle_hit_list(cls, hits=None):
        hits = hits or []
        hits = [cls.handle_hit(hit) for hit in hits]
        hits = cls.add_converge_count(hits)
        hits = cls.add_plugin_type_display(hits)
        ActionSignalTranslator().translate_from_dict(hits, "signal", "signal_display")
        return hits

    @classmethod
    def add_plugin_type_display(cls, hits):
        for hit in hits:
            hit["action_plugin_type_display"] = hit.get("action_plugin").get("name", hit["action_plugin_type"])
        return hits

    @classmethod
    def add_converge_count(cls, hits):
        """
        追加处理记录的收敛告警数量
        """
        converge_ids = set()
        for hit in hits:
            if hit.get("is_converge_primary") and hit.get("converge_id"):
                converge_ids.add(hit["converge_id"])

        queryset = ConvergeRelation.objects.filter(
            converge_id__in=list(converge_ids), converge_status=ConvergeStatus.SKIPPED
        )

        converge_alerts = defaultdict(set)
        for converge in queryset:
            converge_alerts[converge.converge_id].update(converge.alerts)

        for hit in hits:
            if hit.get("is_converge_primary") and hit.get("converge_id"):
                hit["converge_count"] = len(converge_alerts.get(hit["converge_id"], []))
            else:
                hit["converge_count"] = 0
        return hits

    @classmethod
    def handle_hit(cls, hit):
        cleaned_data = super().handle_hit(hit)

        if "duration" in cleaned_data:
            # 转换为人类可读形式
            cleaned_data["duration"] = hms_string(cleaned_data["duration"])

        cleaned_data["dimension_string"] = AlertDimensionFormatter.get_dimensions_str(
            cleaned_data.get("dimensions", [])
        )
        cleaned_data["ex_data"] = cleaned_data["ex_data"] or {}
        cleaned_data["status_tips"] = cleaned_data["ex_data"].get("message") or ""

        return cleaned_data

    def parse_condition_item(self, condition: dict) -> Q:
        if condition["key"] == "duration":
            # 对 key 为 stage 进行特殊处理
            return reduce(
                operator.or_,
                [
                    Q("range", duration=self.DurationOption.FILTER[value])
                    for value in condition["value"]
                    if value in self.DurationOption.FILTER
                ],
            )
        return super(ActionQueryHandler, self).parse_condition_item(condition)

    def add_overview(self, search_object):
        # 总览聚合
        search_object.aggs.bucket("status", "terms", field="status")
        return search_object

    def add_aggs(self, search_object):
        # 高级筛选聚合
        search_object.aggs.bucket("action_plugin_type", "terms", field="action_plugin_type", size=10000)
        search_object.aggs.bucket("signal", "terms", field="signal")
        search_object.aggs.bucket("duration", "range", field="duration", ranges=list(self.DurationOption.AGG.values()))
        return search_object

    def handle_overview(self, search_result):
        result = {
            "id": "action",
            "name": _("处理记录"),
            "count": search_result.hits.total.value,
            "children": [],
        }

        if search_result.aggs:
            bucket_dict = {bucket.key: bucket.doc_count for bucket in search_result.aggs.status.buckets}
        else:
            bucket_dict = {}

        overview_status = self.status or [ActionDisplayStatus.SUCCESS, ActionDisplayStatus.FAILURE]

        for status in overview_status:
            result["children"].append(
                {
                    "id": status,
                    "name": ACTION_DISPLAY_STATUS_DICT[status],
                    "count": bucket_dict.get(status, 0),
                }
            )

        return result

    @classmethod
    def handle_aggs(cls, search_result):
        fields = [
            (
                "action_plugin_type",
                _("套餐类型"),
                [(plugin.plugin_key, plugin.name) for plugin in ActionPlugin.objects.all()],
            ),
            (
                "signal",
                _("触发信号"),
                [
                    item
                    for item in list(ActionSignal.ACTION_SIGNAL_DICT.items())
                    if item[0] not in [ActionSignal.EXECUTE]
                ],
            ),
            ("duration", _("处理时长"), list(cls.DurationOption.DISPLAY.items())),
        ]

        results = []

        for field_name, display_name, choices in fields:
            if search_result.aggs:
                bucket_dict = {bucket.key: bucket.doc_count for bucket in search_result.aggs[field_name].buckets}
            else:
                bucket_dict = {}

            result = {
                "id": field_name,
                "name": display_name,
                "count": sum(bucket_dict.values()),
                "children": [
                    {"id": key, "name": display, "count": bucket_dict.get(key, 0)} for key, display in choices
                ],
            }
            results.append(result)
        return results

    def date_histogram(self, interval: str = "auto"):
        status_choices = {
            ActionDisplayStatus.SUCCESS: _lazy("成功"),  # 处理成功
            ActionDisplayStatus.FAILURE: _lazy("失败"),  # 处理失败
        }

        interval = self.calculate_agg_interval(self.start_time, self.end_time, interval)

        # 查询时间对齐
        start_time = self.start_time // interval * interval
        end_time = self.end_time // interval * interval + interval

        search_object = self.get_search_object(start_time=start_time, end_time=end_time)
        search_object = self.add_conditions(search_object)
        search_object = self.add_query_string(search_object)
        search_object.aggs.bucket(
            "display_status", "filter", {"terms": {"status": list(status_choices.keys())}}
        ).bucket("status", "terms", field="status").bucket(
            "time", "date_histogram", field="end_time", fixed_interval=f"{interval}s"
        )
        search_result = search_object[:0].execute()

        all_series = defaultdict(dict)
        for ts in range(start_time, end_time, interval):
            for status in status_choices:
                all_series[status][ts * 1000] = 0

        if search_result.aggs:
            for status_bucket in search_result.aggs.display_status.status.buckets:
                for time_bucket in status_bucket.time.buckets:
                    all_series[status_bucket.key][int(time_bucket.key_as_string) * 1000] = time_bucket.doc_count

        result_data = {
            "series": [
                {"data": list(series.items()), "name": status, "display_name": status_choices[status]}
                for status, series in all_series.items()
            ],
            "unit": "",
        }

        return result_data

    def top_n(self, fields: List, size=10, translators: Dict[str, AbstractTranslator] = None):
        translators = {
            "signal": ActionSignalTranslator(),
            "action_plugin_type": ActionPluginTypeTranslator(),
            "bk_biz_id": BizTranslator(),
        }
        return super(ActionQueryHandler, self).top_n(fields, size, translators)


from selenium.webdriver.common.by import By
from core.helpers.app_sections_helper import AppSectionsHelper

class EventTabsCommon(AppSectionsHelper):
    # Locators
    BUTTON_EDIT = (By.XPATH, "//div[@class='action-buttons']//span[contains(text(), 'Редактировать')]/parent::button")
    BUTTON_BACK = (By.XPATH, "//div[@class='buttons-container']//span[contains(text(), 'Назад')]/parent::button")
    BUTTON_CANCEL = (By.XPATH, "//div[@class='buttons-container']//span[contains(text(), 'Отмена')]/parent::button")
    BUTTON_SAVE = (By.XPATH, "//div[@class='buttons-container']//span[contains(text(), 'Сохранить')]/parent::button")
    MESSAGE_SAVE_SUCCESS = (By.XPATH, "//div[contains(text(), 'Сохранено успешно')]")

    def _check_buttons(self, edit: bool):
        if edit:
            self._check_element_visible(locator=self.BUTTON_EDIT, visibility=True)
            self._check_element_editable(locator=self.BUTTON_EDIT, disabled=True)
            self._check_element_visible(locator=self.BUTTON_BACK, visibility=False)
            self._check_element_visible(locator=self.BUTTON_CANCEL, visibility=True)
            self._check_element_editable(locator=self.BUTTON_CANCEL, disabled=False)
            self._check_element_visible(locator=self.BUTTON_SAVE, visibility=True)
            self._check_element_editable(locator=self.BUTTON_SAVE, disabled=False)
        else:
            self._check_element_visible(locator=self.BUTTON_EDIT, visibility=True)
            self._check_element_editable(locator=self.BUTTON_EDIT, disabled=False)
            self._check_element_visible(locator=self.BUTTON_BACK, visibility=True)
            self._check_element_editable(locator=self.BUTTON_BACK, disabled=False)
            self._check_element_visible(locator=self.BUTTON_CANCEL, visibility=False)
            self._check_element_visible(locator=self.BUTTON_SAVE, visibility=True)
            self._check_element_editable(locator=self.BUTTON_SAVE, disabled=True)


import os,argparse
from PIL import Image
from PIL import ImageEnhance

def main():
	parser = argparse.ArgumentParser(description="This program crops and saves a series of images.")

	parser.add_argument('-p', '--path', nargs='+', help="Path of original images.")
	parser.add_argument('-r', '--rows', type=int, nargs='+', help="Row range to choose.")
	parser.add_argument('-c', '--columns', type=int, nargs='+', help="Column range to choose.")

	args = parser.parse_args()

	currentPath = os.path.split(os.path.abspath(__file__))[0]
	filePath = os.path.join(currentPath, *args.path)
	fileNames = [os.path.join(filePath, x) for x in os.listdir(filePath)]
	outputPath = os.path.join(currentPath, 'cropped_images')

	try:
		os.mkdir(outputPath)
		print("Directory made!")
	except:
		print("Directory already exists!")

	im = Image.open(fileNames[0])
	shape = im.size

	if not args.rows:
		r_1, r_2 = 0, shape[1]
	else:
		r_1, r_2  = args.rows

	if not args.columns:
		c_1, c_2 = 0, shape[0]
	else:
		c_1, c_2 = args.columns

	box = (c_1, r_1, c_2, r_2)
	size = (180, 230)

	for file in fileNames:
		outputName = os.path.split(file)[1].split('.')[0] + '_cropped.jpg'
		im = Image.open(file)
		im_cropped = im.crop(box)
		im_cropped.thumbnail(size)

		# Adjust image brightness
		# An enhancement factor of 0.0 gives a black image. A factor of 1.0
		# gives the original image.
		enhancer_1 = ImageEnhance.Brightness(im_cropped)
		enhanced_1 = enhancer_1.enhance(1.5)

		# Adjust image color balance
		# An enhancement factor of 0.0 gives a black and white image. A factor
		# of 1.0 gives the original image.
		enhancer_2 = ImageEnhance.Color(enhanced_1)
		enhanced_2 = enhancer_2.enhance(1.1)

		# Adjust image contrast
		# An enhancement factor of 0.0 gives a solid grey image. A factor of 1.0
		# gives the original image.
		enhancer_3 = ImageEnhance.Contrast(enhanced_2)
		enhanced_3 = enhancer_3.enhance(1.1)

		# Adjust image sharpness
		# An enhancement factor of 0.0 gives a blurred image, a factor of 1.0 gives
		# the original image, and a factor of 2.0 gives a sharpened image.
		enhancer_4 = ImageEnhance.Sharpness(enhanced_3)
		enhanced_4 = enhancer_4.enhance(1.3)

		# Save the image
		enhanced_4.save(os.path.join(outputPath, outputName))

	print("Done!")

if __name__ == "__main__":
	main()


###################################################################
##### for testing with number of SVM parameters in all cases  #####
###################################################################

import matplotlib.pyplot as plt
import matplotlib as mpl

from sklearn import datasets
from sklearn.externals.six.moves import xrange

from sklearn import svm
from sklearn.svm import SVC
import numpy as np
import time

from sklearn.metrics import accuracy_score
from sklearn import metrics
from sklearn.metrics import confusion_matrix
import seaborn as sns
import mglearn
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import LinearSVC

## Choose only one of the two flags.
gamma_change = True
C_change = False

def plot_svc_decision_function(model, ax=None, plot_support=True):
    """Plot the decision function for a 2D SVC"""
    if ax is None:
        ax = plt.gca()
    xlim = ax.get_xlim()
    ylim = ax.get_ylim()

    # create grid to evaluate model
    x = np.linspace(xlim[0], xlim[1], 30)
    y = np.linspace(ylim[0], ylim[1], 30)
    Y, X = np.meshgrid(y, x)
    xy = np.vstack([X.ravel(), Y.ravel()]).T
    P = model.decision_function(xy).reshape(X.shape)

    # plot decision boundary and margins
    ax.contour(X, Y, P, colors='k',
               levels=[-1, 0, 1], alpha=0.5,
               linestyles=['--', '-', '--'])

    # plot support vectors
    if plot_support:
        ax.scatter(model.support_vectors_[:, 0],
                   model.support_vectors_[:, 1],
                   s=300, linewidth=1, facecolors='none')
    ax.set_xlim(xlim)
    ax.set_ylim(ylim)

problem = 0
# problem = 1

if problem == 0:
    train_input = np.loadtxt('./data/p1_train_input.txt')
    train_target = np.loadtxt('./data/p1_train_target.txt')
    test_input = np.loadtxt('./data/p1_test_input.txt')
    test_target = np.loadtxt('./data/p1_test_target.txt')
else:
    train_input = np.loadtxt('./data/p2_train_input.txt')
    train_target = np.loadtxt('./data/p2_train_target.txt')
    test_input = np.loadtxt('./data/p2_test_input.txt')
    test_target = np.loadtxt('./data/p2_test_target.txt')

xx, yy = np.meshgrid(np.linspace(-3, 3, 500),
                     np.linspace(-3, 3, 500))

fig, ax = plt.subplots(1, 5, figsize=(35, 6))
fig.subplots_adjust(left=0.0625, right=0.95, wspace=0.1)

if gamma_change == True:
    ## kernel: {‘linear’, ‘poly’, ‘rbf’, ‘sigmoid’}, default=’rbf’
    gamma_list = [1, 5, 10, 15, 20]
    for i, (axi, gamma) in enumerate (zip(ax, gamma_list)):
        clf = SVC(kernel='rbf', C=10, gamma=gamma, random_state=100)
        clf.fit(train_input, train_target)
        axi.scatter(train_input[:, 0], train_input[:, 1], c=train_target, s=50, cmap='autumn')
        # axi.scatter(test_input[:, 0], test_input[:, 1], c=test_target, s=50, cmap='autumn')
        plot_svc_decision_function(clf, axi)
        axi.scatter(clf.support_vectors_[:, 0],
                    clf.support_vectors_[:, 1],
                    s=300, lw=1, facecolors='none')

        y_pred = clf.predict(test_input)
        acc = accuracy_score(test_target, y_pred)
        print(accuracy_score(test_target, y_pred))
        # Model Precision: what percentage of positive tuples are labeled as such?
        precision = metrics.precision_score(test_target, y_pred)
        print("Precision:", metrics.precision_score(test_target, y_pred))
        # Model Recall: what percentage of positive tuples are labelled as such?
        recall = metrics.recall_score(test_target, y_pred)
        print("Recall:", metrics.recall_score(test_target, y_pred))

        axi.set_title("gamma = {:}\nacc = {:.4f}\nprecision = {}\nrecall = {}"
                        .format(gamma, acc, precision, recall), size=10)
if C_change == True:
    ## kernel: {‘linear’, ‘poly’, ‘rbf’, ‘sigmoid’}, default=’rbf’
    C_list_1 = [1.0, 1E1, 1E2, 1E3, 1E4]
    C_list_2 = [1E5, 1E6, 1E7, 1E8, 1E9]
    for i, (axi, C) in enumerate (zip(ax, C_list_1)):
        clf = SVC(kernel='rbf', C=C, gamma=10, random_state=100)
        clf.fit(train_input, train_target)
        axi.scatter(train_input[:, 0], train_input[:, 1], c=train_target, s=50, cmap='autumn')
        # axi.scatter(test_input[:, 0], test_input[:, 1], c=test_target, s=50, cmap='autumn')
        plot_svc_decision_function(clf, axi)
        axi.scatter(clf.support_vectors_[:, 0],
                    clf.support_vectors_[:, 1],
                    s=300, lw=1, facecolors='none')

        y_pred = clf.predict(test_input)
        acc = accuracy_score(test_target, y_pred)
        print(accuracy_score(test_target, y_pred))
        # Model Precision: what percentage of positive tuples are labeled as such?
        precision = metrics.precision_score(test_target, y_pred)
        print("Precision:", metrics.precision_score(test_target, y_pred))
        # Model Recall: what percentage of positive tuples are labelled as such?
        recall = metrics.recall_score(test_target, y_pred)
        print("Recall:", metrics.recall_score(test_target, y_pred))

        axi.set_title("C = {:}\nacc = {:.4f}\nprecision = {}\nrecall = {}"
                        .format(C, acc, precision, recall), size=10)

plt.show()


# -*- coding:utf-8 -*-

from keras.models import *
from keras.layers import *
from keras.optimizers import *
from keras.callbacks import ModelCheckpoint
import keras.backend as K
import cv2
from data_camvid import *
from myData import *

def iou(y_true, y_pred, label: int):
    """
    Return the Intersection over Union (IoU) for a given label.
    Args:
        y_true: the expected y values as a one-hot
        y_pred: the predicted y values as a one-hot or softmax output
        label: the label to return the IoU for
    Returns:
        the IoU for the given label
    """
    # extract the label values using the argmax operator then
    # calculate equality of the predictions and truths to the label
    y_true = K.cast(K.equal(K.argmax(y_true), label), K.floatx())
    y_pred = K.cast(K.equal(K.argmax(y_pred), label), K.floatx())
    # calculate the |intersection| (AND) of the labels
    intersection = K.sum(y_true * y_pred)
    # calculate the |union| (OR) of the labels
    union = K.sum(y_true) + K.sum(y_pred) - intersection
    # avoid divide by zero - if the union is zero, return 1
    # otherwise, return the intersection over union
    return K.switch(K.equal(union, 0), 1.0, intersection / union)

def mean_iou(y_true, y_pred):
    """
    Return the Intersection over Union (IoU) score.
    Args:
        y_true: the expected y values as a one-hot
        y_pred: the predicted y values as a one-hot or softmax output
    Returns:
        the scalar IoU value (mean over all labels)
    """
    # get number of labels to calculate IoU for
    num_labels = K.int_shape(y_pred)[-1] - 1
    # initialize a variable to store total IoU in
    mean_iou = K.variable(0)

    # iterate over labels to calculate IoU for
    for label in range(num_labels):
        mean_iou = mean_iou + iou(y_true, y_pred, label)

    # divide total IoU by number of labels to get mean IoU
    return mean_iou / num_labels

class myUnet(object):
    def __init__(self, img_rows=512, img_cols=512):
        self.img_rows = img_rows
        self.img_cols = img_cols

    '''
    def load_data(self):
        mydata = dataProcess(self.img_rows, self.img_cols)
        imgs_train, imgs_mask_train = mydata.load_train_data()
        imgs_test = mydata.load_test_data()
        return imgs_train, imgs_mask_train, imgs_test

    '''
    def load_data(self):
        mydata = dataProcess(self.img_rows, self.img_cols)

        #train
        gene = mydata.trainGen()
        return gene

        '''
        #test
        valGen = mydata.valGen()
        return valGen
        '''

        '''
        imgs_train, imgs_mask_train = mydata.trainGen()
        imgs_test = mydata.valGen()
        return imgs_train,imgs_mask_train,imgs_test
        '''

    def get_unet(self):
        inputs = Input((self.img_rows, self.img_cols, 3))

        conv1 = Conv2D(64, 3, activation='relu', padding='same', kernel_initializer='he_normal')(inputs)
        # print(conv1)
        #print "conv1 shape:", conv1.shape
        conv1 = Conv2D(64, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv1)
        #print "conv1 shape:", conv1.shape
        pool1 = MaxPooling2D(pool_size=(2, 2))(conv1)
        #print "pool1 shape:", pool1.shape

        conv2 = Conv2D(128, 3, activation='relu', padding='same', kernel_initializer='he_normal')(pool1)
        #print "conv2 shape:", conv2.shape
        conv2 = Conv2D(128, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv2)
        #print "conv2 shape:", conv2.shape
        pool2 = MaxPooling2D(pool_size=(2, 2))(conv2)
        #print "pool2 shape:", pool2.shape

        conv3 = Conv2D(256, 3, activation='relu', padding='same', kernel_initializer='he_normal')(pool2)
        #print "conv3 shape:", conv3.shape
        conv3 = Conv2D(256, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv3)
        #print "conv3 shape:", conv3.shape
        pool3 = MaxPooling2D(pool_size=(2, 2))(conv3)
        #print "pool3 shape:", pool3.shape

        conv4 = Conv2D(512, 3, activation='relu', padding='same', kernel_initializer='he_normal')(pool3)
        conv4 = Conv2D(512, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv4)
        drop4 = Dropout(0.5)(conv4)
        pool4 = MaxPooling2D(pool_size=(2, 2))(drop4)

        conv5 = Conv2D(1024, 3, activation='relu', padding='same', kernel_initializer='he_normal')(pool4)
        conv5 = Conv2D(1024, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv5)
        drop5 = Dropout(0.5)(conv5)

        up6 = Conv2D(512, 2, activation='relu', padding='same', kernel_initializer='he_normal')(
            UpSampling2D(size=(2, 2))(drop5))
        merge6 = concatenate([drop4,up6], axis = 3)
        print(up6)
        print(merge6)
        conv6 = Conv2D(512, 3, activation='relu', padding='same', kernel_initializer='he_normal')(merge6)
        print(conv6)
        conv6 = Conv2D(512, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv6)
        print(conv6)
        up7 = Conv2D(256, 2, activation='relu', padding='same', kernel_initializer='he_normal')(
            UpSampling2D(size=(2, 2))(conv6))
        merge7 = concatenate([conv3,up7], axis = 3)
        print(up7)
        print(merge7)
        conv7 = Conv2D(256, 3, activation='relu', padding='same', kernel_initializer='he_normal')(merge7)
        print(conv7)
        conv7 = Conv2D(256, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv7)
        print(conv7)
        up8 = Conv2D(128, 2, activation='relu', padding='same', kernel_initializer='he_normal')(
            UpSampling2D(size=(2, 2))(conv7))
        merge8 = concatenate([conv2,up8], axis = 3)
        conv8 = Conv2D(128, 3, activation='relu', padding='same', kernel_initializer='he_normal')(merge8)
        conv8 = Conv2D(128, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv8)

        up9 = Conv2D(64, 2, activation='relu', padding='same', kernel_initializer='he_normal')(
            UpSampling2D(size=(2, 2))(conv8))
        merge9 = concatenate([conv1,up9], axis = 3)
        print(up9)
        print(merge9)
        conv9 = Conv2D(64, 3, activation='relu', padding='same', kernel_initializer='he_normal')(merge9)
        print(conv9)
        conv9 = Conv2D(64, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv9)
        print(conv9)
        conv9 = Conv2D(3, 3, activation='relu', padding='same', kernel_initializer='he_normal')(conv9)
        #print "conv9 shape:", conv9.shape

        conv10 = Conv2D(3, 1, activation='softmax')(conv9)
        print(conv10)
        model = Model(input=inputs, output=conv10)

        model.compile(optimizer=Adam(lr=2e-5), loss='categorical_crossentropy', metrics=['accuracy',mean_iou])

        return model

    def train(self):
        print("loading data")
        #imgs_train, imgs_mask_train, imgs_test = self.load_data()
        myGene = self.load_data()
        print("loading data done")
        model = self.get_unet()
        print("got unet")
        model_checkpoint = ModelCheckpoint('bbbSeg.hdf5', monitor='loss', verbose=1, save_best_only=True)
        print('Fitting model...')
        model.fit_generator(myGene, steps_per_epoch=3947,epochs=1,verbose = 1,shuffle= True,callbacks=[model_checkpoint],)
        '''
        model.fit(imgs_train, imgs_mask_train, batch_size=1, epochs=50, verbose=1,
                  validation_split=0.1, shuffle=True, callbacks=[model_checkpoint])
        '''
        print('predict test data')
        '''
        imgs_mask_test = model.predict(imgs_test, batch_size=1, verbose=1)
        np.save('./results/camvid_mask_test.npy', imgs_mask_test)
        '''

    def predictImg(self):
        valimg = self.load_data()
        print("loading the model")
        model = load_model("E:/WYQ/unet-rgb-master/bbbSeg.hdf5")
        print("loading model done")
        results = model.predict(valimg,batch_size = 2, verbose = 1)
        piclist = []
        for line in open("./te.txt"):
            line = line.strip()
            picname = line.split("\\")[-1]
            piclist.append(picname)
        for i in range(results.shape[0]):
            path = "./results/" + piclist[i]
            img = np.zeros((results.shape[1],results.shape[2],3),dtype=np.uint8)
            for k in range(len(img)):
                for j in range(len(img[k])):
                    num = np.argmax(results[i][k][j])
                    if num == 0:
                        img[k][j] = [128, 128, 128]
                    elif num == 1:
                        img[k][j] = [128, 0, 0]
                    elif num == 2:
                        img[k][j] = [192, 192, 128]
            img = cv2.resize(img, (480, 360), interpolation=cv2.INTER_CUBIC)
            cv2.imwrite(path, img)
        print("the predicted img have saved")

    def save_img(self):
        print("array to image")
        imgs = np.load('./results/camvid_mask_test.npy')
        piclist = []
        for line in open("./results/camvid.txt"):
            line = line.strip()
            picname = line.split('/')[-1]
            piclist.append(picname)
        for i in range(imgs.shape[0]):
            path = "./results/" + piclist[i]
            img = np.zeros((imgs.shape[1], imgs.shape[2], 3), dtype=np.uint8)
            for k in range(len(img)):
                for j in range(len(img[k])):  # cv2.imwrite也是BGR顺序
                    num = np.argmax(imgs[i][k][j])
                    if num == 0:
                        img[k][j] = [128, 128, 128]
                    elif num == 1:
                        img[k][j] = [128, 0, 0]
                    elif num == 2:
                        img[k][j] = [192, 192, 128]
                        '''
                    elif num == 3:
                        img[k][j] = [255, 69, 0]
                    elif num == 4:
                        img[k][j] = [128, 64, 128]
                    elif num == 5:
                        img[k][j] = [60, 40, 222]
                    elif num == 6:
                        img[k][j] = [128, 128, 0]
                    elif num == 7:
                        img[k][j] = [192, 128, 128]
                    elif num == 8:
                        img[k][j] = [64, 64, 128]
                    elif num == 9:
                        img[k][j] = [64, 0, 128]
                    elif num == 10:
                        img[k][j] = [64, 64, 0]
                    elif num == 11:
                        img[k][j] = [0, 128, 192]
                        '''
            img = cv2.resize(img, (480, 360), interpolation=cv2.INTER_CUBIC)
            cv2.imwrite(path, img)

if __name__ == '__main__':

    myunet = myUnet()
    model = myunet.get_unet()
    # model.summary()
    # plot_model(model, to_file='model.png')
    myunet.train()

    '''
    #predict
    myunet = myUnet()
    myunet.predictImg()
    '''


from models import Squawk
from forms import AddSquawkForm
from django.http import HttpResponse
from django.shortcuts import render_to_response
from django.template.context import RequestContext

def squawk_list(request):
    if request.method == "POST":
        add_form = AddSquawkForm(request.POST)
        if add_form.is_valid():
            s = Squawk()
            s.text = add_form.cleaned_data['squawk']
            s.user = request.user
            s.save()

    squawk_form = AddSquawkForm()
    squawks = Squawk.objects.all().order_by('-id')
    c= {}
    c['squawks'] = squawks
    c['form'] = squawk_form
    return render_to_response("home.html", c, context_instance=RequestContext(request))


import os
from flask import Blueprint, make_response, request, g
from flask.wrappers import Response
import pyproj
from ..context import get_session
from geometry_service.database.postgis import Postgis
from geometry_service.database.actions import db_add_dataset, db_log_action
from geometry_service.database.model import Datasets
from geometry_service.loggers import logger
from ..forms.filter import FilterFileForm, FilterStringForm, FilterBufferForm

def _before_requests():
    """Executed before each request for this blueprint.

    Get the session details of the corresponding token, validates the form, and retrieves the dataset from database. The dataset and the form are stored as global flask objects, to be accessible from the requests.

    Returns:
        (None|Response): In case of validation error, returns a Flask response, None otherwise.
    """
    response = get_session()
    logger.info('API request [endpoint: "%s", token: "%s"]', request.endpoint, g.session['token'])
    if isinstance(response, Response):
        return response
    if request.endpoint == 'filter.within_buffer':
        form = FilterBufferForm()
    else:
        form = FilterFileForm() if 'wkt' in request.files.keys() else FilterStringForm()
    if not form.validate_on_submit():
        return make_response(form.errors, 400)
    if form.src.data == '':
        dataset = Datasets().get(uuid=g.session['active_instance'])
        if dataset is None:
            return make_response({"status": "No active dataset found."}, 404)
    else:
        dataset = Datasets().get(session=session['uuid'], label=form.src.data, deleted=False)
    g.dataset = dataset
    g.form = form

def _filter(action, label, dataset, wkt=None, arg=None, crs=None):
    """Creates a new dataset with filtered records.

    Creates a new DB View with the new dataset, and logs the action to the DB. All the records of the dataset that fulfil the condition of the PostGIS function (action) will be included in the view. The argument of the function is either supplied directly with the arg parameter either constructed from the geometry of the wkt parameter.

    Arguments:
        action (str): The PostGIS function that will be used to filter the table.
        label (str): The label given to the new dataset.
        dataset (dict): The dataset DB record.

    Keyword Arguments:
        wkt (str): The WKT to supply to the filter function (required if arg is None; default: {None})
        arg (str): The explicit argument of the filter function (required if wkt is None; default: {None})
        crs (str): The CRS of the WKT; if None the dataset CRS will be assumed (default: {None})

    Returns:
        (dict): Metadata for the new view dataset.

    Raises:
        TypeError: When none of wkt, arg is given.
    """
    meta = dataset['meta']
    if wkt is not None:
        srid = pyproj.crs.CRS.from_user_input(crs).to_epsg() if crs is not None and crs != '' else meta['epsg']
        arg = "ST_GeomFromText('{wkt}', {srid})".format(wkt=wkt, srid=srid)
    if arg is None:
        raise TypeError("_filter() missing one of arguments 'wkt', 'arg'")
    postgis = Postgis(g.session['db_schema'])
    view = postgis.create_view_filter(label, dataset['table'], action, arg, column='geom')
    tgt = db_add_dataset(session=g.session['uuid'], label=label, table=view, meta=meta)
    db_log_action(session=g.session['uuid'], action=request.endpoint, src_ds=dataset['uuid'], result_ds=tgt['uuid'])
    return meta

# FLASK ROUTES

bp = Blueprint('filter', __name__, url_prefix='/filter')
bp.before_request(_before_requests)

@bp.route('/contains', methods=['POST'])
def contains():
    """**Flask POST rule**.

    Apply contains filter on the dataset with a given geometry.
    ---
    post:
        summary: Apply contains filter on the dataset with a given geometry.
        description: Creates a new dataset, subset of the source, with the condition that the given geometry is completely inside the geometry of every feature in this dataset. The geometry is provided either as a WKT string either as a text file containing the WKT.
        tags:
            - Filter
        parameters:
            - sessionToken
        requestBody:
            required: true
            content:
                application/x-www-form-urlencoded:
                    schema: filterForm
                multipart/form-data:
                    schema: filterFormMultipart
        responses:
            200: newDatasetResponse
            400: validationErrorResponse
            401: noSessionResponse
            404: datasetNotFoundResponse
    """
    meta = _filter('ST_Contains', g.form.label.data, g.dataset, wkt=g.form.wkt.data, crs=g.form.crs.data)
    return make_response(meta, 200)

@bp.route('/contains_properly', methods=['POST'])
def contains_properly():
    """**Flask POST rule**.

    Apply contains_properly filter on the dataset with a given geometry.
    ---
    post:
        summary: Apply contains_properly filter on the dataset with a given geometry.
        description: Creates a new dataset, subset of the source, with the condition that the given geometry intersect the geometry of every feature in this dataset, **but** not its boundary (or exterior). The geometry is provided either as a WKT string either as a text file containing the WKT.
        tags:
            - Filter
        parameters:
            - sessionToken
        requestBody:
            required: true
            content:
                application/x-www-form-urlencoded:
                    schema: filterForm
                multipart/form-data:
                    schema: filterFormMultipart
        responses:
            200: newDatasetResponse
            400: validationErrorResponse
            401: noSessionResponse
            404: datasetNotFoundResponse
    """
    meta = _filter('ST_ContainsProperly', g.form.label.data, g.dataset, wkt=g.form.wkt.data, crs=g.form.crs.data)
    return make_response(meta, 200)

@bp.route('/covers', methods=['POST'])
def covers():
    """**Flask POST rule**.

    Apply covers filter on the dataset with a given geometry.
    ---
    post:
        summary: Apply covers filter on the dataset with a given geometry.
        description: Creates a new dataset, subset of the source, with the condition that no point in the given geometry is outside the geometry of every feature in this dataset. The geometry is provided either as a WKT string either as a text file containing the WKT.
        tags:
            - Filter
        parameters:
            - sessionToken
        requestBody:
            required: true
            content:
                application/x-www-form-urlencoded:
                    schema: filterForm
                multipart/form-data:
                    schema: filterFormMultipart
        responses:
            200: newDatasetResponse
            400: validationErrorResponse
            401: noSessionResponse
            404: datasetNotFoundResponse
    """
    meta = _filter('ST_Covers', g.form.label.data, g.dataset, wkt=g.form.wkt.data, crs=g.form.crs.data)
    return make_response(meta, 200)

@bp.route('/covered_by', methods=['POST'])
def covered_by():
    """**Flask POST rule**.

    Apply covered_by filter on the dataset with a given geometry.
    ---
    post:
        summary: Apply covered_by filter on the dataset with a given geometry.
        description: Creates a new dataset, subset of the source, with the condition that no point in the geometry of every feature in this dataset is outside the given geometry. The geometry is provided either as a WKT string either as a text file containing the WKT.
        tags:
            - Filter
        parameters:
            - sessionToken
        requestBody:
            required: true
            content:
                application/x-www-form-urlencoded:
                    schema: filterForm
                multipart/form-data:
                    schema: filterFormMultipart
        responses:
            200: newDatasetResponse
            400: validationErrorResponse
            401: noSessionResponse
            404: datasetNotFoundResponse
    """
    meta = _filter('ST_CoveredBy', g.form.label.data, g.dataset, wkt=g.form.wkt.data, crs=g.form.crs.data)
    return make_response(meta, 200)

@bp.route('/crosses', methods=['POST'])
def crosses():
    """**Flask POST rule**.

    Apply crosses filter on the dataset with a given geometry.
    ---
    post:
        summary: Apply crosses filter on the dataset with a given geometry.
        description: Creates a new dataset, subset of the source, with the condition that the intersection of the given geometry and the geometry of each feature in this dataset *spatially crosses*, that is, the geometries have some, but not all interior points in common. The geometry is provided either as a WKT string either as a text file containing the WKT.
        tags:
            - Filter
        parameters:
            - sessionToken
        requestBody:
            required: true
            content:
                application/x-www-form-urlencoded:
                    schema: filterForm
                multipart/form-data:
                    schema: filterFormMultipart
        responses:
            200: newDatasetResponse
            400: validationErrorResponse
            401: noSessionResponse
            404: datasetNotFoundResponse
    """
    meta = _filter('ST_Crosses', g.form.label.data, g.dataset, wkt=g.form.wkt.data, crs=g.form.crs.data)
    return make_response(meta, 200)

@bp.route('/disjoint', methods=['POST'])
def disjoint():
    """**Flask POST rule**.

    Apply disjoint filter on the dataset with a given geometry.
    ---
    post:
        summary: Apply disjoint filter on the dataset with a given geometry.
        description: >-
            Creates a new dataset, subset of the source, with only those features that their geometry respects all of the following conditions:

            * **Do not spatially overlap** with the given geometry. Two geometries spatially overlap when they intersect, but one does not completely contain the other.

            * **Do not touch** the given geometry, i.e. if the two geometries have common points, these are not belong only on their exteriors (boundaries).

            * **Do not contain** the given geometry, i.e. there is at least one point of the given geometry outside the feature's geometry.

            > The geometry is provided either as a WKT string either as a text file containing the WKT.
        tags:
            - Filter
        parameters:
            - sessionToken
        requestBody:
            required: true
            content:
                application/x-www-form-urlencoded:
                    schema: filterForm
                multipart/form-data:
                    schema: filterFormMultipart
        responses:
            200: newDatasetResponse
            400: validationErrorResponse
            401: noSessionResponse
            404: datasetNotFoundResponse
    """
    meta = _filter('ST_Disjoint', g.form.label.data, g.dataset, wkt=g.form.wkt.data, crs=g.form.crs.data)
    return make_response(meta, 200)

@bp.route('/intersects', methods=['POST'])
def intersects():
    """**Flask POST rule**.

    Apply intersects filter on the dataset with a given geometry.
    ---
    post:
        summary: Apply intersects filter on the dataset with a given geometry.
        description: Creates a new dataset, subset of the source, with the condition that the given geometry and the geometry of each feature in this dataset share any portion of space. The geometry is provided either as a WKT string either as a text file containing the WKT.
        tags:
            - Filter
        parameters:
            - sessionToken
        requestBody:
            required: true
            content:
                application/x-www-form-urlencoded:
                    schema: filterForm
                multipart/form-data:
                    schema: filterFormMultipart
        responses:
            200: newDatasetResponse
            400: validationErrorResponse
            401: noSessionResponse
            404: datasetNotFoundResponse
    """
    meta = _filter('ST_Intersects', g.form.label.data, g.dataset, wkt=g.form.wkt.data, crs=g.form.crs.data)
    return make_response(meta, 200)

@bp.route('/within', methods=['POST'])
def within():
    """**Flask POST rule**.

    Apply within filter on the dataset with a given geometry.
    ---
    post:
        summary: Apply within filter on the dataset with a given geometry.
        description: Creates a new dataset, subset of the source, with the condition that each feature in this dataset is completely inside the given geometry. The geometry is provided either as a WKT string either as a text file containing the WKT.
        tags:
            - Filter
        parameters:
            - sessionToken
        requestBody:
            required: true
            content:
                application/x-www-form-urlencoded:
                    schema: filterForm
                multipart/form-data:
                    schema: filterFormMultipart
        responses:
            200: newDatasetResponse
            400: validationErrorResponse
            401: noSessionResponse
            404: datasetNotFoundResponse
    """
    meta = _filter('ST_Within', g.form.label.data, g.dataset, wkt=g.form.wkt.data, crs=g.form.crs.data)
    return make_response(meta, 200)

@bp.route('/within_buffer', methods=['POST'])
def within_buffer():
    """**Flask POST rule**.

    Apply within_buffer filter on the dataset with a given buffer.
    ---
    post:
        summary: Apply within_buffer filter on the dataset with a given buffer.
        description: Creates a new dataset, subset of the source, with the condition that each feature in this dataset is within a given *radius* from a given point defined by *center_x*, *center_y*.
        tags:
            - Filter
        parameters:
            - sessionToken
        requestBody:
            required: true
            content:
                application/x-www-form-urlencoded:
                    schema: filterBufferForm
        responses:
            200: newDatasetResponse
            400: validationErrorResponse
            401: noSessionResponse
            404: datasetNotFoundResponse
    """
    crs = g.form.crs.data
    srid = pyproj.crs.CRS.from_user_input(crs).to_epsg() if crs is not None and crs != '' else g.dataset['meta']['epsg']
    point = "ST_SetSRID( ST_Point( {center_x}, {center_y}), {srid})".format(center_x=g.form.center_x.data, center_y=g.form.center_y.data, srid=srid)
    if srid != g.dataset['meta']['epsg']:
        point = "ST_Transform({point}, {srid})".format(point=point, srid=g.dataset['meta']['epsg'])
    arg = "{point}, {radius}".format(point=point, radius=g.form.radius.data)
    meta = _filter('ST_DWithin', g.form.label.data, g.dataset, arg=arg)
    return make_response(meta, 200)


import spacy
import pandas as pd
import gensim
import gensim.corpora as corpora
from gensim import utils
from gensim.utils import simple_preprocess
from preprocessor import initial_text_clean_up
from nltk.corpus import stopwords

stop_words = stopwords.words('english')

df = pd.DataFrame(pd.read_csv('../data/dev_en.tsv', sep='\t'))

df = df.loc[df['HS'] == 1]
df = df.filter(items = ['text'])

data = df.values.flatten().tolist()

data = [initial_text_clean_up(sent) for sent in data]

def sent_to_words(sentences):
    for sentence in sentences:
        yield(gensim.utils.simple_preprocess(str(sentence), deacc=True))  # deacc=True removes punctuations

data_words = list(sent_to_words(data))

# Build the bigram and trigram models
bigram = gensim.models.Phrases(data_words, min_count=5, threshold=100) # higher threshold fewer phrases.
trigram = gensim.models.Phrases(bigram[data_words], threshold=100)

# Faster way to get a sentence clubbed as a trigram/bigram
bigram_mod = gensim.models.phrases.Phraser(bigram)
trigram_mod = gensim.models.phrases.Phraser(trigram)

# Define functions for stopwords, bigrams, trigrams and lemmatization
def remove_stopwords(texts):
    return [[word for word in simple_preprocess(str(doc)) if word not in stop_words] for doc in texts]

def make_bigrams(texts):
    return [bigram_mod[doc] for doc in texts]

def make_trigrams(texts):
    return [trigram_mod[bigram_mod[doc]] for doc in texts]

def lemmatization(texts, allowed_postags=['NOUN', 'ADJ', 'VERB', 'ADV']):
    """https://spacy.io/api/annotation"""
    texts_out = []
    for sent in texts:
        doc = nlp(" ".join(sent))
        texts_out.append([token.lemma_ for token in doc if token.pos_ in allowed_postags])
    return texts_out

# Remove Stop Words
data_words_nostops = remove_stopwords(data_words)

# Form Bigrams
data_words_bigrams = make_bigrams(data_words_nostops)

# Initialize spacy 'en' model, keeping only tagger component (for efficiency)
nlp = spacy.load('en', disable=['parser', 'ner'])

# Do lemmatization keeping only noun, adj, vb, adv
data_lemmatized = lemmatization(data_words_bigrams, allowed_postags=['NOUN', 'ADJ', 'VERB', 'ADV'])

# Create Dictionary
id2word = corpora.Dictionary(data_lemmatized)

# Create Corpus
texts = data_lemmatized

# Term Document Frequency
corpus = [id2word.doc2bow(text) for text in texts]

TOPICS = 5;

# Build LDA model
optimal_model = gensim.models.ldamodel.LdaModel(corpus=corpus,
                                           id2word=id2word,
                                           num_topics=TOPICS,
                                           random_state=100,
                                           update_every=1,
                                           chunksize=100,
                                           passes=10,
                                           alpha='auto',
                                           per_word_topics=True)

def extract_topic_features(features, text, top=TOPICS):
    bow = id2word.doc2bow(utils.simple_preprocess(text))
    bow_dict = dict(optimal_model[bow][0])

    for i in range(top):
        features['topic_probability {0}:'.format(i+1)] = float(bow_dict.get(i, 0))


#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Compress model with our ternary compressed algorithm and
using compressed network to classify data sampled from CIFAR10 data.

Network can be customed, see class My_Model for more details about how to custome model,
which will be added with a classification layer.  Note that VGG net will first be
trained with all CIFAR10 dataset for a better classification.
"""

__author__ = "Model_compression"
__copyright__ = "Copyright 2021, Lossless compression"
__license__ = "GPL"
__version__ = "1.0.1"
__email__ = "yongqi_du@hust.edu.cn"
__status__ = "Production"
import sys
import os

sys.path.append(
    os.path.dirname(
        os.path.dirname(os.path.dirname(os.path.realpath(__file__)))))
import math
from collections import Counter, OrderedDict

import numpy as np
import torch
import torch.backends.cudnn as cudnn
import torch.nn as nn
import torchvision
import torchvision.transforms as transforms
from torch.utils.data import DataLoader, Dataset
from model_define.model import My_Model
from equation_solve.solve_equation import solve_equation

from vgg_net_cifar10 import VGG

device = "cuda:1" if torch.cuda.is_available() else "cpu"

class Feature_Dataset(Dataset):

    def __init__(self, X, Y) -> None:
        super().__init__()
        self.X, self.Y = X, Y

    def __getitem__(self, idx):
        return self.X[idx, :], self.Y[idx]

    def __len__(self):
        return self.X.shape[0]

class sample_ternary_weight(object):

    def __init__(self, kesi) -> None:
        self.kesi = kesi

    def sample(self):
        init = torch.distributions.uniform.Uniform(0,
                                                   1).sample(torch.Size([1]))
        if init < self.kesi:
            init = 0
        else:
            mask = torch.distributions.bernoulli.Bernoulli(0.5).sample(
                torch.Size([1]))
            if mask == 0:
                init = 1 / np.sqrt(1 - self.kesi)
            else:
                init = -1 / np.sqrt(1 - self.kesi)
        return init

    def sample_n(self, number):
        init = [self.sample() for _ in range(number)]
        init = np.array(init)
        return init

if __name__ == '__main__':
    # data
    # gpu_usage()
    # ------------------------------Data Preparing------------------------------------
    model_vgg = VGG('VGG19')
    model_vgg.load_state_dict(torch.load('./model_vgg'))
    # load data
    transform_train = transforms.Compose([
        transforms.RandomCrop(32, padding=4),
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor(),
        transforms.Normalize((0.4914, 0.4822, 0.4465),
                             (0.2023, 0.1994, 0.2010)),
    ])

    transform_test = transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize((0.4914, 0.4822, 0.4465),
                             (0.2023, 0.1994, 0.2010)),
    ])

    train_data = torchvision.datasets.CIFAR10(root='./data',
                                              train=True,
                                              download=True,
                                              transform=transform_train)
    trainloader = torch.utils.data.DataLoader(train_data,
                                              batch_size=50000,
                                              shuffle=False)

    test_data = torchvision.datasets.CIFAR10(root='./data',
                                             train=False,
                                             download=True,
                                             transform=transform_test)
    testloader = torch.utils.data.DataLoader(test_data,
                                             batch_size=10000,
                                             shuffle=False)

    classes = ('Airplane', 'Car', 'Bird', 'Cat', 'Deer', 'Dog', 'Frog',
               'Horse', 'Ship', 'Truck')

    # ------------------------------Feature Extration----------------------------------
    # output of feature
    train_data, train_label = next(iter(trainloader))
    test_data, test_label = next(iter(testloader))
    with torch.no_grad():
        feature_train = model_vgg.features(train_data)
        feature_train = feature_train.view(feature_train.shape[0], -1)
        feature_test = model_vgg.features(test_data)
        feature_test = feature_test.view(feature_test.shape[0], -1)
        p = feature_train.shape[1]
        N = feature_train.shape[0]
        mean_selected_data = torch.mean(feature_train, dim=0)
        norm2_selected_data = torch.sum(
            (feature_train - mean_selected_data)**2, (0, 1)) / N
        feature_train = feature_train - mean_selected_data
        feature_train = feature_train / np.sqrt(norm2_selected_data)

        p = feature_test.shape[1]
        N = feature_test.shape[0]
        mean_selected_data = torch.mean(feature_test, dim=0)
        norm2_selected_data = torch.sum((feature_test - mean_selected_data)**2,
                                        (0, 1)) / N
        feature_test = feature_test - mean_selected_data
        feature_test = feature_test / np.sqrt(norm2_selected_data)

    # dataset for future training testing
    feature_train_dataset = Feature_Dataset(feature_train, train_label)
    feature_test_dataset = Feature_Dataset(feature_test, test_label)

    tau_zero = torch.sqrt(
        torch.mean(torch.diag(torch.mm(feature_train,
                                       feature_train.t())))).detach().numpy()

    # tau_zero = 1
    print(tau_zero)

    # -------------------------------- Network Setting---------------------------------
    # origin network setting
    layer_num = 3  # layer number for network
    input_num = 512  # input dimension for network 784/256
    weight_num_list = [400, 400, 200]  # number for neurons for each layer
    activation_list = [
        {
            'name': 'ReLU',
            'args': None
        },
        # {'name' : 'Binary_Zero', 'args' : {'s1':1, 's2': 2, 'b1': 1}},
        {
            'name': 'ReLU',
            'args': None
        },
        # {'name' : 'Sign', 'args' : None},
        # {'name' : 'Sign', 'args' : None}]
        {
            'name': 'ReLU',
            'args': None
        }
    ]  # activation for each layer, if with param, write as Binary_Zero here

    #  define origin model
    model = My_Model(layer_num=layer_num,
                     input_num=input_num,
                     weight_num_list=weight_num_list,
                     activation_list=activation_list,
                     tau_zero=tau_zero)
    res = solve_equation(model, tau_zero, loop=10)
    activation_list = res
    # define compressed model!!!!!!!!!!!
    new_model = My_Model(layer_num=layer_num,
                         input_num=input_num,
                         weight_num_list=weight_num_list,
                         activation_list=activation_list,
                         tau_zero=tau_zero)
    model_new = nn.Sequential(
        OrderedDict([
            ('feature', new_model),
            ('classification',
             nn.Linear(model.weight_num_list[-1], 10, bias=False)),
            ('activation', nn.Softmax()),
        ]))

    # --------------------------------Model Initilization-------------------------------
    # model initialization
    initialization_way = 'ternary'  # select from ['normal', 'random_sparsity', 'ternary']
    kesi = 0.95  # change from 0 to 1, only used for ['random sparsity', 'ternary']

    if initialization_way == 'normal':
        # normal initialization
        for fc in model_new.feature.fc_layers:
            nn.init.normal_(fc.weight)
            fc.weight.requires_grad = False
    elif initialization_way == 'random_sparsity':
        # random sparse gaussian weight(break assumption1)
        for fc in model_new.feature.fc_layers:
            mask = np.zeros(fc.weight.shape).flatten()
            mask[:round((1 - kesi) * mask.size)] = 1
            np.random.shuffle(mask)
            mask = torch.tensor(mask.reshape(fc.weight.shape)).float()
            nn.init.normal_(fc.weight)
            with torch.no_grad():
                fc.weight = torch.nn.Parameter(mask * fc.weight.data,
                                               requires_grad=False)
    elif initialization_way == 'ternary':
        # tarnary weight with sparsity kesi
        for fc in model_new.feature.fc_layers:
            init = np.zeros(fc.weight.shape).flatten()
            init[:round(1 / 2 * (1 - kesi) *
                        init.size)] = 1 / np.sqrt(1 - kesi)
            init[round(1 / 2 * (1 - kesi) * init.size):2 *
                 round(1 / 2 *
                       (1 - kesi) * init.size)] = -1 / np.sqrt(1 - kesi)
            # c = Counter(init)
            np.random.shuffle(init)
            init = torch.tensor(init.reshape(fc.weight.shape)).float()
            with torch.no_grad():
                fc.weight = torch.nn.Parameter(init, requires_grad=False)

    # --------------------------------Preparing-------------------------------------------
    batch_size = 128
    # define data
    feature_train_dataloader = DataLoader(feature_train_dataset,
                                          batch_size=batch_size,
                                          shuffle=False,
                                          num_workers=10,
                                          pin_memory=True)
    feature_test_dataloader = DataLoader(feature_test_dataset,
                                         batch_size=batch_size,
                                         shuffle=False,
                                         num_workers=10,
                                         pin_memory=True)

    # you can load model origin as the initialization values for model new(the classification layer)
    # path = "./model_origin[5000, 5000, 2500]"
    # # '''load origin parameters!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!'''
    # state_dict= torch.load(path)
    # model_new.classification.weight = torch.nn.Parameter(state_dict['classification.weight'].detach().cpu())
    net = model_new
    criterion = nn.CrossEntropyLoss()
    net = net.to(device)
    net.eval()
    loss_record = []
    accuracy_record = []
    # ---------------------------Origin Loading Validation(optional)-----------------------------
    # Validation the initial accuracy for model(after loading parameters from origin model)
    # validation
    for val_data, val_label in feature_test_dataloader:
        val_data, val_label = val_data.to(device), val_label.to(device)
        with torch.no_grad():
            pred = net(val_data)
            loss = criterion(pred, val_label)
        loss_record.append(loss.item())
        # accuracy
        _, index = pred.data.cpu().topk(1)
        index_label = val_label.data.cpu()
        accuracy_batch = np.sum((index.squeeze(dim=1) == index_label).numpy())
        accuracy_batch = accuracy_batch / len(val_label)
        accuracy_record.append(accuracy_batch)
    val_loss = sum(loss_record) / len(feature_test_dataloader)
    val_accuracy = sum(accuracy_record) / len(accuracy_record)

    model_new_noretrain_accuracy, model_new_noretrain_loss = val_accuracy, val_loss
    print(
        f'compressed model(without retrain): Valid loss: {model_new_noretrain_loss:.4f}, Valid accuracy: {model_new_noretrain_accuracy:.4f}'
    )

    # --------------------------------Preparing------------------------------------------
    net = model_new
    net = net.to(device)
    if device == 'cuda:1':
        cudnn.benchmark = True
    batch_size = 128
    lr = 0.01
    config = {"save_path": "./model_origin", "early_stop": 20, 'n_epochs': 500}
    early_stop_count = 0
    epochs, best_loss, step, early_stop_count = config[
        'n_epochs'], math.inf, 0, 0
    optimizer = torch.optim.SGD(net.parameters(),
                                lr=lr,
                                momentum=0.9,
                                weight_decay=5e-4)
    criterion = nn.CrossEntropyLoss()

    # ------------------------------Training and Validation-------------------------------
    for epoch in range(epochs):
        # Training
        net.train()
        loss_record = []
        accuracy_record = []
        for train_data, train_label in feature_train_dataloader:
            optimizer.zero_grad()
            train_data, train_label = train_data.to(device), train_label.to(
                device)
            pred = net(train_data)
            loss = criterion(pred, train_label)
            loss.backward()
            optimizer.step()
            loss_record.append(loss.item())
            # accuracy
            _, index = pred.data.cpu().topk(1, dim=1)
            index_label = train_label.data.cpu()
            accuracy_batch = np.sum(
                (index.squeeze(dim=1) == index_label).numpy())
            accuracy_batch = accuracy_batch / len(train_label)
            accuracy_record.append(accuracy_batch)
        train_loss = sum(loss_record) / len(loss_record)
        train_accuracy = sum(accuracy_record) / len(accuracy_record)
        # validation
        net.eval()
        loss_record = []
        accuracy_record = []
        for val_data, val_label in feature_test_dataloader:
            val_data, val_label = val_data.to(device), val_label.to(device)
            with torch.no_grad():
                pred = net(val_data)
                loss = criterion(pred, val_label)
            loss_record.append(loss.item())
            # accuracy
            _, index = pred.data.cpu().topk(1, dim=1)
            index_label = val_label.data.cpu()
            accuracy_batch = np.sum(
                (index.squeeze(dim=1) == index_label).numpy())
            accuracy_batch = accuracy_batch / len(val_label)
            accuracy_record.append(accuracy_batch)
        val_loss = sum(loss_record) / len(loss_record)
        val_accuracy = sum(accuracy_record) / len(accuracy_record)

        print(
            f'Epoch [{epoch+1}/{epochs}]: Train loss: {train_loss:.4f},Train accuracy: {train_accuracy:.4f}, Valid loss: {val_loss:.4f}, Valid accuracy: {val_accuracy:.4f}'
        )

        if val_loss < best_loss:
            best_loss = val_loss
            torch.save(net.state_dict(), "./model_new")  # Save your best model
            print('Saving model with loss {:.3f}...'.format(best_loss))
            early_stop_count = 0
        else:
            early_stop_count += 1

        if early_stop_count >= config['early_stop']:
            print('\nModel is not improving, so we halt the training session.')
            break

    # --------------------------------Calculate Memories---------------------------------------
    # calculate origin model's memory
    me_org = (input_num * weight_num_list[0] + weight_num_list[0] *
              weight_num_list[1] + weight_num_list[1] * weight_num_list[2] +
              2 * weight_num_list[2]) * 32 + (sum(weight_num_list)) * 32
    print('MEM_origin = ', me_org)

    # calculate new model's memory
    me_new = (input_num * weight_num_list[0] + weight_num_list[0] *
              weight_num_list[1] + weight_num_list[1] * weight_num_list[2] +
              2 * weight_num_list[2]) * (1 - kesi) + (sum(weight_num_list))
    print('MEM_new = ', me_new)

    print(str(weight_num_list))
    print(kesi)
    print(
        f'compressed model(without retrain): Valid loss: {model_new_noretrain_loss:.4f}, Valid accuracy: {model_new_noretrain_accuracy:.4f}'
    )
    print(
        f'compressed model(with retrain): Valid loss: {val_loss:.4f}, Valid accuracy: {val_accuracy:.4f}'
    )

    # try:
    #     # print(path)
    # except:
    #     pass
    # print(f'origin model: Valid loss: {model_origin_final_loss:.4f}, Valid accuracy: {model_origin_final_accuracy:.4f}')


import pygame
from classes import Lab_lvl
from settings import screen, width, height, BUTTON_STYLE, BUTTON_STYLE2
from button import Button
class Player:
    def __init__(self):
        self.image = pygame.image.load("images/pc3.png")
        self.geometry = self.image.get_rect()
        self.geometry.x=10
        self.geometry.y=15
        self.shift = 0
        self.shift2=0

    def check_edges(self):
        if self.geometry.top <= 0 or self.geometry.bottom >= height:
            self.shift = 0
            self.shift2 = 0
        if self.geometry.left <= 0 or self.geometry.right >= width:
            self.shift = 0
            self.shift2 = 0

    def move(self):
        self.geometry.y += self.shift
        self.geometry.x += self.shift2
        self.check_edges()

    def move_to_start(self):
        self.geometry.x = 10
        self.geometry.y = 15

    def process_event(self, event):
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_w:
                self.shift = -2
                self.shift2 = 0
            elif event.key == pygame.K_s:
                self.shift = 2
                self.shift2 = 0
            elif event.key == pygame.K_a:
                self.shift2 = -2
                self.shift = 0
            elif event.key == pygame.K_d:
                self.shift2 = 2
                self.shift = 0
        elif event.type == pygame.KEYUP:
            self.shift = 0
            self.shift2=0

class Enemy:
    def __init__(self):
        self.image = pygame.image.load("images/pac.png")
        self.geometry = self.image.get_rect()
        self.geometry.x=10
        self.geometry.y=15
        self.shift = 0
        self.shift2= 1

    def check_edges(self):
        if self.geometry.top <= 0 or self.geometry.bottom >= height:
            self.shift = 0
            self.shift2 = 0
        if self.geometry.left <= 0 or self.geometry.right >= width:
            self.shift = 0
            self.shift2 = 0

    def move(self):
        self.geometry.y += self.shift
        self.geometry.x += self.shift2
        self.check_edges()

    def move_to_start(self):
        self.geometry.x = 110
        self.geometry.y = 265

class Labyrinth:
    def __init__(self):
        self.walls = []
        self.walls2 = []
        wallx=0
        wally=0
        wallx2=0
        w_all=Lab_lvl.lvl_1()
        self.walls=w_all.return_of_y()
        self.walls2=w_all.return_of_x()
        for i in range(13):
            self.walls.append(Lab_lvl.Wall(wallx, wally))
            wally+=60
        for i in range(3):
            self.walls2.append(Lab_lvl.Wall2(wallx, 180))
            wallx+=60
        for i in range(15):
            self.walls2.append(Lab_lvl.Wall2(wallx2, wally))
            wallx2+=60
        wallx=1010
        wally=0
        for i in range(13):
            self.walls.append(Lab_lvl.Wall(wallx, wally))
            wally+=60
        wallx2=80
        for i in range(17):
            self.walls2.append(Lab_lvl.Wall2(wallx2, 0))
            wallx2+=60
        wallx=0
        for i in range(3):
            self.walls2.append(Lab_lvl.Wall2(wallx, 395))
            wallx+=60

    def get_walls(self):
        return self.walls
    def get_walls2(self):
        return self.walls2

class Menu:
    def __init__(self):
        pygame.font.init()
        self.active = True
        self.bg = pygame.image.load("images/menu_pict.png").convert()
        self.bg = pygame.transform.smoothscale(self.bg, screen.get_size())
        self.font = pygame.font.Font(None, width * height * 3 // 20000)
        self.text = self.font.render("PACMAN", True, pygame.Color('yellow'))
        self.text_rect = self.text.get_rect(center=(width / 2, height / 10))
        button_NewGame = pygame.Rect(250, height / 1.5 + height / 10, 200, 150)
        button_Exit = pygame.Rect(550, height / 1.5 + height / 10, 200, 150)
        self.new_game_button = Button(button_NewGame, pygame.Color('gray'), self.change_sceene, text='New game', **BUTTON_STYLE)
        self.exit_button = Button(button_Exit, pygame.Color('gray'), exit, text='Exit', **BUTTON_STYLE)
    def print_menu(self):
        screen.blit(self.bg, (0, 0))
        screen.blit(self.text, self.text_rect)
        self.new_game_button.update(screen)
        self.exit_button.update(screen)

    def button_clicked(self, event):
        self.new_game_button.check_event(event)
        self.exit_button.check_event(event)

    def change_sceene(self):
        self.active = False

class Game:
    def __init__(self):
        self.walls = Labyrinth().get_walls()
        self.walls2 = Labyrinth().get_walls2()
        self.player = Player()
        self.enemy = Enemy()
        self.active = False

    def print_labyrinth(self):
        screen.fill(pygame.Color('black'))
        screen.blit(self.enemy.image, self.enemy.geometry)
        screen.blit(self.player.image, self.player.geometry)
        for i in self.walls:
            screen.blit(i.image, i.geometry)
        for i in self.walls2:
            screen.blit(i.image, i.geometry)

    def check_collision(self):
        for i in self.walls:
            if self.player.geometry.colliderect(i.geometry):
                self.player.geometry.x += -self.player.shift2
                self.player.shift2 = 0
                self.player.geometry.y += -self.player.shift
                self.player.shift = 0
        for i in self.walls:
            if self.enemy.geometry.colliderect(i.geometry):
                self.enemy.shift=-self.enemy.shift

        for i in self.walls2:
            if self.player.geometry.colliderect(i.geometry):
                self.player.geometry.y += -self.player.shift
                self.player.shift = 0
                self.player.geometry.x += -self.player.shift2
                self.player.shift2 = 0
        for i in self.walls2:
            if self.enemy.geometry.colliderect(i.geometry):

                self.enemy.shift2=-self.enemy.shift2
    def new_game(self):
        self.active = True
        self.enemy.move_to_start()
        self.player.move_to_start()
        self.print_labyrinth()
        pygame.display.flip()
        self.player.shift = 0
        self.player.shift2 = 0

class Death:
    def __init__(self):
        self.active = False
        self.bg = pygame.image.load("images/game_over.jpg").convert()
        self.bg = pygame.transform.smoothscale(self.bg, screen.get_size())
        button_NewGame = pygame.Rect(250, height / 1.5 + height / 10, 200, 150)
        button_Exit = pygame.Rect(550, height / 1.5 + height / 10, 200, 150)
        self.new_game_button = Button(button_NewGame, pygame.Color('gray'), self.change_sceene, text='New game', **BUTTON_STYLE2)
        self.exit_button = Button(button_Exit, pygame.Color('gray'), exit, text='Exit', **BUTTON_STYLE2)

    def print_death(self):
        screen.blit(self.bg, (0, 0))
        self.new_game_button.update(screen)
        self.exit_button.update(screen)

    def button_clicked(self, event):
        self.new_game_button.check_event(event)
        self.exit_button.check_event(event)

    def change_sceene(self):
        self.active = False


from typing import List

class Comentario:
    def __init__(self, texto:str, nota:int, respuestas: List['Comentario'] = None):
        self.texto = texto
        self.respuestas = respuestas if respuestas is not None else []

# Recorre la lista aplicando la función a cada uno de los comentarios
# primero recorre lo aplica al comentario y posteriormente a sus respuestas
def recorrer (comentarios:List[Comentario], # Array de comentarios a recorrer
              funcion,                      # Función que quieres realizar
              max_profundidad:int = 2,      # Anidamiento de respuestas máximo
              profundidad:int = 0):         # Profudidad actual del arbol

    if not comentarios or profundidad > max_profundidad:
        return

    for comentario in comentarios:
        funcion(comentario)
        recorrer(comentario.respuestas, funcion, max_profundidad, profundidad+1)

# TEST DE EJEMPLO | SOLO SE EJECUTA SI EJECUTAS ESTE FICHERO COMO MAIN
if __name__ == "__main__":

    comentario0 = Comentario ("Hola soy la raíz", 0)
    comentario1 = Comentario ("Hola soy una respuesta", 1)
    comentario2 = Comentario ("Hola soy una respuesta a una respuesta", 2)
    comentario3 = Comentario ("De vuelta a la raíz", 3)
    comentarioN = Comentario ("Este comentario no debería de salir", -1)

    comentario0.respuestas.append(comentario1)
    comentario1.respuestas.append(comentario2)
    comentarioN.respuestas.append(comentarioN)

    comentarios = [comentario0, comentario3]

    def verTexto(comentario:Comentario):
        print(comentario.texto)

    recorrer(comentarios, verTexto)


import io
from random import randint, uniform
from userbot import bot, CMD_HELP
from userbot.events import register

from PIL import Image, ImageEnhance, ImageOps
from telethon.tl.types import DocumentAttributeFilename

from telethon import events

@register(pattern="^.deepfry(?: |$)(.*)", outgoing=True)
async def deepfryer(event):
    try:
        frycount = int(event.pattern_match.group(1))
        if frycount < 1:
            raise ValueError
    except ValueError:
        frycount = 1

    if event.is_reply:
        reply_message = await event.get_reply_message()
        data = await check_media(reply_message)

        if isinstance(data, bool):
            await event.edit("`Bunu deepfry edə bilmərəm!`")
            return
    else:
        await event.edit("`Deepfry eləmək üçün bir şəkilə vəya stikerə cavab olaraq qarşısına yazmalısız.`")
        return

    # Fotoğrafı (yüksek çözünürlük) bayt dizisi olarak indir
    await event.edit("`Şəkil yüklənir...`")
    image = io.BytesIO()
    await event.client.download_media(data, image)
    image = Image.open(image)

    # Resime uygula
    await event.edit("`Şəkilə deepfry edilir...`")
    for _ in range(frycount):
        image = await deepfry(image)

    fried_io = io.BytesIO()
    fried_io.name = "image.jpeg"
    image.save(fried_io, "JPEG")
    fried_io.seek(0)

    await event.reply(file=fried_io)

async def deepfry(img: Image) -> Image:
    colours = (
        (randint(50, 200), randint(40, 170), randint(40, 190)),
        (randint(190, 255), randint(170, 240), randint(180, 250))
    )

    img = img.copy().convert("RGB")

    # Resim formatı ayarla
    img = img.convert("RGB")
    width, height = img.width, img.height
    img = img.resize((int(width ** uniform(0.8, 0.9)), int(height ** uniform(0.8, 0.9))), resample=Image.LANCZOS)
    img = img.resize((int(width ** uniform(0.85, 0.95)), int(height ** uniform(0.85, 0.95))), resample=Image.BILINEAR)
    img = img.resize((int(width ** uniform(0.89, 0.98)), int(height ** uniform(0.89, 0.98))), resample=Image.BICUBIC)
    img = img.resize((width, height), resample=Image.BICUBIC)
    img = ImageOps.posterize(img, randint(3, 7))

    # Renk yerleşimi oluştur
    overlay = img.split()[0]
    overlay = ImageEnhance.Contrast(overlay).enhance(uniform(1.0, 2.0))
    overlay = ImageEnhance.Brightness(overlay).enhance(uniform(1.0, 2.0))

    overlay = ImageOps.colorize(overlay, colours[0], colours[1])

    # Kırmızı ve sarıyı ana görüntüye yerleştir ve keskinleştir
    img = Image.blend(img, overlay, uniform(0.1, 0.4))
    img = ImageEnhance.Sharpness(img).enhance(randint(5, 300))

    return img

async def check_media(reply_message):
    if reply_message and reply_message.media:
        if reply_message.photo:
            data = reply_message.photo
        elif reply_message.document:
            if DocumentAttributeFilename(file_name='AnimatedSticker.tgs') in reply_message.media.document.attributes:
                return False
            if reply_message.gif or reply_message.video or reply_message.audio or reply_message.voice:
                return False
            data = reply_message.media.document
        else:
            return False
    else:
        return False

    if not data or data is None:
        return False
    else:
        return data

CMD_HELP.update({
    "deepfry":
    "✏**Əmr:** .deepfry [rəqəm 1-5]\
    \n🔰**İşlədilişi:** Seçilən şəkilə deepfry efekti edər."
})


import yaml

class Generator(object):
    def __init__(self, schema_path):
        self.schema_path = schema_path
        self.tables = []
        self.triggers = []
        self.data = None

    def read_schema(self):
        with open(self.schema_path, 'r') as f:
            self.data = yaml.load(f.read())
        # print(self.data['Category']['relations'])

    @staticmethod
    def create_table(name, data):
        table = (
            'DROP TABLE IF EXISTS {table_name};\n'
            'CREATE TABLE {table_name} (\n'
            '    id SERIAL NOT NULL PRIMARY KEY,\n'
            '    {fields},\n'
            '    created TIMESTAMP NOT NULL,\n'
            '    updated TIMESTAMP NOT NULL\n'
            ');\n'
        ).format(
            table_name=name.lower(),
            fields=',\n    '.join(
                [f'{k} {v.upper()}' for k, v in data['fields'].items()]
            )
        )
        return table

    @staticmethod
    def trigger_for_created(name):
        trigger = (
            'CREATE OR REPLACE FUNCTION updated() RETURNS TRIGGER\n'
            'AS $$\n'
            'BEGIN\n'
            '    UPDATE {table_name} SET updated = NOW() WHERE id = OLD.id;\n\n'
            '    RETURN OLD;\n'
            'END;\n'
            '$$ LANGUAGE plpgsql;\n\n'
            'DROP TRIGGER IF EXISTS tr_updated ON {table_name};\n'
            'CREATE TRIGGER tr_updated AFTER UPDATE ON {table_name}\n'
            'FOR EACH ROW EXECUTE PROCEDURE updated();\n'

        ).format(
            table_name=name.lower()
        )
        return trigger

    @staticmethod
    def trigger_for_updated(name):
        trigger = (
            'CREATE OR REPLACE FUNCTION created() RETURNS TRIGGER\n'
            'AS $$\n'
            'BEGIN\n'
            '    UPDATE {table_name} SET created = NOW() WHERE id = OLD.id;\n\n'
            '    RETURN OLD;\n'
            'END;\n'
            '$$ LANGUAGE plpgsql;\n\n'
            'DROP TRIGGER IF EXISTS tr_created ON {table_name};\n'
            'CREATE TRIGGER tr_created AFTER INSERT ON {table_name}\n'
            'FOR EACH ROW EXECUTE PROCEDURE created();\n'

        ).format(
            table_name=name.lower()
        )
        return trigger

    def create_relations(self, table):
        rel = self.data[table]['relations']
        keys = list(rel.keys())
        result = ''

        for i in keys:
            t = table.lower()
            t2 = i.lower()

            if rel[i] == 'one' and self.data[i]['relations'][table] == 'many':
                return f'ALTER TABLE {t} ADD COLUMN {t2}_id INTEGER REFERENCES {t2}(id);\n'

            if rel[i] == 'many' and self.data[i]['relations'][table] == 'many':
                result = f'DROP TABLE IF EXISTS {t}_{t2};\n' \
                         f'CREATE TABLE {t}_{t2} (\n' \
                         f'     {t}_id INTEGER REFERENCES {t}(id),\n' \
                         f'     {t2}_id INTEGER REFERENCES {t2}(id)\n' \
                          ');\n'
                del self.data[i]['relations'][table]

        return result

    def generate_tables(self):
        for table, data in self.data.items():
            self.tables.append(self.create_table(table, data))
            self.tables.append(self.create_relations(table))

    def generate_triggers(self):
        for i in self.data:
            self.triggers.append(self.trigger_for_created(i))
            self.triggers.append(self.trigger_for_updated(i))

    def write_to_file(self):
        with open('db.sql', 'w') as f:
            f.write('\n'.join(self.tables))
            f.write('\n')
            f.write('\n'.join(self.triggers))

    def generate(self):
        self.read_schema()
        self.generate_tables()
        self.generate_triggers()
        self.write_to_file()

g = Generator('schema.yml')
g.generate()


# 2260. Minimum Consecutive Cards to Pick Up
# Given an integer array cards, find the length of the shortest subarray that contains at least one duplicate.
# If the array has no duplicates, return -1.

from collections import defaultdict

class Solution:
    def minimumCardPickup(self, cards: list[int]) -> int:
        # THIS VERSION STORES EVERY CARD INDEX IN card_positons DICTIONARY - O(n) EVERY RUN
        # card_positions = defaultdict(list)
        # shortest = float("inf")
        # for i in range(len(cards)):
        #     card_positions[cards[i]].append(i)  # when card appears, append its index to to it

        # shortest = float("inf")
        # for key in card_positions:
        #     index_list = card_positions[key]  # each card's list of indexes
        #     for i in range(len(index_list) - 1):  # length of 'index_list - 1' since next line accesses 'i + 1'
        #         sub_array_len = index_list[i + 1] - index_list[i] + 1  # since card indexes in order, results in subarray length
        #         shortest = min(shortest, sub_array_len)

        # THIS VERSION ONLY STORES INDEX IN card_positons DICTIONARY WHEN NEEDED - O(n) IN WORST CASE OF NO DUPLICATE CARDS
        card_positions = defaultdict(int)
        shortest = float("inf")
        for i in range(len(cards)):
            if cards[i] in card_positions:
                # (current card index) - (last index card was seen at) + 1
                shortest = min(shortest, i - card_positions[cards[i]] + 1)

            # update last index card was seen at
            card_positions[cards[i]] = i

        return shortest if shortest < float("inf") else -1  # type: ignore

cards = [1, 2, 7, 5, 2, 4]
# Output: 4

sol = Solution()
print(sol.minimumCardPickup(cards))


"""Run this test under backend folder."""
from subprocess import Popen, PIPE, call
import time
import requests
import logging
from tqdm import tqdm
import pandas as pd

n = 10
my_url= "http://localhost:8080/api/warnings/new"
res_redis = []
res_sql = []
logging.basicConfig(filename="logs/test_cache_locality.log",
					format='%(asctime)s %(message)s',
					filemode='w')
logger=logging.getLogger()
logger.setLevel(logging.DEBUG)

def test1():
    ## This part tests for cache/no cache difference ###
    # Clearly the size of the cache influences the performance #
    call ("./bin/clearall.sh")
    ### TEST 1###
    # This part: after inserting 1000 pieces of warnings, get_new #
    # Cache: 1000 queries, history_compare: 1000 queries#
    # Anticipation: the cache is not going to work properly #
    logger.debug("##### TEST 1 #####")
    # This is test_mode=cache #

    # inserted 10 new warnings into history and cache
    call("python3 generate_warnings.py random cache 100", shell=True)
    url_str_cache= "http://localhost:8080/warnings/new"
    test1_cache_start = time.time()
    r = requests.get(url_str_cache)
    test1_cache_end = time.time()
    test1_cache_time = test1_cache_end - test1_cache_start
    logger.debug("Time used for cache + database: " + str(test1_cache_time))

    # inserted 10 new warnings into history_compare and cache
    call("python3 generate_warnings.py random nocache 100", shell=True)
    url_str_cache= "http://localhost:8080/compare/warnings/new"
    test1_nocache_start = time.time()
    r = requests.get(url_str_cache)
    test1_nocache_end = time.time()
    test1_nocache_time = test1_nocache_end - test1_nocache_start
    logger.debug("Time used for database only: " + str(test1_nocache_time))
    logger.debug("##### END OF TEST 1 #####\n")
    return test1_cache_time, test1_nocache_time

def test2():
    ### TEST 2###
    # This part: after inserting 1000 pieces of warnings, get_new, insert 10 pieces of warnings, get_new #
    # Cache: 10 queries, history_compare: 1010 queries#
    # Anticipation: the cache is going to work properly #
    call ("./bin/clearall.sh")
    logger.debug("##### TEST 2 #####")
    # inserted 100 new warnings into history and cache
    call("python3 generate_warnings.py random cache 100", shell=True)
    requests.get("http://localhost:8080/warnings/new")
    # test the time needed to get another 10 new warnings
    call("python3 generate_warnings.py random cache 10", shell=True)
    test2_cache_start = time.time()
    requests.get("http://localhost:8080/warnings/new")
    test2_cache_end = time.time()
    test2_cache_time = test2_cache_end - test2_cache_start
    logger.debug("Time used for cache + database: " + str(test2_cache_time))

    call("python3 generate_warnings.py random nocache 100", shell=True)
    requests.get("http://localhost:8080/compare/warnings/new")
    call("python3 generate_warnings.py random nocache 10", shell=True)
    test2_nocache_start = time.time()
    requests.get("http://localhost:8080/compare/warnings/new")
    test2_nocache_end = time.time()
    test2_nocache_time = test2_nocache_end - test2_nocache_start
    logger.debug("Time used for database only: " + str(test2_nocache_time))

    logger.debug("##### END OF TEST 2 #####\n")
    return test2_cache_time, test2_nocache_time

def test3():
    ### TEST 3###
    # This part: compare between inserting 1000 pieces of random warnings and naive locality #
    # Anticipation: the cache is not going to work properly #
    logger.debug("##### TEST 3 #####")
    # This is test_mode=cache #
    # clear all memories, including mysql databases and redis cache
    call("./bin/clearall.sh")

    call("python3 generate_warnings.py random cache 100", shell=True)
    test3_random_start = time.time()
    r = requests.get("http://localhost:8080/warnings/new")
    test3_random_end = time.time()
    test3_random_time = test3_random_end - test3_random_start
    logger.debug("Time used for random: " + str(test3_random_time))

    call("python3 generate_warnings.py locality cache 100", shell=True)
    test3_locality_start = time.time()
    r = requests.get("http://localhost:8080/warnings/new")
    test3_locality_end = time.time()
    test3_locality_time = test3_locality_end - test3_locality_start
    logger.debug("Time used for locality: " + str(test3_locality_time))

    logger.debug("##### END OF TEST 3 #####\n")
    return test3_random_time, test3_locality_time

def stats_helper(test_id, test_results, col1, col2):
    print("### RESULTS FOR TEST " + str(test_id) + " ###")
    print("mean:")
    print(col1 + ": " + str(test_results[col1].mean()))
    print(col2 + ": " + str(test_results[col2].mean()))
    print("max:")
    print(col1 + ": " + str(test_results[col1].max()))
    print(col2 + ": " + str(test_results[col2].max()))
    print("min:")
    print(col1 + ": " + str(test_results[col1].min()))
    print(col2 + ": " + str(test_results[col2].min()))

def result_collector(testid, func, col1, col2):
    res1 = []
    res2 = []
    global n
    for _ in tqdm(range(n)):
        temp1, temp2 = func()
        res1.append(temp1)
        res2.append(temp2)
    data = {col1: res1, col2: res2}
    test1_results = pd.DataFrame(data,columns = [col1, col2])
    result_str = "experiment_results/test" + str(testid) + "_detail.csv"
    test1_results.to_csv(result_str)
    stats_helper(testid, test1_results, col1, col2)

def main():
    result_collector(1, test1, "with cache", "no cache")
    result_collector(2, test2, "with cache", "no cache")
    result_collector(3, test3, "random", "locality")

if __name__ == "__main__":
   main()


from django.urls import path
from . import views

urlpatterns = [
    path('Adjectives/', views.Adjectives.as_view(),
         name='Adjectives'),
    path('Categorize/', views.Categorize.as_view(),
         name='Categorize'),
    path('Nouns/', views.Nouns.as_view(),
         name='Nouns'),
    path('RankPositiveSentiments/', views.RankPositiveSentiments.as_view(),
         name='RankPositiveSentiments'),
    path('RankNegativeSentiments/', views.RankNegativeSentiments.as_view(),
         name='RankNegativeSentiments'),
]