import asyncio
import json
from asyncio import CancelledError
from copy import copy
from decimal import Decimal
from unittest import TestCase
from unittest.mock import patch

from aioresponses import aioresponses

import hummingbot.connector.parrot as parrot

class ParrotConnectorUnitTest(TestCase):
    # logging.Level required to receive logs from the data source logger
    level = 0

    @classmethod
    def setUpClass(cls):
        cls.ev_loop: asyncio.AbstractEventLoop = asyncio.get_event_loop()

    def setUp(self) -> None:
        super().setUp()
        self.log_records = []

        parrot.logger().setLevel(1)
        parrot.logger().addHandler(self)

        self.campaigns_get_resp = {"status": "success", "campaigns": [
            {"id": 1, "campaign_name": "zilliqa", "link": "https://zilliqa.com/index.html", "markets": [
                {"market_id": 1, "exchange_name": "binance", "base_asset": "ZIL", "quote_asset": "USDT",
                 "base_asset_full_name": "zilliqa", "quote_asset_full_name": "tether", "trading_pair": "ZILUSDT",
                 "return": 1.4600818845692998, "last_snapshot_ts": 1592263560000,
                 "last_snapshot_volume": 7294.967867187001, "trailing_1h_volume": 525955.48182515,
                 "hourly_payout_usd": 1.488095238095238, "bots": 10, "last_hour_bots": 14, "filled_24h_volume": 0.0,
                 "market_24h_usd_volume": 0.0},
            ]}]}
        self.expected_campaign_no_markets = parrot.CampaignSummary(market_id=1, trading_pair='ZIL-USDT',
                                                                   exchange_name='binance', spread_max=Decimal('0'),
                                                                   payout_asset='', liquidity=Decimal('0'),
                                                                   liquidity_usd=Decimal('0'), active_bots=0,
                                                                   reward_per_wk=Decimal('0'), apy=Decimal('0'))
        self.expected_campaign_w_markets = parrot.CampaignSummary(market_id=1, trading_pair='ZIL-USDT',
                                                                  exchange_name='binance', spread_max=Decimal('0.02'),
                                                                  payout_asset='ZIL', liquidity=Decimal('0'),
                                                                  liquidity_usd=Decimal('0'), active_bots=15,
                                                                  reward_per_wk=Decimal('205930.0'), apy=Decimal('0'))
        self.expected_campaign_32_markets = {
            32: parrot.CampaignSummary(market_id=32, trading_pair='ALGO-USDT', exchange_name='binance',
                                       spread_max=Decimal('0.015'), payout_asset='ALGO', liquidity=Decimal('0'),
                                       liquidity_usd=Decimal('0'), active_bots=18, reward_per_wk=Decimal('341.0'),
                                       apy=Decimal('0'))}
        self.markets_get_resp = {"status": "success", "markets": [
            {"base_asset": "ZIL",
             "base_asset_full_name": "zilliqa", "exchange_name": "binance",
             "market_id": 1, "quote_asset": "USDT", "quote_asset_full_name": "tether", "trading_pair": "ZIL/USDT",
             "base_asset_address": "", "quote_asset_address": "",
             "active_bounty_periods": [
                 {"bounty_period_id": 2396, "bounty_campaign_id": 38, "bounty_campaign_name": "dafi",
                  "bounty_campaign_link": "https://zilliqa.com/index.html", "start_timestamp": 1657584000000,
                  "end_timestamp": 1658188800000, "budget": {"bid": 102965.0, "ask": 102965.0}, "spread_max": 2.0,
                  "payout_asset": "ZIL"}], "return": 8.694721275945772, "last_snapshot_ts": 1657812180000,
             "last_snapshot_volume": 3678.5291375, "trailing_1h_volume": 261185.66037849995,
             "hourly_payout_usd": 4.317788244047619, "bots": 15, "last_hour_bots": 18, "filled_24h_volume": 6816.23476,
             "weekly_reward_in_usd": 751.8118232323908, "weekly_reward": {"ZIL": 205735.9191468253},
             "has_user_bots": 'false', "market_24h_usd_volume": 0.0}]}

        self.get_fail = {"status": "error", "message": "ERROR message"}

        self.snapshot_get_resp = {"status": "success", "market_snapshot": {"market_id": 32, "timestamp": 1657747860000,
                                                                           "last_snapshot_ts": 1657747864000,
                                                                           "annualized_return": 0.4026136989303596,
                                                                           "payout_summary": {"open_volume": {
                                                                               "reward": {
                                                                                "ask": {"ALGO": 0.01691468253968254},
                                                                                "bid": {
                                                                                "ALGO": 0.01691468253968254}},
                                                                               "reward_profoma": {
                                                                                "ask": {"ALGO": 0.01691468253968254},
                                                                                "bid": {
                                                                                "ALGO": 0.01691468253968254}},
                                                                               "payout_asset_usd_rate": {
                                                                                "ALGO": 0.30415},
                                                                               "total_hourly_payout_usd": 0.6173520833333332},
                                                                               "filled_volume": {}},
                                                                           "summary_stats": {"open_volume": {
                                                                               "ask": {"accumulated_roll_over": 0},
                                                                               "bid": {"accumulated_roll_over": 0},
                                                                               "bots": 17, "oov_ask": 16274,
                                                                               "oov_bid": 31099, "bots_ask": 14,
                                                                               "bots_bid": 9,
                                                                               "spread_ask": 0.29605111465204803,
                                                                               "spread_bid": 0.33684674006707405,
                                                                               "last_hour_bots": 19,
                                                                               "oov_eligible_ask": 16156,
                                                                               "oov_eligible_bid": 26059,
                                                                               "last_hour_bots_ask": 16,
                                                                               "last_hour_bots_bid": 15,
                                                                               "base_asset_usd_rate": 0.30415,
                                                                               "quote_asset_usd_rate": 1},
                                                                               "filled_volume": {}}},
                                  "user_snapshot": {"timestamp": 1657747860000, "is_default": True,
                                                    "rewards_summary": {"ask": {}, "bid": {}},
                                                    "summary_stats": {"oov_ask": 0, "oov_bid": 0, "reward_pct": 0,
                                                                      "spread_ask": -1, "spread_bid": -1,
                                                                      "reward": {"ask": {}, "bid": {}},
                                                                      "reward_profoma": {"ask": {}, "bid": {}},
                                                                      "open_volume_pct": 0, "oov_eligible_ask": 0,
                                                                      "oov_eligible_bid": 0}},
                                  "market_mid_price": 0.30415}
        self.expected_snapshots_bad_timestamp = {"status": "error",
                                                 "message": "Data not available for timestamp 1657747860000."}
        self.expected_snapshots_error = {"status": "error", "message": "404: Not Found"}

        self.expected_summary = {
            'ALGO-USDT': parrot.CampaignSummary(market_id=32, trading_pair='ALGO-USDT', exchange_name='binance',
                                                spread_max=Decimal('0.015'), payout_asset='ALGO',
                                                liquidity=Decimal('42215'),
                                                liquidity_usd=Decimal('12839.69224999999898390035113'), active_bots=17,
                                                reward_per_wk=Decimal('341.0'),
                                                apy=Decimal('0.40261369893035958700266974119585938751697540283203125'))}

    def handle(self, record):
        self.log_records.append(record)

    def _is_logged(self, log_level: str, message: str) -> bool:
        return any(record.levelname == log_level and record.getMessage().startswith(message)
                   for record in self.log_records)

    @aioresponses()
    def test_get_active_campaigns_empty_markets(self, mocked_http):
        mocked_http.get(f"{parrot.PARROT_MINER_BASE_URL}campaigns", body=json.dumps(self.campaigns_get_resp))
        mocked_http.get(f"{parrot.PARROT_MINER_BASE_URL}markets", body=json.dumps(""))

        campaigns = self.ev_loop.run_until_complete(parrot.get_active_campaigns("binance"))

        self.assertEqual({1: self.expected_campaign_no_markets}, campaigns)
        self.assertTrue(self._is_logged("WARNING",
                                        "Could not get active markets from Hummingbot API"
                                        " (returned response '')."))

    @aioresponses()
    def test_get_active_campaigns_failed_markets(self, mocked_http):
        mocked_http.get(f"{parrot.PARROT_MINER_BASE_URL}campaigns", body=json.dumps(self.campaigns_get_resp))
        mocked_http.get(f"{parrot.PARROT_MINER_BASE_URL}markets", body=json.dumps(self.get_fail))

        campaigns = self.ev_loop.run_until_complete(parrot.get_active_campaigns("binance"))

        self.assertEqual({1: self.expected_campaign_no_markets}, campaigns)
        self.assertTrue(self._is_logged("WARNING",
                                        "Could not get active markets from Hummingbot API"
                                        f" (returned response '{self.get_fail}')."))

    @aioresponses()
    def test_get_active_campaigns_markets_wrong_id(self, mocked_http):
        mocked_http.get(f"{parrot.PARROT_MINER_BASE_URL}campaigns", body=json.dumps(self.campaigns_get_resp))
        market_wrong_id = self.markets_get_resp
        market_wrong_id["markets"][0]["market_id"] = 10
        mocked_http.get(f"{parrot.PARROT_MINER_BASE_URL}markets", body=json.dumps(market_wrong_id))

        campaigns = self.ev_loop.run_until_complete(parrot.get_active_campaigns("binance"))

        self.assertEqual({1: self.expected_campaign_no_markets}, campaigns)
        self.assertFalse(self._is_logged("WARNING",
                                         "Could not get active markets from Hummingbot API"
                                         f" (returned response '{self.get_fail}')."))

    @aioresponses()
    def test_get_active_campaigns_markets(self, mocked_http):
        mocked_http.get(f"{parrot.PARROT_MINER_BASE_URL}campaigns", body=json.dumps(self.campaigns_get_resp))
        mocked_http.get(f"{parrot.PARROT_MINER_BASE_URL}markets", body=json.dumps(self.markets_get_resp))

        campaigns = self.ev_loop.run_until_complete(parrot.get_active_campaigns("binance", ["ZIL-USDT"]))
        self.assertEqual({1: self.expected_campaign_w_markets}, campaigns)

    # def test_get_active_campaigns_markets_live(self):
    #    campaigns = self.ev_loop.run_until_complete(parrot.get_active_campaigns("binance", ["ALGO-USDT"]))
    #    self.assertEqual({1: self.expected_campaign_w_markets}, campaigns)

    @aioresponses()
    def test_get_active_markets(self, mocked_http):
        mocked_http.get(f"{parrot.PARROT_MINER_BASE_URL}markets", body=json.dumps(self.markets_get_resp))
        campaigns = {1: copy(self.expected_campaign_no_markets)}
        campaigns = self.ev_loop.run_until_complete(parrot.get_active_markets(campaigns))
        self.assertNotEqual({1: self.expected_campaign_no_markets}, campaigns)
        self.assertEqual({1: self.expected_campaign_w_markets}, campaigns)

    @aioresponses()
    def test_get_market_snapshots(self, mocked_http):
        market_id = 32
        mocked_http.get(
            f"{parrot.PARROT_MINER_BASE_URL}charts/market_band?chart_interval=1&market_id={market_id}",
            body=json.dumps({"status": "success", "data": [
                {"timestamp": 1662589860000, "price": 0.30005, "ask": 0.301145, "bid": 0.298362,
                 "spread_ask": 0.3647958323482506, "spread_bid": 0.5624147716913023, "liquidity": 32932.5255}]}))
        snapshot = self.ev_loop.run_until_complete(parrot.get_market_snapshots(market_id))
        self.assertEqual({'data': [{'ask': 0.301145,
                                    'bid': 0.298362,
                                    'liquidity': 32932.5255,
                                    'price': 0.30005,
                                    'spread_ask': 0.3647958323482506,
                                    'spread_bid': 0.5624147716913023,
                                    'timestamp': 1662589860000}],
                          'status': 'success'}, snapshot)

    @aioresponses()
    def test_get_market_snapshots_returns_none(self, mocked_http):
        market_id = 32
        # 'status' == "error"
        mocked_http.get(
            f"{parrot.PARROT_MINER_BASE_URL}charts/market_band?chart_interval=1&market_id={market_id}",
            body=json.dumps({"status": "error", "data": []}))
        snapshot = self.ev_loop.run_until_complete(parrot.get_market_snapshots(market_id))
        self.assertEqual(None, snapshot)

        # No 'status' field
        mocked_http.get(
            f"{parrot.PARROT_MINER_BASE_URL}charts/market_band?chart_interval=1&market_id={market_id}",
            body=json.dumps({"data": []}))
        snapshot = self.ev_loop.run_until_complete(parrot.get_market_snapshots(market_id))
        self.assertEqual(None, snapshot)

        # JSON resp is None
        mocked_http.get(
            f"{parrot.PARROT_MINER_BASE_URL}charts/market_band?chart_interval=1&market_id={market_id}",
            body=json.dumps(None))
        snapshot = self.ev_loop.run_until_complete(parrot.get_market_snapshots(market_id))
        self.assertEqual(None, snapshot)

    @aioresponses()
    def test_get_market_last_snapshot(self, mocked_http):
        market_id = 32
        timestamp = 1662589860000
        mocked_http.get(
            f"{parrot.PARROT_MINER_BASE_URL}user/single_snapshot?aggregate_period=1m&market_id={market_id}&timestamp={timestamp}",
            body=json.dumps(self.snapshot_get_resp))
        with patch("hummingbot.connector.parrot.get_market_snapshots") as mocked_snapshots:
            mocked_snapshots.return_value = {"status": "success", "data": [{"timestamp": timestamp}]}
            snapshot = self.ev_loop.run_until_complete(parrot.get_market_last_snapshot(market_id))
        self.assertEqual(self.snapshot_get_resp, snapshot)

    # This test is likely to fail with time as the data will change
    # def test_get_market_last_snapshot_live(self):
    #    market_id = 32
    #    snapshot = self.ev_loop.run_until_complete(parrot.get_market_last_snapshot(market_id))
    #    self.assertEqual(self.snapshot_get_resp, snapshot)

    @aioresponses()
    def test_get_campaign_summary(self, mocked_http):
        timestamp = 16577478600000
        mocked_http.get(
            f"{parrot.PARROT_MINER_BASE_URL}user/single_snapshot?aggregate_period=1m&market_id={32}&timestamp={timestamp}",
            body=json.dumps(self.snapshot_get_resp))
        with patch("hummingbot.connector.parrot.get_market_snapshots") as mocked_snapshots:
            mocked_snapshots.return_value = {"status": "success", "data": [{"timestamp": timestamp}]}
            with patch('hummingbot.connector.parrot.get_active_campaigns') as mocked_ac:
                mocked_ac.return_value = self.expected_campaign_32_markets
                summary = self.ev_loop.run_until_complete(parrot.get_campaign_summary("binance", ["ALGO-USDT"]))
        self.assertEqual(self.expected_summary, summary)

    @aioresponses()
    def test_get_campaign_summary_http_error(self, mocked_http):
        timestamp = 16577478600000
        mocked_http.get(
            f"{parrot.PARROT_MINER_BASE_URL}user/single_snapshot?market_id={32}&timestamp={timestamp}&aggregate_period=1m",
            body=json.dumps(self.snapshot_get_resp))
        with patch('hummingbot.connector.parrot.get_active_campaigns') as mocked_ac:
            with patch("hummingbot.connector.parrot.get_market_snapshots") as mocked_snapshots:
                mocked_snapshots.return_value = {"status": "success", "data": [{"timestamp": timestamp}]}
                with patch('hummingbot.connector.parrot.get_market_snapshots') as mocked_ss:
                    mocked_ac.return_value = self.expected_campaign_32_markets
                    mocked_ss.return_value = self.expected_snapshots_error
                    summary = self.ev_loop.run_until_complete(parrot.get_campaign_summary("binance", ["ALGO-USDT"]))
        # No snapshot, just dict re-arrangement
        self.assertEqual({}, summary)
        self.assertTrue(self._is_logged("ERROR", "Unexpected error while requesting data from Hummingbot API."))

    @aioresponses()
    def test_get_campaign_summary_exception(self, mocked_http):
        mocked_http.get(
            f"{parrot.PARROT_MINER_BASE_URL}user/single_snapshot?market_id={32}&timestamp={-1}&aggregate_period=1m",
            body=json.dumps(self.snapshot_get_resp))
        with patch('hummingbot.connector.parrot.get_active_campaigns') as mocked_ac:
            with patch('hummingbot.connector.parrot.get_market_snapshots') as mocked_ss:
                with self.assertRaises(CancelledError):
                    mocked_ac.side_effect = asyncio.CancelledError
                    mocked_ss.return_value = self.expected_campaign_32_markets
                    self.ev_loop.run_until_complete(parrot.get_campaign_summary("binance", ["ALGO-USDT"]))
                    self.assertTrue(
                        self._is_logged("ERROR", "Unexpected error while requesting data from Hummingbot API."))

                with self.assertRaises(CancelledError):
                    mocked_ac.return_value = self.expected_campaign_32_markets
                    mocked_ss.side_effect = asyncio.CancelledError
                    self.ev_loop.run_until_complete(parrot.get_campaign_summary("binance", ["ALGO-USDT"]))
                    self.assertTrue(
                        self._is_logged("ERROR", "Unexpected error while requesting data from Hummingbot API."))

    @aioresponses()
    def test_retrieve_active_campaigns_error_is_logged(self, mock_api):
        resp = {"status": "error", "message": "Rate limit exceeded: 10 per 1 minute"}
        mock_api.get(f"{parrot.PARROT_MINER_BASE_URL}campaigns", body=json.dumps(resp))
        mock_api.get(f"{parrot.PARROT_MINER_BASE_URL}markets", body=json.dumps(resp))

        campaigns = asyncio.get_event_loop().run_until_complete(
            parrot.get_active_campaigns(
                exchange="binance",
                trading_pairs=["COINALPHA-HBOT"]))

        self.assertEqual(0, len(campaigns))
        self.assertTrue(self._is_logged("WARNING",
                                        "Could not get active campaigns from Hummingbot API"
                                        f" (returned response '{resp}')."))

    @aioresponses()
    def test_active_campaigns_are_filtered_by_token_pair(self, mock_api):
        url = f"{parrot.PARROT_MINER_BASE_URL}campaigns"
        resp = {
            "status": "success",
            "campaigns": [{
                "id": 26,
                "campaign_name": "xym",
                "link": "https://symbolplatform.com/",
                "markets": [{
                    "market_id": 62,
                    "trading_pair": "XYM-BTC",
                    "exchange_name": "kucoin",
                    "base_asset": "XYM",
                    "base_asset_full_name": "symbol",
                    "quote_asset": "BTC",
                    "quote_asset_full_name": "bitcoin"}]},
                {
                    "id": 27,
                    "campaign_name": "test",
                    "link": "https://symbolplatform.com/",
                    "markets": [{
                        "market_id": 63,
                        "trading_pair": "COINALPHA-HBOT",
                        "exchange_name": "kucoin",
                        "base_asset": "COINALPHA",
                        "base_asset_full_name": "coinalpha",
                        "quote_asset": "HBOT",
                        "quote_asset_full_name": "hbot"}]}]}

        mock_api.get(url, body=json.dumps(resp))
        mock_api.get(f"{parrot.PARROT_MINER_BASE_URL}markets", body=json.dumps(self.markets_get_resp))

        campaigns = asyncio.get_event_loop().run_until_complete(
            parrot.get_active_campaigns(
                exchange="kucoin",
                trading_pairs=["COINALPHA-HBOT"]))

        self.assertEqual(1, len(campaigns))
        campaign_summary: parrot.CampaignSummary = campaigns[63]
        self.assertEqual("COINALPHA-HBOT", campaign_summary.trading_pair)
        self.assertEqual("kucoin", campaign_summary.exchange_name)
        self.assertEqual(Decimal("0"), campaign_summary.spread_max)

    @aioresponses()
    def test_active_campaigns_are_filtered_by_exchange_name(self, mock_api):
        url = f"{parrot.PARROT_MINER_BASE_URL}campaigns"
        resp = {
            "status": "success",
            "campaigns": [{
                "id": 26,
                "campaign_name": "xym",
                "link": "https://symbolplatform.com/",
                "markets": [{
                    "market_id": 62,
                    "trading_pair": "XYM-BTC",
                    "exchange_name": "ascendex",
                    "base_asset": "XYM",
                    "base_asset_full_name": "symbol",
                    "quote_asset": "BTC",
                    "quote_asset_full_name": "bitcoin"}],
                "bounty_periods": [{
                    "id": 823,
                    "start_datetime": "2021-10-05T00:00:00",
                    "end_datetime": "2021-10-12T00:00:00",
                    "payout_parameters": [{
                        "id": 2212,
                        "market_id": 62,
                        "bid_budget": 1371.5,
                        "ask_budget": 1371.5,
                        "exponential_decay_function_factor": 8.0,
                        "spread_max": 1.5,
                        "payout_asset": "XYM"}]}]}]}

        mock_api.get(url, body=json.dumps(resp))
        mock_api.get(f"{parrot.PARROT_MINER_BASE_URL}markets", body=json.dumps(self.markets_get_resp))

        campaigns = asyncio.get_event_loop().run_until_complete(
            parrot.get_active_campaigns(
                exchange="test_exchange",
                trading_pairs=["XYM-BTC"]))

        self.assertEqual(0, len(campaigns))

        mock_api.get(url, body=json.dumps(resp))
        mock_api.get(f"{parrot.PARROT_MINER_BASE_URL}markets", body=json.dumps(self.markets_get_resp))

        campaigns = asyncio.get_event_loop().run_until_complete(
            parrot.get_active_campaigns(
                exchange="ascend_ex",
                trading_pairs=["XYM-BTC"]))
        self.assertEqual(1, len(campaigns))

    @aioresponses()
    def test_get_campaign_summary_logs_error_if_exception_happens(self, mock_api):
        url = f"{parrot.PARROT_MINER_BASE_URL}campaigns"

        mock_api.get(url, exception=Exception("Test error description"))

        campaigns = asyncio.get_event_loop().run_until_complete(
            parrot.get_campaign_summary(
                exchange="test_exchange",
                trading_pairs=["XYM-BTC"]))

        self.assertEqual(0, len(campaigns))
        self.assertTrue(self._is_logged("ERROR",
                                        "Unexpected error while requesting data from Hummingbot API."))

    def test_are_same_entity(self):
        self.assertTrue(parrot.are_same_entity("ascend_ex", "ascendex"))
        self.assertTrue(parrot.are_same_entity("ascend_ex", "ascend_ex"))
        self.assertTrue(parrot.are_same_entity("gate_io", "gateio"))
        self.assertFalse(parrot.are_same_entity("gate_io", "gateios"))


