import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt

confm = pd.read_csv('../data/Conflict Data/Conflict Data for Mali.csv')
confb = pd.read_csv('../data/Conflict Data/Conflict Data for Burkina Faso.csv')
confn = pd.read_csv('../data/Conflict Data/Conflict Data for Niger.csv')

# Select columns I'm interested in
confm.rename(columns={'country':'adm0_name',
                    'admin1':'adm1_name',
                    'admin2':'adm2_name',
                    'admin3':'adm3_name',
                    'event_date':'date',
                    'year':'reference_year'}, inplace=True)
confb.rename(columns={'country':'adm0_name',
                    'admin1':'adm1_name',
                    'admin2':'adm2_name',
                    'admin3':'adm3_name',
                    'event_date':'date',
                    'year':'reference_year'}, inplace=True)
confn.rename(columns={'country':'adm0_name',
                    'admin1':'adm1_name',
                    'admin2':'adm2_name',
                    'admin3':'adm3_name',
                    'event_date':'date',
                    'year':'reference_year'}, inplace=True)
confm = confm[['reference_year','date','adm0_name','adm1_name','adm2_name','adm3_name',
        'event_type','sub_event_type','fatalities']]
confb = confb[['reference_year','date','adm0_name','adm1_name','adm2_name','adm3_name',
        'event_type','sub_event_type','fatalities']]
confn = confn[['reference_year','date','adm0_name','adm1_name','adm2_name','adm3_name',
        'event_type','sub_event_type','fatalities']]

# Extract reference_year
confm = confm[confm.reference_year.isin([2014,2015,2016,2017,2018,2019])]
confb = confb[confb.reference_year.isin([2014,2015,2016,2017,2018,2019])]
confn = confn[confn.reference_year.isin([2014,2015,2016,2017,2018,2019])]

# Select adm1_name to work with
confm = confm[confm.adm1_name.isin(['Gao','Mopti','Tombouctou','Nord','Sahel','Est','Tahoua','Tillaberi'])]
confm = confm.reset_index(drop=True)
confb = confb[confb.adm1_name.isin(['Gao','Mopti','Tombouctou','Nord','Sahel','Est','Tahoua','Tillaberi'])]
confb = confb.reset_index(drop=True)
confn = confn[confn.adm1_name.isin(['Gao','Mopti','Tombouctou','Nord','Sahel','Est','Tahoua','Tillaberi'])]
confn = confn.reset_index(drop=True)

# Manipulate data to create consistency with the other data
# adm3=='Ayorou' => adm2:'Ayerou'
# adm3=='Torodi' => adm2:'Torodi'
# adm3=='Abala' => adm2:'Abala'
for i in confn.index:
    if confn.loc[i,'adm3_name']=='Ayorou':
        confn.at[i,'adm2_name']='Ayerou'
    if confn.loc[i,'adm3_name']=='Torodi':
        confn.at[i,'adm2_name']='Torodi'
    if confn.loc[i,'adm3_name']=='Abala':
        confn.at[i,'adm2_name']='Abala'

confm = confm[confm.adm2_name.isin(['Bankass','Koro','Douentza','Djenne','Bandiagara','Tenenkou','Mopti','Youwarou', 'Gourma-Rharous','Dire','Niafunke', 'Gao','Ansongo','Menaka','Bourem'])]
confb = confb[confb.adm2_name.isin(['Yatenga','Loroum', 'Yagha','Seno','Soum','Oudalan', 'Komonjdjari'])]
confn = confn[confn.adm2_name.isin(['Tillia', 'Banibangou','Filingue','Ouallam','Say','Tera','Torodi','Abala','Ayerou'])]#removed: Tassara, Gotheye, Bankilare, Balleyara Because are not in the database, Tillaberi,Tahoua because in lean these data are mess
confm = confm.reset_index(drop=True)
confb = confb.reset_index(drop=True)
confn = confn.reset_index(drop=True)

# Total conflicts
conf = confm.append(confb.append(confn)).reset_index()

conf['fatalities'] = conf['fatalities'].astype(str).astype(int)

# Plot number of conflicts per year per adm2_name
ncy = pd.DataFrame(columns=['reference_year','adm2_name','conflicts','fatalities'])
for year in conf['reference_year'].unique():
    for adm2_name in conf['adm2_name'].unique():
        ncy = ncy.append(pd.Series([year, adm2_name, 0, 0],index=ncy.columns),ignore_index=True)

ncy = ncy.sort_values(by=['reference_year','adm2_name'])
ncy = ncy.reset_index(drop=True)

# Counts the number of conflicts for each adm2_name in Mali for each year
c = pd.DataFrame({'conflicts' : conf.groupby(['reference_year','adm2_name']).size()}).reset_index()
c = c.sort_values(by=['reference_year','adm2_name'])
c = c.reset_index(drop=True)
# Counts the number of kills for each adm2_name in Mali for each year
f = pd.DataFrame({'fatalities' : conf.groupby(['reference_year','adm2_name'])['fatalities'].sum()}).reset_index()
f = f.sort_values(by=['reference_year','adm2_name'])
f = f.reset_index(drop=True)

for index, row in c.iterrows():
    ncy.loc[(ncy.reference_year == row.reference_year) & (ncy.adm2_name == row.adm2_name), 'conflicts'] = row['conflicts']

for index, row in f.iterrows():
    ncy.loc[(ncy.reference_year == row.reference_year) & (ncy.adm2_name == row.adm2_name), 'fatalities'] = row['fatalities']

# Plot number of conflicts and fatalities in Gao per reference_year
plt.style.use('fivethirtyeight')
g = ncy[ncy.adm2_name.isin(['Youwarou'])].plot(x='reference_year',y=['conflicts','fatalities'],figsize=(10,7))
g.xaxis.label.set_visible(False)
plt.show()

# Export data
ncy.to_csv('../data/Conflict Data/conflict_numb.csv',index=False)


from collections import namedtuple
from math import isclose

from gradescope_mean.get_mean_drop_low import *

TestCase = namedtuple('TestCase', ['perc', 'weight', 'drop_n', 'mean_exp'])

