from datetime import date, datetime

from jinja2 import Markup
from wtforms.widgets.core import html_params

from pycroft.helpers import utc
from web.template_filters import date_filter, datetime_filter

class Column:
    """A class representing a bootstrap-table column

    This class bundles all the attributes commonly needed to represent
    a table column as used in a bootstrap-table.  It defines a method
    :py:meth:`build_col_args` for building the args needed in the
    corresponding ```` element for the table header.

    For documentation concerning bootstrap-tables in general, see
    http://bootstrap-table.wenzhixin.net.cn/documentation/

    :param name: The name of the column.  This must coincide with the
        key given in the JSON endpoint's response, e.g. if this
        column's name is ``user_id``, the response JSON has to be of
        the form ``{"items": [{"user_id": value, …}, …]}``.
    :param title: The title to be displayed in the column header.
    :param formatter: An optional formatter to use.  The referenced
        value must be available as a javascript function for the
        column's value parsing to work properly.  See the
        ``data-formatter`` attribute in the bootstrap-table docs for
        details.
    :param width: An optional width, being translated to the
        ``col-sm-{width}`` bootstrap class.
    :param cell_style: Similar to :param:`formatter`, an optional
        javascript function's name to be passed to
        ``data-cell-style``.
    """
    def __init__(self, name, title, formatter=None, width=0, cell_style=None):
        self.name = name
        self.title = title
        self.formatter = formatter if formatter is not None else False
        self.cell_style = cell_style if cell_style is not None else False
        self.width = width

    def __repr__(self):
        return "<{cls} {name!r} title={title!r}>".format(
            cls=type(self).__name__,
            name=self.name,
            title=self.title,
        )

    def build_col_args(self, **kwargs):
        """Build th html-style attribute string for this column.

        This string can be used to add this column to a table in the
        header: ``"	".format(col.build_col_args())``.
        Attributes are utilized as described in :meth:`__init__`.

        :param kwargs: Keyword arguments which are merged into the
            dict of html attributes.
        """
        html_args = {
            'class': "col-sm-{}".format(self.width) if self.width else False,
            'data-sortable': "true",
            'data-field': self.name,
            'data-formatter': self.formatter,
            'data-cell-style': self.cell_style,
        }
        html_args.update(kwargs)
        return html_params(**html_args)

    def render(self):
        """Render this column as a ```` html tag.

        This uses the arguments provided by :meth:`build_col_args` and
        the :attr:`title` for the inner HTML.
        """
        return "{}	".format(self.build_col_args(), self.title)

    __str__ = render
    __html__ = render

class BootstrapTable:
    """An extendable, HTML-renderable bootstrap-table

    The table's HTML can be rendered using :meth:`render`.  NB:
    :meth:`__str__` and :meth:`__html__` are NOT provided, since
    :meth:`render` expects an obligatory `table_id`!

    :param columns: A list of :py:cls:`Column` objects defining the
        columns.
    :param data_url: The URL to be used as a JSON endpoint.  The JSON
        endpoint must provide the table data in the scheme defaulting
        to ``{"rows": [], "total": …}``.  In this instance, a custom
        response handler is used, which accesses the table contents on
        the sub-key ``items``: ``{"items": {"rows": …, "total": …}}``.
        The endpoint should also support the parameters limit, offset,
        search, sort, order to make server-side pagination work.
    :param table_args: Additional things to be passed to table_args.
    """
    def __init__(self, columns, data_url, table_args=None):
        self.columns = columns
        self.data_url = data_url
        self.table_args = table_args if table_args is not None else {}
        self._init_table_args()

    def __repr__(self):
        return "<{cls} cols={numcols} data_url={data_url!r}>".format(
            cls=type(self).__name__,
            numcols=len(self.columns),
            data_url=self.data_url,
        )

    def _init_table_args(self):
        """Set the defaults of :py:attr:`table_args`"""
        default_args = {
            'data-toggle': "table",
            'data-url': self.data_url,
        }
        for key, val in default_args.items():
            self.table_args.setdefault(key, val)

    def generate_table_header(self):
        """Generate the table header from :py:attr:`columns`.

        :rtype: generator
        """
        yield "
"
        yield "
"
        for col in self.columns:
            yield str(col)
        yield "
"
        yield "
