from __future__ import division
import sys
import torch
import torch.nn as nn
import torch.nn.functional as F
import torchvision.models as models
from utils.model_util import norm_col_init, weights_init

from .model_io import ModelOutput

import scipy.sparse as sp
import numpy as np
import scipy.io as scio
import math

object_list = ['AlarmClock', 'Book', 'Bowl', 'CellPhone', 'Chair', 'CoffeeMachine', 'DeskLamp', 'FloorLamp',
'Fridge', 'GarbageCan', 'Kettle', 'Laptop', 'LightSwitch', 'Microwave', 'Pan', 'Plate', 'Pot',
'RemoteControl', 'Sink', 'StoveBurner', 'Television', 'Toaster',]

class Target_Aware_Self_Attention_Layer(nn.Module):

    def __init__(self,
                 hidden_dim,
                 C_in=None,
                 num_heads=1,
                 dropout_rate=0.0,
                 length_out = 0):
        super(Target_Aware_Self_Attention_Layer, self).__init__()
        self.length_out = length_out
        self.hidden_dim = hidden_dim
        self.norm_mixer = nn.LayerNorm(C_in)
        self.linear_V = nn.Linear(C_in, num_heads * hidden_dim)
        self.num_heads = num_heads
        self.dropout = nn.Dropout(p=dropout_rate)
        self.V_dynamic_0 = nn.Sequential(
            nn.Linear(hidden_dim, self.length_out),
            nn.ReLU(),
        )
        self.V_dynamic_1 = nn.Sequential(
            nn.Conv1d(hidden_dim, self.length_out, kernel_size=3, bias=True,dilation=1),
            nn.ReLU(),
        )
        self.V_dynamic_2 = nn.Sequential(
            nn.Conv1d(hidden_dim, self.length_out, kernel_size=3, bias=True,dilation=2),
            nn.ReLU(),
        )

        self.head_communicate = nn.Linear(num_heads, 1)

    def forward(self, V):
        """
        :param Q: A 3d tensor with shape of [N, T_q, C_q]
        :param K: A 3d tensor with shape of [N, T_k, C_k]
        :param V: A 3d tensor with shape of [N, T_v, C_v]
        :return:
        """
        num_heads = self.num_heads
        N = 1
        length_in = V.shape[0]
        V = V.unsqueeze(0)

        V = self.norm_mixer(V)

        V_l = nn.ReLU()(self.linear_V(V))        #(1, n, num_heads * hidden_dim)

        V_split = V_l.split(split_size=self.hidden_dim, dim=2)

        V_ = torch.cat(V_split, dim=0)  # (num_heads, n, hidden_dim)

        V_0 = V_[0,:,:]
        V_1 = torch.cat((V_[1,length_in - 1, :].unsqueeze(0),V_[1,:,:],V_[1,0, :].unsqueeze(0)), dim =0)   #(n+2, hidden_dim)
        V_2 = torch.cat((V_[2,length_in - 2, :].unsqueeze(0),V_[2,length_in - 1, :].unsqueeze(0),V_[2,:,:],V_[2,0, :].unsqueeze(0),V_[2,1, :].unsqueeze(0)), dim =0)  #(n+4, hidden_dim)

        shorten_kernel_0 = self.V_dynamic_0(V_0.unsqueeze(0)).permute(0,2,1)   #(1, k, n)
        shorten_kernel_1 = self.V_dynamic_1(V_1.unsqueeze(0).permute(0,2,1))    #(1, k, n)
        shorten_kernel_2 = self.V_dynamic_2(V_2.unsqueeze(0).permute(0,2,1))    #(1, k, n)

        shorten_kernel = torch.cat((shorten_kernel_0, shorten_kernel_1, shorten_kernel_2), dim = 0)  #(3, k, n)

        outputs = torch.bmm(shorten_kernel, V_)  # (num_heads, k, n)  *  (num_heads, n, hidden_dim) = (num_heads, k, hidden_dim)

        # Restore shape
        outputs = outputs.transpose(0,2).transpose(0,1)    #(k, hidden_dim, num_heads)
        outputs = self.head_communicate(outputs).transpose(0,2).transpose(1,2)   #(1, k, hidden_dim)

        outputs = outputs.squeeze(0)

        return outputs

class Target_Aware_Self_Attention_Block(nn.Module):
    def __init__(self,
                C_out,
                C_in,
                num_heads = 1,
                dropout = 0,
                length_out = 0):
        super(Target_Aware_Self_Attention_Block, self).__init__()
        self.length_out = length_out
        self.attention = Target_Aware_Self_Attention_Layer(C_out, C_in, num_heads, dropout, self.length_out)
        self.target_attention = nn.Sequential(
            nn.Linear(64, C_out),
            nn.ReLU(),
            nn.Linear(C_out, C_out),
            nn.ReLU(),
        )

    def forward(self, input, target):

        input = self.attention(input)
        target_attention = self.target_attention(target)
        output = input * target_attention
        return output

class Navigation_Graph_Embedding(nn.Module):
    def __init__(self,
                hidden_dim,
                C_in,
                num_heads = 1,
                dropout = 0,
                nav_length = 27):
        super(Navigation_Graph_Embedding, self).__init__()
        self.graph = torch.zeros(nav_length, C_in)
        self.self_attention_1 = Target_Aware_Self_Attention_Block(hidden_dim, C_in, num_heads, dropout, length_out = int(nav_length/9))
        self.outlinear = nn.Sequential(
            nn.Linear(3*hidden_dim, hidden_dim),
            nn.ReLU(),
        )
        self.layer1_pool = nn.AdaptiveAvgPool1d(1)
        self.layer2_pool = nn.AdaptiveAvgPool1d(1)

    def forward(self, input, target):    #input (n, 16)

        graph = self.graph.to(target.device)
        graph[:input.shape[0], :] = input
        graph = self.self_attention_1(graph, target)   #(3, hidden_dim)
        output_layer1 = self.layer1_pool(graph.t().unsqueeze(0)).squeeze(0).t()
        graph = graph.split(split_size=1, dim=0)
        output = torch.cat(graph, dim=1)         #（1, 3*hidden_dim)
        output = self.outlinear(output)
        output = output + output_layer1

        return output   #(1,hidden_dim)