def test_get_mean_drop_low():
    test_case_list = [
        TestCase(perc=[1, .9, .8],
                 weight=[1, 1, 1],
                 drop_n=0,
                 mean_exp=.9),
        TestCase(perc=[1, .9, .8],
                 weight=[1, 0, 0],
                 drop_n=0,
                 mean_exp=1),
        TestCase(perc=[1, .9, .8],
                 weight=[1, 1, 1],
                 drop_n=1,
                 mean_exp=.95),
        TestCase(perc=[1, .8, np.nan],
                 weight=[1, 1, 1],
                 drop_n=0,
                 mean_exp=.9),
        TestCase(perc=[1, .8, np.nan],
                 weight=[1, 1, 1],
                 drop_n=1,
                 mean_exp=1),
        TestCase(perc=[1, .8, .8],
                 weight=[1, 1, 10],
                 drop_n=1,
                 mean_exp=.9)]

    for idx, test_case in enumerate(test_case_list):
        mean = get_mean_drop_low(perc=test_case.perc,
                                 weight=test_case.weight,
                                 drop_n=test_case.drop_n)
        assert isclose(mean, test_case.mean_exp), f'fail case: {idx}'


from typing import Dict

import torch
import torch.nn as nn
from torch import Tensor

from .pure_layers import (
    PureModule,
    PureSequential,
    PureLinear,
    PureConv2d,
    PureProxy,
)

class LeNet(nn.Sequential):
    """
    Very similar to LeNet, but:
        - we use ReLU instead of Tanh
        - we add AdaptiveAvgPool2d since our image sizes are different from 28x28
    """
    def __init__(self, config: Dict):
        layers = [
            # Body
            nn.Conv2d(1, 6, 5),
            nn.ReLU(),
            nn.AvgPool2d(2),
            nn.Conv2d(6, 16, 5),
            nn.ReLU(),
            nn.AvgPool2d(2),
            nn.Conv2d(16, 120, 5),
            nn.ReLU(),

            # Neck
            nn.AdaptiveAvgPool2d((1, 1)),
            nn.Flatten(),

            # Head
            nn.Linear(120, 84),
            nn.ReLU(),
            nn.Linear(84, config['training']['num_classes_per_task']),
        ]

        super().__init__(*layers)

class PureLeNet(PureModule):
    """
    LeNet architecture above, but rewritten as a pure module
    """
    def __init__(self, config: Dict):
        super().__init__()

        self.config = config
        self.model = PureSequential(
            # Body
            PureConv2d(1, 6, 5),
            PureProxy(nn.ReLU()),
            PureProxy(nn.AvgPool2d(2)),
            PureConv2d(6, 16, 5),
            PureProxy(nn.ReLU()),
            PureProxy(nn.AvgPool2d(2)),
            PureConv2d(16, 120, 5),
            PureProxy(nn.ReLU()),

            # Neck
            PureProxy(nn.AdaptiveAvgPool2d((1, 1))),
            PureProxy(nn.Flatten()),

            # Head
            PureLinear(120, 84),
            PureProxy(nn.ReLU()),
            PureLinear(84, config['training']['num_classes_per_task']),
        )

        self.size = self.model.size
        self.params = None

    def get_initial_params(self):
        return self.model.get_initial_params()

    def bind_params(self, params: Tensor):
        self.params = params

    def unbind_params(self):
        self.params = None

    def forward(self, x: Tensor, params: Tensor=None):
        params = params if not params is None else self.params

        return self.model(x, params)


#!/usr/bin/python

import sys
import time
import json
from contextlib import contextmanager

import bottle
from zmq import green as zmq
import gevent
from gevent import queue

from webapp import app, stats, settings

ctx = zmq.Context()
shows = {}
max_lifetime = 60 * 60 * 3

def delete_show(id):
    global shows

    this = shows[id]

    this['s'].send_json({
        'msg': 'close',
        })
    this['s'].close()

    del shows[id]

@contextmanager
def subcontext(id):
    global ctx

    s = ctx.socket(zmq.SUB)
    s.setsockopt(zmq.SUBSCRIBE, '')
    s.connect('inproc://%s' % id)

    yield s

    s.close()

@contextmanager
def pollcounter():
    stats.polling += 1
    yield
    stats.polling -= 1

def query_worker(id, rfile):
    global shows

    with subcontext(id) as s, pollcounter() as pc:
        poll = zmq.Poller()
        poll.register(s, zmq.POLLIN)
        poll.register(rfile, zmq.POLLERR|zmq.POLLIN)

        while True:
            events = dict(poll.poll())

            if rfile.fileno() in events:
                break

            msg = s.recv_json()

            if msg['msg'] == 'close':
                break
            elif msg['msg'] != 'update':
                continue

            yield( json.dumps({
                'msg': 'update',
                'id': id,
                'url': msg['url'],
                }))

            break

@app.route('/show/ping')
def api_ping():
    return {'msg': 'pong'}

@app.route('/show/<id>/poll')
def api_poll_show(id):
    global shows

    # On OpenShift this method will be called using an alternate
    # port so we need to add a CORS header.
    if settings.using_openshift:
        bottle.response.headers['Access-Control-Allow-Origin'] = '*'

    if not id in shows:
        raise bottle.HTTPError(404)

    rfile = bottle.request.environ['wsgi.input'].rfile
    return query_worker(id, rfile)

@app.route('/show/<id>', method='GET')
def api_query_show(id):
    global shows

    if not id in shows:
        raise bottle.HTTPError(404)

    return json.dumps({
        'msg': 'info',
        'id': id,
        'base': shows[id]['base'],
        'url': shows[id]['url'],
        })

@app.route('/show/<id>', method='PUT')
def api_update_show(id):
    global shows

    if not id in shows:
        raise bottle.HTTPError(404)

    url = bottle.request.params['url']
    secret = bottle.request.params.get('secret')

    if shows[id]['secret'] is not None and shows[id]['secret'] != secret:
        raise bottle.HTTPError(401)

    shows[id]['url'] = url
    shows[id]['s'].send_json({
        'msg': 'update',
        'url': bottle.request.params['url'],
        })

    return {
            'id': id,
            'status': 'updated',
            'url': url,
            }

@app.route('/show/<id>', method='POST')
def api_create_show(id):
    global shows

    now = time.time()
    url = bottle.request.params['url']
    secret = bottle.request.params.get('secret')

    if id in shows:
        this = shows[id]

        if this['secret'] is not None and this['secret'] == secret:
            # allow owner to replace show
            delete_show(id)
        elif this['created'] < (now - max_lifetime):
            # allow stale shows to be replaced
            delete_show(id)
        else:
            raise bottle.HTTPError(409)

    shows[id] = {
            'id': id,
            'created_at': time.time(),
            'created_by': bottle.request.environ.get(
                'HTTP_X_FORWARDED_FOR',
                bottle.request.environ.get('REMOTE_ADDR')),
            'base': url,
            'url': url,
            'secret': secret,
            's': ctx.socket(zmq.PUB),
            }
    shows[id]['s'].bind('inproc://%s' % id)

    return { 'id': id, 'status': 'created' }