"

    @staticmethod
    def generate_toolbar():
        """Return an empty iterator.

        Used to generate the inner HTML contents of the toolbar.

        :rtype: iterator
        """
        return iter(())

    @staticmethod
    def generate_table_footer():
        """Return an empty iterator.

        Used to generate the outer HTML contents of the footer.  Must
        yield the ``
`` tag as well.

        :rtype: iterator
        """
        return iter(())

    def render(self, table_id):
        """Render the table
        """
        # NB: in html_args, setting an argument to `False` makes it
        # disappear.
        html = []

        toolbar_args = html_params(id="{}-toolbar".format(table_id),
                                   class_="btn-toolbar",
                                   role="toolbar")
        html.append("
".format(toolbar_args))
        html += list(self.generate_toolbar())
        html.append("
")

        table_args = self.table_args
        table_args.update({
            'id': table_id,
            'data-toolbar': "#{}-toolbar".format(table_id),
        })

        html.append("
".format(html_params(**table_args)))
        html += list(self.generate_table_header())
        html += list(self.generate_table_footer())
        html.append("
")

        return Markup("\n".join(html))

class SplittedTable(BootstrapTable):
    def __init__(self, *a, splits, **kw):
        """Initialize a new Splitted Table

        :param splits: Split definitions of the format
            (('split_1_prefix', "Display_Name"), …).  The format will
            be checked
        :param kwargs: Passed to super()
        """
        super().__init__(*a, **kw)
        # each split shall have the format:
        # ('split_prefix', "Name to be displayed")
        if any(len(x) != 2 for x in splits):
            raise ValueError("`splits` must be a tuple of 2-tuples")
        self.splits = splits

    def generate_table_header(self):
        yield "
"
        yield "
"
        for _, split_name in self.splits:
            yield ("{}	"
                   .format(len(self.columns), split_name))
        yield "
"

        yield "
"
        def prefixed_col(prefix, col_name):
            return "{prefix}_{col_name}".format(prefix=prefix, col_name=col_name)
        for split_prefix, _ in self.splits:
            for col in self.columns:
                new_name = prefixed_col(split_prefix, col.name)
                yield "{}	".format(
                    col.build_col_args(**{'data-field': new_name}),
                    col.title
                )
        yield "
"
        yield "
"

def date_format(dt, default=None):
    """
    Format date or datetime objects for `table.dateFormatter`.
    :param datetime|date|None dt: a date or datetime object or None
    :param str|None default: formatted value to use if `dt` is None
    :return:
    """
    if dt is not None:
        return {
            'formatted': date_filter(dt),
            'timestamp': int(datetime.combine(dt, utc.time_min()).timestamp()),
        }
    else:
        return {
            'formatted': default if default is not None else date_filter(None),
            'timestamp': None,
        }

def datetime_format(dt, default=None):
    """
    Format datetime objects for `table.dateFormatter`.
    :param datetime|None dt: a datetime object or None
    :param str|None default: formatted value to use if `dt` is None
    :return:
    """
    if dt is not None:
        return {
            'formatted': datetime_filter(dt),
            'timestamp': int(dt.timestamp()),
        }
    else:
        return {
            'formatted': default if default is not None else datetime_filter(None),
            'timestamp': None,
        }


from __future__ import annotations

import argparse
import json
import re
from typing import Any, Dict, List

import together
from together import Complete
from together.utils import get_logger

logger = get_logger(str(__name__))

def add_parser(subparsers: argparse._SubParsersAction[argparse.ArgumentParser]) -> None:
    COMMAND_NAME = "complete"
    subparser = subparsers.add_parser(COMMAND_NAME)

    subparser.add_argument(
        "prompt",
        metavar="PROMPT",
        default=None,
        type=str,
        help="A string providing context for the model to complete.",
    )

    subparser.add_argument(
        "--model",
        "-m",
        default=together.default_text_model,
        type=str,
        help=f"The name of the model to query. Default={together.default_text_model}",
    )

    subparser.add_argument(
        "--no-stream",
        default=False,
        action="store_true",
        help="Indicates wether to disable streaming",
    )

    subparser.add_argument(
        "--max-tokens",
        default=128,
        type=int,
        help="Maximum number of tokens to generate. Default=128",
    )
    subparser.add_argument(
        "--stop",
        default=["<human>"],
        nargs="+",
        type=str,
        metavar="STOP_WORD",
        help="Strings that will truncate (stop) text generation. Default='<human>'",
    )
    subparser.add_argument(
        "--temperature",
        default=0.7,
        type=float,
        help="Determines the degree of randomness in the response. Default=0.7",
    )
    subparser.add_argument(
        "--top-p",
        default=0.7,
        type=float,
        help="Used to dynamically adjust the number of choices for each predicted token based on the cumulative probabilities. Default=0.7",
    )
    subparser.add_argument(
        "--top-k",
        default=50,
        type=int,
        help="Used to limit the number of choices for the next predicted word or token. Default=50",
    )
    subparser.add_argument(
        "--repetition-penalty",
        default=None,
        type=float,
        help="Controls the diversity of generated text by reducing the likelihood of repeated sequences. Higher values decrease repetition.",
    )
    subparser.add_argument(
        "--logprobs",
        default=None,
        type=int,
        help="Specifies how many top token log probabilities are included in the response for each token generation step.",
    )
    subparser.add_argument(
        "--raw",
        default=False,
        action="store_true",
        help="temperature for the LM",
    )
    subparser.set_defaults(func=_run_complete)

def _enforce_stop_tokens(text: str, stop: List[str]) -> str:
    """Cut off the text as soon as any stop words occur."""
    return re.split("|".join(stop), text)[0]

def no_streamer(args: argparse.Namespace, response: Dict[str, Any]) -> None:
    if args.raw:
        print(json.dumps(response, indent=4))

    else:
        if "output" in response.keys():
            if "choices" in dict(response["output"]).keys():
                text = str(response["output"]["choices"][0]["text"])
                print(text.strip())
            elif "error" in dict(response["output"]).keys():
                raise together.ResponseError(response["output"]["error"])
            else:
                raise together.ResponseError(
                    f"Unknown error occured. Received unhandled response: {response}"
                )

        elif "error" in response.keys():
            if response["error"] == "Returned error: no instance":
                message = f"No running instances for {args.model}. You can start an instance by navigating to the Together Playground at api.together.xyz"
                raise together.InstanceError(model=args.model, message=message)
            else:
                raise together.ResponseError(
                    message=f"Error raised: {response['error']}"
                )

        else:
            raise together.ResponseError("Unknown response received. Please try again.")

def _run_complete(args: argparse.Namespace) -> None:
    complete = Complete()

    if args.no_stream:
        try:
            response = complete.create(
                prompt=args.prompt,
                model=args.model,
                max_tokens=args.max_tokens,
                stop=args.stop,
                temperature=args.temperature,
                top_p=args.top_p,
                top_k=args.top_k,
                repetition_penalty=args.repetition_penalty,
                logprobs=args.logprobs,
            )
        except together.AuthenticationError:
            logger.critical(together.MISSING_API_KEY_MESSAGE)
            exit(0)
        no_streamer(args, response)
    else:
        try:
            for text in complete.create_streaming(
                prompt=args.prompt,
                model=args.model,
                max_tokens=args.max_tokens,
                stop=args.stop,
                temperature=args.temperature,
                top_p=args.top_p,
                top_k=args.top_k,
                repetition_penalty=args.repetition_penalty,
                raw=args.raw,
            ):
                if not args.raw:
                    print(text, end="", flush=True)
                else:
                    print(text)
        except together.AuthenticationError:
            logger.critical(together.MISSING_API_KEY_MESSAGE)
            exit(0)
        if not args.raw:
            print("\n")


import random
import cv2
import numpy as np
import torch

class Compose:
    def __init__(self, transforms):
        self.transforms = transforms

    def __call__(self, image, targets):
        for transform in self.transforms:
            image, targets = transform(image, targets)
        return image, targets

class FlipColorChannelOrder:
    def __call__(self, image, targets=None):
        image = image[:, :, ::-1]
        return image, targets

class Normalize:
    def __call__(self, image, targets=None):
        image = image.astype(np.float32) / 255
        return image, targets

class NormalizeTargets:
    def __call__(self, image, targets=None):
        size = max(image.shape[:2])
        if targets is not None:
            targets[:, :4] /= size
        return image, targets

class Pad:
    def __init__(self, random_padding):
        self.random_padding = random_padding

    def __call__(self, image, targets=None):
        h, w = image.shape[:2]
        offset = self._compute_offset(np.array([w, h]))
        left, top = offset
        out_size = max(w, h)
        new_image = np.ones((out_size, out_size, 3), dtype=np.uint8) * 127
        new_image[top:top + h, left:left + w] = image
        if targets is not None:
            targets[:, :2] += offset
        return new_image, targets

    def _compute_offset(self, image_size):
        out_size = max(image_size)
        w, h = image_size
        if self.random_padding:
            dx = np.random.randint(out_size - w + 1)
            dy = np.random.randint(out_size - h + 1)
        else:
            dx = (out_size - w) // 2
            dy = (out_size - h) // 2
        return np.array([dx, dy])

class RandomDistort:
    def __init__(self, hue, saturation, exposure):
        self.hue = hue
        self.saturation = saturation
        self.exposure = exposure

    def __call__(self, image, targets=None):
        image = self._randomly_distort(image)
        return image, targets

    @staticmethod
    def _compute_random_scale(max_scale):
        scale = np.random.uniform(1, max_scale)
        return scale if random.random() < 0.5 else 1 / scale

    def _randomly_distort(self, image):
        diff_hue = np.random.uniform(-self.hue, self.hue)
        sat_scale = self._compute_random_scale(self.saturation)
        exp_scale = self._compute_random_scale(self.exposure)

        hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
        hsv = hsv.astype(np.float32)
        hsv[:, :, 0] /= 179
        hsv[:, :, 1:] /= 255
        hue = hsv[:, :, 0] + diff_hue
        hsv[:, :, 1] *= sat_scale
        hsv[:, :, 2] *= exp_scale
        if diff_hue > 0:
            hue[hue > 1] -= 1
        else:
            hue[hue < 0] += 1
        hsv[:, :, 0] = np.round((hue * 179).clip(0, 179))
        hsv[:, :, 1:] = np.round((hsv[:, :, 1:] * 255).clip(0, 255))
        hsv = hsv.astype(np.uint8)
        image = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
        return image

class RandomHorizontalFlip:
    def __call__(self, image, targets=None):
        if random.random() < 0.5:
            image = image[:, ::-1]
            if targets is not None:
                targets[:, 0] = 1 - targets[:, 0]
        return image, targets

class Resize:
    def __init__(self, out_size, random_aspect_ratio_jitter):
        self.out_size = out_size
        self.jitter = random_aspect_ratio_jitter

    def __call__(self, image, targets=None):
        h, w = image.shape[:2]
        org_size = np.array([w, h])
        new_size = self.jitter_and_scale_size(org_size)
        image = cv2.resize(image, tuple(new_size))
        if targets is not None:
            scale = new_size / org_size
            targets[:, :4] *= np.concatenate([scale, scale])
        return image, targets

    def jitter_and_scale_size(self, image_size):
        w, h = self._jitter_size(image_size, self.jitter)
        new_size = self._scale_size_based_on_longer_edge(self.out_size, w / h)
        return new_size

    @staticmethod
    def _jitter_size(image_size, jitter):
        max_dw, max_dh = image_size * jitter
        dw = np.random.uniform(-max_dw, max_dw)
        dh = np.random.uniform(-max_dh, max_dh)
        return image_size + np.array([dw, dh])

    @staticmethod
    def _scale_size_based_on_longer_edge(out_size, new_aspect_ratio):
        if new_aspect_ratio < 1:
            new_h = out_size
            new_w = new_h * new_aspect_ratio
        else:
            new_w = out_size
            new_h = new_w / new_aspect_ratio
        return np.array([new_w, new_h]).astype(np.int)

class ToFixedSizeTargets:
    def __init__(self, max_targets):
        self.max_targets = max_targets

    def __call__(self, image, targets=None):
        padded_targets = np.zeros((self.max_targets, 5))
        if targets is not None:
            targets = targets[:self.max_targets]
            padded_targets[:len(targets)] = targets
        return image, padded_targets

class ToTensor:
    def __call__(self, image, targets):
        image = torch.from_numpy(image.transpose(2, 0, 1)).float()
        if targets is not None:
            targets = torch.from_numpy(targets).float()
        return image, targets

class ToYOLOTargets:
    def __call__(self, image, targets):
        """Convert COCO annotation to target

        Args:
            image (np.ndarray): image
            targets (dict): COCO annotation
                bounding box is represented as (x0, y0, w, h) where
                    (x0, y0): coordinates of top-left corner of it
                    (w, h): size

        Returns:
            (tuple): (image, targets)
                image (np.ndarray): image
                targets (np.ndarray or None): (shape: Nx5)
                    each row is (bbox, category_index) where
                        bbox: (shape: 4) (xc, yc, w, h) where
                            (xc, yc): coordinates of center of the
                                bounding box
                            (w, h): size of the bounding box
                        category_index: category index in the list
                            of categories considered

        """
        converted_targets = []
        for annotation in targets:
            bbox = np.asarray(annotation['bbox'])
            bbox[:2] = bbox[:2] + bbox[2:] / 2
            converted_targets.append([*bbox, annotation['category_index']])
        if len(converted_targets) > 0:
            converted_targets = np.vstack(converted_targets)
        else:
            converted_targets = None
        return image, converted_targets


import pytest

from dbt.cli.main import dbtRunner
from dbt.contracts.graph.manifest import Manifest
from dbt.exceptions import ParsingError
from dbt.tests.util import run_dbt, get_manifest

from tests.functional.metrics.fixtures import (
    mock_purchase_data_csv,
    models_people_sql,
    models_people_metrics_yml,
    invalid_models_people_metrics_yml,
    invalid_metrics_missing_model_yml,
    invalid_metrics_missing_expression_yml,
    names_with_spaces_metrics_yml,
    names_with_special_chars_metrics_yml,
    names_with_leading_numeric_metrics_yml,
    long_name_metrics_yml,
    downstream_model_sql,
    invalid_derived_metric_contains_model_yml,
    derived_metric_yml,
    invalid_metric_without_timestamp_with_time_grains_yml,
    invalid_metric_without_timestamp_with_window_yml,
    metricflow_time_spine_sql,
    semantic_model_people_yml,
    semantic_model_purchasing_yml,
    purchasing_model_sql,
)

class TestSimpleMetrics:
    @pytest.fixture(scope="class")
    def models(self):
        return {
            "people_metrics.yml": models_people_metrics_yml,
            "metricflow_time_spine.sql": metricflow_time_spine_sql,
            "semantic_model_people.yml": semantic_model_people_yml,
            "people.sql": models_people_sql,
        }

    def test_simple_metric(
        self,
        project,
    ):
        runner = dbtRunner()
        result = runner.invoke(["parse"])
        assert result.success
        assert isinstance(result.result, Manifest)
        manifest = get_manifest(project.project_root)
        metric_ids = list(manifest.metrics.keys())
        expected_metric_ids = [
            "metric.test.number_of_people",
            "metric.test.collective_tenure",
            "metric.test.collective_window",
            "metric.test.average_tenure",
            "metric.test.average_tenure_minus_people",
        ]
        assert metric_ids == expected_metric_ids

        assert (
            len(manifest.metrics["metric.test.number_of_people"].type_params.input_measures) == 1
        )
        assert (
            len(manifest.metrics["metric.test.collective_tenure"].type_params.input_measures) == 1
        )
        assert (
            len(manifest.metrics["metric.test.collective_window"].type_params.input_measures) == 1
        )
        assert len(manifest.metrics["metric.test.average_tenure"].type_params.input_measures) == 2
        assert (
            len(
                manifest.metrics[
                    "metric.test.average_tenure_minus_people"
                ].type_params.input_measures
            )
            == 3
        )

class TestInvalidRefMetrics:
    @pytest.fixture(scope="class")
    def models(self):
        return {
            "people_metrics.yml": invalid_models_people_metrics_yml,
            "people.sql": models_people_sql,
        }

    # tests that we get a ParsingError with an invalid model ref, where
    # the model name does not have quotes
    def test_simple_metric(
        self,
        project,
    ):
        # initial run
        with pytest.raises(ParsingError):
            run_dbt(["run"])

class TestInvalidMetricMissingModel:
    @pytest.fixture(scope="class")
    def models(self):
        return {
            "people_metrics.yml": invalid_metrics_missing_model_yml,
            "people.sql": models_people_sql,
        }

    # tests that we get a ParsingError with an invalid model ref, where
    # the model name does not have quotes
    def test_simple_metric(
        self,
        project,
    ):
        # initial run
        with pytest.raises(ParsingError):
            run_dbt(["run"])

class TestInvalidMetricMissingExpression:
    @pytest.fixture(scope="class")
    def models(self):
        return {
            "people_metrics.yml": invalid_metrics_missing_expression_yml,
            "people.sql": models_people_sql,
        }

    # tests that we get a ParsingError with a missing expression
    def test_simple_metric(
        self,
        project,
    ):
        # initial run
        with pytest.raises(ParsingError):
            run_dbt(["run"])

class TestNamesWithSpaces:
    @pytest.fixture(scope="class")
    def models(self):
        return {
            "people_metrics.yml": names_with_spaces_metrics_yml,
            "people.sql": models_people_sql,
        }

    def test_names_with_spaces(self, project):
        with pytest.raises(ParsingError) as exc:
            run_dbt(["run"])
        assert "cannot contain spaces" in str(exc.value)

class TestNamesWithSpecialChar:
    @pytest.fixture(scope="class")
    def models(self):
        return {
            "people_metrics.yml": names_with_special_chars_metrics_yml,
            "people.sql": models_people_sql,
        }

    def test_names_with_special_char(self, project):
        with pytest.raises(ParsingError) as exc:
            run_dbt(["run"])
        assert "must contain only letters, numbers and underscores" in str(exc.value)

class TestNamesWithLeandingNumber:
    @pytest.fixture(scope="class")
    def models(self):
        return {
            "people_metrics.yml": names_with_leading_numeric_metrics_yml,
            "people.sql": models_people_sql,
        }

    def test_names_with_leading_number(self, project):
        with pytest.raises(ParsingError) as exc:
            run_dbt(["run"])
        assert "must begin with a letter" in str(exc.value)

class TestLongName:
    @pytest.fixture(scope="class")
    def models(self):
        return {
            "people_metrics.yml": long_name_metrics_yml,
            "people.sql": models_people_sql,
        }

    def test_long_name(self, project):
        with pytest.raises(ParsingError) as exc:
            run_dbt(["run"])
        assert "cannot contain more than 250 characters" in str(exc.value)

class TestInvalidDerivedMetrics:
    @pytest.fixture(scope="class")
    def models(self):
        return {
            "derived_metric.yml": invalid_derived_metric_contains_model_yml,
            "downstream_model.sql": downstream_model_sql,
        }

    def test_invalid_derived_metrics(self, project):
        with pytest.raises(ParsingError):
            run_dbt(["run"])

class TestMetricDependsOn:
    @pytest.fixture(scope="class")
    def models(self):
        return {
            "people.sql": models_people_sql,
            "metricflow_time_spine.sql": metricflow_time_spine_sql,
            "semantic_models.yml": semantic_model_people_yml,
            "people_metrics.yml": models_people_metrics_yml,
        }

    def test_metric_depends_on(self, project):
        manifest = run_dbt(["parse"])
        assert isinstance(manifest, Manifest)

        expected_depends_on_for_number_of_people = ["semantic_model.test.semantic_people"]
        expected_depends_on_for_average_tenure = [
            "metric.test.collective_tenure",
            "metric.test.number_of_people",
        ]

        number_of_people_metric = manifest.metrics["metric.test.number_of_people"]
        assert number_of_people_metric.depends_on.nodes == expected_depends_on_for_number_of_people

        average_tenure_metric = manifest.metrics["metric.test.average_tenure"]
        assert average_tenure_metric.depends_on.nodes == expected_depends_on_for_average_tenure

class TestDerivedMetric:
    @pytest.fixture(scope="class")
    def models(self):
        return {
            "downstream_model.sql": downstream_model_sql,
            "purchasing.sql": purchasing_model_sql,
            "metricflow_time_spine.sql": metricflow_time_spine_sql,
            "semantic_models.yml": semantic_model_purchasing_yml,
            "derived_metric.yml": derived_metric_yml,
        }

    # not strictly necessary to use "real" mock data for this test
    # we just want to make sure that the 'metric' calls match our expectations
    # but this sort of thing is possible, to have actual data flow through and validate results
    @pytest.fixture(scope="class")
    def seeds(self):
        return {
            "mock_purchase_data.csv": mock_purchase_data_csv,
        }

    def test_derived_metric(
        self,
        project,
    ):
        # initial parse
        results = run_dbt(["parse"])

        # make sure all the metrics are in the manifest
        manifest = get_manifest(project.project_root)
        metric_ids = list(manifest.metrics.keys())
        expected_metric_ids = [
            "metric.test.count_orders",
            "metric.test.sum_order_revenue",
            "metric.test.average_order_value",
        ]
        assert metric_ids == expected_metric_ids

        # make sure the downstream_model depends on these metrics
        metric_names = ["average_order_value", "count_orders", "sum_order_revenue"]
        downstream_model = manifest.nodes["model.test.downstream_model"]
        assert sorted(downstream_model.metrics) == [[metric_name] for metric_name in metric_names]
        assert sorted(downstream_model.depends_on.nodes) == [
            "metric.test.average_order_value",
            "metric.test.count_orders",
            "metric.test.sum_order_revenue",
        ]
        assert sorted(downstream_model.config["metric_names"]) == metric_names

        # make sure the 'expression' metric depends on the two upstream metrics
        derived_metric = manifest.metrics["metric.test.average_order_value"]
        assert sorted(derived_metric.depends_on.nodes) == [
            "metric.test.count_orders",
            "metric.test.sum_order_revenue",
        ]

        # actually compile
        results = run_dbt(["compile", "--select", "downstream_model"])
        compiled_code = results[0].node.compiled_code

        # make sure all these metrics properties show up in compiled SQL
        for metric_name in manifest.metrics:
            parsed_metric_node = manifest.metrics[metric_name]
            for property in [
                "name",
                "label",
                "type",
                "type_params",
                "filter",
            ]:
                expected_value = getattr(parsed_metric_node, property)
                assert f"{property}: {expected_value}" in compiled_code

class TestInvalidTimestampTimeGrainsMetrics:
    @pytest.fixture(scope="class")
    def models(self):
        return {
            "people_metrics.yml": invalid_metric_without_timestamp_with_time_grains_yml,
            "people.sql": models_people_sql,
        }

    # Tests that we get a ParsingError with an invalid metric definition.
    # This metric definition is missing timestamp but HAS a time_grains property
    def test_simple_metric(
        self,
        project,
    ):
        # initial run
        with pytest.raises(ParsingError):
            run_dbt(["run"])

class TestInvalidTimestampWindowMetrics:
    @pytest.fixture(scope="class")
    def models(self):
        return {
            "people_metrics.yml": invalid_metric_without_timestamp_with_window_yml,
            "people.sql": models_people_sql,
        }

    # Tests that we get a ParsingError with an invalid metric definition.
    # This metric definition is missing timestamp but HAS a window property
    def test_simple_metric(
        self,
        project,
    ):
        # initial run
        with pytest.raises(ParsingError):
            run_dbt(["run"])


from tqdm import tqdm
import torch
import numpy as np
from utils.io import writeFlow
import torch.nn as nn

def epe(input_flow, target_flow, mean=True):
    """
    End-point-Error computation
    Args:
        input_flow: estimated flow [BxHxW,2]
        target_flow: ground-truth flow [BxHxW,2]
    Output:
        Averaged end-point-error (value)
    """
    EPE = torch.norm(target_flow - input_flow, p=2, dim=1)
    if mean:
        EPE = EPE.mean()
    return EPE

def correct_correspondences(input_flow, target_flow, alpha, img_size):
    """
    Computation PCK, i.e number of the pixels within a certain threshold
    Args:
        input_flow: estimated flow [BxHxW,2]
        target_flow: ground-truth flow [BxHxW,2]
        alpha: threshold
        img_size: image size
    Output:
        PCK metric
    """
    # input flow is shape (BxHgtxWgt,2)
    dist = torch.norm(target_flow - input_flow, p=2, dim=1)
    # dist is shape BxHgtxWgt
    pck_threshold = alpha * img_size
    mask = dist.le(pck_threshold) # Computes dist ≤ pck_threshold element-wise (element then equal to 1)
    return mask.sum().item()

def F1_kitti_2015(input_flow, target_flow, tau=[3.0, 0.05]):
    """
    Computation number of outliers
    for which error > 3px(tau[0]) and error/magnitude(ground truth flow) > 0.05(tau[1])
    Args:
        input_flow: estimated flow [BxHxW,2]
        target_flow: ground-truth flow [BxHxW,2]
        alpha: threshold
        img_size: image size
    Output:
        PCK metric
    """
    # input flow is shape (BxHgtxWgt,2)
    dist = torch.norm(target_flow - input_flow, p=2, dim=1)
    gt_magnitude = torch.norm(target_flow, p=2, dim=1)
    # dist is shape BxHgtxWgt
    mask = dist.gt(3.0) & (dist/gt_magnitude).gt(0.05)
    return mask.sum().item()

def calculate_epe_and_pck_per_dataset(test_dataloader, network, device, threshold_range, path_to_save=None,
                                      compute_F1=False, save=False):
    aepe_array = []
    pck_alpha_0_05_over_image = []
    pck_thresh_1_over_image = []
    pck_thresh_5_over_image = []
    F1 = 0.0

    n_registered_pxs = 0.0
    array_n_correct_correspondences = np.zeros(threshold_range.shape, dtype=np.float32)

    pbar = tqdm(enumerate(test_dataloader), total=len(test_dataloader))
    for i_batch, mini_batch in pbar:
        source_img = mini_batch['source_image']
        target_img = mini_batch['target_image']
        mask_gt = mini_batch['correspondence_mask'].to(device)
        flow_gt = mini_batch['flow_map'].to(device)
        if flow_gt.shape[1] != 2:
            # shape is BxHxWx2
            flow_gt = flow_gt.permute(0,3,1,2)
        bs, ch_g, h_g, w_g = flow_gt.shape

        flow_estimated = network.estimate_flow(source_img, target_img, device, mode='channel_first')

        # torch tensor of shape Bx2xH_xW_, will be the same types (cuda or cpu) depending on the device
        # H_ and W_ could be smaller than the ground truth flow (ex DCG Net takes only 240x240 images)
        if flow_estimated.shape[2] != h_g or flow_estimated.shape[3] != w_g:
            '''
            the estimated flow is downscaled (the original images were downscaled before
            passing through the network)
            as it is the case with DCG Net, the estimate flow will have shape 240x240
            it needs to be upscaled to the same size as flow_target_x and rescaled accordingly:
            '''
            ratio_h = float(h_g) / float(flow_estimated.shape[2])
            ratio_w = float(w_g) / float(flow_estimated.shape[3])
            flow_estimated = nn.functional.interpolate(flow_estimated, size=(h_g, w_g), mode='bilinear',
                                                       align_corners=False)
            flow_estimated[:, 0, :, :] *= ratio_w
            flow_estimated[:, 1, :, :] *= ratio_h
        assert flow_estimated.shape == flow_gt.shape

        flow_target_x = flow_gt.permute(0, 2, 3, 1)[:, :, :, 0]
        flow_target_y = flow_gt.permute(0, 2, 3, 1)[:, :, :, 1]
        flow_est_x = flow_estimated.permute(0, 2, 3, 1)[:, :, :, 0]  # B x h_g x w_g
        flow_est_y = flow_estimated.permute(0, 2, 3, 1)[:, :, :, 1]

        flow_target = \
            torch.cat((flow_target_x[mask_gt].unsqueeze(1),
                       flow_target_y[mask_gt].unsqueeze(1)), dim=1)
        flow_est = \
            torch.cat((flow_est_x[mask_gt].unsqueeze(1),
                       flow_est_y[mask_gt].unsqueeze(1)), dim=1)
        # flow_target_x[mask_gt].shape is (number of pixels), then with unsqueze(1) it becomes (number_of_pixels, 1)
        # final shape is (B*H*W , 2), B*H*W is the number of registered pixels (according to ground truth masks)

        # let's calculate EPE per batch
        aepe = epe(flow_est, flow_target)  # you obtain the mean per pixel
        aepe_array.append(aepe.item())

        # let's calculate PCK values
        img_size = max(mini_batch['source_image_size'][0], mini_batch['source_image_size'][1]).float().to(device)
        alpha_0_05 = correct_correspondences(flow_est, flow_target, alpha=0.05, img_size=img_size)
        px_1 = correct_correspondences(flow_est, flow_target, alpha=1.0/float(img_size), img_size=img_size) # threshold of 1 px
        px_5 = correct_correspondences(flow_est, flow_target, alpha=5.0/float(img_size), img_size=img_size) # threshold of 5 px

        # percentage per image is calculated for each
        pck_alpha_0_05_over_image.append(alpha_0_05/flow_target.shape[0])
        pck_thresh_1_over_image.append(px_1/flow_target.shape[0])
        pck_thresh_5_over_image.append(px_5/flow_target.shape[0])

        # PCK curve for different thresholds ! ATTENTION, here it is over the whole dataset and not per image
        n_registered_pxs += flow_target.shape[0]  # also equal to number of correspondences that should be correct
        # according to ground truth mask
        for t_id, threshold in enumerate(threshold_range):
            array_n_correct_correspondences[t_id] += correct_correspondences(flow_est,
                                                                             flow_target,
                                                                             alpha=threshold,
                                                                             img_size=img_size)
            # number of correct pixel correspondence below a certain threshold, added for each batch

        if compute_F1:
            F1 += F1_kitti_2015(flow_est, flow_target)

        if save:
            writeFlow(np.dstack([flow_est_x[0].cpu().numpy(), flow_est_y[0].cpu().numpy()]),
            'batch_{}'.format(i_batch), path_to_save)

    output = {'final_eape': np.mean(aepe_array),
              'pck_alpha_0_05_average_per_image': np.mean(pck_alpha_0_05_over_image),
              'pck_thresh_1_average_per_image': np.mean(pck_thresh_1_over_image),
              'pck_thresh_5_average_per_image': np.mean(pck_thresh_5_over_image),
              'alpha_threshold': threshold_range.tolist(),
              'pixel_threshold': np.round(threshold_range * img_size.cpu().numpy(), 2).tolist(),
              'pck_per_threshold_over_dataset': np.float32(array_n_correct_correspondences /
                                                           (n_registered_pxs + 1e-6)).tolist()}

    if compute_F1:
        output['kitti2015-F1'] = F1 / float(n_registered_pxs)
    return output


from utils.clear_screen import clear_screen
import random

clear_screen()

deck = []

def draw_card():
    return deck.pop(random.randint(0, len(deck) - 1))

def get_score(cards):
    score = sum(cards)

    while score > 21:
        if 11 in cards:
            cards[cards.index(11)] = 1
            return get_score(cards)
        else:
            break

    return score

user_cards = []
dealer_cards = []

def display_score(is_stand):

    user_score = get_score(user_cards)
    print(f"Your deck: {user_cards} Score: {user_score}")

    if not is_stand:
        print(f"Dealer's deck: [{dealer_cards[1]}]")
    else:
        dealer_score = get_score(dealer_cards)
        print(f"Dealer's deck: {dealer_cards} Score: {dealer_score}")

def setup():
    global deck

    deck = [11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10,
            11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10,
            11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10,
            11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10]

    global user_cards
    global dealer_cards

    user_cards = [draw_card(), draw_card()]
    dealer_cards = [draw_card(), draw_card()]
    display_score(False)

setup()

def hit():
    user_cards.append(draw_card())
    display_score(False)

def stand():

    dealer_score = get_score(dealer_cards)

    while dealer_score < random.randint(15, 21):
        dealer_cards.append(draw_card())
        dealer_score = get_score(dealer_cards)

    display_score(True)

def play():

    playing = True

    user_score = get_score(user_cards)

    if user_score == 21:
        print("* * * Blackjack * * * YOU WON")
        playing = False

    while playing:

        playing_input = input("Do you want to hit or stand. h or s: ").lower()

        clear_screen()

        if playing_input == "h":
            hit()

            user_score = get_score(user_cards)
            if user_score > 21:
                print("BUST - YOU LOST")
                playing = False
            elif user_score == 21:
                print("YOU WON")
                playing = False

        else:
            stand()

            dealer_score = get_score(dealer_cards)
            user_score = get_score(user_cards)
            if dealer_score > 21:
                print("Dealer Bust - YOU WON")
            elif dealer_score == 21:
                print("YOU LOST")
            elif user_score > dealer_score:
                print("YOU WON")
            elif dealer_score > user_score:
                print("YOU LOST")
            else:
                print("DRAW")

            playing = False

    playing_input = input("Do you want to continue playing. y or n: ").lower()
    if playing_input == 'y':
        clear_screen()
        setup()
        play()

play()


import requests
from django.contrib.sitemaps import Sitemap
from django.urls import reverse
from django.utils.dateparse import parse_datetime

from dimagi.data.blog import nav_categories
from dimagi.data.case_studies import studies
from dimagi.data.sectors import sub_sectors
from dimagi.data.terms import PREVIOUS_TERMS, LATEST_TERMS
from dimagi.data.toolkits import toolkits
from dimagi.data.quick_start import all_areas
from dimagi.pages.models.terms import VERSION_2
from dimagi.utils.wordpress_api import get_json

class MainViewSitemap(Sitemap):
    protocol = 'https'

    @staticmethod
    def _get_changefreq(slug):
        view_to_changefreq = {
            'home': 'daily',
            'commcare': 'daily',
            'commcare_home': 'daily',
            'careers': 'daily',
            'blog_home': 'daily',
        }
        return view_to_changefreq.get(slug, 'weekly')

    @staticmethod
    def _get_priority(slug):
        view_to_priority = {
            'home': 1.0,
            'commcare': 1.0,
            'commcare_pricing': 1.0,
            'services': 0.9,
            'about': 0.9,
            'contact': 0.8,
            'careers': 0.8,
            'toolkits': 0.6,
            'sectors': 0.6,
            'press': 0.6,
            'blog_home': 0.7,
            'archive': 0.6,
            'team': 0.9,
            'monitoring_evaluation': 0.9,
            'commcare_features': 0.9,
            'ict4d': 0.9,
            'enterprise': 0.9,
            'mobile_data_collection': 0.9,
            'data_collection': 0.9,
            'community_health_worker': 0.9,

        }
        return view_to_priority.get(slug, 0.5)

    def items(self):
        return [
            'home',
            'services',
            'contact',
            'india',
            'resources',
            'research_and_data',
            'partners',
            'focus',
            'awards',
            'covid_19',
            'ict4d',
            'covid19',
            'webinar_home',
            'global_me',
            'data_already',
            'optimize',
            'interoperability',
            'data_democracy',
            'frontline',
            'adapt',
            'new_function',
            'data_clean',
            'remote',
            'power_bi',
            'focus_mdm',
            'focus_mdm_pricing',
            'research',
            'commcare_onboarding',
            'classroom',
            'commcare_messaging',
            'enterprise',
            'vaccine_delivery',
            'monitoring_evaluation',
            'commcare_features',
            'sector_nutrition_programs',
            'sector_disease_treatment',
            'sector_agriculture_extension_programs',
            'financial_inclusion',
            'commcare_integration',
            'mobile_data_collection',
            'data_collection',
            'community_health_worker',
            'us_health',
            'data_driven_programs',
            'partner_program',
            'careers',
            'commcare',
            'commcare_pricing',
            'case_studies',
            'toolkits',
            'sectors',
            'press',
            'archive',
            'blog_home',
            'team',
            'about',
            'proposals',
            'quick_start',
            'case_management',
        ]

    def priority(self, obj):
        return self._get_priority(obj)

    def changefreq(self, obj):
        return self._get_changefreq(obj)

    def location(self, obj):
        return reverse(obj)

class BlogPostSitemap(Sitemap):
    protocol = 'https'
    changefreq = 'never'
    priority = 0.6

    def items(self):
        return get_json('blog/sitemap').get('posts', [])

    def location(self, obj):
        return reverse('blog_post', args=[obj.get('slug')])

    def lastmod(self, obj):
        return parse_datetime(obj.get('date'))

class BlogArchiveCategorySitemap(Sitemap):
    protocol = 'https'
    changefreq = 'daily'
    priority = 0.6

    def items(self):
        return nav_categories

    def location(self, obj):
        return reverse('archive_category', args=[obj.slug])

class SectorSitemap(Sitemap):
    protocol = 'https'
    changefreq = 'monthly'
    priority = 0.5

    def items(self):
        return sub_sectors

    def location(self, obj):
        return reverse('sector', args=[obj.SECTOR.slug])

class CaseStudySitemap(Sitemap):
    protocol = 'https'
    changefreq = 'monthly'
    priority = 0.5

    def items(self):
        return studies

    def location(self, obj):
        return reverse('case_study', args=[obj.STUDY.slug])

class ToolkitSitemap(Sitemap):
    protocol = 'https'
    changefreq = 'monthly'
    priority = 0.5

    def items(self):
        return toolkits

    def location(self, obj):
        return reverse('toolkit', args=[obj.TOOLKIT.slug])

class QuickStartSitemap(Sitemap):
    protocol = 'https'
    changefreq = 'monthly'
    priority = 0.5

    def items(self):
        return all_areas

    def location(self, obj):
        return reverse('quick_start_area', args=[obj.AREA.slug])

class TermsSitemap(Sitemap):
    protocol = 'https'
    priority = 0.4

    def items(self):
        terms = [
            'default',
            'latest',
            'previous'
        ]
        terms.extend(PREVIOUS_TERMS)
        terms.extend(LATEST_TERMS)
        return terms

    def location(self, obj):
        if obj == 'default':
            return reverse('terms_default')

        if obj in ['latest', 'previous']:
            return reverse('terms_version', args=[obj])

        if obj.version == VERSION_2:
            version = 'previous'
        else:
            version = 'latest'

        return reverse('terms', args=[version, obj.slug])

class JobsSitemap(Sitemap):
    protocol = 'https'
    changefreq = 'daily'
    priority = 0.6

    def items(self):
        data = requests.get("https://api.greenhouse.io/v1/boards/dimagi/jobs")
        data = data.json()
        return data.get('jobs', [])

    def location(self, obj):
        return reverse('careers_job', args=[obj['id']])

class TeamMemberSitemap(Sitemap):
    protocol = 'https'
    changefreq = 'monthly'
    priority = 0.5

    def items(self):
        return get_json('team/sitemap')

    def location(self, obj):
        return reverse(
            'team_member', args=[obj['office'], obj['slug']]
        )


#!/usr/bin/python3

import argparse
from secrets import randbits
import dew

def _encrypt(args):
    if (args.keyfile):
        with open(args.keyfile, 'rb') as f:
            key = int.from_bytes(f.read(), byteorder='little')
    else:
        key = randbits(256)

    nonce0 = randbits(256)
    nonce1 = randbits(255)

    if (args.cmdtext):
        with open(args.outfile, 'wb') as out:
            result = dew.transform(args.infile.encode(), key, nonce0, nonce1)
            out.write(nonce0.to_bytes(32, byteorder='little')
                      + nonce1.to_bytes(32, byteorder='little')
                      + result)
    else:
        with open('{}'.format(args.infile), 'rb') as f, open(args.outfile, 'wb') as out:
            result = dew.transform(f.read(), key, nonce0, nonce1)
            out.write(nonce0.to_bytes(32, byteorder='little')
                      + nonce1.to_bytes(32, byteorder='little')
                      + result)

    if not args.keyfile:
        with open('{}.key'.format(args.outfile), 'wb') as out:
            out.write(key.to_bytes(32, byteorder='little'))

def _decrypt(args):
    with open(args.keyfile, 'rb') as f:
        key = int.from_bytes(f.read(), byteorder='little')

    with open('{}'.format(args.infile), 'rb') as f, open(args.outfile, 'wb') as out:
        nonce0 = int.from_bytes(f.read(32), byteorder='little')
        nonce1 = int.from_bytes(f.read(32), byteorder='little')

        result = dew.transform(f.read(), key, nonce0, nonce1)
        out.write(result)

if __name__ == '__main__':
    #Main argument parser
    parser = argparse.ArgumentParser()

    subparsers = parser.add_subparsers(dest='operation')
    subparsers.required = True

    #Subparser for encryption
    parser_e = subparsers.add_parser('encrypt', help='Option to select to encrypt input')
    parser_e.add_argument('--cmdtext', action='store_true',
                        help="Specifiy this command to treat the 'infile' argument as the text the encrypt")
    parser_e.add_argument('infile', help="The plaintext wanted to be encrypted/decrypted")
    parser_e.add_argument('--keyfile', help="Optional keyfile to encrypt the file, truncated/padded to 256 bits")
    parser_e.add_argument('outfile', help="Name of output encrypted file")
    parser_e.set_defaults(func=_encrypt)

    #Subparer for decryption
    parser_d = subparsers.add_parser('decrypt', help='Option to select to decrypt input')
    parser_d.add_argument('infile', help="The plaintext wanted to be encrypted/decrypted")
    parser_d.add_argument('keyfile', help="The file generated holding the key during encryption")
    parser_d.add_argument('outfile', help="Name of output unencrypted file")
    parser_d.set_defaults(func=_decrypt)

    args = parser.parse_args()
    args.func(args)


import json as json_lib

from absl.testing import absltest
from tfx.types import channel_utils, standard_artifacts

from tfx_addons.model_card_generator import artifact
from tfx_addons.model_card_generator.component import ModelCardGenerator

class ComponentTest(absltest.TestCase):
  def test_component_construction(self):
    model_card_gen = ModelCardGenerator(
        statistics=channel_utils.as_channel(
            [standard_artifacts.ExampleStatistics()]),
        evaluation=channel_utils.as_channel(
            [standard_artifacts.ModelEvaluation()]),
        pushed_model=channel_utils.as_channel(
            [standard_artifacts.PushedModel()]),
        json=json_lib.dumps(
            {'model_details': {
                'name': 'my model',
                'version': {
                    'name': 'v1'
                }
            }}),
        template_io=[('path/to/html/template', 'mc.html'),
                     ('path/to/md/template', 'mc.md')],
    )

    with self.subTest('outputs'):
      self.assertEqual(model_card_gen.outputs['model_card'].type_name,
                       artifact.ModelCard.TYPE_NAME)

    with self.subTest('exec_properties'):
      self.assertDictEqual(
          {
              'json':
              json_lib.dumps({
                  'model_details': {
                      'name': 'my model',
                      'version': {
                          'name': 'v1'
                      }
                  }
              }),
              'template_io': [('path/to/html/template', 'mc.html'),
                              ('path/to/md/template', 'mc.md')],
              'features_include':
              None,
              'features_exclude':
              None,
              'metrics_include':
              None,
              'metrics_exclude':
              None,
          }, model_card_gen.exec_properties)

  def test_empty_component_construction(self):
    model_card_gen = ModelCardGenerator()
    with self.subTest('outputs'):
      self.assertEqual(model_card_gen.outputs['model_card'].type_name,
                       artifact.ModelCard.TYPE_NAME)

  def test_component_construction_with_filtered_features(self):
    model_card_gen = ModelCardGenerator(features_include=['feature_name1'])
    self.assertEqual(model_card_gen.exec_properties['features_include'],
                     ['feature_name1'])

    model_card_gen_features_exclude = ModelCardGenerator(
        features_exclude=['feature_name2'], )
    self.assertEqual(
        model_card_gen_features_exclude.exec_properties['features_exclude'],
        ['feature_name2'])

    with self.assertRaises(ValueError):
      ModelCardGenerator(
          features_include=['feature_name1'],
          features_exclude=['feature_name2'],
      )

  def test_component_construction_with_filtered_metrics(self):
    model_card_gen = ModelCardGenerator(metrics_include=['accuracy'])
    self.assertEqual(model_card_gen.exec_properties['metrics_include'],
                     ['accuracy'])

    model_card_gen_metrics_exclude = ModelCardGenerator(
        metrics_exclude=['loss'], )
    self.assertEqual(
        model_card_gen_metrics_exclude.exec_properties['metrics_exclude'],
        ['loss'])

    with self.assertRaises(ValueError):
      ModelCardGenerator(
          metrics_include=['accuracy'],
          metrics_exclude=['loss'],
      )

if __name__ == '__main__':
  absltest.main()


import datetime
import hashlib
import hmac
import json
from base64 import b64decode, b64encode

import requests

class SentinelApiConnector:
    def __init__(self, *, workspace_id: str, log_analytics_uri: str, shared_key: str, log_type: str):
        self.workspace_id = workspace_id
        self.shared_key = shared_key
        self.key_encoder = KeyEncoder(shared_key)
        self.log_type = log_type
        self.uri = log_analytics_uri
        self.resource = "/api/logs"

    def post(self, json_body: list) -> None:
        body = json.dumps(json_body)
        headers = self._build_headers(len(body))
        requests.post(
            self.uri + self.resource, params={"api-version": "2016-04-01"}, data=body, headers=headers
        ).raise_for_status()

    def _build_headers(self, content_length: int) -> dict:
        date = _make_rfc1123date()
        signature = self._build_signature(date, content_length)
        return {
            "content-type": "application/json",
            "Authorization": signature,
            "Log-Type": self.log_type,
            "x-ms-date": date,
        }

    def _build_signature(self, date: str, content_length: int) -> str:
        string_to_hash = SIGNATURE_TEMPLATE.format(content_length=content_length, date=date, resource=self.resource)
        encoded_hash = self.key_encoder.encode(string_to_hash)
        return f"SharedKey {self.workspace_id}:{encoded_hash}"

def _make_rfc1123date() -> str:
    return datetime.datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S GMT")

SIGNATURE_TEMPLATE = """
POST
{content_length}
application/json
x-ms-date:{date}
{resource}
""".strip()

class KeyEncoder:
    def __init__(self, key: str):
        self.key = b64decode(key)

    def encode(self, text: str) -> str:
        return b64encode(hmac.new(self.key, bytes(text, encoding="utf-8"), digestmod=hashlib.sha256).digest()).decode()


from flask import Flask, render_template, request, session, url_for, redirect
import pymysql.cursors
import datetime
from pyecharts.charts import Bar
from pyecharts import options as opts

from appdef import *

def authenticateCustomer():
    username = ""
    try:
        #could be that there is no user, make sure
        username = session['username']
    except:
        return False

    cursor = conn.cursor()
    query = 'select * from customer where email=%s'
    cursor.execute(query, (username))
    data = cursor.fetchall()
    cursor.close()
    if data:
        return True
    else:
        #Logout before returning error message
        session.pop('username')
        return False

@app.route('/customerHome')
def customerHome():
  if not authenticateCustomer():
    error = 'Invalid Credentials'
    return redirect(url_for('errorpage', error=error))
  else:
    username = session['username']
    cursor = conn.cursor()
    query = 'SELECT purchases.ticket_id, ticket.airline_name, ticket.flight_num, departure_airport, departure_time, arrival_airport, arrival_time \
    FROM purchases, ticket, flight \
    WHERE purchases.ticket_id = ticket.ticket_id \
    AND ticket.airline_name = flight.airline_name \
    AND ticket.flight_num = flight.flight_num \
    AND customer_email = %s AND departure_time > curdate()'
    cursor.execute(query, (username))
    data = cursor.fetchall()
    cursor.close()
    return render_template('customer.html', username=username, posts=data)

@app.route('/viewUpcomingFlights', methods=['GET', 'POST'])
def viewUpcomingFlights():
  if authenticateCustomer():
    username = session['username']
    cursor = conn.cursor()
    if request.method == 'POST':
      city = request.form.get('citysearchbox', False)
      if city:
        query='SELECT purchases.ticket_id, ticket.airline_name, ticket.flight_num, departure_airport, departure_time, arrival_airport, arrival_time \
                FROM purchases, ticket, flight, airport \
                WHERE purchases.ticket_id = ticket.ticket_id \
                AND ticket.airline_name = flight.airline_name \
                AND ticket.flight_num = flight.flight_num \
                AND (flight.arrival_airport = airport_name or flight.departure_airport = airport_name)\
                AND airport.airport_city = %s\
                AND customer_email = %s AND departure_time > curdate();'
        cursor.execute(query, (city, username))
        data = cursor.fetchall()
        cursor.close()
        return render_template('viewUpcomingFlights.html', username=username, posts=data)

      airport = request.form.get('airportsearchbox', False)
      ##########################################################################
      error = request.args.get('error')
      if len(airport)>3:
        error = "Please enter the abbreviation of airport name."
        return render_template('viewUpcomingFlights.html',error = error)
      cursor = conn.cursor()
      query1 = "select * from airport where airport_name = %s"
      cursor.execute(query1,airport)
      data1 = cursor.fetchall()
      cursor.close()
      if not data1:
        error = " The airport doesn't exist."
        return render_template('viewUpcomingFlights.html',error = error)
      ##########################################################################
      if airport:
        query='SELECT purchases.ticket_id, ticket.airline_name, ticket.flight_num, departure_airport, departure_time, arrival_airport, arrival_time \
                FROM purchases, ticket, flight\
                WHERE purchases.ticket_id = ticket.ticket_id \
                AND ticket.airline_name = flight.airline_name \
                AND ticket.flight_num = flight.flight_num \
                AND (flight.arrival_airport = %s or flight.departure_airport = %s)\
                AND customer_email = %s AND departure_time > curdate();'
        cursor.execute(query, (airport, airport, username))
        data = cursor.fetchall()
        cursor.close()
        return render_template('viewUpcomingFlights.html', username=username, posts=data)

      begintime = request.form["begintime"]
      endtime = request.form["endtime"]

      if datetime.datetime.strptime(begintime, "%Y-%m-%d") > datetime.datetime.strptime(endtime, "%Y-%m-%d"):
        return render_template('viewUpcomingFlights.html', username=username, error="The dates you entered are invalid.")
      else:
        query="SELECT distinct purchases.ticket_id, ticket.airline_name, ticket.flight_num, departure_airport, departure_time, arrival_airport, arrival_time \
              FROM purchases, ticket, flight\
              WHERE purchases.ticket_id = ticket.ticket_id \
              AND ticket.airline_name = flight.airline_name \
              AND ticket.flight_num = flight.flight_num \
              AND purchases.customer_email = %s \
              AND flight.departure_time > curdate()\
              and ((date(flight.departure_time) between %s and %s) or (date(flight.arrival_time) between %s and %s));"
        cursor.execute(query, (username, begintime, endtime, begintime, endtime))
        data = cursor.fetchall()
        cursor.close()
        return render_template('viewUpcomingFlights.html', username=username, posts=data)

    query = 'SELECT purchases.ticket_id, ticket.airline_name, ticket.flight_num, departure_airport, departure_time, arrival_airport, arrival_time \
            FROM purchases, ticket, flight \
            WHERE purchases.ticket_id = ticket.ticket_id \
            AND ticket.airline_name = flight.airline_name \
            AND ticket.flight_num = flight.flight_num \
            AND customer_email = %s AND departure_time > curdate();'
    cursor.execute(query, (username))
    data = cursor.fetchall()
    cursor.close()
    return render_template('viewUpcomingFlights.html', username=username, posts=data)
  else:
    error = 'Invalid Credentials'
    return redirect(url_for('errorpage', error=error))

@app.route('/searchPageCustomer')
def searchPageCustomer():
  if authenticateCustomer():
    return render_template('searchCustomer.html')
  else:
    error = 'Invalid Credentials'
    return redirect(url_for('errorpage', error=error))

@app.route('/searchCustomer', methods=['POST'])
def searchCustomer():
  if authenticateCustomer():
    username = session['username']
    cursor = conn.cursor()
    fromcity = request.form['fromcity']
    fromairport = request.form['fromairport']
    fromdate = request.form['fromdate']
    tocity = request.form['tocity']
    toairport = request.form['toairport']
    todate = request.form['todate']
    ##############################################################
    if datetime.datetime.strptime(fromdate, "%Y-%m-%d") > datetime.datetime.strptime(todate, "%Y-%m-%d"):
        return render_template('searchCustomer.html', error="The dates you entered are invalid.")
    ##############################################################
    query = 'SELECT * FROM flight, airport, purchases, ticket \
            WHERE airport.airport_name=flight.departure_airport \
            AND flight.flight_num = ticket.flight_num AND flight.airline_name = ticket.airline_name\
            AND ticket.ticket_id = purchases.ticket_id\
            AND purchases.customer_email = %s\
            AND airport.airport_city = %s \
            AND airport.airport_name = %s \
            # AND flight.status = "Upcoming"\
            AND %s BETWEEN DATE_SUB(flight.departure_time, INTERVAL 2 DAY) AND DATE_ADD(flight.departure_time, INTERVAL 2 DAY) \
            AND %s BETWEEN DATE_SUB(flight.arrival_time, INTERVAL 2 DAY) AND DATE_ADD(flight.arrival_time, INTERVAL 2 DAY) \
            AND (flight.airline_name, flight.flight_num) in \
              (SELECT flight.airline_name, flight.flight_num FROM flight, airport \
              WHERE airport.airport_name=flight.arrival_airport \
              AND airport.airport_city = %s \
              AND airport.airport_name = %s)'
    cursor.execute(query, (username, fromcity, fromairport, fromdate, todate, tocity, toairport))
    data = cursor.fetchall()
    cursor.close()
    error = None
    if(data):
      return render_template('searchCustomer.html', username=username, results=data)
    else:
      #returns an error message to the html page
      error = 'No results found'
      return render_template('searchCustomer.html', error=error)
  else:
    error = 'Invalid Credentials'
    return redirect(url_for('errorpage', error=error))

@app.route('/trackMySpending', methods=['GET', 'POST'])
def trackMySpending():
  if not authenticateCustomer():
    error = 'Invalid Credentials'
    return redirect(url_for('errorpage', error=error))
  else:
    username = session['username']
    if request.method == 'POST':
          to_date = request.form['to_date']
          from_date = request.form['from_date']
          if datetime.datetime.strptime(from_date, "%Y-%m-%d") > datetime.datetime.strptime(to_date, "%Y-%m-%d"):
              return render_template('viewCustomerSpending.html', error="The dates you entered are invalid.")
          to_date_format = datetime.datetime.strptime(to_date, '%Y-%m-%d')
          from_date_format = datetime.datetime.strptime(from_date, '%Y-%m-%d')
          year = to_date_format.year
          month = to_date_format.month
          date = to_date_format.day
          from_year = from_date_format.year
          from_month = from_date_format.month
          from_date_date = from_date_format.day
          from_date_string = '{}-{}-{}'.format(from_year, from_month, from_date_date)
          to_date_string = '{}-{}-{}'.format(year, month, date)
          monthnum = (year - from_year)*12 + month - from_month
    else:
          to_date = datetime.datetime.now()
          year = to_date.year
          month = to_date.month
          if month-6 < 0:
            from_month = 12 + (month-6)
            from_year = to_date.year - 1
          else:
            from_month = month-6
            from_year = year
          date = to_date.day
          monthnum = 5
          string = '{} 1 {} 00:00'.format(month, from_year)
          from_date = datetime.datetime.strptime(string, '%m %d %Y %H:%M')
          from_date_string = '{}-{}-{}'.format(from_year, from_month, date)
          to_date_string = '{}-{}-{}'.format(year, month, date)

    cursor = conn.cursor()
    sumPrice = 'SELECT COALESCE(sum(flight.price),0) as sum\
              FROM purchases,ticket,flight\
              WHERE purchases.customer_email = %s\
              AND ticket.ticket_id = purchases.ticket_id\
              and ticket.flight_num = flight.flight_num\
              and ticket.airline_name = flight.airline_name\
              and purchases.purchase_date >= %s\
              and purchases.purchase_date <= %s;'
    cursor.execute(sumPrice, (username, from_date_string, to_date_string ))
    sumSpending = float(cursor.fetchone()['sum'])

    if month < 12:
        string = '{} 1 {} 00:00'.format(month+1, year + 1)
    else:
        string = '{} 1 {} 00:00'.format(1, year + 2)
    temp_date = datetime.datetime.strptime(string, '%m %d %Y %H:%M')

    labels = []
    values = []
    temp_year = year
    temp_month = month
    for i in range(0,monthnum + 1):
        this_date = temp_date
        this_month = temp_month
        temp_month = (month-i)%12
        if temp_month == 0:
            temp_month = 12
        if temp_month > this_month:
            temp_year = temp_year - 1
        string = '{} 1 {} 00:00'.format(temp_month, temp_year)
        temp_date = datetime.datetime.strptime(string, '%m %d %Y %H:%M')
        query = 'SELECT COALESCE(sum(flight.price),0) as sum_month\
              FROM purchases,ticket,flight\
              WHERE purchases.customer_email = %s\
              AND ticket.ticket_id = purchases.ticket_id\
              and ticket.flight_num = flight.flight_num\
              and ticket.airline_name = flight.airline_name\
              and purchases.purchase_date > %s\
              and purchases.purchase_date < %s;'
        cursor.execute(query, (username, temp_date, this_date, ))
        data = cursor.fetchone()
        label = '{}-{}'.format(temp_year, temp_month)
        labels.append(label)
        values.append(float(data['sum_month']))
    cursor.close()
    labels.reverse()
    values.reverse()
    try:
        mymax = max(values)
    except:
        mymax = 100
    return render_template('viewCustomerSpending.html', username=username, sumSpending = sumSpending, max = mymax, from_date = from_date_string, to_date = to_date_string, labels=labels, values=values)


import os
import typing
import logging
import warnings

from ncempy.io.dm import fileDM
import numpy as np

from libertem.common.math import prod
from libertem.common import Shape
from libertem.io.dataset.base.file import OffsetsSizes
from libertem.common.messageconverter import MessageConverter
from .base import (
    DataSet, FileSet, BasePartition, DataSetException, DataSetMeta, File,
    IOBackend,
)

log = logging.getLogger(__name__)

if typing.TYPE_CHECKING:
    from numpy import typing as nt

class SingleDMDatasetParams(MessageConverter):
    SCHEMA = {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "$id": "http://libertem.org/DMDatasetParams.schema.json",
        "title": "DMDatasetParams",
        "type": "object",
        "properties": {
            "type": {"const": "DM"},
            "path": {"type": "string"},
            "nav_shape": {
                "type": "array",
                "items": {"type": "number", "minimum": 1},
                "minItems": 2,
                "maxItems": 2
            },
            "sig_shape": {
                "type": "array",
                "items": {"type": "number", "minimum": 1},
                "minItems": 2,
                "maxItems": 2
            },
            "sync_offset": {"type": "number"},
            "io_backend": {
                "enum": IOBackend.get_supported(),
            },
            "force_c_order": {"type": "boolean"},
        },
        "required": ["type", "path"]
    }

    def convert_to_python(self, raw_data):
        data = {
            k: raw_data[k]
            for k in ["path"]
        }
        for k in ["nav_shape", "sig_shape", "sync_offset", "force_c_order"]:
            if k in raw_data:
                data[k] = raw_data[k]
        return data

class StackedDMDatasetParams(MessageConverter):
    SCHEMA: typing.Dict = {}

    def convert_from_python(self, raw_data):
        return super().convert_from_python(raw_data)

    def convert_to_python(self, raw_data):
        return super().convert_to_python(raw_data)

def _get_metadata(path):
    fh = fileDM(path, on_memory=True)
    if fh.numObjects == 1:
        idx = 0
    else:
        idx = 1
    return {
        'offset': fh.dataOffset[idx],
        'zsize': fh.zSize[idx],
    }

class StackedDMFile(File):
    def get_array_from_memview(self, mem: memoryview, slicing: OffsetsSizes):
        mem = mem[slicing.file_offset:-slicing.skip_end]
        res = np.frombuffer(mem, dtype="uint8")
        itemsize = np.dtype(self._native_dtype).itemsize
        sigsize = int(prod(self._sig_shape))
        cutoff = 0
        cutoff += (
            self.num_frames * itemsize * sigsize
        )
        res = res[:cutoff]
        return res.view(dtype=self._native_dtype).reshape(
            (self.num_frames, -1)
        )[:, slicing.frame_offset:slicing.frame_offset + slicing.frame_size]

class DMFileSet(FileSet):
    pass

class DMDataSet(DataSet):
    """
    Factory class for DigitalMicrograph file datasets

     - Passing either the :code:`files` kwarg or a tuple/list as first
       argument will create an instance of :class:`StackedDMDataSet`
     - Passing either the :code:`path` kwarg or any other object
       as first argument will create a :class:`SingleDMDataSet`

    This class is necessary to handle the difference in signatures and
    behaviours of the two DM dataset implementations, but these may
    later be fused if a markup format for multi-file datasets is implemented

    This class implements the methods necessary to expose a DMDataSet in
    the web GUI, which it does by deferring to SingleDMDataSet. At this
    time multi-file datasets are not supported in the UI.

    NOTE this way of generating the subclasses breaks deeper
    subclassing, as this __new__ method will always instantiate
    a SingleDMDataSet or StackedDMDataSet, and not a subclass of
    either of these. This could potentially be improved by using
    the .__instance_subclass__() staticmethod to register the
    subclasses and what they inherit from.
    """
    def __new__(cls, *args, **kwargs):
        # delayed here to avoid circular reference
        from .dm_single import SingleDMDataSet
        if 'path' in kwargs:
            subclass = SingleDMDataSet
        elif 'files' in kwargs:
            subclass = StackedDMDataSet
        elif args and isinstance(args[0], (list, tuple)):
            subclass = StackedDMDataSet
        else:
            subclass = SingleDMDataSet
        return super().__new__(subclass)

    @classmethod
    def get_supported_extensions(cls):
        return {"dm3", "dm4"}

    @classmethod
    def get_msg_converter(cls):
        return SingleDMDatasetParams

    @classmethod
    def detect_params(cls, path, executor):
        # delayed here to avoid circular reference
        from .dm_single import SingleDMDataSet
        return SingleDMDataSet.detect_params(path, executor)

class StackedDMDataSet(DMDataSet):
    """
    Reader for stacks of DM3/DM4 files.

    Note
    ----
    This DataSet is not supported in the GUI yet, as the file dialog needs to be
    updated to `properly handle opening series
    <https://github.com/LiberTEM/LiberTEM/issues/498>`_.

    Note
    ----
    Single-file 3/4D DM datasets are supported through the
    :class:`~libertem.io.datasets.dm_single.SingleDMDataSet` class.

    Note
    ----
    You can use the PyPI package `natsort <https://pypi.org/project/natsort/>`_
    to sort the filenames by their numerical components, this is especially useful
    for filenames without leading zeros.

    Parameters
    ----------

    files : List[str]
        List of paths to the files that should be loaded. The order is important,
        as it determines the order in the navigation axis.

    nav_shape : Tuple[int, ...] or None
        By default, the files are loaded as a 3D stack. You can change this
        by specifying the nav_shape, which reshapes the navigation dimensions.
        Raises a `DataSetException` if the shape is incompatible with the data
        that is loaded.

    sig_shape: Tuple[int, ...], optional
        Signal/detector size (height, width)

    sync_offset: int, optional
        If positive, number of frames to skip from start
        If negative, number of blank frames to insert at start

    same_offset : bool
        When reading a stack of dm3/dm4 files, it can be expensive to read in
        all the metadata from all files, which we currently only use for
        getting the offsets and sizes of the main data in each file. If you
        absolutely know that the offsets and sizes are the same for all files,
        you can set this parameter and we will skip reading all metadata but
        the one from the first file.
    """
    def __init__(self, files=None, scan_size=None, same_offset=False, nav_shape=None,
                 sig_shape=None, sync_offset=0, io_backend=None):
        super().__init__(io_backend=io_backend)
        self._meta = None
        self._same_offset = same_offset
        self._nav_shape = tuple(nav_shape) if nav_shape else nav_shape
        self._sig_shape = tuple(sig_shape) if sig_shape else sig_shape
        self._sync_offset = sync_offset
        # handle backwards-compatability:
        if scan_size is not None:
            warnings.warn(
                "scan_size argument is deprecated. please specify nav_shape instead",
                FutureWarning
            )
            if nav_shape is not None:
                raise ValueError("cannot specify both scan_size and nav_shape")
            self._nav_shape = tuple(scan_size)
        self._filesize = None
        self._files = files
        if not isinstance(files, (list, tuple)):
            raise DataSetException("files argument must be an iterable\
                                    of file paths, recieved {type(files)}")
        if len(files) == 0:
            raise DataSetException("need at least one file as input!")
        self._fileset = None
        # per-file cached attributes:
        self._z_sizes = {}
        self._offsets = {}

    def __new__(cls, *args, **kwargs):
        '''
        Skip the superclasse's :code:`__new__()` method.

        Instead, go straight to the grandparent. That disables the
        :class:`DMDataSet` type determination magic. Otherwise unpickling will
        always yield a :class:`SingleDMDataSet` since this class inherits the
        parent's :code:`__new__()` method and unpickling calls it without
        parameters, making it select :class:`SingleDMDataSet`.

        It mimics calling the superclass :code:`__new__(cls)` without additional
        parameters, just like the parent's method.
        '''
        return DataSet.__new__(cls)

    def _get_sig_shape_and_native_dtype(self):
        first_fn = self._get_files()[0]
        first_file = fileDM(first_fn, on_memory=True)
        if first_file.numObjects == 1:
            idx = 0
        else:
            idx = 1
        try:
            raw_dtype = first_file._DM2NPDataType(first_file.dataType[idx])
            native_sig_shape = (first_file.ySize[idx], first_file.xSize[idx])
        except IndexError as e:
            raise DataSetException("could not determine dtype or signal shape") from e
        return native_sig_shape, raw_dtype

    def _get_fileset(self):
        start_idx = 0
        files = []
        for fn in self._get_files():
            z_size = self._z_sizes[fn]
            f = StackedDMFile(
                path=fn,
                start_idx=start_idx,
                end_idx=start_idx + z_size,
                sig_shape=self._meta.shape.sig,
                native_dtype=self._meta.raw_dtype,
                file_header=self._offsets[fn],
            )
            files.append(f)
            start_idx += z_size
        return DMFileSet(files)

    def _get_files(self):
        return self._files

    def _get_filesize(self):
        return sum(
            os.stat(p).st_size
            for p in self._get_files()
        )

    def initialize(self, executor):
        self._filesize = executor.run_function(self._get_filesize)
        if self._same_offset:
            metadata = executor.run_function(_get_metadata, self._get_files()[0])
            self._offsets = {
                fn: metadata['offset']
                for fn in self._get_files()
            }
            self._z_sizes = {
                fn: metadata['zsize']
                for fn in self._get_files()
            }
        else:
            metadata = dict(zip(
                self._get_files(),
                executor.map(_get_metadata, self._get_files()),
            ))
            self._offsets = {
                fn: metadata[fn]['offset']
                for fn in self._get_files()
            }
            self._z_sizes = {
                fn: metadata[fn]['zsize']
                for fn in self._get_files()
            }
        self._image_count = sum(self._z_sizes.values())
        if self._nav_shape is None:
            self._nav_shape = (sum(self._z_sizes.values()),)
        native_sig_shape, native_dtype = executor.run_function(self._get_sig_shape_and_native_dtype)
        if self._sig_shape is None:
            self._sig_shape = tuple(native_sig_shape)
        elif int(prod(self._sig_shape)) != int(prod(native_sig_shape)):
            raise DataSetException(
                "sig_shape must be of size: %s" % int(prod(native_sig_shape))
            )
        shape = self._nav_shape + self._sig_shape
        self._nav_shape_product = int(prod(self._nav_shape))
        self._sync_offset_info = self.get_sync_offset_info()
        self._meta = DataSetMeta(
            shape=Shape(shape, sig_dims=len(self._sig_shape)),
            raw_dtype=native_dtype,
            sync_offset=self._sync_offset,
            image_count=self._image_count,
        )
        self._fileset = executor.run_function(self._get_fileset)
        return self

    @classmethod
    def get_supported_extensions(cls):
        return {"dm3", "dm4"}

    @classmethod
    def get_msg_converter(cls) -> typing.Type[MessageConverter]:
        return StackedDMDatasetParams

    @classmethod
    def detect_params(cls, path, executor):
        # FIXME: this doesn't really make sense for file series
        # pl = path.lower()
        # if pl.endswith(".dm3") or pl.endswith(".dm4"):
        #     return {
        #         "parameters": {
        #             "files": [path]
        #         },
        #     }
        return False

    @property
    def dtype(self) -> "nt.DTypeLike":
        return self._meta.raw_dtype

    @property
    def shape(self):
        return self._meta.shape

    def check_valid(self):
        first_fn = self._get_files()[0]
        try:
            with fileDM(first_fn, on_memory=True):
                pass
            return True
        except OSError as e:
            raise DataSetException("invalid dataset: %s" % e)

    def get_partitions(self):
        for part_slice, start, stop in self.get_slices():
            yield BasePartition(
                meta=self._meta,
                partition_slice=part_slice,
                fileset=self._fileset,
                start_frame=start,
                num_frames=stop - start,
                io_backend=self.get_io_backend(),
            )

    def __repr__(self):
        return "<DMDataSet for a stack of %d files>" % (len(self._get_files()),)


"""Module to query till request is complete."""

import time
from collections.abc import Callable
from typing import Any

from requests import exceptions

from lol_stats import logging

_LOGGER = logging.create_colored_logger(__name__)

def query(
    command: Callable,
    args: list[Any] = [],  # noqa: B006
    kwargs: dict[Any, Any] = {},  # noqa: B006
) -> dict:
    while True:
        try:
            return command(*args, **kwargs)
        except exceptions.HTTPError as error:
            _LOGGER.info(
                msg=(
                    "Waiting for 120 seconds for the next request.\n"
                    "This is likely required because because you exceeded your limit."
                ),
            )
            _LOGGER.debug(str(error))
            time.sleep(120)


import os
import sys
import argparse
from twilight.lib import tweets

import logging
logger = logging.getLogger(__name__)

def main(parser):
    '''
    Add country match to TTV2 data on STDIN.
    Output format: [...TTV2 fields...]<TAB>country_iso3_code
    '''
    parser.add_argument('input', nargs='?', type=argparse.FileType('r'), default=sys.stdin)
    parser.add_argument('output', nargs='?', type=argparse.FileType('w'), default=sys.stdout)
    parser.add_argument('--map', help='ESRI Shapefile filepath',
        default=os.path.expanduser('~/corpora/TM_WORLD_BORDERS-0.3/TM_WORLD_BORDERS-0.3.shp'))
    opts = parser.parse_args()

    from geo import shapes
    from geo.types import Feature, FeatureCollection

    countries = FeatureCollection([])
    for polygons, bbox, attributes in shapes.read_shapefile(opts.map):
        # TM_WORLD_BORDERS datasets have shapefiles with these field names:
        #   FIPS, ISO2, ISO3, UN, NAME, AREA, POP2005, REGION, SUBREGION, LON, LAT
        geometry = dict(type='MultiPolygon', coordinates=polygons)
        properties = dict(name=attributes['NAME'])
        countries.features += [Feature(geometry, properties, polygons, id=attributes['ISO3'], bbox=bbox)]

    if opts.input.isatty():
        raise IOError('You must pipe in uncompressed TTV2-formatted tweets')

    for i, line in enumerate(opts.input):
        tweet = tweets.TTV2.from_line(line)

        if tweet.coordinates == '':
            logger.debug('No coordinates [%s] @%s: %s', tweet.id, tweet.user_screen_name, tweet.text)
        else:
            lon, lat = map(float, tweet.coordinates.split(','))
            # for country_match in countries.areas_containing(lon, lat):
            country_match = countries.first_feature_containing(lon, lat)
            if country_match:
                extended_line = unicode(tweet) + u'\t' + unicode(country_match.id)
                print >> opts.output, extended_line.encode('utf8')


import gensim
from gensim.models import Word2Vec
import numpy as np
from gensim.models import KeyedVectors

def featureVector(input,num_features):
    words = input.split()
    featureVec = np.zeros((num_features,), dtype='float32')
    num_words = 0
    for word in words:
        num_words += 1
        featureVec = np.add(featureVec, gensim.models.Word2Vec(word, min_count = 1,size = 100, window = 5))

    if (num_words > 0):
        featureVec = np.divide(featureVec, num_words)

    return featureVec

print("[INFO] Model loaded...")


from flask import Flask, request, jsonify, make_response, abort
from flask_sqlalchemy import SQLAlchemy
import os

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///lilekov.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app=app)

class Users(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(length=20), nullable=False)
    surname = db.Column(db.String(length=20), nullable=False)
    phone = db.Column(db.Integer, nullable=False)

    def __repr__(self):
        return '<Users %r>' % self.id

    def get_user_info(self):
        return {
            'id': self.id,
            'user_name': self.name,
            'user_surname': self.surname,
            'user_phone': self.phone
        }

@app.route('/users', methods=['POST'])
def add_user():
    if not request.json:
        abort(400)

    new_user = Users(name=request.json['name'],
                     surname=request.json['surname'], phone=request.json['phone'])
    try:
        db.session.add(new_user)
        db.session.commit()
        return jsonify({'result': True}), 201
    except:
        abort(400)

@app.route('/users', methods=['GET'])
def all_users():
    users = [user.get_user_info() for user in Users.query.all()]
    return jsonify({'users': users})

@app.route('/users/<int:user_id>', methods=['DELETE'])
def delete_user(user_id):
    find_id = Users.query.get_or_404(user_id)

    try:
        db.session.delete(find_id)
        db.session.commit()
        return jsonify({'result': True})
    except:
        abort(400)

@app.errorhandler(404)
def not_found(error):
    return make_response(jsonify({'error': 'Not Found'}), 404)

if __name__ == '__main__':
    if not os.path.exists('lilekov.db'):
        db.create_all()

    app.run(debug=True, host='0.0.0.0',  port='80')


from rest_framework import serializers
from accounts.models import ShoppingListItem
from posts.serializers import IngredientQuantitySerializer

class ShoppingListItemSerializer(serializers.ModelSerializer):
    ingredients = serializers.SerializerMethodField('get_ingredients',
                                                    read_only=True)
    userid = serializers.PrimaryKeyRelatedField(read_only=True)

    class Meta:
        model = ShoppingListItem
        fields = ('id', 'item', 'userid', 'ingredients')

    def create(self, validated_data):
        userid = self.context['request'].user
        item = ShoppingListItem.objects.create(
            userid=userid,
            item=validated_data.get('item')
        )
        return item

    def get_ingredients(self, obj):
        return IngredientQuantitySerializer(obj.item).data


"""empty message

Revision ID: f293e999f5de
Revises:
Create Date: 2023-02-28 12:39:58.945500

"""
from alembic import op
import sqlalchemy as sa

# revision identifiers, used by Alembic.
revision = 'f293e999f5de'
down_revision = None
branch_labels = None
depends_on = None

def upgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.create_table('purchases',
    sa.Column('id_purchase', sa.Integer(), nullable=False),
    sa.Column('date', sa.Date(), nullable=True),
    sa.Column('name', sa.String(length=120), nullable=True),
    sa.Column('brand', sa.String(length=120), nullable=True),
    sa.Column('season', sa.String(length=120), nullable=True),
    sa.Column('price', sa.Float(), nullable=True),
    sa.Column('amount_purchase', sa.Integer(), nullable=True),
    sa.PrimaryKeyConstraint('id_purchase')
    )
    op.create_index(op.f('ix_purchases_date'), 'purchases', ['date'], unique=False)
    op.create_table('user',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('name_user', sa.String(), nullable=False),
    sa.Column('email', sa.String(), nullable=False),
    sa.Column('password', sa.String(), nullable=False),
    sa.Column('is_admin', sa.Boolean(), nullable=False),
    sa.Column('is_user', sa.Boolean(), nullable=False),
    sa.Column('not_active', sa.Boolean(), nullable=False),
    sa.PrimaryKeyConstraint('id'),
    sa.UniqueConstraint('email')
    )
    op.create_table('sales',
    sa.Column('id', sa.Integer(), nullable=False),
    sa.Column('date', sa.Date(), nullable=True),
    sa.Column('purchase_id', sa.Integer(), nullable=True),
    sa.Column('amount_sale', sa.Integer(), nullable=True),
    sa.Column('total', sa.Float(), nullable=True),
    sa.Column('user_id', sa.Integer(), nullable=True),
    sa.ForeignKeyConstraint(['purchase_id'], ['purchases.id_purchase'], ),
    sa.ForeignKeyConstraint(['user_id'], ['user.id'], ),
    sa.PrimaryKeyConstraint('id')
    )
    op.create_index(op.f('ix_sales_date'), 'sales', ['date'], unique=False)
    # ### end Alembic commands ###

def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    op.drop_index(op.f('ix_sales_date'), table_name='sales')
    op.drop_table('sales')
    op.drop_table('user')
    op.drop_index(op.f('ix_purchases_date'), table_name='purchases')
    op.drop_table('purchases')
    # ### end Alembic commands ###


from collections import defaultdict
from functools import lru_cache
ddict =dict()
with open('input.txt') as f:
    for line in f:
        flines = line.split(' ')
        start = flines[1]
        f_rate = flines[4][5:-1]
        ends = [s.strip().strip(',').strip('\n') for s in flines[9:]]
        ddict[start] = [int(f_rate), ends]
@lru_cache(maxsize=None)

def maxflow(cur, opened, min_left):
    if min_left <= 0:
        return 0
    best = 0
    if cur not in opened:
        val = (min_left - 1) * ddict[cur][0]
        cur_opened = tuple(sorted(opened + (cur,)))
        for adj in ddict[cur][1]:
            if val > 0:
                best = max(best ,
                    val + maxflow(adj, cur_opened, min_left - 2))
            best = max(best,
                maxflow(adj , opened, min_left - 1))
    else:
        for(adj) in ddict[cur][1]:
            best = max(best,
                maxflow(adj, opened, min_left - 1))
    return best

print("Part 1: ",maxflow('AA', (), 30))

@lru_cache(maxsize=None)
def maxflow2(my_cur, e_curr, opened, min_left):
    if min_left <= 0:
        return 0
    best = 0
    val_my = (min_left - 1) * ddict[my_cur][0]
    val_e = (min_left - 1) * ddict[e_curr][0]
    for adj_my in ddict[my_cur][1]:
        for adj_e in ddict[e_curr][1]:
            if adj_my == adj_e:
                continue
            if adj_my not in opened and adj_e not in opened:
                best = max(best,
                    val_my + val_e + maxflow2(adj_my, adj_e, opened + (adj_my, adj_e), min_left - 2))
            elif adj_my not in opened:
                best = max(best,
                    val_my + maxflow2(adj_my, adj_e, opened + (adj_my,), min_left - 2))
            elif adj_e not in opened:
                best = max(best,
                    val_e + maxflow2(adj_my, adj_e, opened + (adj_e,), min_left - 2))
            else:
                best = max(best,
                    maxflow2(adj_my, adj_e, opened, min_left - 2))
    return best

print(maxflow2('AA','AA', (), 26))