class Multihead_Attention(nn.Module):
    """
    multihead_attention
    """

    def __init__(self,
                 hidden_dim,
                 C_q=None,
                 C_k=None,
                 num_heads=1,
                 dropout_rate=0.0):
        super(Multihead_Attention, self).__init__()
        self.hidden_dim = hidden_dim
        C_q = C_q if C_q else hidden_dim
        C_k = C_k if C_k else hidden_dim
        self.linear_Q = nn.Linear(C_q, hidden_dim)
        self.linear_K = nn.Linear(C_k, hidden_dim)
        self.num_heads = num_heads
        self.dropout = nn.Dropout(p=dropout_rate)
        self.linear_out = nn.Linear(num_heads, 1)

    def forward(self,
                Q, K):
        """
        :param Q: A 3d tensor with shape of [T_q, C_q]
        :param K: A 3d tensor with shape of [T_k, C_k]
        :param V: A 3d tensor with shape of [T_v, C_v]
        :return:
        """
        num_heads = self.num_heads
        N = 1                                           #batch
        Q = Q.unsqueeze(dim = 0)
        K = K.unsqueeze(dim = 0)

        # Linear projections
        Q_l = nn.ReLU()(self.linear_Q(Q))
        K_l = nn.ReLU()(self.linear_K(K))

        # Split and concat
        Q_split = Q_l.split(split_size=self.hidden_dim // num_heads, dim=2)
        K_split = K_l.split(split_size=self.hidden_dim // num_heads, dim=2)

        Q_ = torch.cat(Q_split, dim=0)  # (h*N, T_q, C/h)
        K_ = torch.cat(K_split, dim=0)  # (h*N, T_k, C/h)

        # Multiplication
        outputs = torch.bmm(Q_, K_.transpose(2, 1))    #(h*N, T_q(1), T_k)

        # Scale
        outputs = outputs / (K_.size()[-1] ** 0.5)

        # Dropouts
        outputs = self.dropout(outputs)
        outputs = outputs.split(N, dim=0)
        outputs = torch.cat(outputs, dim=1)  #(1, num_heads, num_point)
        outputs = outputs.transpose(1,2)     #(1, num_point, num_heads)
        outputs = self.linear_out(outputs)   ##(1, num_point, 1)
        outputs = nn.Softmax(dim=1)(outputs).squeeze(dim=0)

        return outputs

class DAT(torch.nn.Module):
    def __init__(self, args):
        action_space = args.action_space
        self.num_cate = args.num_category
        resnet_embedding_sz = args.hidden_state_sz
        hidden_state_sz = args.hidden_state_sz
        super(DAT, self).__init__()

        self.image_size = 300
        self.conv1 = nn.Conv2d(resnet_embedding_sz, 64, 1)

        self.action_at_a = nn.Parameter(torch.tensor([0.0, 0.0, 0.0, 0.0, 0.0, 1.0]), requires_grad=False)
        self.action_at_b = nn.Parameter(torch.tensor([1.0, 1.0, 1.0, 1.0, 1.0, 0.0]), requires_grad=False)
        self.action_at_scale = nn.Parameter(torch.tensor(0.58), requires_grad=False)
        self.graph_detection_feature = nn.Sequential(
            nn.Linear(262, 128),
            nn.ReLU(),
            nn.Linear(128, 49),
        )

        self.embed_action = nn.Linear(action_space, 10)

        self.nav_embedding_dim = 32
        pointwise_in_channels = 64 + self.num_cate + 10 + self.nav_embedding_dim

        self.pointwise = nn.Conv2d(pointwise_in_channels, 64, 1, 1)

        self.lstm_input_sz = 7 * 7 * 64

        self.hidden_state_sz = hidden_state_sz
        self.lstm = nn.LSTM(self.lstm_input_sz, hidden_state_sz, 2)
        num_outputs = action_space
        self.critic_linear_1 = nn.Linear(hidden_state_sz, 64)
        self.critic_linear_2 = nn.Linear(64, 1)
        self.actor_linear = nn.Linear(hidden_state_sz, num_outputs)

        self.apply(weights_init)
        relu_gain = nn.init.calculate_gain("relu")
        self.conv1.weight.data.mul_(relu_gain)

        self.actor_linear.weight.data = norm_col_init(
            self.actor_linear.weight.data, 0.01
        )
        self.actor_linear.bias.data.fill_(0)

        self.critic_linear_1.weight.data = norm_col_init(
            self.critic_linear_1.weight.data, 1.0
        )
        self.critic_linear_1.bias.data.fill_(0)
        self.critic_linear_2.weight.data = norm_col_init(
            self.critic_linear_2.weight.data, 1.0
        )
        self.critic_linear_2.bias.data.fill_(0)

        self.lstm.bias_ih_l0.data.fill_(0)
        self.lstm.bias_ih_l1.data.fill_(0)
        self.lstm.bias_hh_l0.data.fill_(0)
        self.lstm.bias_hh_l1.data.fill_(0)
        self.dropout_rate = 0.35
        self.dropout = nn.Dropout(p=self.dropout_rate)
        self.info_embedding = nn.Linear(5,49)

        self.target_object_attention = torch.nn.Parameter(torch.FloatTensor(self.num_cate, self.num_cate), requires_grad=True)
        self.target_object_attention.data.fill_(1/22)

        self.scene_object_attention = torch.nn.Parameter(torch.FloatTensor(4, self.num_cate, self.num_cate), requires_grad=True)
        self.scene_object_attention.data.fill_(1/22)

        self.attention_weight = torch.nn.Parameter(torch.FloatTensor(2), requires_grad=True)
        self.attention_weight.data.fill_(1/2)

        self.avgpool = nn.AdaptiveAvgPool2d((1,1))    #(64,7,7) -> (64,1,1)

        self.muti_head_attention = Multihead_Attention(hidden_dim = 512, C_q = resnet_embedding_sz + 64, C_k = 262, num_heads = 8, dropout_rate = 0.3)
        self.conf_threshod = 0.6

        self.num_cate_embed = nn.Sequential(
            nn.Linear(self.num_cate, 32),
            nn.ReLU(),
            nn.Linear(32, 64),
            nn.ReLU(),
        )

        self.nav_dim = args.nav_dim
        self.nav_length = args.nav_length

        self.linear_graph = nn.Sequential(
            nn.Linear(self.nav_dim + 2, 16),
            nn.ReLU(),
        )

        self.coord_dim = 6

        self.norm  = nn.LayerNorm(pointwise_in_channels)
        self.target_attent_coord = nn.Sequential(
            nn.Linear(64, 32),
            nn.ReLU(),
            nn.Linear(32, 32),
            nn.ReLU(),
        )

        self.navgraph_embedding = Navigation_Graph_Embedding(hidden_dim = self.nav_embedding_dim, C_in = 16, num_heads = 3, dropout = 0, nav_length = self.nav_length)

    def one_hot(self, spa):

        y = torch.arange(spa).unsqueeze(-1)
        y_onehot = torch.FloatTensor(spa, spa)

        y_onehot.zero_()
        y_onehot.scatter_(1, y, 1)

        return y_onehot   ## (22,22)

    def get_coord(self, coord, start_coord):

        if start_coord['horizon'] == -10:
            start_coord['x'] = coord.x
            start_coord['y'] = coord.y
            start_coord['rotation'] = coord.rotation * math.pi/180
            start_coord['horizon'] = coord.horizon * math.pi/180

        x = coord.x - start_coord['x']
        y = coord.y - start_coord['y']
        rotate = coord.rotation * math.pi/180 - start_coord['rotation']
        horizon = coord.horizon * math.pi/180

        coord = torch.tensor([x, y, rotate, horizon])
        return coord, start_coord

    def coord_centring(self, navgraph, coord):
        navgraph_copy = torch.zeros(navgraph.shape[0], self.nav_dim + 2).to(navgraph.device)
        nav_coord = navgraph[:,5: 7]
        rotation = navgraph[:,7]
        horizon = navgraph[:,8]

        navgraph_copy[:,: 5] = navgraph[:,: 5]
        navgraph_copy[:,5: 7] = nav_coord - coord[:2]
        navgraph_copy[:,7] = torch.sin(rotation - coord[2])
        navgraph_copy[:,8] = torch.cos(rotation - coord[2])
        navgraph_copy[:,9] = torch.sin(horizon - coord[3])
        navgraph_copy[:,10] = torch.cos(horizon - coord[3])

        return navgraph_copy

    def embedding(self, state, target, action_embedding_input, target_object, nav_graph, coord, start_coord):

        at_v = torch.mul(target['scores'].unsqueeze(dim=1), target['indicator'])
        at = torch.mul(torch.max(at_v), self.action_at_scale)
        action_at = torch.mul(at, self.action_at_a) + self.action_at_b

        #Search Thinking Network
        target_object = target['indicator']

        action_embedding = F.relu(self.embed_action(action_embedding_input))
        action_reshaped = action_embedding.view(1, 10, 1, 1).repeat(1, 1, 7, 7)

        image_embedding = F.relu(self.conv1(state))

        x = self.dropout(image_embedding)

        target_appear = target['features']
        target_conf = target['scores'].unsqueeze(dim=1)
        target_bbox = target['bboxes'] / self.image_size

        target = torch.cat((target_appear, target_bbox, target_conf, target_object), dim=1)

        target_object_attention = F.softmax(self.target_object_attention, 0)

        attention_weight = F.softmax(self.attention_weight, 0)

        object_attention = target_object_attention * attention_weight[0]

        object_select = torch.sign(target_conf - 0.6)  #(22,1)
        object_select[object_select > 0] = 0
        object_select[object_select < 0] = - object_select[object_select < 0]   #(1,22)
        object_select_appear = object_select.squeeze().expand(262, 22).bool()
        target_mutiHead = target.masked_fill(object_select_appear.t(),0)

        image_object_attention = self.avgpool(state).squeeze(dim = 2).squeeze(dim = 0).t()   #(1,512)
        spa = self.one_hot(self.num_cate).to(target.device)
        num_cate_index = torch.mm(spa.t(), target_object).t()
        num_cate_index = self.num_cate_embed(num_cate_index)
        image_object_attention = torch.cat((image_object_attention, num_cate_index), dim = 1)  #(1,512+64=576)
        image_object_attention = self.muti_head_attention(image_object_attention, target_mutiHead)

        target_attention= torch.mm(object_attention, target_object)
        target_attention = target_attention + image_object_attention * attention_weight[1]

        target = F.relu(self.graph_detection_feature(target))
        target = target * target_attention
        target_embedding = target.reshape(1, self.num_cate, 7, 7)
        target_embedding = self.dropout(target_embedding)

        #Navigation Thinking Network
        coord, start_coord = self.get_coord(coord, start_coord)
        coord = coord.to(target.device)

        target_bbox = torch.mm(target_bbox.t(), target_object).t()

        nav_node = torch.zeros(1,self.nav_dim).to(target.device)
        nav_node[:,:4] = target_bbox
        nav_node[:,4] = at
        nav_node[:,5: 5 + 4] = coord

        if at/self.action_at_scale > 0.4:
            if nav_graph.sum() == 0:
                nav_graph = nav_node
            else:
                if nav_graph.shape[0] < self.nav_length:
                    nav_graph = torch.cat((nav_graph, nav_node), dim = 0)
                else:
                    nav_graph = torch.cat((nav_graph[1:, :], nav_node), dim = 0)

        if nav_graph.sum() == 0:
            nav_graph_mean = torch.zeros(1 ,self.nav_embedding_dim, 7, 7).to(target.device)    # (1, 32)
        else:
            nav_graph_center = self.coord_centring(nav_graph, coord)

            nav_graph_embeded = self.linear_graph(nav_graph_center)  #  (n, 11) -> (n, 16)

            nav_graph_embeded = self.navgraph_embedding(nav_graph_embeded, num_cate_index)   #(n, 16) -> (1, 32)

            nav_graph_mean = nav_graph_embeded.view(1, self.nav_embedding_dim, 1, 1).repeat(1, 1, 7, 7)  #  (1, 32, 7, 7)
            nav_graph_mean = self.dropout(nav_graph_mean)

        #Adaptive Fusion
        x = torch.cat((x, target_embedding, action_reshaped, nav_graph_mean), dim=1)

        x = self.norm(x.permute(0,2,3,1)).permute(0,3,1,2)
        x = F.relu(self.pointwise(x))
        x = self.dropout(x)
        out = x.view(x.size(0), -1)

        return out, image_embedding, action_at, nav_graph, start_coord

    def a3clstm(self, embedding, prev_hidden_h, prev_hidden_c):

        embedding = embedding.reshape([1, 1, self.lstm_input_sz])
        output, (hx, cx) = self.lstm(embedding, (prev_hidden_h, prev_hidden_c))

        x = output.reshape([1, self.hidden_state_sz])

        actor_out = self.actor_linear(x)
        critic_out = self.critic_linear_1(x)
        critic_out = self.critic_linear_2(critic_out)

        return actor_out, critic_out, (hx, cx)

    def forward(self, model_input, model_options):
        coord = model_input.coord
        start_coord = model_input.start_coord
        nav_graph = model_input.nav_graph
        target_object = model_input.target_object

        state = model_input.state
        (hx, cx) = model_input.hidden

        target = model_input.target_class_embedding
        action_probs = model_input.action_probs

        x, image_embedding , action_at,  nav_graph, start_coord= self.embedding(state, target, action_probs, target_object, nav_graph, coord, start_coord)
        actor_out, critic_out, (hx, cx) = self.a3clstm(x, hx, cx)
        actor_out = torch.mul(actor_out, action_at)
        return ModelOutput(
            value=critic_out,
            logit=actor_out,
            hidden=(hx, cx),
            embedding=image_embedding,
            nav_graph = nav_graph,
            start_coord = start_coord
        )


import GUI
from GUI.MovieWindow import MovieWindow
from pyforms import BaseWidget
from pyforms.Controls import ControlList, ControlText, ControlButton

# TO DO: write specifications

class MovieListWindow(BaseWidget):
    """
    This applications is a GUI implementation of the People class
    """

    def __init__(self, movieController, rentalController):
        # MovieController.__init__(self, R)
        BaseWidget.__init__(self, 'Movie')
        # Definition of the forms fields2
        self._searchInput = ControlText("Search")
        self._searchButton = ControlButton("Go")
        self._formset = [
            ('_searchInput',
             ('_searchButton')),
            ("_movieList")
        ]

        self._movieList = ControlList('Movies',
                                      plusFunction=self.__addPersonBtnAction,
                                      minusFunction=self.__removeMovieBtnAction)
        self.__controller = movieController
        self.__rentalController = rentalController
        data = [[x.id, x.title, x.description, x.genre] for x in self.__controller.getAllMovies()]
        self._movieList.value += data
        self._movieList.selectEntireRow = True
        self._movieList.readOnly = True
        self._movieList.horizontalHeaders = ['Id', 'Title', 'Description', 'Genre']
        self._movieList.cellDoubleClicked = self.updateMovieAction
        self._searchButton.value = self.searchData

    def updateMovieAction(self, row, item):
        win = MovieWindow(False)
        win.getData(*self._movieList.value[row])
        win.parent = self
        win.show()

    def __addPersonBtnAction(self):
        """
        Add person button event.
        """
        # A new instance of the PersonWindow is opened and shown to the user.
        win = MovieWindow(True)
        win.parent = self
        win.show()

    def addMovie(self, id, title, description, genre):
        self.__controller.addMovie(id, title, description, genre)
        self.renderData()

    def updateMovie(self, id, title, description, genre):
        self.__controller.updateMovie(id, title, description, genre)
        self.renderData()

    def __removeMovieBtnAction(self):
        """
        Remove movie button event
        """
        # self.removePerson(self._peopleList.selected_row_index)
        if len(self._movieList.mouseSelectedRowsIndexes) == 1:
            self.__controller.removeMovie(int(self._movieList.value[self._movieList.mouseSelectedRowIndex][0]))
            self.__rentalController.removeAllAppOfMovie(self._movieList.value[self._movieList.mouseSelectedRowIndex][0])
        else:
            for i in self._movieList.mouseSelectedRowsIndexes:
                self.__controller.removeMovie(int(self._movieList.value[i][0]))
                self.__rentalController.removeAllAppOfMovie(self._movieList.value[i][0])
        self.renderData()
        # Execute the application

    def renderData(self):
        data = [[x.id, x.title, x.description, x.genre] for x in GUI.MainApp.MainApp.movieController.getAllMovies()]
        self._movieList.value = data

    def searchData(self):
        self.renderData()
        data = self._movieList.value
        search = self._searchInput.value
        values = []
        if len(search.strip()) == 0:
            self.renderData()
            return
        for d in data:
            for l in d:
                if search.strip().lower() in l.lower():
                    values.append(d)
                    break
        self._movieList.value = values


import cv2 as cv
import numpy as np
import google_streetview.api as gsv
import matplotlib.pyplot as plt
import math

# enter venv : > src/Scripts/activate

# feature match params

sift = cv.SIFT_create()

FLANN_INDEX_KDTREE = 0
index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
search_params = dict(checks=50)

flann = cv.FlannBasedMatcher(index_params, search_params)

# get key

f = open('MapRH/key.txt', 'r')
API_KEY = f.read()

# find near addresses

def iter_string(string, p):
	fstword = string.split()[0]

	remaining = ""

	for i in range (1, len(string.split())):
		remaining = remaining + " " + string.split()[i]

	fstword = str(int(fstword) + p)

	reconst = fstword + remaining

	return reconst

# get the coordinates of the images

def get_c(r1, r2):
	k = ['date', 'location', 'pano_id', 'status']

	for i, kv in enumerate(r1.metadata[:10]):
		for ki in k:
			if ki in kv:
				if ki == 'location':
					cl1 = [kv[ki]['lng'], kv[ki]['lat']]

	for i, kv in enumerate(r2.metadata[:10]):
		for ki in k:
			if ki in kv:
				if ki == 'location':
					cl2 = [kv[ki]['lng'], kv[ki]['lat']]

	return cl1, cl2

# calculate distance between coordinates

def c_dist(c1, c2):
	long1, lat1 = c1[0], c1[1]
	long2, lat2 = c2[0], c2[1]

	R = 6317

	phi1 = lat1 * math.pi / 180
	phi2 = lat2 * math.pi / 180
	d_phi = (lat2 - lat1) * math.pi / 180
	d_lam = (long2 - long1) * math.pi / 180

	a = math.sin(d_phi/2) * math.sin(d_phi/2) + math.cos(phi1) * math.cos(phi2) * math.sin(d_lam/2) * math.sin(d_lam/2)
	c = 2*math.atan2(math.sqrt(a), math.sqrt(1 - a))
	d = R * c * 1000

	return d

# get single image

def get_image(loc, heading, pitch, name):

	params = [{
		'size': '480x480', # max 640x640 pixels
		'location': loc,
		'heading': heading,
		'pitch': pitch,
		'key': API_KEY
	}]

	results = gsv.results(params)

	for i, url in enumerate(results.links):
		if results.metadata[i]['status'] == 'OK':
			file_path = 'MapRH/Images/' + name + '.jpg'
			gsv.helpers.download(url, file_path)

	return results

# get all images

def get_scene(loc):
	res = []

	locs = [iter_string(loc, 2), iter_string(loc, 4)]
	count = 0

	for l in locs:
		res.append(get_image(l, 157, 0, str(count)))
		count = count + 1

	c1, c2 = get_c(res[0], res[1])
	return c_dist(c1, c2)

def draw_pts(img, pts):
	img_out = img
	for pt in pts:
		x = pt[0]
		y = pt[1]

		img_out = cv.circle(img_out, (int(x), int(y)), radius=5, color=(0, 255, 0), thickness=3)

	return img_out

# pixel disparity

def disp(x1, x2):
    return abs(x1 - x2)

# 3D coordinate calculation

def pt(pL, pR):
    u_l, v_l = pL[0], pL[1]
    u_r, v_r = pR[0], pR[1]

    d = disp(u_l, u_r)

    x = (b/d) * (u_l - im1.shape[0]/2)
    y = (b/d)  * (v_l - im1.shape[1]/2)
    z = (b/d) * 100

    return [x, y, z]

b = get_scene('ENTER ADDRESS HERE') #c_dist([43.6684822,-79.3950423], [43.6685049,-79.394918])

# load images and detect matching points

im1 = cv.imread('MapRH/Images/0.jpg')
im2 = cv.imread('MapRH/Images/1.jpg')

pts_1, desc_1 = sift.detectAndCompute(im1, None)
pts_2, desc_2 = sift.detectAndCompute(im2, None)

matches = flann.knnMatch(desc_1, desc_2, k=2)

masked_1_pts = []
masked_2_pts = []

lowe_coeff = 0.8

for i0, (m0,n0) in enumerate(matches):
    if m0.distance < lowe_coeff * n0.distance:
        masked_2_pts.append(pts_2[m0.trainIdx].pt)
        masked_1_pts.append(pts_1[m0.queryIdx].pt)

masked_1_pts = np.int32(masked_1_pts)
masked_2_pts = np.int32(masked_2_pts)

F, mask = cv.findFundamentalMat(masked_1_pts, masked_2_pts, cv.FM_LMEDS)

masked_1_pts = masked_1_pts[mask.ravel()==1]
masked_2_pts = masked_2_pts[mask.ravel()==1]

# calculate x, y, z values

pts_3D = []

for p in range (len(masked_1_pts[:, 0])):
    pt_3D = pt(masked_1_pts[p, :], masked_2_pts[p, :])
    pts_3D.append(pt_3D)

pts_3D = np.double(pts_3D)

# plot on x, y, z axes

fig = plt.figure()
ax = plt.axes(projection='3d')

ax.scatter3D(pts_3D[:, 0], pts_3D[:, 1], pts_3D[:, 2], 'gray')
# ax.set_zlim(0, max(pts_3D[:, 2]) + 0.2)
# ax.set_ylim(min(pts_3D[:, 1]) - 0.1, max(pts_3D[:, 1]) + 0.1)
# ax.set_xlim(min(pts_3D[:, 0]) - 0.1, max(pts_3D[:, 0]) + 0.1)

plt.show()

# pt_im1 = draw_pts(im1, masked_1_pts)
# pt_im2 = draw_pts(im2, masked_2_pts)

# plt.imshow(pt_im2)
# plt.show()


from datetime import datetime
from bson.tz_util import FixedOffset
from bson.regex import Regex
import unidecode

class Produtos:
    connection = None
    def __init__(self, connection):
        self.connection = connection
        self.database = self.connection['DigisatServer']
        self.collection_movimentacoes = self.database["Movimentacoes"]
        self.collection_produtos_servicos = self.database["ProdutosServicos"]
        self.collection_pessoas = self.database["Pessoas"]

    def get_prods(self):
        query = {"Ativo": True, "CamposPersonalizado": {u"$exists": True}}
        cursor = self.collection_produtos_servicos.find(query)
        produtos = []
        try:
            for doc in cursor:
                produto = {
                    'codigo': doc['CodigoInterno'],
                    'descricao': doc['Descricao'],
                    'marca': '',
                    'produto': False,
                    'tipo': False,
                    'classe': False,
                    'especie': False,
                    'percentual': False,
                    'safra': False,
                    'unidade': doc['UnidadeMedida']['Sigla']
                }
                if 'Marca' in doc:
                        produto['Marca'] = doc['Marca']['Descricao']

                if 'CamposPersonalizado' in doc:
                    for campo in doc['CamposPersonalizado']:
                        if campo['TipoPersonalizado']['Ativo'] is True:
                            campo_desc = unidecode.unidecode(campo['TipoPersonalizado']['Descricao']).lower()
                            if  campo_desc == 'codigo_sisdevin' and campo['Valor'] != '':
                                produto['codigo'] = campo['Valor']

                            if  campo_desc == 'produto' and campo['Valor'] != '':
                                produto['produto'] = campo['Valor']

                            if campo_desc == 'tipo' and campo['Valor'] != '':
                                produto['tipo'] = campo['Valor']

                            if campo_desc == 'classe' and campo['Valor'] != '':
                                produto['classe'] = campo['Valor']

                            if campo_desc == 'especie' and campo['Valor'] != '':
                                produto['especie'] = campo['Valor']

                            if campo_desc == 'percentual' and campo['Valor'] != '':
                                produto['percentual'] = campo['Valor']

                            if campo_desc == 'safra' and campo['Valor'] != '':
                                produto['safra'] = campo['Valor']

                if produto not in produtos and False not in produto.values():
                    produtos.append(produto)
        finally:
            return produtos

    def get_notas(self):
        produtos = []
        gte, lte = self.get_period()
        query = {
            "DataHoraEmissao": {
                u"$gte": gte,
                u"$lte": lte
            },
            "$or": [
                {
                    u"_t": Regex(u".*NotaFiscalEletronicaSaida.*", "i")
                },
                {
                    u"_t": Regex(u".*NotaFiscalConsumidorEletronica.*", "i")
                }
            ],
            "Situacao.Codigo": {
                u"$not": {
                    u"$in": [
                        1,
                        4,
                        12
                    ]
                }
            }
        }

        cursor = self.collection_movimentacoes.find(query)
        notas = []

        for doc in cursor:
            if 'NotaFiscalConsumidorEletronica' in doc['_t']:
                tipo = 2
            elif 'NotaFiscalEletronicaSaida' in doc['_t']:
                tipo = 1
            else:
                tipo = 3

            if 'EnderecoPrincipal' not in doc['Pessoa']:
                pessoa = self.collection_pessoas.find_one({'_id': doc['Pessoa']['PessoaReferencia']})
                pessoa = pessoa['Carteira']
            else:
                pessoa = doc['Pessoa']

            nota = {
                'mes':doc['DataHoraEmissao'].month,
                'ano': doc['DataHoraEmissao'].year,
                'operacao': '01',
                'numero': doc['Numero'],
                'uf': pessoa['EnderecoPrincipal']['Municipio']['Uf']['Sigla'],
                'tipo': tipo,
                'serie': doc['Serie'],
                'itens': []
            }

            for item in doc['ItensBase']:
                prod = self.collection_produtos_servicos.find_one({'_id': item['ProdutoServico']['ProdutoServicoReferencia']})
                valid = self.is_prod_valid(prod)
                if valid:
                    prod_valid = {
                        'produto': '',
                        'embalagem': '',
                        'litros': ''
                    }
                    for campo in prod['CamposPersonalizado']:
                        if campo['TipoPersonalizado']['Ativo'] is True:
                            campo_desc = unidecode.unidecode(campo['TipoPersonalizado']['Descricao']).lower()
                            if  campo_desc == 'codigo_sisdevin' and campo['Valor'] != '':
                                prod_valid['produto'] = campo['Valor']

                            if  campo_desc == 'embalagem' and campo['Valor'] != '':
                                prod_valid['embalagem'] = campo['Valor']

                            if  campo_desc == 'quantidade_baixar' and campo['Valor'] != '':
                                prod_valid['litros'] = item['Quantidade'] * campo['Valor']
                    nota['itens'].append(prod_valid)
            if nota['itens']:
                notas.append(nota)
        return notas

    def is_prod_valid(self, doc):
        cont = 0
        campos = ['codigo_sisdevin', 'embalagem', 'quantidade_baixar']
        if 'CamposPersonalizado' in doc:
            for campo in doc['CamposPersonalizado']:
                if campo['TipoPersonalizado']['Ativo'] is True:
                    campo_desc = unidecode.unidecode(campo['TipoPersonalizado']['Descricao']).lower()
                    for x in campos:
                        if campo_desc == x and campo['Valor'] != '':
                            cont += 1
            if cont == len(campos):
                return True
            else:
                return False
        else:
            return False

    def get_period(self):
        date = datetime.now()
        try:
            date_initial = input('Digite a data inicial no seguinte formato DIA-MES-ANO, exemplo {0}-{1}-{2}: '.format(date.day, date.month, date.year))
            gte = datetime.strptime("{0} 00:00:00.000000".format(date_initial), "%d-%m-%Y %H:%M:%S.%f").replace(tzinfo = FixedOffset(-180, "-0300"))
        except:
            print('Data inicial ou formato, incorreto, vamos tentar de novo')
            gte, lte = self.get_period()

        try:
            date_ended = input('Digite a data final no seguinte formato DIA-MES-ANO, exemplo {0}-{1}-{2}: '.format(date.day, date.month, date.year))
            lte = datetime.strptime("{0} 23:59:59.000000".format(date_ended), "%d-%m-%Y %H:%M:%S.%f").replace(tzinfo = FixedOffset(-180, "-0300"))
        except:
            print('Data final invalida ou formato, incorreto, vamos tentar de novo')
            gte, lte = self.get_period()
        return gte, lte


import torch
import torch.nn.functional as F
from torch import nn, einsum
from torch.optim import Adam

from einops import rearrange, repeat
import sidechainnet as scn
from invariant_point_attention import IPATransformer

BATCH_SIZE = 1
GRADIENT_ACCUMULATE_EVERY = 16

def cycle(loader, len_thres = 200):
    while True:
        for data in loader:
            if data.seqs.shape[1] > len_thres:
                continue
            yield data

net = IPATransformer(
    dim = 16,
    num_tokens = 21,
    depth = 5,
    require_pairwise_repr = False,
    predict_points = True
).cuda()

data = scn.load(
    casp_version = 12,
    thinning = 30,
    with_pytorch = 'dataloaders',
    batch_size = BATCH_SIZE,
    dynamic_batching = False
)

dl = cycle(data['train'])
optim = Adam(net.parameters(), lr=1e-3)

for _ in range(10000):
    for _ in range(GRADIENT_ACCUMULATE_EVERY):
        batch = next(dl)
        seqs, coords, masks = batch.seqs, batch.crds, batch.msks

        seqs = seqs.cuda().argmax(dim = -1)
        coords = coords.cuda()
        masks = masks.cuda().bool()

        l = seqs.shape[1]
        coords = rearrange(coords, 'b (l s) c -> b l s c', s = 14)

        # Keeping only the Ca atom

        coords = coords[:, :, 1, :]
        noised_coords = coords + torch.randn_like(coords)

        denoised_coords = net(
            seqs,
            translations = noised_coords,
            mask = masks
        )

        loss = F.mse_loss(denoised_coords[masks], coords[masks])
        (loss / GRADIENT_ACCUMULATE_EVERY).backward()

    print('loss:', loss.item())
    optim.step()
    optim.zero_grad()


"""
@file
@brief Helpers to convert docstring to various format.
"""
import re
import textwrap
import os
from io import StringIO
from docutils import core, languages
from docutils.io import StringInput, StringOutput
from .utils_sphinx_doc import migrating_doxygen_doc
from .helpgen_exceptions import HelpGenConvertError
from ..texthelper.texts_language import TITLES
from ..loghelper.flog import noLOG

def default_sphinx_options(fLOG=noLOG, **options):
    """
    Defines or overrides default options for :epkg:`Sphinx`, listed below.

    .. runpython::

        from pyquickhelper.helpgen.rst_converters import default_sphinx_options
        options = default_sphinx_options()
        for k, v in sorted(options.items()):
            print("{0} = {1}".format(k, v))

    :epkg:`latex` is not available on :epkg:`Windows`.
    """
    # delayed import to speed up time
    from .conf_path_tools import find_graphviz_dot, find_dvipng_path

    res = {  # 'output_encoding': options.get('output_encoding', 'unicode'),
        # 'doctitle_xform': options.get('doctitle_xform', True),
        # 'initial_header_level': options.get('initial_header_level', 2),
        # 'input_encoding': options.get('input_encoding', 'utf-8-sig'),
        'blog_background': options.get('blog_background', False),
        'sharepost': options.get('sharepost', None),
        'todoext_link_only': options.get('todoext_link_only', False),
        'mathdef_link_only': options.get('mathdef_link_only', True),
        'blocref_link_only': options.get('blocref_link_only', False),
        'faqref_link_only': options.get('faqref_link_only', False),
        'nbref_link_only': options.get('nbref_link_only', False),
        'todo_link_only': options.get('todo_link_only', False),
        'language': options.get('language', 'en'),
        # 'outdir': options.get('outdir', '.'),
        # 'imagedir': options.get('imagedir', '.'),
        # 'confdir': options.get('confdir', '.'),
        # 'doctreedir': options.get('doctreedir', '.'),
        'math_number_all': options.get('math_number_all', False),
        # graphviz
        'graphviz_output_format': options.get('graphviz_output_format', 'png'),
        'graphviz_dot': options.get('graphviz_dot', find_graphviz_dot(exc=False)),
        # latex
        'imgmath_image_format': options.get('imgmath_image_format', 'png'),
        # containers
        'out_blogpostlist': [],
        'out_runpythonlist': [],
        # 'warning_stream': StringIO(),
    }

    if res['imgmath_image_format'] == 'png':
        try:
            imgmath_latex, imgmath_dvipng, imgmath_dvisvgm = find_dvipng_path(
                exc=False)
            has_latex = True
        except FileNotFoundError:
            # miktex is not available,
            has_latex = False

        if has_latex:
            res['imgmath_latex'] = imgmath_latex
            res['imgmath_dvipng'] = imgmath_dvipng
            res['imgmath_dvisvgm'] = imgmath_dvisvgm

    for k, v in options.items():
        if k not in res:
            res[k] = v

    return res

def rst2html(s, fLOG=noLOG, writer="html", keep_warnings=False,
             directives=None, language="en",
             layout='docutils', document_name="<<string>>",
             external_docnames=None, filter_nodes=None,
             new_extensions=None, update_builder=None,
             ret_doctree=False, destination=None, destination_path=None,
             **options):
    """
    Converts a string from :epkg:`RST`
    into :epkg:`HTML` format or transformed :epkg:`RST`.

    @param      s                   string to convert
    @param      fLOG                logging function (warnings will be logged)
    @param      writer              ``'html'`` for :epkg:`HTML` format,
                                    ``'rst'`` for :epkg:`RST` format,
                                    ``'md'`` for :epkg:`MD` format,
                                    ``'elatex'`` for :epkg:`latex` format,
                                    ``'doctree'`` to get the doctree, *writer* can also be a tuple
                                    for custom formats and must be like ``('buider_name', builder_class)``.
    @param      keep_warnings       keep_warnings in the final HTML
    @param      directives          new directives to add (see below)
    @param      language            language
    @param      layout              ``'docutils'``, ``'sphinx'``, ``'sphinx_body'``, see below.
    @param      document_name       document name, not really important since the input is a string
    @param      external_docnames   if the string to parse makes references to other documents,
                                    if one is missing, an exception is raised.
    @param      filter_nodes        transforms the doctree before writing the results (layout must be 'sphinx'),
                                    the function takes a doctree as a single parameter
    @param      new_extensions      additional extension to setup
    @param      update_builder      update the builder after it is instantiated
    @param      ret_doctree         returns the doctree
    @param      destination         set a destination (requires for some extension)
    @param      destination_path    set a destination path (requires for some extension)
    @param      options             :epkg:`Sphinx` options see
                                    `Render math as images <https://www.sphinx-doc.org/en/master/ext/math.html#module-sphinx.ext.imgmath>`_,
                                    a subset of options is used, see @see fn default_sphinx_options.
                                    By default, the theme (option *html_theme*) will ``'basic'``.
    @return                         HTML format

    *directives* is None or a list of 2 or 5-uple:

    * a directive name (mandatory)
    * a directive class: see `Sphinx Directive
      <https://www.sphinx-doc.org/en/master/development/tutorials/helloworld.html>`_,
      see also @see cl RunPythonDirective as an example (mandatory)
    * a docutils node: see @see cl runpython_node as an example
    * two functions: see @see fn visit_runpython_node, @see fn depart_runpython_node as an example

    The parameter *layout* specify the kind of HTML you need.

    * ``'docutils'``: very simple :epkg:`HTML`, style is not included, recursive
      directives are not processed (recursive means they modify the doctree).
      The produced :epkg:`HTML` only includes the body (no :epkg:`HTML` header).
    * ``'sphinx'``: in memory :epkg:`sphinx`, the produced :epkg:`HTML` includes the header, it is also recursive
      as directives can modify the doctree.
    * ``'sphinx_body'``: same as ``'sphinx'`` but only the body is returned.

    If the writer is a tuple, it must be a 2-uple ``(builder_name, builder_class)``.
    However, the builder class must contain an attribute ``_writer_class`` with
    the associated writer. The builcer class must also implement a method
    ``iter_pages`` which enumerates all written pages:
    ``def iter_pages(self) -> Dict[str,str]`` where the key is the document name
    and the value is its content.

    .. exref::
        :title: How to test a Sphinx directive?

        The following code defines a simple directive
        definedbased on an existing one.
        It also defined what to do if a new node
        is inserted in the documentation.

        ::

            from docutils import nodes
            from pyquickhelper.helpgen import rst2html

            class runpythonthis_node(nodes.Structural, nodes.Element):
                pass

            class RunPythonThisDirective (RunPythonDirective):
                runpython_class = runpythonthis_node

            def visit_node(self, node):
                self.body.append("
visit_node
")
            def depart_node(self, node):
                self.body.append("
depart_node
")

            content = '''
                        test a directive
                        ================

                        .. runpythonthis::

                            print("this code shoud appear" + "___")
                        '''.replace("                    ", "")
                        # to remove spaces at the beginning of the line

            tives = [ ("runpythonthis", RunPythonThisDirective,
                       runpythonthis_node, visit_node, depart_node) ]

            html = rst2html(content, writer="html", keep_warnings=True,
                            directives=tives)

        Unfortunately, this functionality is only tested on :epkg:`Python` 3.
        It might not work on :epkg:`Python` 2.7.
        The function produces files if the document contains latex
        converted into image.

    .. faqref::
       :title: How to get more about latex errors?
       :index: latex

        :epkg:`Sphinx` is not easy to use when it comes to debug latex expressions.
        I did not find an easy way to read the error returned by latex about
        a missing bracket or an unknown command. I finally added a short piece
        of code in ``sphinx.ext.imgmath.py`` just after the call to
        the executable indicated by *imgmath_latex*

        ::

            if b'...' in stdout or b'LaTeX Error' in stdout:
                print(self.builder.config.imgmath_latex_preamble)
                print(p.returncode)
                print("################")
                print(latex)
                print("..........")
                print(stdout.decode("ascii").replace("\\r", ""))
                print("-----")
                print(stderr)

        It displays the output if an error happened.

    .. faqref::
        :title: How to hide command line window while compiling latex?
        :lid: command line window

        :epkg:`Sphinx` calls :epkg:`latex` through command line.
        On :epkg:`Windows`, a command line window
        can annoyingly show up anytime a formula is compiled.
        The following can be added to hide it:

        ::

            startupinfo = STARTUPINFO()
            startupinfo.dwFlags |= STARTF_USESHOWWINDOW

        And ``, startupinfo=startupinfo`` must be added to lines ``p = Popen(...``.

    By default, the function now interprets :epkg:`Sphinx`
    directives and not only *docutils* ones.
    Parameter *directives* adds a directive
    before parsing the :epkg:`RST`.
    The function is more consistent.
    Format ``rst`` is available as well as
    custom builders.
    New nodes are optional in *directives*.
    Markdown format was added.
    """
    # delayed import to speed up time
    def _get_MockSphinxApp():
        from .sphinxm_mock_app import MockSphinxApp
        return MockSphinxApp
    MockSphinxApp = _get_MockSphinxApp()

    if 'html_theme' not in options:
        options['html_theme'] = 'basic'
    defopt = default_sphinx_options(**options)
    if "master_doc" not in defopt:
        defopt["master_doc"] = document_name
    if writer in ('latex', 'elatex') and 'latex_documents' not in defopt:
        latex_documents = [(document_name, ) * 5]
        defopt['latex_documents'] = latex_documents

    if writer in ["custom", "sphinx", "HTMLWriterWithCustomDirectives", "html"]:
        mockapp, writer, title_names = MockSphinxApp.create(
            "sphinx", directives, confoverrides=defopt,
            new_extensions=new_extensions,
            fLOG=fLOG, destination_path=destination_path)
        writer_name = "HTMLWriterWithCustomDirectives"
    elif writer in ("rst", "md", "latex", "elatex", 'text', 'doctree'):
        writer_name = writer
        mockapp, writer, title_names = MockSphinxApp.create(
            writer, directives, confoverrides=defopt,
            new_extensions=new_extensions,
            fLOG=fLOG, destination_path=destination_path)
    elif isinstance(writer, tuple):
        # We extect something like ("builder_name", builder_class)
        writer_name = writer
        mockapp, writer, title_names = MockSphinxApp.create(
            writer, directives, confoverrides=defopt,
            new_extensions=new_extensions,
            fLOG=fLOG, destination_path=destination_path)
    else:
        raise ValueError(
            f"Unexpected writer '{writer}', should be 'rst' or 'html' or 'md' or 'elatex' or 'text'.")

    if writer is None and directives is not None and len(directives) > 0:
        raise NotImplementedError(
            "The writer must not be null if custom directives will be added, check the documentation of the fucntion.")

    # delayed import to speed up time
    from sphinx.environment import default_settings
    settings_overrides = default_settings.copy()
    settings_overrides["warning_stream"] = StringIO()
    settings_overrides["master_doc"] = document_name
    settings_overrides["source"] = document_name
    settings_overrides["contentsname"] = document_name
    settings_overrides.update({k: v[0]
                               for k, v in mockapp.new_options.items()})

    # next
    settings_overrides.update(defopt)
    config = mockapp.config
    config.blog_background = True
    config.blog_background_page = False
    config.sharepost = None

    if hasattr(writer, "add_configuration_options"):
        writer.add_configuration_options(mockapp.new_options)
    for k in {'outdir', 'imagedir', 'confdir', 'doctreedir'}:
        setattr(writer.builder, k, settings_overrides.get(k, ''))
    if destination_path is not None:
        writer.builder.outdir = destination_path
    if update_builder:
        update_builder(writer.builder)

    env = mockapp.env
    if env is None:
        raise ValueError("No environment was built.")

    env.temp_data["docname"] = document_name
    env.temp_data["source"] = document_name
    if mockapp.builder.env is None:
        mockapp.builder.env = env
    else:
        mockapp.builder.env.temp_data["docname"] = document_name
        mockapp.builder.env.temp_data["source"] = document_name
    settings_overrides["env"] = env

    lang = languages.get_language(language)
    for name in title_names:
        if name not in lang.labels:
            lang.labels[name] = TITLES[language][name]

    for k, v in sorted(settings_overrides.items()):
        fLOG(f"[rst2html] {k}={v}{' --- added' if hasattr(config, k) else ''}")
    for k, v in sorted(settings_overrides.items()):
        if hasattr(writer.builder.config, k) and writer.builder.config[k] != v:
            writer.builder.config[k] = v

    _, pub = core.publish_programmatically(
        source=s, source_path=None, destination_path=destination_path, writer=writer,
        writer_name=writer_name, settings_overrides=settings_overrides,
        source_class=StringInput, destination_class=StringOutput,
        destination=destination, reader=None, reader_name='standalone',
        parser=None, parser_name='restructuredtext', settings=None,
        settings_spec=None, config_section=None, enable_exit_status=False)

    doctree = pub.document

    if filter_nodes is not None:
        if layout == "docutils" and writer != "doctree":
            raise ValueError(
                "filter_nodes is not None, layout must not be 'docutils'")
        filter_nodes(doctree)

    mockapp.finalize(doctree, external_docnames=external_docnames)
    parts = pub.writer.parts

    if not keep_warnings:
        if isinstance(parts["whole"], list):
            # Not html.
            exp = "".join(parts["whole"])
        else:
            exp = re.sub(
                '(
(.|\\n)*?
)', "", parts["whole"])
    else:
        if isinstance(parts["whole"], list):
            exp = "".join(parts["whole"])
        else:
            exp = parts["whole"]

    if ret_doctree:
        return doctree

    if layout == "docutils":
        return exp
    else:
        page = None
        pages = []
        main = (f"/{document_name}.m.html",
                f"/{document_name}.m.{writer_name}",
                document_name)
        if not hasattr(writer.builder, "iter_pages"):
            raise AttributeError(
                f"Class '{writer.builder}' must have a method 'iter_pages' which returns a dictionary.")
        contents = []
        for k, v in writer.builder.iter_pages():
            pages.append(k)
            contents.append(v)
            if k in main:
                page = v
                break
        if page is None and len(contents) == 1:
            page = contents[0]
        if page is None:
            raise ValueError(
                f"No page contents was produced, only '{pages}'.")
        if layout == "sphinx":
            if isinstance(page, str):
                return page
            else:
                return "\n".join(page)
        elif layout == "sphinx_body":
            lines = page.replace('', '\n').split("\n")
            keep = []
            begin = False
            for line in lines:
                s = line.strip(" \n\r")
                if s == "":
                    begin = False
                if begin:
                    keep.append(line)
                if s == "":
                    begin = True
            res = "\n".join(keep)
            return res
        else:
            raise ValueError(
                f"Unexpected value for layout '{layout}'")

def correct_indentation(text):
    """
    Tries to improve the indentation before running :epkg:`docutils`.

    @param      text        text to correct
    @return                 corrected text
    """
    title = {}
    rows = text.split("\n")
    for row in rows:
        row = row.replace("\t", "    ")
        cr = row.lstrip()
        ind = len(row) - len(cr)

        tit = cr.strip("\r\n\t ")
        if len(tit) > 0 and tit[0] in "-+=*^" and tit == tit[0] * len(tit):
            title[ind] = title.get(ind, 0) + 1

    if len(title) > 0:
        mint = min(title.keys())
    else:
        mint = 0
    if mint > 0:
        newrows = []
        for row in rows:
            i = 0
            while i < len(row) and row[i] == ' ':
                i += 1

            rem = min(i, mint)
            if rem > 0:
                newrows.append(row[rem:])
            else:
                newrows.append(row)

        return "\n".join(newrows)
    else:
        return text

def docstring2html(function_or_string, format="html", fLOG=noLOG, writer="html",
                   keep_warnings=False, directives=None, language="en",
                   layout='docutils', document_name="<<string>>",
                   filter_nodes=None, **options):
    """
    Converts a docstring into a :epkg:`HTML` format.

    @param      function_or_string      function, class, method or doctring
    @param      format                  output format (``'html'`` or '``rawhtml``')
    @param      fLOG                    logging function
    @param      writer                  ``'html'`` for :epkg:`HTML` format,
                                        ``'rst'`` for :epkg:`RST` format,
                                        ``'md'`` for :epkg:`MD` format
    @param      keep_warnings           keep_warnings in the final :epkg:`HTML`
    @param      directives              new directives to add (see below)
    @param      language                language
    @param      layout                  ``'docutils'``, ``'sphinx'``, ``'sphinx_body'``, see below.
    @param      document_name           document_name for this string
    @param      filter_nodes            transform the doctree before writing the results
                                        (layout must be 'sphinx')
    @param      options                 Sphinx options see `Render math as images
                                        <https://www.sphinx-doc.org/en/master/ext/math.html#module-sphinx.ext.imgmath>`_,
                                        a subset of options is used, see @see fn default_sphinx_options.
                                        By default, the theme (option *html_theme*) will ``'basic'``.
    @return                             (str) :epkg:`HTML` format or (IPython.core.display.HTML)

    .. exref::
        :title: Produce HTML documentation for a function or class

        The following code can display the dosstring in :epkg:`HTML` format
        to display it in a :epkg:`notebook`.

        ::

            from pyquickhelper.helpgen import docstring2html
            import sklearn.linear_model
            docstring2html(sklearn.linear_model.LogisticRegression)

    The output format is defined by:

    * ``'html'``: IPython :epkg:`HTML` object
    * ``'rawhtml'``: :epkg:`HTML` as text + style
    * ``'rst'``: :epkg:`rst`
    * ``'text'``: raw text
    """
    if not isinstance(function_or_string, str):
        doc = function_or_string.__doc__
    else:
        doc = function_or_string

    if format == "text":
        return doc

    if doc is None:
        return ""

    javadoc = migrating_doxygen_doc(doc, "None", log=False)[1]
    rows = javadoc.split("\n")
    from .utils_sphinx_doc import _private_migrating_doxygen_doc
    rst = _private_migrating_doxygen_doc(
        rows, index_first_line=0, filename="None")
    rst = "\n".join(rst)
    ded = textwrap.dedent(rst)

    try:
        html = rst2html(ded, fLOG=fLOG, writer=writer,
                        keep_warnings=keep_warnings, directives=directives,
                        language=language, filter_nodes=filter_nodes,
                        document_name=document_name,
                        layout=layout, **options)
    except Exception:
        # we check the indentation
        ded = correct_indentation(ded)
        try:
            html = rst2html(ded, fLOG=fLOG, writer=writer,
                            keep_warnings=keep_warnings, directives=directives,
                            language=language, filter_nodes=filter_nodes,
                            document_name=document_name,
                            layout=layout, **options)
        except Exception as e:
            lines = ded.split("\n")
            lines = ["%04d  %s" % (i + 1, _.strip("\n\r"))
                     for i, _ in enumerate(lines)]
            raise HelpGenConvertError(
                "Unable to process:\n{0}".format("\n".join(lines))) from e

    ret_doctree = writer == "doctree"
    if ret_doctree:
        writer = "doctree"

    if writer in ('doctree', 'rst', 'md'):
        return html

    if format == "html":
        from IPython.core.display import HTML
        return HTML(html)
    if format in ("rawhtml", 'rst', 'md', 'doctree'):
        return html
    raise ValueError(
        "Unexpected format: '{}', should be html, rawhtml, text, rst, "
        "md, doctree.".format(format))

def rst2rst_folder(rststring, folder, document_name="index", **options):
    """
    Converts a :epkg:`RST` string into simplified :epkg:`RST`.

    @param      rststring       :epkg:`rst` string
    @param      folder          the builder needs to write the resuts in a
                                folder defined by this parameter
    @param      document_name   main document
    @param      options         additional options (same as *conf.py*)
    @return                     converted string
    """
    if not os.path.exists(folder):
        raise FileNotFoundError(folder)

    new_options = {}
    new_options.update(options)

    def update_builder(builder):
        builder.outdir = folder

    rst = rst2html(rststring, writer="rst", document_name="example",
                   update_builder=update_builder, layout="sphinx",
                   **new_options)
    return rst


from typing import List

# Write any import statements here

def getSecondsRequired(N: int, F: int, P: List[int]) -> int:
    # Write your code here

    if F == 1:
        return N - P[0]

    counter = 0
    P.sort()

    while True:
        if P[0] < P[1] - 1:
            counter += P[1] - P[0] - 1
            P[0] = P[1] - 1
        else:
            # find next free slot
            pos = F
            for i in range(2, len(P)):
                if P[i] > P[i - 1] + 1:
                    pos = i
                    break
            if pos == F:
                counter += (N - P[-1]) + (F - 1)
                return counter
            else:
                offset = (P[pos] - P[pos - 1]) - 1
                counter += offset
                for i in range(pos):
                    P[i] += offset

print(getSecondsRequired(10**10, 5, [584, 78748, 225, 8885525, 55]))


#collaboratory_api/urls.py
from django.contrib import admin
from django.urls import include, path, re_path
from rest_framework import routers
from . import views
from django.views.generic.base import TemplateView
from django.conf.urls import url
from collaboratory_api.views import landing

from django.conf.urls import include, url
from collaboratory_api.views import register, landing

from .views import *

router = routers.DefaultRouter()
router.register(r'regions', views.RegionViewSet)
router.register(r'roles', views.RoleViewSet)
router.register(r'causes', views.CauseViewSet)
router.register(r'users', views.UserViewSet)
router.register(r'organizations', views.OrganizationViewSet)
router.register(r'events', views.EventViewSet)
router.register(r'channels', views.ChannelViewSet)
router.register(r'announcement', views.AnnouncementViewSet)
router.register(r'post', views.PostViewSet)

# Wire up our API using automatic URL routing.
# Additionally, we include login URLs for the browsable API.
urlpatterns = [
    # this route catches the "naked" URL with no path specified. you can link to it in most places
    path(r'dashboard/home', views.MainView.as_view(), name='react_app'),
    # this route catches any url below the main one, so the path can be passed to the front end
    path(r'dashboard/<path:path>', views.MainView.as_view(), name='react_app_with_path'),
    #login #what's the difference between path and url? path & re_path?
    url(r"^accounts/", include("django.contrib.auth.urls")),
    re_path(r'^landing', views.landing, name='landing'),
    #registration
    url(r"^register/", register, name="register"),
    #current user
    re_path(r'^currentuser/$', views.current_user),

    # Rest API + React (Working)
    path('', include(router.urls)),
    path('api-auth/', include('rest_framework.urls', namespace='rest_framework')),
    # re_path(r'^organizations/$', views.organizations_list),
    # re_path(r'^organizations/([0-9])$', views.organizations_detail),
    re_path(r'^users/$', views.users_list),
    re_path(r'^userss/([0-9])$', views.users_detail),
    re_path(r'^events/$', views.events_list),
    re_path(r'^post/$', views.posts_list),
    # this route catches the "naked" URL with no path specified. you can link to it in most places
    path(r'dashboard/home', views.MainView.as_view(), name='react_app'),
    # this route catches any url below the main one, so the path can be passed to the front end
    path(r'dashboard/<path:path>', views.MainView.as_view(), name='react_app_with_path'),
    #login #what's the difference between path and url? path & re_path?
    path('accounts/', include('django.contrib.auth.urls')),
    re_path(r'^landing', views.landing, name='landing'),
    # url(r"^landing/", landing, name="landing"),
    # url(r"^dashboard/", dashboard, name="dashboard"),

    # Search filters
    path('orgsearch/', OrganizationSearchFilter.as_view(), name = 'Organization Search'),
    path('orgfilter/', OrganizationFilterForm.as_view(), name = 'Organization Filter'),

    path('personsearch/', PersonSearchFilter.as_view(), name = 'Person Search'),

    # Discussion Post Filter
    path('postfilter/', PostFilter.as_view(), name = 'Post Filter')

]


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

import random
from django.shortcuts import render
from my_game.models import System, AsteroidField

# функция генерации астероидных полей
def asteroid_generation(request):
    if request.method == "POST" and request.POST.get('add_button') is not None:

        asteroid = int(request.POST.get('asteroid', None))
        for i in range(asteroid):
            #генерация кооржинат поля
            system = System.objects.filter().order_by('x').first()
            x_min = system.x - 10
            system = System.objects.filter().order_by('x').last()
            x_max = system.x + 10
            system = System.objects.filter().order_by('y').first()
            y_min = system.y - 10
            system = System.objects.filter().order_by('y').last()
            y_max = system.y + 10
            x = round(random.uniform(x_min, x_max), 3)
            y = round(random.uniform(y_min, y_max), 3)
            z = round(random.uniform(-30, 30), 3)

            # размер поля
            k = random.random()
            if 0.07 > k:
                size = random.randint(3000000, 5000000)
            else:
                if 0.07 <= k <= 0.2:
                    size = random.randint(1000000, 3000000)
                else:
                    if 0.2 < k < 0.8:
                        size = random.randint(500000, 1000000)
                    else:
                        size = random.randint(100000, 500000)

            #количество артефактов в поле
            k = random.random()
            if 0.02 > k:
                artifact = 5
            elif 0.02 <= k <= 0.1:
                artifact = 4
            elif 0.1 < k <= 0.2:
                artifact = 3
            elif 0.2 < k <= 0.4:
                artifact = 2
            elif 0.4 < k <= 0.7:
                artifact = 1
            else:
                artifact = 0

            # уровень обогащения поля
            k = random.random()
            if 0.05 > k:
                ore = round(random.uniform(0.8, 0.95), 3)
            elif 0.05 <= k <= 0.35:
                ore = round(random.uniform(0.799, 0.8), 3)
            else:
                ore = round(random.uniform(0.6, 0.799), 3)

            mineral_koef = round(random.uniform(0.07, 0.2), 3) * ore
            resource_koef = ore - mineral_koef

            koef_res_1 = round(round(random.uniform(0.2, 0.3), 3) * resource_koef, 3)
            koef_res_2 = round(round(random.uniform(0.2, 0.3), 3) * resource_koef, 3)
            koef_res_3 = round(round(random.uniform(0.2, 0.3), 3) * resource_koef, 3)
            koef_res_4 = round(resource_koef - (koef_res_1 + koef_res_2 + koef_res_3), 3)
            koef_min_1 = round(round(random.uniform(0.2, 0.3), 3) * mineral_koef, 3)
            koef_min_2 = round(round(random.uniform(0.2, 0.3), 3) * mineral_koef, 3)
            koef_min_3 = round(round(random.uniform(0.2, 0.3), 3) * mineral_koef, 3)
            koef_min_4 = round(mineral_koef - (koef_min_1 + koef_min_2 + koef_min_3), 3)

            asteroid_test = AsteroidField.objects.filter(x=x, y=y, z=z).first()

            if asteroid_test:
                size = asteroid_test.size
                koef_res_1 = asteroid_test.koef_res_1
                koef_res_2 = asteroid_test.koef_res_2
                koef_res_3 = asteroid_test.koef_res_3
                koef_res_4 = asteroid_test.koef_res_4
                koef_min_1 = asteroid_test.koef_min_1
                koef_min_2 = asteroid_test.koef_min_2
                koef_min_3 = asteroid_test.koef_min_3
                koef_min_4 = asteroid_test.koef_min_4

                asteroid = AsteroidField(
                    x=x,
                    y=y,
                    z=z,
                    size=size,
                    koef_res_1=koef_res_1,
                    koef_res_2=koef_res_2,
                    koef_res_3=koef_res_3,
                    koef_res_4=koef_res_4,
                    koef_min_1=koef_min_1,
                    koef_min_2=koef_min_2,
                    koef_min_3=koef_min_3,
                    koef_min_4=koef_min_4,
                    artifact=artifact
                )
                asteroid.save()
            else:
                asteroid = AsteroidField(
                    x=x,
                    y=y,
                    z=z,
                    size=size,
                    koef_res_1=koef_res_1,
                    koef_res_2=koef_res_2,
                    koef_res_3=koef_res_3,
                    koef_res_4=koef_res_4,
                    koef_min_1=koef_min_1,
                    koef_min_2=koef_min_2,
                    koef_min_3=koef_min_3,
                    koef_min_4=koef_min_4,
                    artifact=artifact
                )
                asteroid.save()

        message = 'Поля сгенерированы'
        output = {'message': message}

        return render(request, "admin/generation.html", output)


from flask import Flask, request, jsonify
import tensorflow as tf
from PIL import Image
import numpy as np
import cv2
import os
import random

app = Flask(__name__)

# Load your pre-trained model
model = tf.keras.models.load_model('your_model.h5')

def related_images(tag):
    folder_path = os.path.join('tiles',tag)
    result = [os.path.join('tiles',tag,item) for item in os.listdir(folder_path)]
    return random.sample(result, 6)

def preprocess_image(image_path):
    img = Image.open(image_path)
    img = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
    resize = tf.image.resize(img, (128, 128))
    img = resize / 255.0  # Remove np.expand_dims
    return img

@app.route('/predict', methods=['POST'])
def predict():
    try:
        # Get the image file from the POST request
        if 'image' not in request.files:
            return jsonify({'error': 'No image provided'})

        image = request.files['image']

        # Preprocess the image
        image_data = preprocess_image(image)

        # Make predictions
        predictions = model.predict(np.expand_dims(image_data, axis=0))

        maxi = np.argmax(predictions)

        avail_labels = ['tiles', 'fans', 'light_bulb']
        # print(predictions)

        resp = related_images(avail_labels[maxi])
        # print(resp, 'sameer')
        # Return the predictions as JSON
        response = {'data': resp}
        print(jsonify(response))
        return jsonify(response)
    except Exception as e:
        return jsonify({'error': str(e)})

@app.route('/test_predict', methods=['GET'])
def test_predict():
    try:
        # Use an image from the "images" folder for testing
        test_image_path = 'images/image.jpeg'  # Adjust the path to the image you want to test

        # Preprocess the test image
        test_image_data = preprocess_image(test_image_path)

        # Make predictions
        predictions = model.predict(np.expand_dims(test_image_data, axis=0))

        # Return the predictions as JSON
        response = {'predictions': predictions.tolist()}
        print("~~~~~~~~~~~~~~~~~~~~~~~~~~~")
        print(jsonify(response))
        return jsonify(response)
    except Exception as e:
        return jsonify({'error': str(e)})

@app.route('/', methods=['GET'])
def root():
    try:
        return jsonify({"message":"hello_world!"})
    except Exception as e:
        return jsonify({'error': str(e)})

if __name__ == '__main__':
    app.run()


"""
Author: Abdullah Najjar
Version: 0.1
Description: This game is called Adventure
# TODO: Fix player speed and problem in movement, also screen size issues + add map tiling
"""
import arcade
import os
import random

# Global variables
SPRITE_SCALING = 0.5 #Character size
SPRITE_SCALING_COIN = .50 #Size of coins
COIN_COUNT = 50 #Number of coins

SCREEN_WIDTH = 800 #Width of window
SCREEN_HEIGHT = 600 #Height of window
SCREEN_TITLE = "Adventure" #Window title

MAX_SPEED = 2.7 # Speed limit
ACCELERATION_RATE = 0.1 # How fast we accelerate
FRICTION = 0.02 # How fast to slow down after we letr off the key

SPRITE_PIXEL_SIZE = 128
GRID_PIXEL_SIZE = (SPRITE_PIXEL_SIZE * SPRITE_SCALING)

# How many pixels to keep as a minimum margin between the character
# and the edge of the screen.
VIEWPORT_MARGIN = SPRITE_PIXEL_SIZE * SPRITE_SCALING
RIGHT_MARGIN = 4 * SPRITE_PIXEL_SIZE * SPRITE_SCALING

# Physics
MOVEMENT_SPEED = 4 * SPRITE_SCALING
JUMP_SPEED = 50 * SPRITE_SCALING
GRAVITY = .5 * SPRITE_SCALING

class Player(arcade.Sprite):
    """
    Player class
    """
    def update(self):
        """
        Update for the movement of the player
        # TODO: Make the screen edge move as the player moves
        """
        self.center_x += self.change_x
        self.center_y += self.change_y

        # Check to see if we hit the screen edge
        if self.left < 0:
            self.left = 0
            self.change_x = 0 # Zero x speed
        elif self.right > SCREEN_WIDTH - 1:
            self.right = SCREEN_WIDTH - 1
            self.change_x = 0

        if self.bottom < 0:
            self.bottom = 0
            self.change_y = 0
        elif self.top > SCREEN_HEIGHT - 1:
            self.top = SCREEN_HEIGHT - 1
            self.change_y = 0

class MyGame(arcade.Window):
    """
    Main application class.
    """

    def __init__(self, width, height, title):
        """
        Initializer
        """

        # Call the parent class initializer
        super().__init__(width, height, title)

        # Set the working directory (where we expect to find files) to the same
        # directory this .py file is in. You can leave this out of your own
        # code, but it is needed to easily run the examples using "python -m"
        # as mentioned at the top of this program.
        file_path = os.path.dirname(os.path.abspath(__file__))
        os.chdir(file_path)

        # Variables that will hold sprite lists
        self.all_sprites_list = None
        self.all_wall_list = None
        self.static_wall_list = None
        self.moving_wall_list = None
        self.player_list = None
        self.coin_list = None

        # Set up the player info
        self.player_sprite = None
        self.physics_engine = None
        self.view_left = 0
        self.view_bottom = 0
        self.end_of_map = 0
        self.game_over = False

        self.score = 0

        # Track the current state of what key is pressed
        self.left_pressed = False
        self.right_pressed = False
        self.up_pressed = False
        self.down_pressed = False

        width, height = self.get_size()
        self.set_viewport(0, width, 0, height)

        # Set the background color
        arcade.set_background_color(arcade.color.BABY_BLUE)

    def setup(self):
        """ Set up the game and initialize the variables. """

        # Sprite lists -> Player & coins
        self.player_list = arcade.SpriteList()
        self.coin_list = arcade.SpriteList()
        self.all_wall_list = arcade.SpriteList()
        self.static_wall_list = arcade.SpriteList()
        self.moving_wall_list = arcade.SpriteList()

        self.score = 0    # Score

        # Set up the player character image, size and position
        self.player_sprite = Player(":resources:images/animated_characters/male_adventurer/maleAdventurer_walk7.png", SPRITE_SCALING)
        self.player_sprite.center_x = 2 * GRID_PIXEL_SIZE
        self.player_sprite.center_y = 3 * GRID_PIXEL_SIZE
        self.player_list.append(self.player_sprite)

        # Create floor
        for i in range(30):
            wall = arcade.Sprite(":resources:images/tiles/grassMid.png", SPRITE_SCALING)
            wall.bottom = 0
            wall.center_x = i * GRID_PIXEL_SIZE
            self.static_wall_list.append(wall)
            self.all_wall_list.append(wall)

        # Create platform side to side
        wall = arcade.Sprite(":resources:images/tiles/grassMid.png", SPRITE_SCALING)
        wall.center_y = 3 * GRID_PIXEL_SIZE
        wall.center_x = 3 * GRID_PIXEL_SIZE
        wall.boundary_left = 2 * GRID_PIXEL_SIZE
        wall.boundary_right = 5 * GRID_PIXEL_SIZE
        wall.change_x = 2 * SPRITE_SCALING

        self.all_wall_list.append(wall)
        self.moving_wall_list.append(wall)

        # Create platform side to side
        wall = arcade.Sprite(":resources:images/tiles/grassMid.png", SPRITE_SCALING)
        wall.center_y = 3 * GRID_PIXEL_SIZE
        wall.center_x = 7 * GRID_PIXEL_SIZE
        wall.boundary_left = 5 * GRID_PIXEL_SIZE
        wall.boundary_right = 9 * GRID_PIXEL_SIZE
        wall.change_x = -2 * SPRITE_SCALING

        self.all_wall_list.append(wall)
        self.moving_wall_list.append(wall)

        # Create platform moving up and down
        wall = arcade.Sprite(":resources:images/tiles/grassMid.png", SPRITE_SCALING)
        wall.center_y = 5 * GRID_PIXEL_SIZE
        wall.center_x = 5 * GRID_PIXEL_SIZE
        wall.boundary_top = 8 * GRID_PIXEL_SIZE
        wall.boundary_bottom = 4 * GRID_PIXEL_SIZE
        wall.change_y = 2 * SPRITE_SCALING

        self.all_wall_list.append(wall)
        self.moving_wall_list.append(wall)

        # Create platform moving diagonally
        wall = arcade.Sprite(":resources:images/tiles/grassMid.png", SPRITE_SCALING)
        wall.center_y = 5 * GRID_PIXEL_SIZE
        wall.center_x = 8 * GRID_PIXEL_SIZE
        wall.boundary_left = 7 * GRID_PIXEL_SIZE
        wall.boundary_right = 9 * GRID_PIXEL_SIZE

        wall.boundary_top = 8 * GRID_PIXEL_SIZE
        wall.boundary_bottom = 4 * GRID_PIXEL_SIZE
        wall.change_x = 2 * SPRITE_SCALING
        wall.change_y = 2 * SPRITE_SCALING

        self.all_wall_list.append(wall)
        self.moving_wall_list.append(wall)

        self.physics_engine = \
            arcade.PhysicsEnginePlatformer(self.player_sprite,
                                           self.all_wall_list,
                                           gravity_constant=GRAVITY)

        # Create the coins
        for i in range(COIN_COUNT):

            # Create the coin instance -> The Coin image from kenney.nl
            coin = arcade.Sprite(":resources:images/items/coinGold.png",
                                 SPRITE_SCALING_COIN)

            # Position the coin
            coin.center_x = random.randrange(SCREEN_WIDTH)
            coin.center_y = random.randrange(SCREEN_HEIGHT)

            # Add the coin to the lists
            self.coin_list.append(coin)

        # Set the viewport boundaries
        # These numbers set where we have 'scrolled' to.
        self.view_left = 0
        self.view_bottom = 0

        self.game_over = False

    def on_draw(self):
        """
        Render the screen.
        """

        # This command has to happen before we start drawing
        arcade.start_render()

        # Get viewport dimensions
        left, screen_width, bottom, screen_height = self.get_viewport()

        self.coin_list.draw()
        self.static_wall_list.draw()
        self.moving_wall_list.draw()

        # Put the text on the screen.
        # Adjust the text position based on the viewport so that we don't
        # scroll the text too.
        # distance = self.player_sprite.right
        # output = f"Distance: {distance}"
        # arcade.draw_text(output, self.view_left + 10, self.view_bottom + 20,
        #                  arcade.color.WHITE, 14)

        # Put the text on the screen.
        output = f"Score: {self.score}"
        arcade.draw_text(output, 10, 20, arcade.color.WHITE, 14)

        self.player_list.draw()         # Draw all the sprites.

        # Display speed
        arcade.draw_text(f"X Speed: {self.player_sprite.change_x:6.3f}", 10, 50, arcade.color.WHITE)
        arcade.draw_text(f"Y Speed: {self.player_sprite.change_y:6.3f}", 10, 70, arcade.color.WHITE)

    def on_update(self, delta_time):
        """ Movement and game logic """

        # Call update on all sprites (The sprites don't do much in this
        # example though.)
        self.coin_list.update()
        self.physics_engine.update()

        # Track if we need to change the viewport

        changed = False
        # Generate a list of all sprites that collided with the player.
        coins_hit_list = arcade.check_for_collision_with_list(self.player_sprite, self.coin_list)

        # Loop through each colliding sprite, remove it, and add to the score.
        for coin in coins_hit_list:
            coin.remove_from_sprite_lists()
            self.score += 1

        # Add some friction
        if self.player_sprite.change_x > FRICTION:
            self.player_sprite.change_x -= FRICTION
        elif self.player_sprite.change_x < -FRICTION:
            self.player_sprite.change_x += FRICTION
        else:
            self.player_sprite.change_x = 0

        if self.player_sprite.change_y > FRICTION:
            self.player_sprite.change_y -= FRICTION
        elif self.player_sprite.change_y < -FRICTION:
            self.player_sprite.change_y += FRICTION
        else:
            self.player_sprite.change_y = 0

        # Apply acceleration based on the keys pressed
        if self.up_pressed and not self.down_pressed:
            self.player_sprite.change_y += ACCELERATION_RATE
        elif self.down_pressed and not self.up_pressed:
            self.player_sprite.change_y += -ACCELERATION_RATE
        if self.left_pressed and not self.right_pressed:
            self.player_sprite.change_x += -ACCELERATION_RATE
        elif self.right_pressed and not self.left_pressed:
            self.player_sprite.change_x += ACCELERATION_RATE

        if self.player_sprite.change_x > MAX_SPEED:
            self.player_sprite.change_x = MAX_SPEED
        elif self.player_sprite.change_x < -MAX_SPEED:
            self.player_sprite.change_x = -MAX_SPEED
        if self.player_sprite.change_y > MAX_SPEED:
            self.player_sprite.change_y = MAX_SPEED
        elif self.player_sprite.change_y < -MAX_SPEED:
            self.player_sprite.change_y = -MAX_SPEED

        # Call update to move the sprite
        # If using a physics engine, call update on it instead of the sprite
        # list.
        self.player_list.update()

    def on_key_press(self, key, modifiers):
        """Called whenever a key is pressed. """

        if key == arcade.key.UP:
            self.up_pressed = True
        elif key == arcade.key.DOWN:
            self.down_pressed = True
        elif key == arcade.key.LEFT:
            self.left_pressed = True
        elif key == arcade.key.RIGHT:
            self.right_pressed = True

    def on_key_release(self, key, modifiers):
        """Called when the user releases a key. """

        if key == arcade.key.UP:
            if self.physics_engine.can_jump():
                self.player_sprite.change_y = JUMP_SPEED
        elif key == arcade.key.LEFT:
            self.player_sprite.change_x = -MOVEMENT_SPEED
        elif key == arcade.key.RIGHT:
            self.player_sprite.change_x = MOVEMENT_SPEED

def main():
    """ Main method """
    window = MyGame(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
    window.setup()
    arcade.run()

if __name__ == "__main__":
    main()


import PIL.Image as Image
import torch
from torch.utils.data import Dataset
from torchvision import transforms

class CIFARDataset(Dataset):
    def __init__(self, images, labels, training=True):
        self.images = images
        self.labels = labels
        if training:
            self.transform = self._train_transform()
        else:
            self.transform = self._test_transform()

    def __getitem__(self, index):
        img = Image.fromarray(self.images[index])
        img = self.transform(img)
        target = self.labels[index]
        return img, target

    def _train_transform(self):
        transform = transforms.Compose([
            transforms.RandomCrop(32, padding=4),
            transforms.RandomHorizontalFlip(),
            transforms.ToTensor(),
            transforms.Normalize(mean=[0.507, 0.487, 0.441], std=[0.267, 0.256, 0.276])
        ])
        return transform

    def _test_transform(self):
        transform = transforms.Compose([
            transforms.ToTensor(),
            transforms.Normalize(mean=[0.507, 0.487, 0.441], std=[0.267, 0.256, 0.276])
        ])
        return transform

    def __len__(self):
        return len(self.images)

class BYOLCIFARDataset(CIFARDataset):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.train_aug = self._train_transform()
        self.test_aug = self._test_transform()

    def __getitem__(self, index):
        img = Image.fromarray(self.images[index])
        x = self.test_aug(img.copy())
        x1 = self.train_aug(img.copy())
        x2 = self.train_aug(img.copy())
        target = self.labels[index]
        return x, x1, x2, target


from django.contrib import admin

from .models import ItemCategories, MenuItems

# Register your models here.

class MenuItemsAdmin(admin.ModelAdmin):
    list_display = ['__str__', 'price', 'type']
    search_fields = ['name', 'description', 'price']
    list_filter = ['price', 'type']
    list_editable = ['type']

    def get_search_results(self, request, queryset, search_term):
        queryset, use_distinct = super().get_search_results(request, queryset, search_term)

        # You need to define a character for splitting your range, in this example I'll use a hyphen (-)
        try:
            # This will get me the range values if there's only 1 hyphen
            min_price, max_price = search_term.split('-')
        except ValueError:
            # Otherwise it will do nothing
            pass
        else:
            # If the try was successful, it will proceed to do the range filtering
            queryset |= self.model.objects.filter(price__gte=min_price, price__lte=max_price)
        return queryset, use_distinct

    class Meta:
        model = MenuItems

admin.site.register(MenuItems, MenuItemsAdmin)
admin.site.register(ItemCategories)