@app.route('/show/<id>', method='DELETE')
def api_delete_show(id):
    global shows

    now = time.time()
    secret = bottle.request.params.get('secret')

    try:
        this = shows[id]

        if this['secret'] is not None and this['secret'] == secret:
            # allow owner to replace show
            delete_show(id)
        elif this['created'] < (now - max_lifetime):
            # allow stale shows to be replaced
            delete_show(id)
        else:
            raise bottle.HTTPError(401)
    except KeyError:
        raise bottle.HTTPError(404)

    return { 'id': id, 'status': 'deleted' }


import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.metrics import r2_score, mean_squared_error
from sklearn.ensemble import GradientBoostingRegressor

concrete = pd.read_csv("./datasets/concrete_data.csv")

concrete.head()

X = concrete.drop("csMPa", axis = 1)
Y = concrete.csMPa

X = X.drop(["flyash", "coarseaggregate", "fineaggregate"], axis = 1)  # done to reduce dim, and help increase speed

from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(X, Y, test_size = 0.2)

# baseline model, i.e new model acc mustn't be lower than this
baseline = GradientBoostingRegressor(max_depth=3, n_estimators=50)
baseline.fit(x_train, y_train)

from sklearn.metrics import r2_score

y_pred = baseline.predict(x_test)

r2_score(y_test, y_pred)

# get importance of feature to the model
important_features = pd.Series(baseline.feature_importances_, index = X.columns).sort_values(ascending = False)

important_features

# gridSearch
gbr = GradientBoostingRegressor(max_depth=3)

parameters = {"n_estimators": [1, 5, 10, 50, 100, 200, 300, 400, 500]}

gridsearch_reg = GridSearchCV(gbr, param_grid=parameters, cv = 3, n_jobs=-1)

gridsearch_reg.fit(x_train, y_train)

gridsearch_reg.best_params_

x_train, x_test, y_train, y_test = train_test_split(X, Y, test_size = 0.2)

gbr_best = GradientBoostingRegressor(max_depth=3, n_estimators=gridsearch_reg.best_params_["n_estimators"])
gbr_best.fit(x_train, y_train)

y_pred = gbr_best.predict(x_test)

r2_score(y_test, y_pred)

"""
warmstart = True, means reuse solutions of previous call to predictor to fit and add
more estimators of ensemble
"""
gbr = GradientBoostingRegressor(max_depth = 3, warm_start = True)

# early stopping code
min_val_error = float("inf")
error_increasing = 0

for n_estimators in range(1, 1000):
    gbr.n_estimators = n_estimators
    gbr.fit(x_train, y_train)

    y_pred = gbr.predict(x_test)
    val_error = mean_squared_error(y_test, y_pred)

    print("No. of estimators: ", gbr.n_estimators)
    print("Error: ", val_error)

    if val_error < min_val_error:  # error reducing
        min_val_error = val_error  # updates min error value
        error_increasing = 0
    else:
        error_increasing += 1
        if error_increasing == 10:   # error keeps increasing for 6 times i.e overfitting
            break

n_estimators # best num of estimators from early stopping

# reshuffle train and test data
x_train, x_test, y_train, y_test = train_test_split(X, Y, test_size = 0.2)

gbr_best = GradientBoostingRegressor(max_depth = 3, n_estimators = n_estimators)

gbr_best.fit(x_train, y_train)

y_pred = gbr_best.predict(x_test)

r2_score(y_test, y_pred)


from typing import Any

from captain.internal.manager import ConnectionManager
from captain.types.worker import WorkerJobResponse
from captain.utils.status_codes import STATUS_CODES

class Signaler:
    """
    Class used to signal the status of the topology to the front-end client
    """

    def __init__(self, ws: ConnectionManager):
        self.ws = ws

    async def signal_node_results(
        self, jobset_id: str, node_id: str, func_name: str, result: dict[str, Any]
    ):
        msg = WorkerJobResponse(
            jobset_id=jobset_id,
            result=result,
            cmd=func_name,
            node_id=node_id,
        )
        await self.ws.broadcast(msg)

    async def signal_current_running_node(
        self, jobset_id: str, node_id: str, func_name: str
    ):
        msg = WorkerJobResponse(
            jobset_id=jobset_id,
            sys_status=STATUS_CODES["RUNNING_PYTHON_JOB"] + func_name,
            running_node=node_id,
        )
        await self.ws.broadcast(msg)

    async def signal_failed_nodes(
        self, jobset_id: str, node_id: str, func_name: str, error: str
    ):
        msg = WorkerJobResponse(
            jobset_id=jobset_id,
            sys_status=STATUS_CODES["FAILED_NODE"] + func_name,
            failed_nodes={node_id: error},
        )
        await self.ws.broadcast(msg)

    async def signal_prejob_op(self, jobset_id: str):
        msg = WorkerJobResponse(
            jobset_id=jobset_id, sys_status=STATUS_CODES["RUN_PRE_JOB_OP"]
        )
        await self.ws.broadcast(msg)

    async def signal_standby(self, jobset_id: str):
        msg = WorkerJobResponse(
            jobset_id=jobset_id,
            sys_status=STATUS_CODES["STANDBY"],
            failed_nodes=[],
            running_node="",
        )
        await self.ws.broadcast(msg)

    async def signal_max_runtime_exceeded(self, jobset_id: str):
        msg = WorkerJobResponse(
            jobset_id=jobset_id,
            sys_status=STATUS_CODES["MAXIMUM_RUNTIME_EXCEEDED"],
            failed_nodes=[],
            running_node="",
        )
        await self.ws.broadcast(msg)


import numpy as np
from enum import Enum

# Project modules
import modules.UnitsConstantsModule as HBTWN_UCM