import matplotlib.pyplot as plt
import cv2
import numpy as np

# show image in easy way
def showImage(window_name, image_name):
    cv2.imshow(window_name, image_name)
    cv2.waitKey(0)
    cv2.destroyAllWindows

def requiredPartOfImage(image, vertices):
    mask = np.zeros_like(image)
    matchMaskColor = 255
    cv2.fillPoly(mask,vertices,matchMaskColor)
    maskedImage = cv2.bitwise_and(image,mask)
    return maskedImage

def drawLines(image, lines):
    image = np.copy(image)
    blankImage = np.zeros((image.shape[0], image.shape[1],3),dtype=np.uint8)

    for line in lines:
        for x1, y1, x2, y2 in line:
            cv2.line(blankImage,(x1,y1),(x2,y2),(0,255,0),thickness=10)

    image = cv2.addWeighted(image, 0.8, blankImage, 1, 0.0)
    return image

"""
dont need anymore after the processing video

# load an image
image = cv2.imread("road_lane.png")
#showImage("original image",image)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
"""

def process(image):

    # shape[0]  height  -  shape[1] width  -  shape[2] color channel
    height = image.shape[0]
    width = image.shape[1]

    # to get lane part of image
    verticesOfRequiredPartOfImage = \
        [
            (0,height),
            (width/2,height/2),
            (width,height)
        ]

    grayImage = cv2.cvtColor(image,cv2.COLOR_RGB2GRAY)
    #showImage("gray",grayImage)

    cannyImage = cv2.Canny(grayImage, 100, 120)
    #showImage("canny",cannyImage)

    croppedImage = requiredPartOfImage(cannyImage,np.array([verticesOfRequiredPartOfImage],np.int32))
    #showImage("cropped",croppedImage)

    #lines = cv2.HoughLinesP(croppedImage,2,np.pi/60,160,np.array([]),40,100)
    lines = cv2.HoughLinesP(croppedImage, 2, np.pi / 180, 200, np.array([]), 40, 100)

    imageWithLines = drawLines(image,lines)

    return imageWithLines