'''
calculate_telescope_size - calculate telescope size which is needed to see object in input resolution
_target_obj_physical_size - target object physical size as array: [ size, unit ]
_target_obj_physical_dist - target object physical distance as array: [ distance, unit ]
_object_shape - object shape (default: ObjectShape.SPHERICAL)
_number_of_pixels - number of pixels on image (default: 100)
_wavelength - wavelength value (default: [522.0, nm])
_telescope_size_unit - telescope size unit (default: mm)
@return calculated telescope size value and unit as array and object size in arcsec
'''
def calculate_telescope_size(_target_obj_physical_size, _target_obj_physical_dist , _object_shape = HBTWN_UCM.ObjectShape.SPHERICAL, _number_of_pixels = 100, _wavelength = [522.0, 'nm'], _telescope_size_unit = 'mm'):

    try:
        size_m = HBTWN_UCM.dist_units_converter(_target_obj_physical_size[0], _target_obj_physical_size[1], 'm')
        size_scaled_m = [ size_m[0]*(1.0/_number_of_pixels), size_m[1] ]
        dist_m = HBTWN_UCM.dist_units_converter(_target_obj_physical_dist[0], _target_obj_physical_dist[1], 'm')

        '''
        Angular size of objects in radians and arcsec
        delta [rad] = 2*arctan(diameter [m] / (2*distance [m]))
        delta [rad] = 2*arcsin(diameter [m] / (2*distance [m]))
        '''
        angular_size_in_rads = 0.0
        angular_size_in_rads_for_pixel = 0.0
        if _object_shape is HBTWN_UCM.ObjectShape.FLAT:
            angular_size_in_rads = 2.0 * np.arctan(size_m[0]/(dist_m[0]+dist_m[0]))
            angular_size_in_rads_for_pixel = 2.0 * np.arctan(size_scaled_m[0]/(dist_m[0]+dist_m[0]))
        else:
            _object_shape = HBTWN_UCM.ObjectShape.SPHERICAL
            angular_size_in_rads = 2.0 * np.arcsin(size_m[0]/(dist_m[0]+dist_m[0]))
            angular_size_in_rads_for_pixel = 2.0 * np.arcsin(size_scaled_m[0]/(dist_m[0]+dist_m[0]))

        angular_size_in_arcsec = HBTWN_UCM.angle_units_converter(angular_size_in_rads, 'rad', 'arcsec')[0]
        angular_size_in_arcsec_for_pixel = HBTWN_UCM.angle_units_converter(angular_size_in_rads_for_pixel, 'rad', 'arcsec')[0]

        '''
        Telescope angular resolution
        theta [rad] = 1.22 * ( lambda [m] / D [m] ), where lambda - wavelength, D - telescope diameter
        D = 1.22 * (lambda/theta)
        '''

        wavelength_m = HBTWN_UCM.dist_units_converter(_wavelength[0],_wavelength[1],'m')

        D = 1.22*(wavelength_m[0]/angular_size_in_rads_for_pixel)
        telescope_diameter = HBTWN_UCM.dist_units_converter(D,'m',_telescope_size_unit)

        return telescope_diameter, [ angular_size_in_arcsec, 'arcsec' ]

    except TypeError as e:
        print('Calculation failure!!!')
        return None, None

'''
calculate_object_size - calculate size of object which could be seen with given telescope and distance
_target_obj_physical_dist - target object physical distance as array: [ distance, unit ]
_target_obj_size_unit - expected unit for object size: unit
_telescope_angular_resolution - telescope angular resolution: [ angular resolution, unit ]
_object_shape - object shape (default: ObjectShape.SPHERICAL)
_number_of_pixels - number of pixels on image (default: 1)
@return calculated object size in given unit
'''
def calculate_object_size(_target_obj_physical_dist, _target_obj_size_unit, _telescope_angular_resolution, _object_shape = HBTWN_UCM.ObjectShape.SPHERICAL, _number_of_pixels = 1):

    try:
        dist_m = HBTWN_UCM.dist_units_converter(_target_obj_physical_dist[0], _target_obj_physical_dist[1], 'm')
        angular_size_in_rads = HBTWN_UCM.angle_units_converter(_telescope_angular_resolution[0], _telescope_angular_resolution[1], 'rad')[0]

        '''
        Observed object diameter in m for flat and spherical objects
        delta [rad] = 2*arctan(diameter [m] / (2*distance [m]))
            z = diameter [m] / (2*distance [m])
        delta [rad] = 2*arctan(z)
        z = tan(delta [rad] / 2)
        diameter [m] = z * (2*distance [m])
        diameter [m] = tan(delta [rad] / 2) * (2*distance [m])

        delta [rad] = 2*arcsin(diameter [m] / (2*distance [m]))
            z = sin(delta [rad] / 2)
        diameter [m] = sin(delta [rad] / 2) * (2*distance [m])
        '''

        object_size_in_m = 0.0
        if _object_shape is HBTWN_UCM.ObjectShape.FLAT:
            object_size_in_m = np.tan(angular_size_in_rads*0.5)*(2.0*dist_m[0])
        else:
            _object_shape = HBTWN_UCM.ObjectShape.SPHERICAL
            object_size_in_m = np.sin(angular_size_in_rads*0.5)*(2.0*dist_m[0])

        # Scale object
        object_size_in_m = object_size_in_m * _number_of_pixels

        return HBTWN_UCM.dist_units_converter(object_size_in_m,'m',_target_obj_size_unit)

    except TypeError as e:
        print('Calculation failure!!!')
        return None

'''
calculate_telescope_resolution - calculate telescope angular resolution
_telescope_parameters - telescope size as array: [size, unit]
_wavelength - wavelength value (default: [522.0, nm])
_resolution_unit - telescope resolution unit (default: arcsec)
@return telescope resolution as array resolution and unit
'''
def calculate_telescope_resolution(_telescope_parameters, _wavelength = [522.0, 'nm'], _resolution_unit = 'arcsec'):
    try:

        size_m = HBTWN_UCM.dist_units_converter(_telescope_parameters[0], _telescope_parameters[1], 'm')
        wavelength_m = HBTWN_UCM.dist_units_converter(_wavelength[0],_wavelength[1],'m')

        '''
        Telescope angular resolution
        theta [rad] = 1.22 * ( lambda [m] / D [m] ), where lambda - wavelength, D - telescope diameter
        '''
        theta = 1.22*(wavelength_m[0]/size_m[0])

        telescope_resolution = HBTWN_UCM.angle_units_converter(theta, 'rad', 'arcsec')
        return telescope_resolution

    except TypeError as e:
        print('Calculation failure!!!')
        return None


from itertools import chain
import datetime
from mobiles.models import Mobile
from periods.models import AvailabilityPeriod, BlockingPeriod
from rest_framework import viewsets
from rest_framework import permissions
from mobiles.serializers import MobileSerializer
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.core.paginator import Paginator
from django.http import HttpResponse, HttpResponseBadRequest
from django.db.models import Q

def string2Date(dateString):
    return datetime.datetime.strptime(dateString, "%Y-%m-%d").date()

def date2String(date):
    return datetime.datetime.strftime(date, "%Y-%m-%d")

def getChangedDate(date, days):
    date = string2Date(date)
    date = date + datetime.timedelta(days=days)
    return date2String(date)

def checkPerfectPeriod(mobileId, beginDate, endDate, mode):
    if mode == 1:
        searchedPeriod = AvailabilityPeriod.objects.filter(
            Q(mobile_id=mobileId,
              enddate__gte=beginDate,
              begindate__lte=endDate)
        ).order_by('begindate')
    else:
        searchedPeriod = BlockingPeriod.objects.filter(
            Q(mobile_id=mobileId,
              enddate__gte=beginDate,
              begindate__lte=endDate)
        ).order_by('begindate')
    length = len(searchedPeriod)
    check = False
    if length == 1:
        return False

    if length >= 2:
        check = checkTightPeriod(searchedPeriod, length, beginDate, endDate)

    return check

def checkTightPeriod(periods, lengthRec, beginDate, endDate):
    inx = 0
    prevItem = None

    for item in periods:
        inx += 1
        if inx == 1:
            if item.begindate > string2Date(beginDate):
                return False
        if inx == lengthRec:
            if item.enddate < string2Date(endDate):
                return False
        if prevItem is not None:
            if getChangedDate(date2String(prevItem.enddate), 1) != date2String(item.begindate):
                return False
        prevItem = item
    return True

def getMobileList(request):
    location = request.GET.get('location', '')
    page = request.GET.get('page', 1)
    items = request.GET.get('items', 10)
    beginDate = request.GET.get('begindate', '')
    endDate = request.GET.get('enddate', '')

    searchedMobiles = []
    searchedMobilesAvailableExact = []
    searchedMobilesAvailableIntersect = []
    searchedMobilesOfBlockingIntersect = []
    searchedMobilesOfBlockingAll = []
    if beginDate != '' and endDate != '':
        # find mobiles contains exact available periods which have beginDate and endDate
        searchedMobilesAvailableExact = Mobile.objects.filter(
            Q(location__icontains=location,
              availabilityperiod__begindate__lte=beginDate,
              availabilityperiod__enddate__gte=endDate))

        # find mobiles contains available periods which have even one day between beginDate and endDate
        searchedMobilesAvailableIntersect = Mobile.objects.filter(
            Q(location__icontains=location,
              availabilityperiod__enddate__gte=beginDate,
              availabilityperiod__begindate__lte=endDate)
        ).order_by('id')

        # find mobiles contains blocking periods which have even one day between beginDate and endDate
        searchedMobilesOfBlockingIntersect = Mobile.objects.filter(
            Q(location__icontains=location,
              blockingperiod__enddate__gte=beginDate,
              blockingperiod__begindate__lte=beginDate) |
            Q(location__icontains=location,
              blockingperiod__enddate__gte=endDate,
              blockingperiod__begindate__lte=endDate)
        ).order_by('id')

        # find all mobiles contains location
        searchedMobilesOfBlockingAll = Mobile.objects.filter(
            Q(location__icontains=location,
              blockingperiod__id__gt=0)
        ).order_by('id')

    else:
        searchedMobiles = Mobile.objects.filter(location__icontains=location).order_by('id')

    searchedMobiles = list(chain(searchedMobiles, searchedMobilesAvailableExact))

    keyList1 = {}
    keyList2 = {}
    keyList3 = {}
    mobileList = []
    # we have to find mobiles has tight available period
    # 1-5,6-10,11-20 => tight
    # 1-3, 5-7 => not tight
    for item in searchedMobilesAvailableIntersect:
        if item.id not in keyList1:
            keyList1[item.id] = 1
            if checkPerfectPeriod(item.id, beginDate, endDate, 1):
                searchedMobiles.append(item)

    # find mobiles to be removed from searchedMobilesOfBlockingAll
    for item in searchedMobilesOfBlockingIntersect:
        if item.id not in keyList2:
            keyList2[item.id] = 1

    # add mobiles to searchedMobiles from searchedMobilesOfBlockingAll except searchedMobilesOfBlockingIntersect
    for item in searchedMobilesOfBlockingAll:
        if item.id not in keyList3 and item.id not in keyList2:
            keyList3[item.id] = 1
            searchedMobiles.append(item)

    for item in searchedMobiles:
        mobileList.append({
            "id": item.id,
            "name": item.name,
            "description": item.description,
            "user": item.user.pk,
            "location": item.location,
        })

    paginator = Paginator(searchedMobiles, items)
    searchedMobiles = paginator.page(page)

    return JsonResponse({
        "mobiles": mobileList[((int(page) - 1) * items):(int(page) * items - 1)],
        "page": page,
        "items": items,
        "totalPages": paginator.num_pages,
        "totalItems": paginator.count,
    })

class MobileViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows mobiles to be viewed or edited.
    """
    queryset = Mobile.objects.all()
    serializer_class = MobileSerializer
    permission_classes = [permissions.IsAuthenticated]

    def partial_update(self, request, *args, **kwargs):
        mobile = self.get_object()
        mobile_serializer = MobileSerializer(mobile, data=request.data, partial=True)
        if mobile_serializer.is_valid():
            mobile_serializer.save()
            return HttpResponse(mobile_serializer.data)
        else:
            return HttpResponseBadRequest()


import torch
from torch import nn
import torch.nn.functional as F
import torch.nn.utils.weight_norm as weightNorm
from baselines.ViT_network import ViT_Cross

class Classifier(nn.Module):
    def __init__(self, in_dim, n_classes):
        super(Classifier, self).__init__()
        self.net = weightNorm(nn.Linear(in_dim, n_classes, bias=False), name='weight')

    def forward(self, x):
        return  self.net(x)

class SourceOnly_net(nn.Module):
    def __init__(self, n_classes, model_path=r'/root/autodl-tmp/Dataset/Pth/ViT/vit_small_distilled.pth'):
        # '/home/ubuntu/sda_fast/Dataset/Pth/ViT/vit_small_distilled.pth'
        #/root/autodl-tmp/Dataset/Pth
        super(SourceOnly_net, self).__init__()
        self.backbone = ViT_Cross()
        self.classifier = Classifier(self.backbone.embed_dim, n_classes)
        # if not use this, the prototype.device is cpu, why?
        # self.classifier = nn.Linear(self.backbone.embed_dim, n_classes, bias=False)
        # AutoDL:/root/autodl-tmp/Dataset/Image_DA/Pth
        if model_path is not None:
            self.backbone.load_param(model_path)

    def forward(self, x, return_latent_output=False):
        tokens, latent_tokens = self.backbone.get_latent_output(x)
        outputs_c = self.classifier(tokens[:, 0])
        if self.training or return_latent_output:  #
            return outputs_c, latent_tokens, tokens
        else:
            return outputs_c

    def predict(self, x):
        tokens, latent_tokens = self.backbone.get_latent_output(x)
        outputs_c = self.classifier(tokens[:, 0])
        return outputs_c

class CrossEntropyLabelSmooth(nn.Module):
    """Cross entropy loss with label smoothing regularizer.
    Reference:
    Szegedy et al. Rethinking the Inception Architecture for Computer Vision. CVPR 2016.
    Equation: y = (1 - epsilon) * y + epsilon / K.
    Args:
        num_classes (int): number of classes.
        epsilon (float): weight.
    """
    def __init__(self, num_classes, epsilon=0.1, reduction=True):
        super(CrossEntropyLabelSmooth, self).__init__()
        self.num_classes = num_classes
        self.epsilon = epsilon
        self.reduction = reduction
        self.logsoftmax = nn.LogSoftmax(dim=1)

    def forward(self, inputs, targets):
        log_probs = self.logsoftmax(inputs).cuda()
        #
        targets = torch.zeros(log_probs.size()).cuda().scatter_(1, targets.unsqueeze(1), 1)
        targets = targets.cuda()
        targets = (1 - self.epsilon) * targets + self.epsilon / self.num_classes
        loss = (- targets * log_probs).sum(dim=1)
        if self.reduction:
            return loss.mean()
        else:
            return loss

# class Training():
#     use Pl
#     def __init__(self, n_classes):
#         self.n_classes = n_classes
#         self.criterion_c = nn.CrossEntropyLoss()
#
#     def forward_classifier(self, x, y):
#         # loss = self.criterion_c(x, y)
#         loss = F.cross_entropy(x, y)
#         return loss
#
#     def get_pseudo_labels(self, x, net_list):
#         # why? if put outside will raise error: no inf checks were recorede for this optimizer
#         o_c_list = torch.tensor([]).to(x.device)
#         for net_ds in net_list[1:]:
#             outputs_c, _, __ = net_ds(x, return_latent_output=True)
#             o_c_list = torch.cat((o_c_list, outputs_c.unsqueeze(0)), 0)
#         o_c_list = o_c_list.mean(0)
#         y = o_c_list.max(1)[1]
#         return y
#
#     def forward(self, x, net_list, **kwargs):
#         outputs_c, latent_tokens, tokens = net_list[0](x)
#         # get pseudo-labels
#         y = self.get_pseudo_labels(x, net_list)
#         # loss = self.forward_classifier(outputs_c, y)
#         loss = F.cross_entropy(outputs_c, y.detach())
#         return loss
#

class Training():
    # Do Not use PL, only source training and predict
    def __init__(self, n_classes):
        self.n_classes = n_classes
        self.criterion_c = nn.CrossEntropyLoss()

    def forward_classifier(self, x, y):
        # loss = self.criterion_c(x, y)
        loss = F.cross_entropy(x, y)
        return loss

    def get_pseudo_labels(self, x, net_list):
        # why? if put outside will raise error: no inf checks were recorede for this optimizer
        o_c_list = torch.tensor([]).to(x.device)
        for net_ds in net_list[1:]:
            outputs_c, _, __ = net_ds(x, return_latent_output=True)
            o_c_list = torch.cat((o_c_list, outputs_c.unsqueeze(0)), 0)
        o_c_list = o_c_list.mean(0)
        y = o_c_list.max(1)[1]
        return y

    def forward(self, x, net_list, **kwargs):
        outputs_c, latent_tokens, tokens = net_list[0](x)
        # get pseudo-labels
        y = self.get_pseudo_labels(x, net_list)
        # loss = self.forward_classifier(outputs_c, y)
        loss = F.cross_entropy(outputs_c, y.detach())
        return loss


import pyttsx3
import datetime
import speech_recognition as sr
import webbrowser as wb
import os

friday = pyttsx3.init()
voice = friday.getProperty('voices')
newVoiceRate = 145
friday.setProperty('rate',newVoiceRate)
friday.setProperty('voice', voice[1].id)

def speak(audio):
    print('F.R.I.D.A.Y : ' + audio)
    friday.say(audio)
    friday.runAndWait()

def time():
    time = datetime.datetime.now().strftime("%H:%M %p")
    speak(time)
# speak('Hello Youtube')

def welcome():
    hour = datetime.datetime.now().hour
    if hour >= 6 and hour < 12:
        speak('Good Morning,sir')
    if hour >= 12 and hour < 18:
        speak('Good afternoon ,sir')
    if hour >= 18 and hour <= 24:
        speak('Good evening,sir')
    if hour < 6:
        speak('Good evening,sir')
    speak("How can I help you?")

def command():
    c = sr.Recognizer()
    with sr.Microphone() as source:
        c.pause_threshold = 2
        audio = c.listen(source)
    try:
        query = c.recognize_google(audio, language="en")
        print("Quoc Cuong : " + query)
    except sr.UnknownValueError:
        print("Please repeat or typing the command")
        query = str(input('Your order is: '))
    return query
if __name__ == "__main__":
    welcome()
    while True:
        query = command().lower()
        if "google" in query:
            speak("What should I search, boss?")
            search = command().lower()
            url = f"https://google.com/search?q={search}"
            wb.get().open(url)
            speak(f"Here is your {search} on Google")
        if "youtube" in query:
            speak("What should I search, boss?")
            search = command().lower()
            url = f"https://youtube.com/search?q={search}"
            wb.get().open(url)
            speak(f"Here is your {search} on Youtube")
        if "open video" in query:
            file = r"E:\Downloads\Marvels.Iron.Fist.S02E10.A.Duel.of.Iron.1080p.NF.WEB-DL.Atmos.DDP5.1.HDR.HEVC (1).mkv"
            speak("Sure, enjoy your video, boss")
            os.startfile(file)
        if "time" in query:
            time()
        if "quit" in query:
            speak("Friday is quiting sir. Goodbye boss")
            quit()


import matplotlib.pyplot as plt
import numpy as np
import networkx as nx
import pandas as pd

# Load Granger matrix
data_m=np.load('granger_01month.npy')

# Thresholding
thres=40
data_m[data_m<thres]=0
data_m[data_m>=thres]=1
plt.spy(data_m)
plt.show()

# Making the graph, and also printed the properties
G = nx.Graph(data_m)
degrees_list=np.zeros((len(data_m),1))

for ii in range(len(degrees_list)):
    degrees_list[ii] = G.degree([ii])[ii]
plt.hist(degrees_list);
plt.show()

cc = nx.number_connected_components(G)
ac = nx.average_clustering(G)

print(f"Number of connected components: {cc}")
print(f"Average clustering coefficient: {ac}")

# Loading the google citation data
data_goo=pd.read_csv('citations.txt',delimiter='\t')
researcher_idx = data_goo['id'].values
researcher_hidx = data_goo['h_index'].values

# Getting the data point of top 50 degrees
degree_high = np.argsort(degrees_list[:,0])[-50:]
c=np.load('granger_indexes.npy')

hidex=[]
for ii in degree_high:
    hidex.append(researcher_hidx[np.where(researcher_idx==c[ii])])

print(researcher_hidx.mean())
print(np.array(hidex).mean())


import datetime as dt
from dateutil import parser
import pandas as pd
import pandas_datareader.data as web

tickers = ['SGDUSD=X',
           'SGDEUR=X',
           'SGDCNY=X',
           'SGDJPY=X',
           'SGDGBP=X',
           'SGDBRL=X',
           'SGDCAD=X',
           'SGDRUB=X',
           'SGDAUD=X',
           'SGDMXN=X',
           'SGDIDR=X',
           'SGDTRY=X',
           'SGDCHF=X',
           'SGDSAR=X']

countries = ['US',
             'EU',
             'CN',
             'JP',
             'GB',
             'BR',
             'CA',
             'RU',
             'AU',
             'MX',
             'ID',
             'TR',
             'CH',
             'SA']

def getGDPData(country):
    df = pd.read_csv("data\\gdp\\" + country + ".csv", index_col = 1, names = ['Country', 'GDP']);
    return df

def getForexData(ticker):
    df = pd.read_csv("data\\forex\\" + ticker + ".csv", index_col = 0, names = ['Price', 'Change']);
    return df

def getIndexChanges(forex, gdp):

    gdp.drop(gdp.tail(1).index,inplace=True)
    forex.drop(forex.tail(1).index,inplace=True)

    indexChanges = []

    #Loop through every day
    for i in range(0, len(forex)):

        dateTime = parser.parse(forex.index.values[i])
        year = dateTime.year;
        if year == 2017:
            year = 2016

        indexChanges.append(calculateWeightedGeometricMean(forex.iloc[i], gdp.loc[str(year)]))

    return indexChanges

def calculateWeightedGeometricMean(forex, gdp):

    a = 1;

    #Loop through every country/currency
    for i in range(0, len(forex)):

        #clean data
        try:
            val = float(forex.iloc[i])
        except ValueError:
            forex.iloc[i] = '1'

        if forex.iloc[i] == '0':
            forex.iloc[i] = '1';

        try:
            val = float(gdp.iloc[i])
        except ValueError:
            gdp.iloc[i] = '1'

        if gdp.iloc[i] == '0':
            gdp.iloc[i] = '1';

        a = a * pow(float(forex.iloc[i]), float(gdp.iloc[i]) / 10000000000.0) #divide 10,000,000,000 ten billion

    a = pow(a, 1 / calculateSumOfGDP(gdp))

    return a

def calculateSumOfGDP(gdps):

    a = 0.0

    for gdp in gdps:
        a = a + float(gdp)

    return a / 10000000000.0

def getIndex(indexChanges):

    indices = []
    index = 100.0

    for i in range(0, len(indexChanges)):

        #Clean data
        if indexChanges[i] != indexChanges[i]:
            indexChanges[i] = 1.0

        index = index * indexChanges[i]
        indices.append(index)

    return indices

gdpAllDf = pd.DataFrame()
forexAllDf = pd.DataFrame()

for i in range(0, len(countries)):

    gdpDf = getGDPData(countries[i])
    gdpDf = gdpDf.iloc[::-1] #Reverse, to be in ascending date
    forexDf = getForexData(tickers[i])

    gdpAllDf[countries[i]] = gdpDf['GDP'];
    forexAllDf[tickers[i]] = forexDf['Change'];

indexChanges = getIndexChanges(forexAllDf, gdpAllDf)
indices = getIndex(indexChanges)

df = pd.DataFrame(indices);
df.to_csv('SGD_Index.csv');


import logging

from aiogram import types
from aiogram.dispatcher.filters.builtin import CommandStart

from loader import dp
from utils.db_api import db_commands as commands

@dp.message_handler(CommandStart())
async def bot_start(message: types.Message):
    """Handler для запуска бота."""
    chat_id = message.from_user.id
    logging.info(f"Бот активирован пользователем telegram id - {chat_id}")
    subscriber = await commands.get_subscriber(message.from_user.id)
    if not subscriber:
        subscriber = await commands.add_subscriber(
            user_id=message.from_user.id,
            first_name=message.from_user.first_name,
            last_name=message.from_user.last_name,
            username=message.from_user.username,
        )
        await message.answer(
            "\n".join(
                [
                    f"Здравствуйте, {message.from_user.username}!",
                    f'Вы были занесен в базу компании "КоРус".',
                    f"Telegram id: {subscriber.user_id}",
                    f"Username: {subscriber.username}",
                    f"ФИО: {subscriber.first_name} {subscriber.last_name}",
                ]
            )
        )
        return
    await message.answer(f"Здравствуйте, {message.from_user.username}!")


import random
import os
import shutil
import xml.etree.ElementTree as ET
import tqdm

def makedir(newdir):
    if not os.path.exists(newdir):
        os.makedirs(newdir)

def delete_cache(path):
    for filename in os.listdir(path):
        if filename.endswith(".cache"):
            os.remove(os.path.join(path, filename))

def onexml2yolo(xmlpath, classname):
    tree = ET.parse(xmlpath)
    root = tree.getroot()
    size = root.find("size")
    width = int(float(size.find("width").text))
    height = int(float(size.find("height").text))
    newlines = []
    for oneobject in root.findall("object"):
        bndbox = oneobject.find("bndbox")
        name = oneobject.find("name").text
        xmin = int(float(bndbox.find("xmin").text))
        ymin = int(float(bndbox.find("ymin").text))
        xmax = int(float(bndbox.find("xmax").text))
        ymax = int(float(bndbox.find("ymax").text))
        xcenter = (xmax + xmin) / (2. * width)
        ycenter = (ymax + ymin) / (2. * height)
        yolowidth = (xmax - xmin) / width
        yoloheight = (ymax - ymin) / height
        if name not in classname.keys():
            continue
        line = f"{classname[name]} " + f"{xcenter:.6f} {ycenter:.6f} {yolowidth:.6f} {yoloheight:.6f}"
        newlines.append(line)
    return newlines

def generate_yolo_label(xmlpath, outpath, classname, dataname):
    makedir(outpath)
    progress_bar = tqdm.tqdm(desc=f"{dataname} xml2yolo", total=len(os.listdir(xmlpath)))
    for xml in os.listdir(xmlpath):
        newname = xml.split(".")[0]
        newname = newname + ".txt"
        xml = os.path.join(xmlpath, xml)
        newlines = onexml2yolo(xml, classname)
        with open(os.path.join(outpath, newname), "w") as f:
            for line in newlines:
                f.write(line + "\n")
        progress_bar.update()
    progress_bar.close()

def split_dataset(train_ratio, images_dir):
    random.seed(42)
    imglist = os.listdir(images_dir)
    random.shuffle(imglist)
    trainset = []
    testset = []
    train_num = int(train_ratio*len(imglist))
    for i in range(len(imglist)):
        img = os.path.join(images_dir, imglist[i])
        if i + 1 <= train_num:
            trainset.append(img)
        else:
            testset.append(img)
    valset = trainset[-5:]
    return trainset, valset, testset

if __name__ == "__main__":
    rdd2020 = os.path.join("../datasets/RDD2020/train")
    sodrv1 = os.path.join("../datasets/SODRv1")
    rdddatasets = ["Czech", "India", "Japan"]
    sodrdatasets = ["collapse", "blockage"]
    classname = {"D00": 0, "D10": 1, "D20": 2, "D40": 3, "collapse": 4, "blockage": 5}   # note that D50: collapse D60: blockage

    # xml to yolo
    for d in rdddatasets:
        xmls = os.path.join(rdd2020, d, "annotations", "xmls")
        outputyolo = os.path.join(rdd2020, d, "labels")
        generate_yolo_label(xmls, outputyolo, classname, "RDD2020_" + d)
    for d in sodrdatasets:
        xmls = os.path.join(sodrv1, d, "xmls")
        outputyolo = os.path.join(sodrv1, d, "labels")
        generate_yolo_label(xmls, outputyolo, classname, "SODRv1_" + d)

    # split train, val, and test
    delete_cache("../datasets")
    train_ratio = 0.8
    test_ratio = 0.2
    train = []
    val = []
    test = []
    for d in rdddatasets:
        imgs = os.path.join(rdd2020, d, "images")
        trainset, valset, testset = split_dataset(train_ratio, imgs)
        train.extend(trainset)
        val.extend(valset)
        test.extend(testset)
    for d in sodrdatasets:
        imgs = os.path.join(sodrv1, d, "images")
        trainset, valset, testset = split_dataset(train_ratio, imgs)
        train.extend(trainset)
        val.extend(valset)
        test.extend(testset)
    with open("../datasets/train.txt", "w") as f:
        for i in train:
            f.write(i.lstrip("../")+"\n")
    with open("../datasets/val.txt", "w") as f:
        for i in val:
            f.write(i.lstrip("../")+"\n")
    with open("../datasets/test.txt", "w") as f:
        for i in test:
            f.write(i.lstrip("../")+"\n")


import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

import pickle
import glob
import os

class Calibration():
    # Chessboard Configuration
    GRID_SIZE = (9, 6)
    CRITERIA = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 30, 0.001)
    SAVE_PATH = 'calibration.calib'
    CALIB_PATH = 'img/Udacity/calib'

    def __init__(self, debug: bool, file_path: str = None) -> None:
        self.debug = debug
        self.calibrated = False

        # Initialize the calibration matrix and distortion coefficients
        self.mtx, self.dist, self.roi, self.newcameramtx = None, None, None, None
        self.rvecs, self.tvecs = None, None

        # Arrays to store object points and image points from all the images.
        self.objPoints = [] # 3d point in real world space
        self.imgPoints = [] # 2d points in image plane.

        # Load calibration if file provided or the calibration already exists
        if file_path and os.path.exists(file_path): self.loadCalibration(file_path)
        elif os.path.exists(self.SAVE_PATH): self.loadCalibration(self.SAVE_PATH)

    def loadCalibration(self, file_path):
        with open(file_path, 'rb') as f:
            self.mtx, self.dist, self.roi, self.newcameramtx = pickle.load(f)
        self.calibrated = True

    def saveCalibration(self, file_path):
        with open(file_path, 'wb') as f:
            pickle.dump((self.mtx, self.dist, self.roi, self.newcameramtx), f)

    def equalize(self, img):
        if not self.calibrated: self._calibrate(img)

        # undistort the image
        undisortedImage = cv.undistort(img, self.mtx, self.dist, None, self.newcameramtx)

        # crop the image
        x, y, w, h = self.roi
        undisortedImage = undisortedImage[y:y+h, x:x+w]
        return undisortedImage

    def _chessboard(self):
        # prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
        objp = np.zeros((self.GRID_SIZE[0] * self.GRID_SIZE[1],3), np.float32)
        objp[:,:2] = np.mgrid[0:self.GRID_SIZE[0],0:self.GRID_SIZE[1]].T.reshape(-1,2)

        # read the chessboard imag
        images = glob.glob(self.CALIB_PATH + '/*.jpg')

        for file_name in images:
            board = cv.cvtColor(cv.imread(file_name), cv.COLOR_BGR2RGB)
            gray_board = cv.cvtColor(board, cv.COLOR_RGB2GRAY)

            # Find the chess board corners
            ret, corners = cv.findChessboardCorners(gray_board, self.GRID_SIZE, None)

            # If found, add object points, image points (after refining them)
            if ret == True:
                self.objPoints.append(objp)
                corners2 = cv.cornerSubPix(gray_board,corners, (11,11), (-1,-1), self.CRITERIA)
                self.imgPoints.append(corners)

                # Draw and display the corners
                if self.debug:
                    cv.drawChessboardCorners(board, self.GRID_SIZE, corners2, ret)
                    print("Grid matched: " + file_name)
                    cv.imshow('img', board)
                    if cv.waitKey(100) & 0xFF == ord('q'):
                        break

        if self.debug: cv.destroyAllWindows()

    def _calibrate(self, img):
        self._chessboard()
        self._generateMatrix(img)
        self.saveCalibration(self.SAVE_PATH)

    def _generateMatrix(self, img):
        # Generate the calibration matrix
        img_cvt = cv.cvtColor(img, cv.COLOR_RGB2GRAY)
        ret, self.mtx, self.dist, self.rvecs, self.tvecs = cv.calibrateCamera(self.objPoints, self.imgPoints, img_cvt.shape[::-1], None, None)

        img = cv.imread('img/Udacity/calib/calibration3.jpg')
        h,  w = img.shape[:2]
        self.newcameramtx, self.roi = cv.getOptimalNewCameraMatrix(self.mtx, self.dist, (w,h), 1, (w,h))
        self.calibrated = True

if __name__ == '__main__':
    calib = Calibration(debug=True)
    plt.imshow(calib.equalize(cv.imread('img/Udacity/calib/calibration3.jpg', cv.COLOR_BGR2RGB)))
    plt.show()