cap = cv2.VideoCapture("Lane.mp4")

while(cap.isOpened()):
    ret, frame = cap.read()
    frame = process(frame)
    cv2.imshow("frame",frame)
    if (cv2.waitKey(1) & 0xFF == ord("q")):
        break

cap.release()
cv2.destroyAllWindows()

# to see coordinates of pixels
#plt.imshow(imageWithLines)
#plt.show()


# Problem: STRGMNZ Contest: LTIME102C
import math

t = int(input())
while t != 0:
    n = int(input())
    x1 = n
    y1 = 10 ** 6 + 1
    for i in range(n + 1, n * 2):
        if i % n != 0:
            z = abs(math.gcd(n, i) - ((n * i) // (math.gcd(n, i))))
            b = min(y1, z)
            if b < y1:
                y1 = b
                x1 = i
    print(x1)
    t = t - 1


#insert this code to train function of predict_3dpose.py
#  export_dataset(train_set_2d,data_mean_2d,data_std_2d,train_set_3d,data_mean_3d,data_std_3d,"train.h5")
#  export_dataset(test_set_2d,data_mean_2d,data_std_2d,test_set_3d,data_mean_3d,data_std_3d,"test.h5")

def export_dataset(train_set_2d,data_mean_2d,data_std_2d,train_set_3d,data_mean_3d,data_std_3d,hdf5_name):
  # Figure out how many frames we have
  data_x=train_set_2d
  data_y=train_set_3d
  camera_frame=FLAGS.camera_frame

  n = 0
  for key2d in data_x.keys():
    n2d, _ = data_x[ key2d ].shape
    n = n + n2d

  encoder_inputs  = np.zeros((n, 32), dtype=float)
  decoder_outputs = np.zeros((n, 48), dtype=float)

  # Put all the data into big arrays
  idx = 0
  for key2d in data_x.keys():
    (subj, b, fname) = key2d
    # keys should be the same if 3d is in camera coordinates
    key3d = key2d if (camera_frame) else (subj, b, '{0}.h5'.format(fname.split('.')[0]))
    key3d = (subj, b, fname[:-3]) if fname.endswith('-sh') and camera_frame else key3d

    n2d, _ = data_x[ key2d ].shape
    encoder_inputs[idx:idx+n2d, :]  = data_x[ key2d ]
    decoder_outputs[idx:idx+n2d, :] = data_y[ key3d ]
    idx = idx + n2d

  # Write DataSet
  print("Export data to "+hdf5_name)
  print(encoder_inputs)
  print(decoder_outputs)
  print(encoder_inputs.shape)
  print(decoder_outputs.shape)
  print(data_mean_2d.shape)
  print(data_std_2d.shape)
  print(data_mean_3d.shape)
  print(data_std_3d.shape)

  with h5py.File(hdf5_name, 'w') as f:
    f.create_dataset('encoder_inputs', data=encoder_inputs)
    f.create_dataset('decoder_outputs', data=decoder_outputs)
    f.create_dataset('data_mean_2d', data=data_mean_2d)
    f.create_dataset('data_std_2d', data=data_std_2d)
    f.create_dataset('data_mean_3d', data=data_mean_3d)
    f.create_dataset('data_std_3d', data=data_std_3d)


#######################################################################################

import feature_extraction.audio_to_feats as atf
import numpy as np
from numpy import *
import pickle
# import keras.models
import config
import keras
from dataset_tools import audio_converter as ac
from dataset_tools import dataset_management as dm
import os
import feature_extraction.map_json_to_feats as jtf

max_sequence_length = config.audioLengthMaxSeconds * 100  # 100 frames per second, or 10 ms per frame
deltaTimeNormalizer = 200  # number that timeFromPrev and timeToNext are divided by to make them more suitable for learning. Arbitrary choice: very roughly average distance between 2 onsets
finishers = config.permitFinishers

def batchGetSongFeatsFromAudios(songFeatPaths):  # needs to also analyze audio instead of just loading feats data, which hasn't been computed for a new audio
    songFeats = []
    tempWavDir = "data/temp/temp.wav"
    for item in songFeatPaths:

        ext = os.path.splitext(item)[-1].lower()
        assert(ext == ".mp3" or ext == ".ogg")

        # this includes standardization
        if ext == ".mp3":
            ac.mp3ToWav(item, tempWavDir)
        if ext == ".ogg":
            ac.oggToWav(item, tempWavDir)
        audioFeat = atf.makeFeats(tempWavDir)
        os.remove(tempWavDir)

        bandMeans = np.loadtxt("data/misc/bandMeans.txt")
        bandStdevs = np.loadtxt("data/misc/bandStdevs.txt")

        audioFeat = dm.normalize(audioFeat, bandMeans, bandStdevs)

        songFeats.append([item[:-4], audioFeat])
    return songFeats

def batchPrepareFeatsForModel(mapInfo, songFeats, SRs):  # mapInfo has tuples of id, onsets, notes for each map. songFeats has 15x40 per onset. Need to make unrollings.

    onsetCount = 0
    for map in mapInfo:
        onsetCount += len(map[1])

    pMapFeats = np.empty((onsetCount, 6+finishers), dtype=float32)  # Everything here should be filled TODO check
    pSongFeats = np.full((onsetCount, 1+2*config.colorAudioBookendLength, 40), config.pad)

    onsetIndex = 0

    # mapPad = np.array([-1,-1,-1,-1,-1,-1,-1,-1])
    # audioPad = np.full((1+2*config.colorAudioBookendLength, 40), config.pad)
    for i, map in enumerate(mapInfo):
        song = songFeats[i]
        sr = SRs[i]

        onsets = np.array(map[1]).astype(int)

        rolledMapData = []
        # don: 0
        # kat: 2/8/10
        # fdon: 4
        # fkat: 6/12/14
        for j, color in enumerate(map[2]):

            isFirstOnset = -1
            if j == 0:
                isFirstOnset = 1

            if j == 0:
                timeFromPrev = -1
                timeToNext = onsets[j+1] - onsets[j]
            elif j == len(onsets) - 1:
                timeFromPrev = onsets[j] - onsets[j-1]
                timeToNext = -1
            else:
                timeFromPrev = onsets[j] - onsets[j-1]
                timeToNext = onsets[j+1] - onsets[j]
            if finishers:
                rolledMapData.append(np.array([-1, -1, -1, -1, timeFromPrev / deltaTimeNormalizer, timeToNext / deltaTimeNormalizer, isFirstOnset, sr]))  # since we are predicting, all colors start 0
            else:
                rolledMapData.append(np.array([-1, -1, timeFromPrev / deltaTimeNormalizer, timeToNext / deltaTimeNormalizer, isFirstOnset, sr]))  # since we are predicting, all colors start 0

        # # Now make unrollings from rolledMapData...
        # for j, item in enumerate(rolledMapData):
        #     mapUnrollingsSet = np.empty((unrollings, 8), dtype=float32)
        #     songUnrollingsSet = np.empty((unrollings, 1+2*config.colorAudioBookendLength, 40), dtype=float32)
        #     for k in range(unrollings):  # 0 to 79
        #         indexToGet = j - unrollings + k  # first is 0 - 80 + 0, through 0 - 80 + 79
        #         if indexToGet < 0:
        #             mapUnrollingsSet[k] = mapPad
        #             songUnrollingsSet[k] = audioPad
        #         else:
        #             assert(indexToGet < len(rolledMapData))
        #             mapUnrollingsSet[k] = rolledMapData[indexToGet]
        #             songUnrollingsSet[k] = song[1][indexToGet]

        #     pMapFeats[onsetIndex] = mapUnrollingsSet
        #     pSongFeats[onsetIndex] = songUnrollingsSet
        #     onsetIndex += 1

    # assert(onsetIndex == onsetCount)

    return rolledMapData, song[1]

def addContextAndTrim(x, onsets, bookendLength):
# x.reshape(())   (config.audioLengthMaxSeconds, 40)?
    padding = np.full((1,40), config.pad, dtype=float32)  # TODO after normalization, this should be like -3 instead of -500. track minimum to determine this
    context = bookendLength
    window = 2*context + 1 # prepend and append context
    # want to create input_shape=(max_sequence_length,15,40) from (max_sequence_length, 40)
    out = np.zeros((len(onsets),window,40))
    onsets = np.array(onsets).astype(int)
    # onsets = onsets.astype(int)
    # #
    truths = onsets // 10

    for i, truth in enumerate(truths): # want: for each onset in onsets (need its corresponding index in x). Could scan and continue for misses.
        bookended = np.zeros((window,40), dtype=float32)
        for j in range (context*-1, context+1):
            indexToGet = int(truth) + j  # if at start of audio this is negative in first half, if at end this is out of bounds positive in second half
            if indexToGet < 0 or indexToGet >= len(x):
                bookended[j + context] = padding
            else:
                bookended[j + context] = x[indexToGet]
        out[i] = bookended
    return out

from dataset_tools import map_to_json_converter
def batchGetMapInfo(batch_maps):
    mapFeats = []
    for item in batch_maps:
        json = map_to_json_converter.mapToJson(item)
        id, onsets, notes, _ = jtf.jsonToFeatsColor(json)  # also passes back SR but we ignore that SR here
        cap = min(len(onsets), config.colorOnsetMax)  # TODO limiting, can remove maybe for prediction
        onsets = onsets[:cap]
        notes = notes[:cap]
        mapFeats.append([id, onsets, notes])
    return mapFeats

mapPad = np.array([-1,-1,-1,-1,-1,-1,-1,-1])
if not finishers:
    mapPad = np.array([-1,-1,-1,-1,-1,-1])
audioPad = np.full((1+2*config.colorAudioBookendLength, 40), config.pad)

def predict(unrollings, model, xMaps, xAudios, temperature): # initially via https://towardsdatascience.com/time-series-forecasting-with-recurrent-neural-networks-74674e289816
    #prediction_list = xMaps #close_data[-unrollings:]
    # TODO construct unrollings here per-onset
    # predictedColors = np.empty((len(xMaps), 4))

    # for i, onsetUnrolling in enumerate(xMaps):
    #     xMap = onsetUnrolling
    #     xAudio = xAudios[i]

    #     out = model.predict() #TODO

    #     predictedColors[i] = out
    #     # I would then need to add this prediction to the next 64 unrollings

    includeAudioFeats = config.includeAudioFeatsInColorModel

    originalMap = xMaps
    originalAudio = xAudios
    leadingSequenceMap = np.full((unrollings, 6+finishers), mapPad)
    leadingSequenceAudio = np.full((unrollings, 1+2*config.colorAudioBookendLength, 40), audioPad)

    # print(leadingSequenceMap.dtype.name + leadingSequenceAudio.dtype.name)

    assert(leadingSequenceMap.dtype.name == "int32")
    assert(leadingSequenceAudio.dtype.name == "float64")

    colorPredictions = []

    totals = [0,0,0,0]  # totals of colors predicted
    totalsRaw = [0.0,0.0,0.0,0.0]  # totals of raw prediction probabilities
    if not finishers:
        totals = [0,0]  # totals of colors predicted
        totalsRaw = [0.0,0.0]  # totals of raw prediction probabilities

    for i in range(len(xMaps)):  # TODO append map and sound data at top of loop, then update color once predicted
        # print(f"i: {i} - Shape of leadingSequenceMap: ")
        # print(leadingSequenceMap.shape)

        leadingSequenceMap = np.append(leadingSequenceMap, reshape(originalMap[i], (1, 6+finishers)), axis=0)
        if includeAudioFeats:
            leadingSequenceAudio = np.append(leadingSequenceAudio, reshape(originalAudio[i], (1, 1+2*config.colorAudioBookendLength, 40)), axis=0)

        xMap = leadingSequenceMap[-(unrollings+1):]  # x gets last 64 onsets
        if includeAudioFeats:
            xAudio = leadingSequenceAudio[-(unrollings+1):]  # x gets last 64 onsets

        # xMap[-1]

        # print(f"i: {i} - Shape of xMap: ")
        # print(xMap.shape)

        xMap = reshape(xMap, (1, unrollings+1, 6+finishers))  # model expects input in batch form, shapes get wonky if no extra first dimension
        if includeAudioFeats:
            xAudio = reshape(xAudio, (1, unrollings+1, 1+2*config.colorAudioBookendLength, 40))

        # print("Shape of xMap: ")
        # print(xMap.shape)
        # print("Shape of xAudio: ")
        # print(xAudio.shape)

        # x = x.reshape((1, unrollings, 1))

        if includeAudioFeats:
            out = model.predict([xMap, xAudio], verbose=0)#[0][0]  # if verbose, prints for every call to model.predict
        else:
            out = model.predict([xMap], verbose=0)

        # update leading sequences with new onset based on the predicted color combined with original data
        colorPrediction = solidifyColorPrediction(out[0], temperature)  # extra dimension in output, again because things are in batch form
        colorPredictions.append(colorPrediction)
        totals = [a + b for a, b in zip(totals, colorPrediction)]
        totalsRaw = [a + b for a, b in zip(totalsRaw, out[0])]

        if finishers:
            newOnsetMap = np.append(colorPrediction, [originalMap[i][4], originalMap[i][5], originalMap[i][6], originalMap[i][7]])
        else:
            assert(len(colorPrediction) == 2)
            newOnsetMap = np.append(colorPrediction, [originalMap[i][2], originalMap[i][3], originalMap[i][4], originalMap[i][5]])
        # newOnsetAudio = originalAudio[i]

        newOnsetMap = reshape(newOnsetMap, (1, 6+finishers))
        leadingSequenceMap[-1] = newOnsetMap  # update onset with predicted color

        # newOnsetAudio = reshape(newOnsetAudio, (1, 1+2*config.colorAudioBookendLength, 40))

        # leadingSequenceMap = np.append(leadingSequenceMap, newOnsetMap, axis=0)
        # leadingSequenceAudio = np.append(leadingSequenceAudio, newOnsetAudio, axis=0)

        if i > 0 and i % 250 == 0:
            print(f"Predicted {i} colors so far...")

    assert(len(colorPredictions) == len(xMaps))
    return colorPredictions, totals, totalsRaw

def solidifyColorPrediction(out, temperature):
    don = [1,0,0,0]
    kat = [0,1,0,0]
    fdon = [0,0,1,0]
    fkat = [0,0,0,1]
    objects = [don,kat,fdon,fkat]

    if not finishers:
        don = [1,0]
        kat = [0,1]
        objects = [don, kat]

    assert(len(out) == 2+finishers)
    colorIndex = sample(out, temperature)
    color = objects[colorIndex]

    return color

def sample(preds, temperature):
    # temp is originally 1.0. Low = predictability, high = stochasticity
    # temp of 0 is equivalent to basic argmax. infinity is equivalent to uniform sampling.
    # tempo of 1 is sampling from original probabilities.
    # decreasing from 1, Probabilities become shifted toward larger ones and away from smaller ones
    # increasing from 1, probabilities become more enarly equal
    preds = np.asarray(preds).astype('float64')
    preds = np.log(preds) / temperature
    exp_preds = np.exp(preds)
    preds = exp_preds / np.sum(exp_preds)
    probas = np.random.multinomial(1, preds, 1)
    return np.argmax(probas)

def makePredictionFromMapAndAudio(model, mapFiles, audioFiles, SRs, temperature): # returns prediction from model. in: model, mapFiles, audioFiles, starRatings

    print(f"Predicting with finishers {finishers}, includeAudio {config.includeAudioFeatsInColorModel}, temperature {temperature}")

    # get onsets first and related info, including color
    mapInfo = batchGetMapInfo(mapFiles)  # id, onsets, notes for each map. Does not include SR since we will take the user provided SR for prediction
    unrollings = config.colorUnrollings

    # Processing this batch to prepare it for the model
    bookendLength = config.colorAudioBookendLength  # number of frames to prepend and append on each side of central frame. For n, we have total 2n+1 frames.
    songFeats = batchGetSongFeatsFromAudios(audioFiles)

    for i, songFeat in enumerate(songFeats):  # TODO only do this for the feats matching with the onsets. Much faster
        songFeat[1] = addContextAndTrim(songFeat[1], mapInfo[i][1], bookendLength)

    # Untested but perhaps good to go
    xMaps, xAudios = batchPrepareFeatsForModel(mapInfo, songFeats, SRs)  # # everything should be same as color training, except all notes are colorless and we provided SR

    prediction = None
    colors = None

    xMaps = reshape(xMaps, (len(xMaps), 6+finishers)).astype(float32)  # want |onsets|, 80, 4+4, 1. 4+4 is the 4 colors and 4 other map feats.
    xAudios = reshape(xAudios, (len(xMaps), 1+2*config.colorAudioBookendLength, 40, 1)).astype(float32)  # want |onsets|, 80, 15, 40, 1: onsets, unrollings, 1+2bookends, freq bands, 1.

    print("Beginning prediction...")

    assert(len(audioFiles) == 1)  # All the onsets are mashed together in one list, would need to separate them by song to support several songs
    for i in range(len(audioFiles)):
        prediction, totals, totalsRaw = predict(unrollings, model, xMaps, xAudios, temperature)
    # prediction = model.predict(my_prediction_batch_generator, batch_size=generator_batch_size, verbose=1)

    if finishers:
        print(f"Predicted colors totals [don, kat, fdon, fkat]: {totals}")
        print(f"Raw prediction probability totals [don, kat, fdon, fkat]: {totalsRaw}")
    else:
        print(f"Predicted colors totals [don, kat]: {totals}")
        print(f"Raw prediction probability totals [don, kat]: {totalsRaw}")

    # print(prediction)
    print("Got to end of prediction")

    with open('models/prediction.pickle', 'wb') as handle:
        pickle.dump(prediction, handle, protocol=pickle.HIGHEST_PROTOCOL)

    return prediction

# def processPrediction(prediction):  # prediction here is the tensor of frequency bands created in makePredictionFromAudio.
#     prediction = prediction[0] # assuming only one prediction, this reshapes data. If many predictions, implement for each element in input.
#     print("Prediction sample:")
#     print(prediction)
#     return "placeholder"


__author__ = 'bemsibom'

from math import *
from numpy import *
from scipy.misc import *
from input_validation import *
from pylab import *
import pylab

def midpoint(f: callable, a: (int, float), b: (int, float), n: int) -> float:
    """
    Integrates a function using the midpoint method
    :param f: The function to be integrated
    :param a: The lower bound of the integral
    :param b: The upper bound of the integral
    :param n: The number of iterations
    :return: The value of the integral
    """
    if dim_validate_argument(a) and dim_validate_argument(b):
        if dim_validate_number(a) and dim_validate_number(b):
            if dim_validate_positive(n):
                h = (b-a)/n
                x = linspace(a, b, n+1)
                mid = [0] * n
                y = [0] * n
                sum = 0
                for i in range(1, n+1):
                    mid[i-1] = (x[i] - x[i-1])/2 + x[i-1]
                    y[i-1] = f(mid[i-1])
                    sum += y[i-1]
                return sum * h
            else:
                raise ValueError("number of iterations can only be a positive integer: "+str(n))
        else:
            raise TypeError("Only numbers accepted for integral limits: "+str(a)+str(" ")+str(b)+str(" "))
    else:
        raise AttributeError("Argumentation incomplete. Please input all parameters")

if __name__ == "__main__":
    def f(x):
        return x**2-1
    sample_a = -2
    sample_b = 2
    sample_n = 10
    print("Integral of f(x) using midpoint method: ",
          midpoint(f, sample_a, sample_b, sample_n))

if __name__ == "__main__":
    def f(x):
        return x**2-1
    sample_a = -2
    sample_b = 2
    sample_n = 10000
    print("Integral of f(x) using midpoint method: ",
          midpoint(f, sample_a, sample_b, sample_n))

if __name__ == "__main__":
    def g(x):
        return 1/x
    sample_a = 0.1
    sample_b = 2
    sample_n = 100
    print("Integral of g(x) using midpoint method: ",
          midpoint(g, sample_a, sample_b, sample_n))

def trapezoidal(f: callable, a: (int, float), b: (int, float), n: int) -> float:
    """
    Calculates integral using trapezoidal rule
    :param f: function to be integrated
    :param a: start point
    :param b: end point
    :param n: number of divisions
    :return: approximate integral of f
    """
    if dim_validate_argument(a) and dim_validate_argument(b):
        if dim_validate_number(a) and dim_validate_number(b) and dim_validate_int_float(n):
            if dim_validate_positive(n):
                x = linspace(a, b, n+1)
                y = f(x)
                h = (b - a)/(2*n)
                sum1 = 0
                for i in range(1, n):
                    sum1 += + 2*y[i]
                integral = h * (f(a) + f(b) + sum1)
                return integral
            else:
                raise ValueError("number of iterations can only be a positive integer: "+str(n))
        else:
            raise TypeError("Only numbers accepted for integral limits, only positive integers for iterations:"+str(a) +
                            str(" ")+str(b)+str(" ")+str(" ")+str(n))
    else:
        raise AttributeError("Argumentation incomplete. Please input all parameters")

if __name__ == "__main__":
    def f(x):
        return x**2-1
    sample_a = -2
    sample_b = 2
    sample_n = 10
    print("Integral of f(x) using trapezoidal method:",
          trapezoidal(f, sample_a, sample_b, sample_n))

if __name__ == "__main__":
    def f(x):
        return x**2-1
    sample_a = -2
    sample_b = 2
    sample_n = 10000
    print("Integral of f(x) using trapezoidal method:",
          trapezoidal(f, sample_a, sample_b, sample_n))

if __name__ == "__main__":
    def g(x):
        return 1/x
    sample_a = 0.1
    sample_b = 2
    sample_n = 100
    print("Integral of g(x) using trapezoidal method: ",
          trapezoidal(g, sample_a, sample_b, sample_n))

# Simpson's method

def simpson(f: callable, a: (int, float), b: (int, float), n: int) -> float:
    """
    Approximates the integral to a function using Simpson's method
    :param f: function to be integrated
    :param a: lower integration bound
    :param b: upper integration bound
    :param n: number of divisions
    :return: Approximate value of integral
    """
    if dim_validate_argument(a) and dim_validate_argument(b):
        if dim_validate_number(a) and dim_validate_number(b) and dim_validate_int_float(n):
            if dim_validate_positive(n):
                x = linspace(a, b, n+1)
                y = f(x)
                h = (b - a)/n
                sum1 = 0
                sum2 = 0
                for i in range(1, n-1, 2):
                    sum1 += 4 * y[i]
                for i in range(2, n, 2):
                    sum2 += 2 * y[i]
                integral = h/3 * (f(a) + f(b) + sum1 + sum2)
                return integral
            else:
                raise ValueError("number of iterations can only be a positive integer: "+str(n))
        else:
            raise TypeError("Only numbers accepted for integral limits, only positive integers for iterations:"+str(a) +
                            str(" ")+str(b)+str(" ")+str(" ")+str(n))
    else:
        raise AttributeError("Argumentation incomplete. Please input all parameters")

if __name__ == "__main__":
    def f(x):
        return x**2-1
    sample_a = -2
    sample_b = 2
    sample_n = 10
    print("Integral of f(x) using simpson's method: ",
          simpson(f, sample_a, sample_b, sample_n))

if __name__ == "__main__":
    def f(x):
        return x**2-1
    sample_a = -2
    sample_b = 2
    sample_n = 10000
    print("Integral of f(x) using Simpson's method: ",
          simpson(f, sample_a, sample_b, sample_n))

if __name__ == "__main__":
    def g(x):
        return 1/x
    sample_a = 0.1
    sample_b = 2
    sample_n = 1000000
    print("Integral of g(x) using Simpson's method: ",
          simpson(g, sample_a, sample_b, sample_n))

def integral_calculator(f: callable, a: (int, float), b: (int, float), n: int, method: str) -> float:
    """
    Calculates integral of a function by one of three methods
    :param f: function to be integrated
    :param a: lower bound of integral
    :param b: upper bound of integral
    :param n: number of iterations
    :return: value of integral
    """
    integral = 0
    if method != "midpoint" and method != "simpson" and method != "trapezoidal":
        raise TypeError("Integral type must be either midpoint, simpson or trapezoidal")
    if method == "midpoint":
        integral = midpoint(f, a, b, n)
    if method == "simpson":
        integral = simpson(f, a, b, n)
    if method == "trapezoidal":
        integral = trapezoidal(f, a, b, n)

    return integral

if __name__ == "__main__":
    def f(x):
        return x**2+2
    sample_a = -2
    sample_b = 2
    sample_n = 10000
    sample_method = "simpson"
    print("Integral from the integral calculator using the", sample_method, "method: ",
          integral_calculator(f, sample_a, sample_b, sample_n, sample_method))

def plot_integral(f: callable, a: (int, float), b: (int, float), n: int):
    """
    Plots the integral of a function against the resolution
    :param f: function to be integrated
    :param a:lower bound of integral
    :param b: upper bound of integral
    :param n: number of iteration
    :return: plot of integral
    """
    x = range(1,n+1)
    I_midpoint = [1]*n
    I_simpson = [1]*n
    I_trapezoidal = [1]*n
    for i in range(1, n):
        I_midpoint[i] = integral_calculator(f, a, b, x[i], "midpoint")
        I_simpson[i] = integral_calculator(f, a, b, x[i], "simpson")
        I_trapezoidal[i] = integral_calculator(f, a, b, x[i], "trapezoidal")
    plot(x, I_midpoint, '-r', label='Midpoint method')
    plot(x, I_simpson, '-b', label='Simpson method')
    plot(x, I_trapezoidal, '-g', label='Trapezoidal method')
    legend(loc='lower left')
    title('Variation of integral values with number of iterations for different numerical methods')
    pylab.savefig('/home/bemsibom/PycharmProjects/Figures/integrals.png')
    show()

if __name__ == "__main__":
    def f(x):
        return sin(x)+cos(x)
    sample_a = -2
    sample_b = 2
    sample_n = 90
    sample_method = "midpoint"
    plot_integral(f, sample_a, sample_b, sample_n)


from aiohttp import test_utils
import json
import pytest
from . import AioHttpInterface
from .. import aiohttp
from ..commonhttp import errors
from ..tests import fake_server
from ... import di, Story

story = None

def teardown_function(function):
    story and story.clear()

@pytest.fixture
def webhook_handler():
    return test_utils.make_mocked_coro(return_value={
        'status': 200,
        'content_type': 'application/json',
        'text': json.dumps({'message': 'Ok!'}),
    })

@pytest.mark.asyncio
async def test_post(event_loop):
    async with fake_server.FakeFacebook(event_loop) as server:
        async with server.session() as session:
            http = AioHttpInterface()
            http.session = session

            assert await http.post(fake_server.URI.format('/v2.6/me/messages/'), json={'message': 'hello world!'})
            assert len(server.history) == 1
            req = server.history[-1]['request']
            assert req.content_type == 'application/json'
            assert await req.json() == {'message': 'hello world!'}

@pytest.mark.asyncio
async def test_listen_webhook(webhook_handler):
    http = AioHttpInterface(port=9876)
    http.webhook(uri='/webhook', handler=webhook_handler, token='qwerty')
    try:
        await http.start()
        res = await http.post_raw('http://localhost:9876/webhook', json={'message': 'Is there anybody in there?'})
        webhook_handler.assert_called_once_with({'message': 'Is there anybody in there?'})
        assert res['status'] == 200
        assert res['text'] == json.dumps({'message': 'Ok!'})
    finally:
        await http.stop()

@pytest.mark.asyncio
async def test_pass_validation_for_correct_request():
    http = AioHttpInterface(port=9876)
    http.webhook(uri='/webhook', handler=None, token='token-value')
    try:
        await http.start()
        res = await http.get_raw('http://localhost:9876/webhook', params={
            'hub.challenge': 'some-challenge',
            'hub.mode': 'subscribe',
            'hub.verify_token': 'token-value',
        })
        assert res['text'] == 'some-challenge'
    finally:
        await http.stop()

@pytest.mark.asyncio
async def test_reject_validation_for_incorrect_request():
    http = AioHttpInterface(port=9876)
    http.webhook(uri='/webhook', handler=None, token='token-value')
    try:
        await http.start()
        await http.get('http://localhost:9876/webhook', params={
            'something': 'incorrect',
        })
    except errors.HttpRequestError as err:
        assert err.code == 422
        assert err.message == 'Error, wrong validation token'
    finally:
        await http.stop()

@pytest.mark.asyncio
async def test_should_not_create_server_if_there_wasnt_any_webhooks():
    http = AioHttpInterface(port=9876)
    try:
        await http.start()
        assert not http.server
    finally:
        await http.stop()

@pytest.mark.skip(reason='too long')
@pytest.mark.asynciod
async def test_get_400_from_wrong_domain():
    http = AioHttpInterface()
    try:
        await http.get('http://wrong-url')
    except errors.HttpRequestError as err:
        assert err.code == 400

@pytest.mark.asyncio
async def test_get_400_from_wrong_path():
    http = AioHttpInterface()
    try:
        await http.get('http://localhost:9876/webhook')
    except errors.HttpRequestError as err:
        assert err.code == 400

@pytest.mark.asyncio
async def test_post_to_wrong_path_get_400(event_loop):
    async with fake_server.FakeFacebook(event_loop) as server:
        async with server.session() as session:
            http = AioHttpInterface()
            http.session = session

            try:
                await http.post(fake_server.URI.format('/v2.6/me/messages/mistake'), json={'message': 'hello world!'})
            except errors.HttpRequestError as err:
                assert err.code == 404

@pytest.mark.skip(reason='too long')
@pytest.mark.asyncio
async def test_post_400_from_wrong_domain():
    http = AioHttpInterface()
    try:
        await http.post('http://wrong-url')
    except errors.HttpRequestError as err:
        assert err.code == 400

@pytest.mark.asyncio
async def test_post_400_from_wrong_path():
    http = AioHttpInterface()
    try:
        await http.post('http://localhost:9876/webhook')
    except errors.HttpRequestError as err:
        assert err.code == 400

@pytest.mark.asyncio
async def test_delete_200(event_loop):
    async with fake_server.FakeFacebook(event_loop) as server:
        async with server.session() as session:
            http = AioHttpInterface()
            http.session = session

            await http.delete(fake_server.URI.format('/v2.6/me/messenger_profile'))

@pytest.mark.asyncio
async def test_delete_400(event_loop):
    async with fake_server.FakeFacebook(event_loop) as server:
        async with server.session() as session:
            http = AioHttpInterface()
            http.session = session

            try:
                await http.delete(fake_server.URI.format('/v2.6/me/wrong'))
            except errors.HttpRequestError as err:
                assert err.code == 404

@pytest.mark.asyncio
async def test_pass_middleware(mocker, webhook_handler):
    handler_stub = mocker.stub()

    def MockMiddleware():
        async def middleware_factory(app, handler):
            async def mock_middleware_handler(request):
                handler_stub(request)
                return await handler(request)

            return mock_middleware_handler

        return middleware_factory

    try:
        http = AioHttpInterface(middlewares=[MockMiddleware()], port=8080)
        http.webhook(uri='/webhook', handler=webhook_handler, token='qwerty')
        await http.start()
        await http.post('http://localhost:8080/webhook', json={})
        assert handler_stub.called
    finally:
        await http.stop()

def test_get_as_deps():
    global story
    story = Story()
    story.use(aiohttp.AioHttpInterface())

    with di.child_scope('http'):
        @di.desc()
        class OneClass:
            @di.inject()
            def deps(self, http):
                self.http = http

        assert isinstance(di.injector.get('one_class').http, aiohttp.AioHttpInterface)

@pytest.mark.asyncio
async def test_shop_should_remove_app():
    http = aiohttp.AioHttpInterface()
    assert not http.has_app()
    http.get_app()
    assert http.has_app()
    await http.stop()
    assert not http.has_app()

@pytest.mark.asyncio
async def test_should_raise_exception_on_webhook_if_aiohttp_already_is_started(webhook_handler):
    http = aiohttp.AioHttpInterface()
    http.get_app()
    await http.start()
    with pytest.raises(aiohttp.WebhookException):
        http.webhook(uri='/webhook', handler=webhook_handler, token='qwerty')


from typing import List, Tuple, Dict, Any
import torch
from typing import Any, Callable, List, Optional, Union, Tuple
from PIL import Image
from torch.utils.data import Dataset
import os
from tqdm import tqdm
import jieba
import torch
# this is the class for dog-breed-recognition
class jena_temp(Dataset):
    def __init__(self,datapath,mode="all") -> None:
        skip=True
        temp=[]
        self.mean=9.4559
        self.std=8.4214
        with open(datapath,'r') as f:
            for item in f:
                if skip:
                    skip=False
                    continue
                citem=item.strip('\n').split(',')
                temp.append(
                    (float(citem[2])-9.4559)/8.4214
                    )
        days=[]
        for id in range(len(temp)):
            if id%144==0:
                days.append([])
            days[-1].append(temp[id])
        days=days[:2919]
        weeks=[]
        for id in range(len(days)):
            if id % 7==0:
                weeks.append([])
            weeks[-1].append(days[id])
        if mode=="train":
            self.weeks=weeks[:263]
        elif mode=="dev":
            self.weeks=weeks[263:313]
        elif mode=="test":
            self.weeks=weeks[313:]
        else:
            self.weeks=weeks
        # weeks :  [weeks,7,144]

    def __getitem__(self, index: int) -> Tuple[Any, Any]:
        return self.weeks[index]

    def __len__(self) -> int:
        return len(self.weeks)

    def collate(self, batch):
        first_5=torch.tensor([
            item[:5]for item in batch
        ])
        next_2=torch.tensor([
            item[5:]for item in batch
        ])

        return first_5,next_2


from aws_cdk import (
    aws_lambda as _lambda,
    aws_apigatewayv2 as api_gw,
    aws_apigatewayv2_integrations as integrations,
    aws_ec2 as ec2,
    aws_efs as efs,
    aws_ecs as ecs,
    aws_ecs_patterns as ecs_patterns,
    aws_iam as iam,
    aws_logs as logs,
    core
)
from aws_cdk.aws_logs import LogGroup, RetentionDays
import os

MOUNT_POINT = "/mnt/data"
LOG_RETENTION = RetentionDays.ONE_MONTH

"""Infrastructure"""
class LambdaDockerStack(core.Stack):
    def __init__(self, scope: core.Construct, construct_id: str, name: str,**kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        """VPC - used in project"""
        vpc = ec2.Vpc(self, f'{name}-VPC', max_azs=2)

        """Filesystem - shared between Lambda and Streamlit - Deletes when stack gets shut down"""
        fs = efs.FileSystem(self, f'{name}-FileSystem',
                            vpc=vpc,
                            removal_policy=core.RemovalPolicy.DESTROY)

        access_point = fs.add_access_point('AccessPoint',
                    create_acl=efs.Acl(owner_gid='1001', owner_uid='1001', permissions='750'),
                    path="/export/lambda",
                    posix_user=efs.PosixUser(gid="1001", uid="1001"))

        """Model folder that contains Lambda code"""
        model_folder = os.path.dirname(os.path.realpath(__file__)) + "/../model"
        lambda_handler = _lambda.DockerImageFunction(self, f'{name}-Lambda',
                    code=_lambda.DockerImageCode.from_image_asset(model_folder), #Uses local code to build the container
                    memory_size=1024, #Adjust to your need - 128MB to 10GB
                    timeout=core.Duration.minutes(5), #Adjust to your need - up to 15 mins
                    vpc=vpc,
                    filesystem=_lambda.FileSystem.from_efs_access_point(access_point, MOUNT_POINT))

        """Custom Log groups for Lambda"""
        lambda_lgs = logs.LogGroup(
            self,
            f'{name}-Lambda-LogGroup',
            log_group_name=f"/aws/lambda/{lambda_handler.function_name}",
            retention=logs.RetentionDays.ONE_WEEK,
            removal_policy=core.RemovalPolicy.DESTROY
        )

        """API Gateway - integrates all methods and ressources - used for Lambda invocation"""
        api = api_gw.HttpApi(self,
                    f'{name}-ApiGw',
                    default_integration=integrations.LambdaProxyIntegration(handler=lambda_handler))

        """"""""""""""""""""""""""""""""""""""""""""""""""""""
        #STREAMLIT RELATED START
        """"""""""""""""""""""""""""""""""""""""""""""""""""""
        '''
        cluster = ecs.Cluster(self, f"{name}-Streamlit-Cluster", vpc=vpc)

        ecs_task = ecs.FargateTaskDefinition(
            self,
            f'{name}-Streamlit-Task-Def',
        )

        streamlit_container = ecs_task.add_container(
            f'{name}-Streamlit-Container',
            image=ecs.ContainerImage.from_asset('streamlit-docker'),
            essential=True,
            environment={
                'API_URL': api.url,
            },
            logging=ecs.LogDrivers.aws_logs(
                stream_prefix=f'{name}-Streamlit-Log'
            )
        )

        streamlit_container.add_port_mappings(
            ecs.PortMapping(
                container_port=8501,
                host_port=8501,
                protocol=ecs.Protocol.TCP
            )
        )

        """Efs Volume - shared between Lambda / Streamlit"""
        ecs_task.add_volume(name=f'{name}-Efs-Volume',
                efs_volume_configuration=ecs.EfsVolumeConfiguration(
                file_system_id=fs.file_system_id,
        ))

        """Efs Mountpoint"""
        streamlit_container.add_mount_points(
            ecs.MountPoint(
                container_path="/mnt/data",
                read_only=False,
                source_volume=f'{name}-Efs-Volume'
        ))

        ecs_task.add_to_task_role_policy(
            statement=iam.PolicyStatement(
                actions=["efs:*"],
                resources=['*'],
                effect=iam.Effect.ALLOW
            )
        )

        """Fargate Service that hosts the Streamlit Application"""
        ecs_service = ecs_patterns.ApplicationLoadBalancedFargateService(self, f'{name}-Fargate-Service',
            cluster=cluster,
            cpu=256,
            desired_count=1,
            task_definition = ecs_task,
            memory_limit_mib=512,
            public_load_balancer=True,
            platform_version=ecs.FargatePlatformVersion.VERSION1_4, #https://forums.aws.amazon.com/thread.jspa?messageID=960420

        )

        fs.connections.allow_default_port_from(
            ecs_service.service.connections)
        '''

        """"""""""""""""""""""""""""""""""""""""""""""""""""""
        #STREAMLIT RELATED END
        """"""""""""""""""""""""""""""""""""""""""""""""""""""

        core.CfnOutput(self, 'URL', value=api.url);


#  uv_project.py (c) 2016 Mattias Fredriksson
#
# ##### BEGIN GPL LICENSE BLOCK #####
#
#  This program is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# ##### END GPL LICENSE BLOCK #####

import bpy, time, sys

from math import *
from mathutils import *
from .funcs_math import *
from .funcs_blender import *
from bpy.props import * #Property objects

class ProjectMesh(bpy.types.Operator):
    """ Projects selected to active / for redo apply transform"""
    bl_idname = "mesh.project_onto_selected_mesh"
    bl_label = "Project Mesh(es) onto Active"
    bl_info = "Projects a selected mesh(es) onto the active mesh"
    bl_options = {'REGISTER', 'UNDO'}

    proj_type_enum = [
        ("AXISALIGNED", "Axis Aligned", "The projected mesh(es) will be rotated so it's axis with the smallest angel toward the camera will face the it", 1),
        ("CAMERA", "Camera View", "The mesh will be projected as is, where each vertice distance from the projection surface will be determined by the furthest point from the camera (plane)", 2),
        ("ZISUP", "Z is Up", "The projected mesh(es) will be rotated so the Z axis will face the camera", 3),
        ]

    displayExecutionTime = False

    proj_type = EnumProperty(items=proj_type_enum,
            name = "Projection Alignment",
            description="Determines how the mesh will be aligned related to camera view before projection onto the surface. ",)
    depthOffset = FloatProperty(name="Depth Offset",
            description="Move the projection closer/away from target surface by a fixed amount (along camera forward axis)",
            default=0, min=-sys.float_info.max, max=sys.float_info.max, step=1)
    bias = FloatProperty(name="Intersection Bias",
            description="Error marginal for intersection tests, can solve intersection problems",
            default=0.00001, min=0.00001, max=1, step=1)

    def invoke(self, context, event) :
        """
        Invoke stage, gathering information of the projection objects:
        """
        start_time = time.time()
        #Fetch camera orientations:
        self.cameraRot = findViewRotation(context)
        self.cameraRotInv = self.cameraRot.transposed()
        self.camAxis = findViewAxis(context)
        self.cameraPos = findViewPos(context)
        self.ortho = viewTypeOrtho(context)
        self.lastOffset = self.depthOffset

        target_ob = context.active_object
        #Verify target
        if not target_ob:
            self.report({'ERROR'}, "No active mesh object found to use as projection target.")
            return {'CANCELLED'}
        elif target_ob.type != 'MESH':
            self.report({'ERROR'}, "Active object was not a mesh. Select an appropriate mesh object as projection target")
            return {'CANCELLED'}
        ob_sources = context.selected_objects
        #Verify selection
        self.ob_list = []
        for ob in ob_sources :
            if ob.type == 'MESH' and ob != target_ob :
                self.ob_list.append(SourceMesh(ob))
        if len(self.ob_list) == 0 :
            if len(ob_sources) > 0 :
                self.report({'ERROR'}, "Only mesh objects can be projected, need atleast one project source and an active object as projection target")
            else :
                self.report({'ERROR'}, "No selection to project found, make sure to select one project source and an active object as projection target")
            return {'CANCELLED'}
        #Generate projection info
        self.generate_BVH(target_ob, context.scene)
        self.target_ob = target_ob.name

        if ProjectMesh.displayExecutionTime :
            self.report({'INFO'}, "Finished, invoke stage execution time: %.2f seconds ---" % (time.time() - start_time))
        return self.execute(context)

    def execute(self, context):
        """
        Project each mesh onto active object
        """
        start_time = time.time()

        offset_change =  self.depthOffset != self.lastOffset

        self.lastOffset = self.depthOffset
        if not offset_change:
            self.report({'INFO'}, "Executing: Mesh Projection")
            #Project the meshes with the gathered information
            self.project(context.scene)
            #Finished
            if ProjectMesh.displayExecutionTime :
                self.report({'INFO'}, "Finished, project stage execution time: %.2f seconds ---" % (time.time() - start_time))
        #Set offset move it on camera forward axis:
        self.depthChange(context.scene)
        return {'FINISHED'}

    def depthChange(self, scene) :
        """ Moves the objects along camera z axis
        """
        mat = Matrix.Translation(self.camAxis[2] * -self.depthOffset)
        for ob in self.ob_list :
            if ob.bmesh_gen is not None:
                setNamedMesh(ob.bmesh_gen, ob.name, scene, Matrix.Translation(self.camAxis[2] * -self.depthOffset))

    def generate_BVH(self, target_ob, scene) :
        #Can't create from object, transformation not applied
        bmesh = createBmesh(target_ob, target_ob.matrix_world, True, scene, True)
        self.bvh = bvhtree.BVHTree.FromBMesh(bmesh, epsilon = self.bias)
        bmesh.free()

    def project(self, scene) :
        """ Project the mesh(es) onto the target
        """
        for ob in self.ob_list :
            #Create a bm mesh copy of the mesh!
            bmesh = ob.bmesh.copy()
            (vMin, vMax) = findMinMax(bmesh)
            mat = self.orientation(ob)
            #createMesh(bmesh, scene, mat) #Generate a aligned debug mesh
            #Find the furthest point of the mesh along camera forward
            depthDist = max(self.camAxis[2].dot(mat * vMin), self.camAxis[2].dot(mat * vMax))
            proj_list = [(None,None) for x in range(len(bmesh.verts))]
            non_proj_list = []
            #Project the vertices:
            count = 0
            count_closest = 0
            for vert in bmesh.verts :
                count += self.projectVert(mat, vert, depthDist, proj_list, non_proj_list)
            for vert in non_proj_list :
                count_closest += self.projectClosestConnect(mat, vert, depthDist, proj_list)
            #Finalize the projection by assigning the bmesh into the blender object
            #Validate one vert was projected first:
            bmesh.select_flush(False)

            if count > 0 :
                ob.bmesh_gen = bmesh
                setNamedMesh(bmesh, ob.name, scene, Matrix.Translation(self.camAxis[2] * -self.depthOffset))
                if count_closest > 0:
                    self.report({'WARNING'}, "Mesh: %s has %d vertices that failed to project and used neighbouring vertex result instead. Verify selected verts is projected OK" %(ob.name, count_closest))
                nonProjCount = len(bmesh.verts) - (count + count_closest)
                if nonProjCount != 0:
                    self.report({'WARNING'}, "Mesh: %s has %d vertices that did not project succesfully. Validate that the mesh is covered by the target" %(ob.name, nonProjCount))
            else :
                self.report({'WARNING'}, "Mesh: %s had no vertices projected onto the target. Validate that the mesh is covered by the target" %(ob.name))
    #Done

    def projectVert(self, transMat, vert, depthDist, proj_list, non_proj) :
        """ Calculate the projection of a single vert (also sets the vert.co)
        transMat:   Object transformation matrix
        vert:       Vert being updated
        """
        co =  transMat * vert.co
        #Find the distance offset to the max point of the mesh along camera axis
        dir = self.getCameraAxis(co)
        #Ray cast:
        (loc, nor, ind, dist) = self.bvh.ray_cast(co, dir, 100000)
        #If intersection occured project it
        if loc is not None:
            offset = -(depthDist - self.camAxis[2].dot(co))
            vert.co = loc + dir * offset
            proj_list[vert.index] = (loc, nor) #Store projection point and normal
            vert.select_set(False)
            return True
        #else:
        non_proj.append(vert)
        vert.select_set(True)
        return False

    def projectClosestConnect(self, transMat, vert, depthDist, proj_list) :
        co =  transMat * vert.co
        for edge in vert.link_edges :
            o_vert_ind = edge.other_vert(vert).index
            if proj_list[o_vert_ind][0] is not None :
                dir = self.getCameraAxis(co)
                rel = proj_list[o_vert_ind][1].dot(dir) #Relation between ray dir and plane normal.
                if abs(rel) <  self.bias:
                    continue
                #Plane d value:
                d = -proj_list[o_vert_ind][1].dot(proj_list[o_vert_ind][0])
                #Calculate distance
                dist = (-d - proj_list[o_vert_ind][1].dot(co)) / rel

                offset = -(depthDist - self.camAxis[2].dot(co))
                #project
                vert.co = co + dir * (dist + offset)
                return True
        return False

    def orientation(self, ob) :
        loc, meshRot, sca = ob.matrix_world.decompose()
        meshRot = meshRot.to_matrix()

        #Calc rotation
        if self.proj_type == 'AXISALIGNED' :
            rot = self.cameraRot * alignRotationMatrix(self.cameraRotInv * meshRot)
        elif self.proj_type == 'ZISUP' :
            rot = self.cameraRot * calculateXYPlaneRot(meshRot.transposed(), self.camAxis)
        else : #self.proj_type == 'CAMERA' :
            rot = meshRot
        #Assemble orientation matrix:
        mat = Matrix.Translation(loc) * (rot * scaleMatrix(sca, 3)).to_4x4()
        #mat[3].xyz = loc
        return mat

    def getCameraAxis(self, target) :
        """ Calculates the projection ray direction
        """
        if self.ortho :
            return self.camAxis[2]
        else :
            dir = target - self.cameraPos
            dir.normalize()
            return dir

class SourceMesh :
    def __init__(self, object):
        self.name = object.name
        self.matrix_world = object.matrix_world.copy()
        self.bmesh = createBmesh(object)
        self.bmesh_gen = None

    def __del__(self) :
        if self.bmesh_gen is not None :
            self.bmesh_gen.free()
        self.bmesh.free()
def calculateXYPlaneRot(meshAxis, camAxis) :
    """ Finds the rotation of the mesh on the camera X,Y plane
    """
    xAxis = meshAxis[0] - meshAxis[0].dot(camAxis[2]) * camAxis[2]
    xAxis.normalize()
    x = xAxis.dot(camAxis[0])
    y = xAxis.dot(camAxis[1])

    angle = atan2(y,x)
    return Matrix.Rotation(angle, 3, Vector((0,0,1))) #Use camAxis[2] if the rotation is applied in world space opposed to camera space

def alignRotationMatrix(rotMat) :
    """
    Aligns the axis with largest Z component to (0,0,1) and orthonormalizes the other two axes.
    """
    #Find axis with largest Z component and orthonormalize the other basis vectors to it:
    if abs(rotMat[2][2]) > max(abs(rotMat[1][2]), abs(rotMat[0][2])) :
        #Z axis is depth:
        rotMat[2] = Vector((0,0,sign(rotMat[2][2])))
        rotMat[2], rotMat[0], rotMat[1] = orthoNormalizeVec3(rotMat[2], rotMat[0], rotMat[1])
    elif abs(rotMat[1][2]) > abs(rotMat[0][2]) :
        #Y axis is depth:
        rotMat[1] = Vector((0,0,sign(rotMat[1][2])))
        rotMat[1], rotMat[0], rotMat[2] = orthoNormalizeVec3(rotMat[1], rotMat[0], rotMat[2])
    else :
        #X axis is depth:
        rotMat[0] = Vector((0,0,sign(rotMat[0][2])))
        rotMat[0], rotMat[1], rotMat[2] = orthoNormalizeVec3(rotMat[0], rotMat[1], rotMat[2])
    return rotMat


"""pro1 URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.conf.urls import url, include
    2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from dal import autocomplete
from django.contrib import admin
from django.views.generic import TemplateView
from gst import views
from django.urls import reverse

#from gst.views import GST_idAutocomplete

urlpatterns = [
    url(r'^$',views.home),
    # url(
    #     r'^gst-autocomplete/$',
    #     GST_idAutocomplete.as_view(),
    #     name='gst-autocomplete',
    # ),

    url(r'^about/$',views.about),

    url(r'^business/$',views.business),
    url(r'^business/create/$',views.create_business),
    url(r'^business/update/$',views.update_business),
    url(r'^business/update/confirm/(?P<id>[0-9]+)$',views.update_confirm),
    url(r'^business/delete/$',views.delete_business),
    url(r'^business/delete/confirm/(?P<id>[0-9]+)$',views.delete_confirm_bus),
    url(r'^business/display/$',views.display),

    url(r'^product/$',views.product),
    url(r'^product/create/$',views.create_product),
    url(r'^product/update/$',views.update_product),
    url(r'^product/update/confirm/(?P<id>[0-9]+)$',views.product_update_confirm),
    url(r'^product/delete/$',views.delete_product),
    url(r'^product/delete/confirm/(?P<id>[0-9]+)$',views.delete_confirm),
    url(r'^product/display/$',views.productdisplay),

    url(r'^b2b/$',views.b2b),
    url(r'^b2b/add_txn/$',views.add_b2b_txn),
    url(r'^b2b/display_txn/$',views.display_b2b),
    url(r'^b2b/update_txn/$',views.update_b2b),
    url(r'^b2b/update/confirm/(?P<id>[0-9]+)$',views.b2b_update_confirm),
    url(r'^b2b/delete_txn/$',views.delete_b2b),
    url(r'^b2b/delete/confirm/(?P<id>[0-9]+)$',views.b2b_delete_confirm),

    url(r'^b2c/$',views.b2c),
    url(r'^b2c/add_txn/$',views.add_b2c_txn),
    url(r'^b2c/display_txn/$',views.display_b2c),
    url(r'^b2c/update_txn/$',views.update_b2c),
    url(r'^b2c/update/confirm/(?P<id>[0-9]+)$',views.b2c_update_confirm),
    url(r'^b2c/delete_txn/$',views.delete_b2c),
    url(r'^b2c/delete/confirm/(?P<id>[0-9]+)$',views.b2c_delete_confirm),

    url(r'^view_by_bussiness/$',views.view_by_bussiness),
    url(r'^view_by_bussiness/(?P<id>[0-9]+)$',views.view_con),

    url(r'^admin/', admin.site.urls),

]


def str_to_int(x):
    try:
        return int(x)
    except ValueError:
        return 0

s = '>' + '1' * 10 + '2' * 20 + '3' * 30
b = list(s)
while '>1' in s or '>2' in s or '>3' in s:
    if '>1' in s:
        s = s.replace('>1', '22>', 1)
    if '>2' in s:
        s = s.replace('>2', '2>', 1)
    if '>3' in s:
        s = s.replace('>3', '1>', 1)
# print(s)
s = list(s)

print(s.remove(s[-1]), s)
print(sum(list(map(int, s))))
print(sum(map(str_to_int, b)))


import os
import io
import json
import requests
import aiohttp
import discord
from typing import Union

class Database():
    def __init__(self) -> None:
        self.url = os.getenv('GAS_PROJECT_URL')+'?'

    #DBへのPOST処理
    async def post_db(self, name:str, data:dict, **kwargs) -> requests.Response:
        base = {'name':name}
        payload = base|kwargs
        res = requests.post(url=self.url, params=payload, data=json.dumps(data))
        return res

    #DBへのGET処理
    async def get_db(self, name:str, **kwargs) -> Union[dict,list]:
        base = {'name':name}
        async with aiohttp.ClientSession() as session:
            async with session.get(url=self.url, params=base|kwargs) as resp:
                resj = await resp.json()
                return resj

class DiscordDatabase():
    def __init__(self) -> None:
        pass

    #DiscordDatabaseサーバーへの画像POST処理(一括)
    async def post_image(self, channel:discord.TextChannel, image:discord.Attachment, filename:str, content:str=None) -> str:
        imgby = await image.read() #bytes型で添付ファイルを取得
        imgbyio = io.BytesIO(imgby) #BytesIO型に変換
        file = discord.File(fp=imgbyio, filename=filename) #discord.Fileで添付ファイルを新規作成
        msg = await channel.send(content=content,file=file) #添付ファイル送信
        url = msg.attachments[0].url
        return url

    #DiscordDatabaseサーバーへの画像POST処理(受取のみ)
    async def post_iimage(self, channel:discord.TextChannel, image:io.BytesIO, filename:str, content:str=None) -> str:
        file = discord.File(fp=image, filename=filename) #discord.Fileで添付ファイルを新規作成
        msg = await channel.send(content=content,file=file) #添付ファイル送信
        url = msg.attachments[0].url
        return url


import pygame as pg
from .. import tools, prepare
from ..components.tournament import Tournament
from ..components.tournaments import TOURNAMENTS
from ..components.labels import GroupLabel as GLabel, Blinker

class Intro(tools._State):
    def __init__(self):
        super(Intro, self).__init__()
        screen = pg.display.get_surface().get_rect()
        font = prepare.FONTS["weblysleekuil"]
        snow_font = prepare.FONTS["SnowtopCaps"]
        self.labels = []
        title = GLabel(self.labels, snow_font, 96, "One Room Shack", "lightblue",
                                   {"midtop": (screen.centerx, screen.top + 20)})
        top = title.rect.bottom + 30
        left = 560
        lines = ["The cooler's well-stocked and there's wood in the stove so",
                    "grab a beer and pull up a bucket - it's ice fishing season!",
                    "YOU'll be competing in ice-fishing derbies to win as",
                    "much cash as you can before the season ends."]
        for line in lines:
            label = GLabel(self.labels, font, 32, line, "dodgerblue",
                                         {"topleft": (left, top)})
            top = label.rect.bottom + 3
        top += 20
        fishing = GLabel(self.labels, font, 48, "Catching Fish", "dodgerblue",
                                       {"midtop": (screen.centerx, top)})
        top = fishing.rect.bottom + 10
        fish_lines = ["Keep the end of your fishing line close to a fish's mouth until",
                           "the fish takes the bait. Drinking beer that a fish likes will make",
                           "them more likely to bite, but also makes controlling your fishing",
                           "rod more difficult."]
        for fish_line in fish_lines:
            fline = GLabel(self.labels, font, 32, fish_line, "dodgerblue",
                                        {"topleft": (left, top)})
            top = fline.rect.bottom + 3
        top += 20
        fc_title = GLabel(self.labels, font, 48, "Fishing Controls", "dodgerblue",
                                        {"midtop": (screen.centerx, top)})
        top = fc_title.rect.bottom + 10
        controls = [("UP / DOWN", "Let out / take in fishing line"),
                         ("LEFT / RIGHT", "Retract / extend fishing rod"),
                         ("SPACE", "Switch between drinking and fishing"),
                         ("ENTER", "Open Menu"),
                         ("ESCAPE", "Quit")]
        left1 = 860
        left2 = 960
        for control_pair in controls:
            key = GLabel(self.labels, font, 32, control_pair[0], "dodgerblue",
                                       {"topright": (left1, top)})
            use = GLabel(self.labels, font, 32, control_pair[1], "dodgerblue",
                                       {"topleft": (left2, top)})
            top = use.rect.bottom + 10

        self.blinker = Blinker(snow_font, 32, "Press Enter to continue", "dodgerblue",
                                       {"midbottom": (screen.centerx, screen.bottom - 20)}, 650)

    def startup(self, persistent):
        self.persist = persistent

    def get_event(self, event):
        if event.type == pg.KEYDOWN:
            if event.key == pg.K_RETURN:
                self.done = True
                self.persist["tournament"] = Tournament(pg.Rect(0, 0, 10, 10), **TOURNAMENTS[0])
                self.next = "TOURNAMENT_INFO"

    def update(self, surface, keys, dt):
        self.draw(surface, dt)

    def draw(self, surface, dt):
        surface.fill(pg.Color("gray90"))
        for label in self.labels:
            label.draw(surface)
        self.blinker.draw(surface, dt)


#!/usr/bin/env python

# Setup.py egregiously copied from another project I maintain
import sys
import distutils.core

from pip.download import PipSession
from pip.req import parse_requirements

__version__ = "0.1"

try:
    import setuptools
except ImportError:
    pass

def requires(path):
    return [str(r.req) for r in parse_requirements(path, session=PipSession())
            if r]

distutils.core.setup(
    name="babymailgun",
    version=__version__,
    packages=["babymailgun"],
    package_data={
        "babymailgun": [],
        },
    author="Matt Dietz",
    author_email="matthew.dietz@gmail.com",
    url="https://github.com/cerberus98/babymailgun",
    download_url="https://github.com/cerberus98/babymailgun",
    license="https://github.com/cerberus98/babymailgun/blob/master/LICENSE",
    description="",
    install_requires=requires("requirements.txt"),
    entry_points={
        "console_scripts": [
            "mailgun_cli = babymailgun.shell:main",
        ]}
    )


import time
import threading
import pyinterface

class m4_controller(object):
    speed = 3000
    low_speed = 100
    acc = 500
    dec = 500

    error = []

    position = ''
    count = 0

    shutdown_flag = False

    def __init__(self, ndev=1):
        self.mtr = pyinterface.create_gpg7204(ndev)
        self.mtr.ctrl.set_limit_config('MTR_LOGIC',0x000c)
        self.mtr.ctrl.off_inter_lock()
        self.get_pos()
        pass

    def print_msg(self, msg):
        print(msg)
        return

    def print_error(self, msg):
        self.error.append(msg)
        self.print_msg('!!!! ERROR !!!! ' + msg)
        return

    def get_count(self):
        self.count = self.mtr.get_position()
        return self.count

    def get_pos(self):
        status = self.mtr.ctrl.get_status('MTR_LIMIT_STATUS')
        """
        if status == 0x0008:
            #SMART
            self.position = 'OUT'
        elif status == 0x0004:
            #NAGOYA
            self.position = 'IN'
        elif status == 0x000c:
            self.position = 'MOVE'
        else:
            self.print_error('limit error')
        """
        if status == 0x0004:
            #SMART
            self.position = 'OUT'
        elif status == 0x0008:
            #NAGOYA
            self.position = 'IN'
        elif status == 0x0000:
            self.position = 'MOVE'
        else:
            self.print_error('limit error')
            return

        return self.position

    def move(self, dist):
        pos = self.get_pos()
        if dist == pos:
            if dist == 'OUT':
                self.print_msg('m4 is already out')
                return
            elif dist == 'IN':
                self.print_msg('m4 is already in')
                return
            else:
                self.print_msg('m4 is already move')
                return
        #elif pos == 'MOVE':
                #self.print_msg('m4 is already move')
                #return

        else:
            if dist == 'OUT':
                nstep = 60500
                self.print_msg('m4 move out')
            elif dist == 'IN':
                nstep = -60500
                self.print_msg('m4 move in')
            else:
                self.print_error('parameter error')
                return
            self.mtr.move(self.speed, nstep, self.low_speed, self.acc,self.dec)
            time.sleep(12.)
            count = self.get_count()
            pos= self.get_pos()
            return

    def m4_out(self):
        self.move('OUT')
        return

    def m4_in(self):
        self.move('IN')
        return

    def stop(self):
        self.mtr.stop()
        return

    def read_pos(self):
        return self.position

    def read_count(self):
        return self.count

def m4_client(host,port):
    client = pyinterface.server_client_wrapper.control_client_wrapper(m4_controller, host, port)
    return client

def m4_monitor_client(host,port):
    client = pyinterface.server_client_wrapper.monitor_client_wrapper(m4_controller, host, port)
    return client

def start_m4_server(port1=6003, port2=6004):
    m4 = m4_controller()
    server = pyinterface.server_client_wrapper.server_wrapper(m4,'', port1, port2)
    server.start()
    return server


# DSC 510
# Week 12
# This program connects with a webservice in order to pull weather data.
# Author
# 03/05/2021

# Importing requests module to send HTTP requests and receive Response Object
# Importing json module to convert json string from Response Object into python dictionary.
import requests
import json

# Made http request using get method from requests library using url and parameters with city name as query and api key.
def city_choice(city_param):

    response = None
    base_url = "http://api.openweathermap.org/data/2.5/weather"
    app_id = "e6d50fdcac9b2157817252047c61978c"
    try:
        response = requests.get(base_url, params={"q": city_param, "units": "imperial", "appid": app_id})
    except ConnectionError:
        print("Connection Error. Please try again.")
    data = json.loads(response.text)
    return data

def zip_choice(zip_param):

    response = None
    endpoint = "http://api.openweathermap.org/data/2.5/weather"
    app_id = "e6d50fdcac9b2157817252047c61978c"
    try:
        response = requests.get(endpoint, params={"zip": zip_param, "appid": app_id})
    except ConnectionError:
        print("Connection Unsuccessful.Please try again.")
    data = json.loads(response.text)
    return data

def city_unit(city_param, city_temp):
    base_url = "http://api.openweathermap.org/data/2.5/weather"
    app_id = "e6d50fdcac9b2157817252047c61978c"
    try:
        if city_temp == 'f':
            response = requests.get(base_url, params={"q": city_param, "units": "imperial", "appid": app_id})
            data = json.loads(response.text)
            print_temp(data)
        elif city_temp == 'c':
            response = requests.get(base_url, params={"q": city_param, "units": "metric", "appid": app_id})
            data = json.loads(response.text)
            print_temp(data)
        elif city_temp == 'k':
            response = requests.get(base_url, params={"q": city_param, "appid": app_id})
            data = json.loads(response.text)
            print_temp(data)
        else:
            print("Invalid input. Please try again.")
    except ConnectionError:
        print("Unable to process your request. Please try again.")

def zip_unit(zip_param, unit2):
    base_url = "http://api.openweathermap.org/data/2.5/weather"
    app_id = "e6d50fdcac9b2157817252047c61978c"
    try:
        if unit2 == 'f':
            response = requests.get(base_url, params={"q": zip_param, "units": "imperial", "appid": app_id})
            data = json.loads(response.text)
            print_temp(data)
        elif unit2 == 'c':
            response = requests.get(base_url, params={"q": zip_param, "units": "metric", "appid": app_id})
            data = json.loads(response.text)
            print_temp(data)
        elif unit2 == 'k':
            response = requests.get(base_url, params={"q": zip_param, "appid": app_id})
            data = json.loads(response.text)
            print_temp(data)
        else:
            print("Invalid input. Please try again.")
    except ConnectionError:
        print("Unable to process your request. Please try again.")

def print_temp(temp):

    print('Current Weather Conditions For {}.'.format(temp['name']))
    print('Current Temp: {:.2f} degrees'.format(temp['main']['temp']))
    print('High Temp: {:.2f} degrees'.format(temp['main']['temp_max']))
    print('Low Temp: {:.2f} degrees'.format(temp['main']['temp_min']))
    print('Pressure: {:.2f} hPa'.format(temp['main']['pressure']))
    print('Humidity: {}%'.format(temp['main']['humidity']))
    print('Weather Condition: {}'.format((temp['weather'][0]['description']).title()))
    print("Longitude: {}".format(temp['coord']['lon']))
    print("Latitude: {}".format(temp['coord']['lat']))

def search_city():
    while True:
        city_name = input("Please enter the name of the city:")
        city_response = city_choice(city_name)
        if city_response['cod'] != 200:
            print("{} is not a valid zip code. Please try again".format(city_name))
            continue
        else:
            print("\nConnection Successful.")
            print("How would you like to view the temperature?")
            while True:
                city_temp = input("Please enter 'f' for Fahrenheit, 'c' for Celsius, 'k' for Kelvin:").lower()
                if city_temp == 'f' or city_temp == 'c' or city_temp == 'k':
                    city_unit(city_name, city_temp)
                    user_wish()
                else:
                    print("Unable to accept {}. Please try again".format(city_temp))
                    continue

# Asks user for zip code and temperature metrics to provide details on the weather zip code.
def search_zip():
    while True:
        zip_code = input("Please enter the zip code:")
        zip_response = zip_choice(zip_code)
        if zip_response['cod'] != 200:
            print("{} is not a valid zip code. Please try again.".format(zip_code))
            continue
        else:
            print("\nConnection Successful.")
            print("How would you like to view the temperature in?")
            while True:
                zip_temp = input("Please enter 'f' for Fahrenheit, 'c' for Celsius, 'k' for Kelvin:").lower()
                if zip_temp == 'f' or zip_temp == 'c' or zip_temp == 'k':
                    zip_unit(zip_code, zip_temp)
                    user_wish()
                else:
                    print("Unable to accept {}. Please try again".format(zip_temp))
                    continue

# Loop to ask if they want to perform additional weather search or quit.
def user_wish():
    while True:
        char = input("Would you like to continue the weather search? (y/n):").lower()
        if char == 'y':
            main()
        elif char == 'n':
            print("You have exited the program. See you soon!")
            quit()
        else:
            print('Sorry, we only have two options available. Please Press y to continue the weather search or n to exit.')
            continue

# main function to start the program via use of above functions to provides user with readable weather information.
def main():
    print("Welcome to search engine for weather.\n")
    while True:
        user = input("Would you like to lookup weather data by US City or zip code? Enter 1 for US City 2 for zip:").lower()
        if user == '1':
            search_city()
        elif user == '2':
            search_zip()
        elif user == 'q':
            print("You have chosen to exit the program. See you again!")
            break
        else:
            print("\nSorry, {} isn't acceptable. Please enter a valid input.".format(user))
            continue

if __name__ == "__main__":
    main()

# Change#:1
# Change(s) Made:1) Changed from nested while loop to functions to loop incorrect user input for all questions asked.
# 2) Changed city_response['cod'] != '200' to city_response['cod'] != 200. Figured the value was an integer instead of
# string of integer
# Date of Change: 03/04/2021
# Author:
# Change Approved by:
# Date Moved to Production: 03/06/2021


import os
from glob import glob

import matplotlib.pyplot as plt

from satlomasproc.unet.train import build_data_generator

def plot_data_generator(num_samples=3, fig_size=(20, 10), *, train_config):
    images_dir = os.path.join(train_config.images_path, 'images')
    mask_dir = os.path.join(train_config.images_path, 'masks')

    images = glob(os.path.join(images_dir, '*.tif'))

    data_generator = build_data_generator(images,
                                          config=train_config,
                                          mask_dir=mask_dir)

    def plot_samples(plt, generator, num):
        j = 0
        for image_batch, mask_batch in data_generator:
            for image, mask in zip(image_batch, mask_batch):
                _, ax = plt.subplots(nrows=1,
                                     ncols=train_config.n_classes + 1,
                                     figsize=fig_size)
                ax[0].imshow(image[:,:,:train_config.n_channels])
                for i in range(train_config.n_classes):
                    ax[i + 1].imshow(mask[:, :, i])
                j += 1
                if j >= num:
                    return

    plot_samples(plt, data_generator, num_samples)
    plt.show()