#!/usr/bin/env python
# coding: utf-8

import os
import torch
import numpy as np
import random
from torch import nn
from torchvision import transforms as tfs
from torch.utils.checkpoint import checkpoint, checkpoint_sequential
from tqdm import tqdm
import hiddenlayer as hl
from PIL import Image
from PIL import ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = True
import pdb
import cv2

class AverageValueMeter():
    def __init__(self):
        self.N = 0
        self.ave = 0

    def add(self, x):
        self.ave = self.N / (1 + self.N) * self.ave + 1 / (1 + self.N) * x
        self.N += 1

    def reset(self):
        self.N = 0
        self.ave = 0

    def value(self):
        return self.ave, self.N

def read_as_list(rootpath):
    datalist = os.listdir(rootpath)
    datapath = [os.path.join(rootpath, i) for i in datalist]
    return datapath

def readimglab(img_root, lab_root):
    ip = read_as_list(img_root)
    lp = read_as_list(lab_root)
    return ip, lp

def random_crop(img, lab, crop_size, rc=True):
    wd, ht = crop_size
    w, h = img.size
    wd = min(wd, w)
    ht = min(ht, h)
    wd = wd - wd % 16
    ht = ht - ht % 16
    if rc:
        if w == wd:
            i = 0
        else:
            i = random.randint(0, w - wd)
        if h == ht:
            j = 0
        else:
            j = random.randint(0, h - ht)
    else:
        i = 0
        j = 0

    return img.crop((i, j, i + wd, j + ht)), lab.crop((i, j, i + wd, j + ht))

def img_transforms(img, lab_d, crop_size, rc=True):
    #     img, lab = random_crop(img, lab, crop_size, rc=True)
    # 转化为SAR图像，即，灰度化，加椒盐噪声
    imgray = np.array(img)
    #     imgray = imgray[:, :, np.newaxis]
    #     imgray = np.asarray(img)
    img_tfs = tfs.Compose([
        tfs.ToTensor(),
        #         tfs.Normalize([0.5], [0.225]),
        tfs.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),
    ])
    img = img_tfs(imgray)

    lab_d = np.array(lab_d)
    lab = np.ones(lab_d.shape[:2], dtype=np.int)
    b = lab_d[:, :, 0] == 0
    g = lab_d[:, :, 1] == 0
    r = lab_d[:, :, 2] == 128
    lab[~b] = 0
    lab[~g] = 0
    lab[~r] = 0
    return img, torch.from_numpy(lab)

class MapDataset(torch.utils.data.Dataset):
    """
    Map dataset
    """
    def __init__(self, crop_size, transform, img_root, lab_root, rc=True):
        self.crop_size = crop_size
        self.rc = rc
        self.transform = transform
        self.data_list, self.label_list = readimglab(img_root, lab_root)
        print("Read " + str(len(self.data_list)) + " images")

    def __getitem__(self, index):
        img = self.data_list[index]
        lab = self.label_list[index]
        img = Image.open(img)
        #         lab = Image.open(lab)
        lab = cv2.imread(lab)
        img, lab = self.transform(img, lab, self.crop_size, rc=self.rc)
        return img, lab

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

def _fast_hist(label_true, label_pred, n_class):
    mask = (label_true >= 0) & (label_true < n_class)
    hist = np.bincount(n_class * label_true[mask].astype(int) +
                       label_pred[mask],
                       minlength=n_class**2).reshape(n_class, n_class)
    return hist

def label_accuracy_score(label_trues, label_preds, n_class):
    """Returns accuracy score evaluation result.

      - overall accuracy
      - mean accuracy
      - mean IU
      - fwavacc
    """
    hist = np.zeros((n_class, n_class))
    for lt, lp in zip(label_trues, label_preds):
        hist += _fast_hist(lt.flatten(), lp.flatten(), n_class)
    acc = np.diag(hist).sum() / hist.sum()
    with np.errstate(divide='ignore', invalid='ignore'):
        acc_cls = np.diag(hist) / hist.sum(axis=1)
    acc_cls = np.nanmean(acc_cls)
    with np.errstate(divide='ignore', invalid='ignore'):
        iu = np.diag(hist) / (hist.sum(axis=1) + hist.sum(axis=0) -
                              np.diag(hist))
    mean_iu = np.nanmean(iu)
    freq = hist.sum(axis=1) / hist.sum()
    fwavacc = (freq[freq > 0] * iu[freq > 0]).sum()
    return acc, acc_cls, mean_iu, fwavacc

def bilinear_kernel(in_channels, out_channels, kernei_size):
    factor = (kernei_size + 1) // 2
    if kernei_size % 2 == 1:
        center = factor - 1
    else:
        center = factor - 0.5
    og = np.ogrid[:kernei_size, :kernei_size]
    filt = (1 - abs(og[0] - center) / factor) * (1 -
                                                 abs(og[1] - center) / factor)
    filtr = filt.reshape(-1)
    filtr = np.tile(filtr, (in_channels, out_channels))
    weight = filtr.reshape(in_channels, out_channels, filt.shape[0],
                           filt.shape[1]).astype(np.float32)
    #     weight = np.zeros((in_channels, out_channels, kernei_size, kernei_size),
    #                       dtype="float32")
    #     print(weight.shape, filt.shape)
    #     weight[range(in_channels), range(out_channels), :, :] = filt

    return torch.from_numpy(weight)

class MFM(nn.Module):
    def __init__(self):
        super(MFM, self).__init__()

    def forward(self, x):
        channels = x.shape[1]
        xo = x[:, 0, :, :]
        xo = torch.unsqueeze(xo, 1)
        for k in range(0, channels, 2):
            xout = torch.cat([
                torch.unsqueeze(x[:, k, :, :], 1),
                torch.unsqueeze(x[:, k + 1, :, :], 1)
            ],
                             dim=1)
            xout, _ = torch.max(xout, dim=1)
            xout = torch.unsqueeze(xout, 1)
            xo = torch.cat([xo, xout], dim=1)
        xo = xo[:, 1:, :, :]
        return xo

class FCN(nn.Module):
    """
    每一层的卷积深度都是64，应该逐层增加，可以为 64,128,256,512，递增
    """
    def __init__(self, in_ch, num_classes):
        super(FCN, self).__init__()
        self.downsample = nn.Conv2d(in_ch, 3, 3, stride=2,
                                    padding=1)  # 相当于一个 preconv 吧
        self.CBM1_1 = nn.Sequential(
            nn.Conv2d(3, 64, 3, padding=1),
            nn.BatchNorm2d(64),
            MFM(),
        )
        self.CBM1_2 = nn.Sequential(
            nn.Conv2d(64 // 2, 64, 3, padding=1),
            nn.BatchNorm2d(64),
            MFM(),
        )
        self.pool1 = nn.MaxPool2d(2, 2, ceil_mode=False)
        self.CBM2_1 = nn.Sequential(
            nn.Conv2d(64 // 2, 64, 3, padding=1),
            nn.BatchNorm2d(64),
            MFM(),
        )
        self.CBM2_2 = nn.Sequential(
            nn.Conv2d(64 // 2, 64, 3, padding=1),
            nn.BatchNorm2d(64),
            MFM(),
        )
        self.pool2 = nn.MaxPool2d(2, 2, ceil_mode=False)

        self.CBM3_1 = nn.Sequential(
            nn.Conv2d(64 // 2, 64, 3, padding=1),
            nn.BatchNorm2d(64),
            MFM(),
        )
        self.CBM3_2 = nn.Sequential(
            nn.Conv2d(64 // 2, 64, 3, padding=1),
            nn.BatchNorm2d(64),
            MFM(),
        )
        self.pool3 = nn.MaxPool2d(2, 2, ceil_mode=False)

        self.CBM4_1 = nn.Sequential(
            nn.Conv2d(64 // 2, 64, 3, padding=1),
            nn.BatchNorm2d(64),
            MFM(),
        )
        self.CBM4_2 = nn.Sequential(
            nn.Conv2d(64 // 2, 64, 3, padding=1),
            nn.BatchNorm2d(64),
            MFM(),
        )

        #         self.upsample_pool1 = nn.ConvTranspose2d(
        #             64 // 2, 64, 4, stride=2,padding=1, bias=False)
        #         self.upsample_pool1.weight.data = bilinear_kernel(64 // 2, 64, 4)
        self.upsample_pool1 = nn.Conv2d(64 // 2, 64, 3, stride=1, padding=1)

        self.upsample_pool2 = nn.ConvTranspose2d(64 // 2,
                                                 64,
                                                 4,
                                                 stride=2,
                                                 padding=1,
                                                 bias=False)
        self.upsample_pool2.weight.data = bilinear_kernel(64 // 2, 64, 4)

        self.upsample_pool3 = nn.ConvTranspose2d(64 // 2,
                                                 64,
                                                 4,
                                                 stride=4,
                                                 padding=0,
                                                 bias=False)
        self.upsample_pool3.weight.data = bilinear_kernel(64 // 2, 64, 4)

        self.upsample_pool4 = nn.ConvTranspose2d(64 // 2,
                                                 64,
                                                 8,
                                                 stride=8,
                                                 padding=0,
                                                 bias=False)
        self.upsample_pool4.weight.data = bilinear_kernel(64 // 2, 64, 8)

        self.fcn1 = nn.Conv2d(64 * 4, 1024, 1, stride=1, padding=0)
        self.fcn2 = nn.Conv2d(1024, num_classes, 1, stride=1, padding=0)

        self.upsample_out_1 = nn.ConvTranspose2d(num_classes,
                                                 num_classes,
                                                 4,
                                                 stride=2,
                                                 padding=1,
                                                 bias=False)
        self.upsample_out_1.weight.data = bilinear_kernel(
            num_classes, num_classes, 4)

#         self.upsample_out_2 = nn.ConvTranspose2d(
#             num_classes, num_classes, 4, stride=2, padding=1,bias=False)
#         self.upsample_out_2.weight.data = bilinear_kernel(
#             num_classes, num_classes, 4)

    def forward(self, x, construct=False):
        h = x
        h = self.downsample(h)
        #         print("downsample",h.shape)#(128,128)
        h = self.CBM1_1(h)
        h = self.CBM1_2(h)
        p1 = h
        h = self.pool1(h)
        h = self.CBM2_1(h)
        h = self.CBM2_2(h)
        p2 = h
        h = self.pool2(h)
        h = self.CBM3_1(h)
        h = self.CBM3_2(h)
        p3 = h
        h = self.pool3(h)
        h = self.CBM4_1(h)
        h = self.CBM4_2(h)

        #         print("p123h",p1.shape, p2.shape, p3.shape, h.shape)
        p1u = self.upsample_pool1(p1)
        p2u = self.upsample_pool2(p2)
        p3u = self.upsample_pool3(p3)
        p4u = self.upsample_pool4(h)
        #         print("p1234u",p1u.shape, p2u.shape, p3u.shape, p4u.shape)
        h = torch.cat((p1u, p2u, p3u, p4u), dim=1)
        if construct:
            return h
        h = self.fcn1(h)
        h = self.fcn2(h)
        h = self.upsample_out_1(h)
        #         h = self.upsample_out_2(h)
        return h

def get_upsampling_weight(in_channels, out_channels, kernel_size):
    """Make a 2D bilinear kernel suitable for upsampling"""
    factor = (kernel_size + 1) // 2
    if kernel_size % 2 == 1:
        center = factor - 1
    else:
        center = factor - 0.5
    og = np.ogrid[:kernel_size, :kernel_size]
    filt = (1 - abs(og[0] - center) / factor) * (1 -
                                                 abs(og[1] - center) / factor)
    weight = np.zeros((in_channels, out_channels, kernel_size, kernel_size),
                      dtype=np.float64)
    weight[range(in_channels), range(out_channels), :, :] = filt
    return torch.from_numpy(weight).float()

class bnFCN8s(nn.Module):
    def __init__(self, encoder, n_class, th_ch=1):
        super().__init__()
        self.n_class = n_class
        self.encoder = encoder
        self.relu = nn.ReLU(inplace=True)
        self.deconv1 = nn.ConvTranspose2d(512,
                                          512,
                                          kernel_size=3,
                                          stride=2,
                                          padding=1,
                                          dilation=1,
                                          output_padding=1)
        self.bn1 = nn.BatchNorm2d(512)
        self.deconv2 = nn.ConvTranspose2d(512,
                                          256,
                                          kernel_size=3,
                                          stride=2,
                                          padding=1,
                                          dilation=1,
                                          output_padding=1)
        self.bn2 = nn.BatchNorm2d(256)
        self.deconv3 = nn.ConvTranspose2d(256,
                                          128,
                                          kernel_size=3,
                                          stride=2,
                                          padding=1,
                                          dilation=1,
                                          output_padding=1)
        self.bn3 = nn.BatchNorm2d(128)
        self.deconv4 = nn.ConvTranspose2d(128,
                                          64,
                                          kernel_size=3,
                                          stride=2,
                                          padding=1,
                                          dilation=1,
                                          output_padding=1)
        self.bn4 = nn.BatchNorm2d(64)
        self.deconv5 = nn.ConvTranspose2d(64,
                                          32,
                                          kernel_size=3,
                                          stride=2,
                                          padding=1,
                                          dilation=1,
                                          output_padding=1)
        self.bn5 = nn.BatchNorm2d(32)
        self.classifier = nn.Conv2d(32, n_class, kernel_size=1)

        self.relu2 = nn.ReLU(inplace=True)
        self.deconv12 = nn.ConvTranspose2d(512,
                                           512,
                                           kernel_size=3,
                                           stride=2,
                                           padding=1,
                                           dilation=1,
                                           output_padding=1)
        self.bn12 = nn.BatchNorm2d(512)
        self.deconv22 = nn.ConvTranspose2d(512,
                                           256,
                                           kernel_size=3,
                                           stride=2,
                                           padding=1,
                                           dilation=1,
                                           output_padding=1)
        self.bn22 = nn.BatchNorm2d(256)
        self.deconv32 = nn.ConvTranspose2d(256,
                                           128,
                                           kernel_size=3,
                                           stride=2,
                                           padding=1,
                                           dilation=1,
                                           output_padding=1)
        self.bn32 = nn.BatchNorm2d(128)
        self.deconv42 = nn.ConvTranspose2d(128,
                                           64,
                                           kernel_size=3,
                                           stride=2,
                                           padding=1,
                                           dilation=1,
                                           output_padding=1)
        self.bn42 = nn.BatchNorm2d(64)
        self.deconv52 = nn.ConvTranspose2d(64,
                                           32,
                                           kernel_size=3,
                                           stride=2,
                                           padding=1,
                                           dilation=1,
                                           output_padding=1)
        self.bn52 = nn.BatchNorm2d(32)
        self.classifier2 = nn.Conv2d(32, th_ch, kernel_size=1)

    def forward(self, x):
        output = self.encoder(x)
        x5 = output['x5']  # size=(N, 512, x.H/32, x.W/32)
        x4 = output['x4']  # size=(N, 512, x.H/16, x.W/16)
        x3 = output['x3']  # size=(N, 256, x.H/8,  x.W/8)

        score = self.relu(self.deconv1(x5))  # size=(N, 512, x.H/16, x.W/16)
        score = self.bn1(score +
                         x4)  # element-wise add, size=(N, 512, x.H/16, x.W/16)
        score = self.relu(self.deconv2(score))  # size=(N, 256, x.H/8, x.W/8)
        score = self.bn2(score +
                         x3)  # element-wise add, size=(N, 256, x.H/8, x.W/8)
        score = self.bn3(self.relu(
            self.deconv3(score)))  # size=(N, 128, x.H/4, x.W/4)
        score = self.bn4(self.relu(
            self.deconv4(score)))  # size=(N, 64, x.H/2, x.W/2)
        score = self.bn5(self.relu(
            self.deconv5(score)))  # size=(N, 32, x.H, x.W)
        score = self.classifier(score)  # size=(N, n_class, x.H/1, x.W/1)

        score2 = self.relu2(self.deconv12(x5))  # size=(N, 512, x.H/16, x.W/16)
        score2 = self.bn12(
            score2 + x4)  # element-wise add, size=(N, 512, x.H/16, x.W/16)
        score2 = self.relu2(
            self.deconv22(score2))  # size=(N, 256, x.H/8, x.W/8)
        score2 = self.bn22(score2 +
                           x3)  # element-wise add, size=(N, 256, x.H/8, x.W/8)
        score2 = self.bn32(self.relu2(
            self.deconv32(score2)))  # size=(N, 128, x.H/4, x.W/4)
        score2 = self.bn42(self.relu2(
            self.deconv42(score2)))  # size=(N, 64, x.H/2, x.W/2)
        score2 = self.bn52(self.relu2(
            self.deconv52(score2)))  # size=(N, 32, x.H, x.W)
        score2 = self.classifier2(score2)  # size=(N, n_class, x.H/1, x.W/1)

        return score, score2  # size=(N, n_class, x.H/1, x.W/1)

from torchvision.models.vgg import VGG

class VGGNet(VGG):
    def __init__(self,
                 model='vgg16',
                 batch_norm=False,
                 requires_grad=True,
                 remove_fc=True,
                 show_params=False,
                 in_channels=3):
        super().__init__(
            make_layers(cfg[model], batch_norm, in_channels=in_channels))
        if batch_norm:
            self.ranges = ranges[model + 'bn']
        else:
            self.ranges = ranges[model]

        if not requires_grad:
            for param in super().parameters():
                param.requires_grad = False

        if remove_fc:  # delete redundant fully-connected layer params, can save memory
            del self.classifier

        if show_params:
            for name, param in self.named_parameters():
                print(name, param.size())

    def forward(self, x):
        output = {}

        # get the output of each maxpooling layer (5 maxpool in VGG net)
        for idx in range(len(self.ranges)):
            for layer in range(self.ranges[idx][0], self.ranges[idx][1]):
                x = self.features[layer](x)
            output["x%d" % (idx + 1)] = x

        return output

    def _initialize_weights(self):
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                nn.init.kaiming_normal_(m.weight,
                                        mode='fan_out',
                                        nonlinearity='relu')
                if m.bias is not None:
                    nn.init.constant_(m.bias, 0)
            elif isinstance(m, nn.BatchNorm2d):
                nn.init.constant_(m.weight, 1)
                nn.init.constant_(m.bias, 0)
            elif isinstance(m, nn.Linear):
                nn.init.normal_(m.weight, 0, 0.01)
                nn.init.constant_(m.bias, 0)

def make_layers(cfg, batch_norm=False, in_channels=3):
    layers = []
    in_channels = in_channels
    for v in cfg:
        if v == 'M':
            layers += [nn.MaxPool2d(kernel_size=2, stride=2)]
        else:
            conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1)
            if batch_norm:
                layers += [conv2d, nn.BatchNorm2d(v), nn.ReLU(inplace=True)]
            else:
                layers += [conv2d, nn.ReLU(inplace=True)]
            in_channels = v
    return nn.Sequential(*layers)

cfg = {
    'vgg11': [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
    'vgg13':
    [64, 64, 'M', 128, 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
    'vgg16': [
        64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M',
        512, 512, 512, 'M'
    ],
    'vgg19': [
        64, 64, 'M', 128, 128, 'M', 256, 256, 256, 256, 'M', 512, 512, 512,
        512, 'M', 512, 512, 512, 512, 'M'
    ],
}

ranges = {
    'vgg11': ((0, 3), (3, 6), (6, 11), (11, 16), (16, 21)),
    'vgg11bn': ((0, 4), (4, 8), (8, 15), (15, 22), (22, 29)),
    'vgg13': ((0, 5), (5, 10), (10, 15), (15, 20), (20, 25)),
    'vgg13bn': ((0, 7), (7, 14), (14, 21), (21, 28), (28, 35)),
    'vgg16': ((0, 5), (5, 12), (12, 22), (22, 32), (32, 42)),
    'vgg16bn': ((0, 7), (7, 14), (14, 24), (24, 34), (34, 44)),
    'vgg19': ((0, 5), (5, 10), (10, 19), (19, 28), (28, 37)),
    'vgg19bn': ((0, 7), (7, 14), (14, 27), (27, 40), (40, 53))
}

# ## 边缘检测

class Edgenet(nn.Module):
    def __init__(self, ):
        """
        算子:
            Sobel 一阶微分算子, 包括纵横双斜角,共四个
            Laplace 二阶微分算子,共一个
        """
        super(Edgenet, self).__init__()
        f_x = torch.tensor([
            [-1, -2, -1],
            [0, 0, 0],
            [1, 2, 1],
        ])
        f_y = torch.tensor([
            [-1, 0, 1],
            [-2, 0, 2],
            [-1, 0, 1],
        ])
        f_tl_br = torch.tensor([
            [-2, -1, 0],
            [-1, 0, 1],
            [0, 1, 2],
        ])
        f_tr_bl = torch.tensor([
            [0, -1, -2],
            [1, 0, -1],
            [2, 1, 0],
        ])
        f_operator = [
            f_x,
            f_y,
            f_tl_br,
            f_tr_bl,
        ]
        self.conv_operator = nn.ModuleList()
        for i, operator_init in enumerate(f_operator):
            self.conv_operator.append(
                nn.Conv2d(
                    1,
                    1,
                    3,
                    padding=1,
                    bias=False,
                ))
            self.conv_operator[i].weight.data[:, :] = operator_init

    def forward(self, lab):
        edge = 0
        lab_l = lab.float()
        for i, conv_op in enumerate(self.conv_operator):
            edge += torch.abs(conv_op(lab_l))
        edge[edge > 0] = 1

        return edge.squeeze().long()

class Sobelnet(nn.Module):
    def __init__(self, in_ch=1, out_ch=1, coef_sobel=1.0):
        """
        算子:
            Sobel 一阶微分算子, 包括纵横双斜角,共四个
            Laplace 二阶微分算子,共一个
        """
        super(Sobelnet, self).__init__()
        f_x = torch.tensor([
            [-1, -2, -1],
            [0, 0, 0],
            [1, 2, 1],
        ])
        f_y = torch.tensor([
            [-1, 0, 1],
            [-2, 0, 2],
            [-1, 0, 1],
        ])
        f_tl_br = torch.tensor([
            [-2, -1, 0],
            [-1, 0, 1],
            [0, 1, 2],
        ])
        f_tr_bl = torch.tensor([
            [0, -1, -2],
            [1, 0, -1],
            [2, 1, 0],
        ])
        f_laplace = torch.tensor([
            [1, 1, 1],
            [1, 8, 1],
            [1, 1, 1],
        ])

        f_operator = [
            f_x,
            f_y,
            f_tl_br,
            f_tr_bl,
            #             f_laplace,
        ]
        self.in_ch = in_ch
        self.out_ch = out_ch
        self.coef_sobel = coef_sobel

        self.conv_operator = nn.ModuleList()
        for i, operator_init in enumerate(f_operator):
            self.conv_operator.append(
                nn.Conv2d(
                    self.in_ch,
                    self.out_ch,
                    3,
                    padding=1,
                    bias=False,
                ))
            self.conv_operator[i].weight.data[:, :] = operator_init

    def forward(self, output_th, pred_seg, lab):
        lab_1 = lab.float() * 1.8 - 0.9
        Res_p = pred_seg - output_th
        loss = 0
        coploss = []
        for i, conv_op in enumerate(self.conv_operator):
            copl = conv_op(lab_1)
            copr = conv_op(Res_p)
            coploss.append(copl)
            #             loss += torch.mean(((1 - lab) * pred_seg.unsqueeze(1) + lab *
            #                                (1 - pred_seg.unsqueeze(1))**0.75 )*
            #                                (conv_op(lab_1) - conv_op(Res_p))**2)
            loss += torch.mean(
                ((1 - lab) * (0.25 + pred_seg.unsqueeze(1)) + lab *
                 (1 - pred_seg.unsqueeze(1))**0.75) * (copl - copr)**2)

#             loss += torch.mean((conv_op(lab_1) - conv_op(Res_p))**2)

        return loss, coploss

class ThresholdLoss(nn.Module):
    def __init__(self, threshold_rate_0, threshold_rate_1):
        super(ThresholdLoss, self).__init__()
        self.threshold_rate_0 = threshold_rate_0
        self.threshold_rate_1 = threshold_rate_1

    def forward(self, output_th, pred_seg, lab):
        lab = lab.float()
        #         print(output_th.shape, pred_seg.shape, lab.shape)
        targets = lab * (pred_seg * self.threshold_rate_1 - 0.) + (1 - lab) * (
            (1 - (1 - pred_seg) * self.threshold_rate_0) + 0.)
        loss = torch.mean((output_th - targets)**2)
        return loss

if __name__ == "__main__":
    device = torch.device("cuda")
    img_root = "road_dataset/image_train/"
    lab_root = "road_dataset/label_train/"

    input_size = (256, 256)
    batch_size = 8
    NUM_CLASSES = 2
    load_path = "FCN8s_SplitNet_EdgeLossV2.pth"
    save_path = "FCN8s_SplitNet_EdgeLossV2.pth"
    EPOCH_start = 0
    EPOCH = 1000
    base_LR = 1e-4
    decay_step = 100
    decay_rate = 0.5
    wd = 1e-3
    mIU_benchmark = 0

    train_data = MapDataset(input_size,
                            img_transforms,
                            img_root,
                            lab_root,
                            rc=False)
    train_dataloader = torch.utils.data.DataLoader(train_data,
                                                   batch_size,
                                                   True,
                                                   num_workers=32,
                                                   drop_last=True)

    img_root_t = "road_dataset/image_val/"
    lab_root_t = "road_dataset/label_val/"

    test_data = MapDataset(input_size,
                           img_transforms,
                           img_root_t,
                           lab_root_t,
                           rc=False)
    test_dataloader = torch.utils.data.DataLoader(test_data,
                                                  8,
                                                  shuffle=False,
                                                  num_workers=8,
                                                  drop_last=True)

    encoder_one = VGGNet('vgg16', batch_norm=True, in_channels=3)
    net_one = bnFCN8s(encoder_one, NUM_CLASSES, 1).to(device)
    thloss = Sobelnet().to(device)
    edgenet = Edgenet().to(device)
    if load_path is not None:
        if os.path.isfile(load_path):
            try:
                checkpoint = torch.load(load_path)
                net_one.load_state_dict(checkpoint['state_one'])
                mIU_benchmark = checkpoint['mIU']
                print("Load last checkpoint OK ")
                print("mIU=", mIU_benchmark)
            except:
                print("Can't Load the checkpoint QAQ")
                mIU_benchmark = 0
        else:
            EPOCH_start = 0
            print("Can't find the checkpoint ,start train from epoch 0 ...")

    his = hl.History()
    canv = hl.Canvas()
    optm_one = torch.optim.Adam(net_one.parameters(),
                                lr=base_LR,
                                weight_decay=wd)
    scheduler_lr_one = torch.optim.lr_scheduler.StepLR(optm_one,
                                                       step_size=decay_step,
                                                       gamma=decay_rate)

    from torch.utils.tensorboard import SummaryWriter
    writer = SummaryWriter(log_dir=os.path.join("./log"))
    # Loss = nn.NLLLoss()
    Loss = nn.CrossEntropyLoss()

    l_seg = AverageValueMeter()
    l_th = AverageValueMeter()
    l_all = AverageValueMeter()
    train_miou_seg = AverageValueMeter()
    train_miou_th = AverageValueMeter()

    test_acc = AverageValueMeter()
    test_mean_iu = AverageValueMeter()
    test_acc_e = AverageValueMeter()
    test_mean_iu_e = AverageValueMeter()

    best_mIU = 0
    best_mIU_2 = mIU_benchmark
    EPOCH_start = 0
    for ep in tqdm(range(EPOCH_start, EPOCH_start + EPOCH),
                   dynamic_ncols=True):
        train_length = len(train_dataloader)
        l_seg.reset()
        l_th.reset()
        l_all.reset()
        train_miou_seg.reset()
        train_miou_th.reset()
        net_one.train()
        for i, data in tqdm(enumerate(train_dataloader),
                            total=train_length,
                            leave=False):
            if i > 10:
                break
            img, lab = data
            img, lab = img.to(device), lab.to(device)
            seg_output, th_output = net_one(img)
            loss_seg = Loss(seg_output, lab)
            seg_output_p = torch.softmax(seg_output, dim=1)[:, 1]
            loss_th, cl = thloss(th_output,
                                 seg_output_p.detach().unsqueeze(1),
                                 lab.unsqueeze(1))
            loss = loss_seg + loss_th
            optm_one.zero_grad()
            loss.backward()
            optm_one.step()

            l_seg.add(loss_seg.item())
            l_th.add(loss_th.item())
            l_all.add(loss.item())

            seg_pred = seg_output.max(dim=1)[1]
            th_pred = torch.zeros_like(seg_pred).squeeze()
            th_pred[seg_output_p > th_output.squeeze()] = 1

            _, _, train_mean_iu_i, _ = label_accuracy_score(
                lab.data.cpu().numpy(),
                seg_pred.data.cpu().numpy(), NUM_CLASSES)
            _, _, train_mean_iu_i_2, _ = label_accuracy_score(
                lab.data.cpu().numpy(),
                th_pred.data.cpu().numpy(), NUM_CLASSES)

            train_miou_seg.add(train_mean_iu_i)
            train_miou_th.add(train_mean_iu_i_2)

        scheduler_lr_one.step()  # 动态学习率

        with torch.no_grad():
            test_acc.reset()
            test_mean_iu.reset()
            test_acc_e.reset()
            test_mean_iu_e.reset()
            net_one.eval()
            for _ in tqdm(range(1), ):
                for i, data in tqdm(enumerate(test_dataloader),
                                    total=test_dataloader.__len__(),
                                    leave=False):
                    if i > 5:
                        break
                    img, lab = data
                    img, lab = img.to(device), lab.to(device)

                    seg_output, th_output = net_one(img)
                    seg_output_p = torch.softmax(seg_output, dim=1)[:, 1]
                    seg_pred = seg_output.max(dim=1)[1]
                    th_pred = torch.zeros_like(seg_pred).squeeze()
                    th_pred[seg_output_p > th_output.squeeze()] = 1

                    test_acc_i, _, test_mean_iu_i, _ = label_accuracy_score(
                        lab.data.cpu().numpy(),
                        seg_pred.data.cpu().numpy(), NUM_CLASSES)
                    test_acc_i_e, _, test_mean_iu_i_e, _ = label_accuracy_score(
                        lab.data.cpu().numpy(),
                        th_pred.data.cpu().numpy(), NUM_CLASSES)

                    test_acc.add(test_acc_i)
                    test_mean_iu.add(test_mean_iu_i)
                    test_acc_e.add(test_acc_i_e)
                    test_mean_iu_e.add(test_mean_iu_i_e)

        #画图
        writer.add_scalars(
            "TrainLoss",
            {
                "loss_seg": l_seg.value()[0],
                "loss_th": l_th.value()[0],
                "loss_all": l_all.value()[0],
            },
            ep,
        )
        writer.add_scalars(
            "miou",
            {
                "train_miou_seg": train_miou_seg.value()[0],
                "train_miou_th": train_miou_th.value()[0],
                "test_miou": test_mean_iu.value()[0],
                "test_miou2": test_mean_iu_e.value()[0],
                "best_mIU": best_mIU,
                "best_mIU2": best_mIU_2,
            },
            ep,
        )
        image_batch = torch.zeros((3, 1, input_size[0], input_size[0])).float()
        image_batch[0, 0] = seg_pred[0].float()
        image_batch[1, 0] = th_pred[0].float()
        image_batch[2, 0] = lab[0].float()
        writer.add_images("test_img",
                          image_batch,
                          global_step=ep,
                          dataformats="NCHW")

        if test_mean_iu_e.value()[0] >= best_mIU_2:
            best_mIU = train_miou_seg.value()[0]
            best_mIU_2 = test_mean_iu_e.value()[0]
            state = {
                'state_one': net_one.state_dict(),
                'EPOCH_start': ep,
                'mIU': best_mIU_2
            }
            torch.save(state, save_path)


#
#
# @param intervals int整型二维数组
# @return int整型
#
from collections import defaultdict

class Solution:
    def eraseOverlapIntervals(self, intervals):
        orders = []
        for interval in intervals:
            orders += [(interval[0], True), (interval[1], False)]
        orders.sort()
        use = defaultdict(int)
        for orderTime, orderType in orders:
            if orderType:
                use[orderTime] += 1
            else:
                use[orderTime] -= 1
        using = 0
        ans = 0
        for num in use.values():
            using += num
            ans = max(ans, using)
        return ans - 1

print(Solution().eraseOverlapIntervals([[1, 2], [2, 3], [3, 4], [1, 3]]))

2020.8/商汤-无重叠区间调度问题.py

商汤-无重叠区间调度问题.py


import numpy as np

def getInput(name):
    with open(name+'.txt', 'r') as file:
        return file.read().strip().split('\n\n')

def part1(input):
    sums = []
    for i in input:
        sums.append ( sum(list(map(lambda i: int(i), i.split('\n')))) )
    print( max (sums))
    return sums

def part2(sums):
    sorted = np.sort(sums)
    return sum(sorted[:-2])

# input = getInput('sample')
input = getInput('input')
result1 = part1(input)
print('part 1:', )
print('part 2:', part2(result1))


import time
import os

# helper function to swap perform a swap
def elem_swap(node, i, j, newI, newJ):
    # Tuples are immutable so create a list and then convert
    newList = [list(y) for y in node]
    newList[i][j], newList[newI][newJ] = newList[newI][newJ], newList[i][j]

    return tuple(tuple(x) for x in newList)

class Node:
    '''Node class containing parent state and current depth; used as value to a dict'''
    __slots__ = ('parent', 'depth')

    def __init__(self, parent, depth):
        self.parent = parent
        self.depth = depth

class IDS:
    '''IDS implementation'''
    def __init__(self, puzzle, end_state, time_limit):
        # info about the puzzle configuration
        self.puzzle = puzzle
        self.N_COL  = len(puzzle)
        self.N_ROW  = len(puzzle[0])
        self.end_state = end_state
        # analytical info
        self.searchPathLength = 0
        self.startTime = time.time()
        self.time_limit = time_limit
        # search algorithm param
        self.max_depth = 0
        # output param
        if not os.path.exists('Outputs'):
            os.makedirs('Outputs')
        self.searchFile = open("./Outputs/IDS Search Path.txt", 'w')
        self.searchFile.write('Here is the IDS search path:\n\n')
        self.solutionFile = open("./Outputs/IDS Solution Path.txt", 'w')
        self.solutionFile.write('Here is the IDS solution path:\n\n')

    def run(self):
        '''
        pop top element in open list and insert on top its children until open list is empty or time exceeds
        '''
        print(f'\nStarting IDS search for {self.N_COL}X{self.N_ROW}\n{self.puzzle}\n')
        while True:
            if self.time_limit:
                if time.time() - self.startTime > 60:
                    print("Exceeded 60 seconds. Solution not found!")
                    self.searchFile.write('no solution')
                    self.solutionFile.write('no solution')
                    return None
            # reset search algorithm param
            self.open_list = {self.puzzle: Node('root', 0)} # Open dict using key as current state and value as node info
            self.closed_list = {} # Closed/visited set
            while self.open_list:   # Search graph until no more to search depending on max_depth
                if self.time_limit:
                    if time.time() - self.startTime > 60:
                        print("Exceeded 60 seconds. Solution not found!")
                        self.searchFile.write('no solution')
                        self.solutionFile.write('no solution')
                        return None

                # pop top element from open_list as a tuple of (current_state, Node(parent, depth))
                node = self.open_list.popitem()
                self.searchPathLength += 1
                self.searchFile.write(str(node[0]) + '\n')

                if node[0] == self.end_state:
                    return self.post_search_info(node)

                # Generate children of current puzzle state if its depth is less than the limit max depth
                if node[1].depth < self.max_depth:
                    children = self.generateChildren(node[0])
                    # Add to Closed Set
                    self.closed_list[node[0]] = node[1].parent

                    for child in children:
                        if child in self.closed_list:
                            continue
                        if child in self.open_list:
                            continue
                        self.open_list[child] = Node(node[0], node[1].depth + 1)

            # increment max depth given open has been all searched
            self.max_depth += 1

    # Helper function to generate children
    def generateChildren(self, node):
        moves = set()
        for i in range(self.N_COL):
            for j in range(self.N_ROW):
                if i < self.N_COL - 1:
                    moves.add(elem_swap(node, i, j, i + 1, j))  # vertical
                if j < self.N_ROW - 1:
                    moves.add(elem_swap(node, i, j, i, j + 1))  # horizontal

        return moves

    # display statistics after search is completed
    def post_search_info(self, node):
        execution_time = (time.time() - self.startTime)
        print("--- %s seconds ---" % execution_time + '\n')
        # Retrace solution path
        solution = [node[0]]
        solution_length = 0
        previousState = node[1].parent
        while True:
            if previousState == 'root':
                break
            else:
                solution.append(previousState)
                previousState = self.closed_list[previousState]
                solution_length += 1

        for x in reversed(solution):
            self.solutionFile.write(str(x) + '\n')
        print(f'Length of search path: {self.searchPathLength}')
        print(f'Length of solution path: {solution_length}')
        print(f'Cost of the solution: {self.searchPathLength}')
        return solution_length, self.searchPathLength, solution_length, execution_time, 0


import os
import urllib
from urllib import request
import requests

with open('dev_urls.txt', 'r', encoding='utf-8') as f:
    for i, line in enumerate(f):
        if i < 1500:
            continue
        data = line.split('\t')
        if len(data) != 5:
            continue
        else:
            name, num, url, rect, md5sum = data
            print(name, num, url)
        if not os.path.exists('images/{}'.format(name)):
            os.mkdir('images/{}'.format(name))
        try:
            est = url[-4:]
            file_name= 'images/{}/{}{}'
            response = requests.get(url, timeout=(3.0, 5.0), allow_redirects=False)
            image = response.content
            with open(file_name.format(name, num, est), 'wb') as im:
                im.write(image)
            #request.urlretrieve(url, 'images/{}/{}.jpg'.format(name, num))
        except requests.exceptions.ConnectionError:
            print('Error occured')
        except requests.exceptions.Timeout:
            print('Timeout')


#! /usr/bin/env python
#
import numpy as np
import platform

def r8_uniform_01(seed):

    # *****************************************************************************80
    #
    # R8_UNIFORM_01 returns a unit pseudorandom R8.
    #
    #  Discussion:
    #
    #    This routine implements the recursion
    #
    #      seed = 16807 * seed mod ( 2^31 - 1 )
    #      r8_uniform_01 = seed / ( 2^31 - 1 )
    #
    #    The integer arithmetic never requires more than 32 bits,
    #    including a sign bit.
    #
    #    If the initial seed is 12345, then the first three computations are
    #
    #      Input     Output      R8_UNIFORM_01
    #      SEED      SEED
    #
    #         12345   207482415  0.096616
    #     207482415  1790989824  0.833995
    #    1790989824  2035175616  0.947702
    #
    #  Licensing:
    #
    #    This code is distributed under the GNU LGPL license.
    #
    #  Modified:
    #
    #    17 March 2013
    #
    #  Author:
    #
    #    John Burkardt
    #
    #  Reference:
    #
    #    Paul Bratley, Bennett Fox, Linus Schrage,
    #    A Guide to Simulation,
    #    Second Edition,
    #    Springer, 1987,
    #    ISBN: 0387964673,
    #    LC: QA76.9.C65.B73.
    #
    #    Bennett Fox,
    #    Algorithm 647:
    #    Implementation and Relative Efficiency of Quasirandom
    #    Sequence Generators,
    #    ACM Transactions on Mathematical Software,
    #    Volume 12, Number 4, December 1986, pages 362-376.
    #
    #    Pierre L'Ecuyer,
    #    Random Number Generation,
    #    in Handbook of Simulation,
    #    edited by Jerry Banks,
    #    Wiley, 1998,
    #    ISBN: 0471134031,
    #    LC: T57.62.H37.
    #
    #    Peter Lewis, Allen Goodman, James Miller,
    #    A Pseudo-Random Number Generator for the System/360,
    #    IBM Systems Journal,
    #    Volume 8, Number 2, 1969, pages 136-143.
    #
    #  Parameters:
    #
    #    Input, integer SEED, the integer "seed" used to generate
    #    the output random number.  SEED should not be 0.
    #
    #    Output, real R, a random value between 0 and 1.
    #
    #    Output, integer SEED, the updated seed.  This would
    #    normally be used as the input seed on the next call.
    #

    i4_huge = 2147483647

    seed = int(seed)

    seed = (seed % i4_huge)

    if (seed < 0):
        seed = seed + i4_huge

    if (seed == 0):
        print('')
        print('R8_UNIFORM_01 - Fatal error!')
        print('  Input SEED = 0!')
        exit('R8_UNIFORM_01 - Fatal error!')

    k = (seed // 127773)

    seed = 16807 * (seed - k * 127773) - k * 2836

    if (seed < 0):
        seed = seed + i4_huge

    r = seed * 4.656612875E-10

    return r, seed

def r8_normal_01(seed):

    # *****************************************************************************80
    #
    # R8_NORMAL_01 samples the standard normal probability distribution.
    #
    #  Discussion:
    #
    #    The standard normal probability distribution function (PDF) has
    #    mean 0 and standard deviation 1.
    #
    #    The Box-Muller method is used.
    #
    #  Licensing:
    #
    #    This code is distributed under the GNU LGPL license.
    #
    #  Modified:
    #
    #    21 January 2016
    #
    #  Author:
    #
    #    John Burkardt
    #
    #  Parameters:
    #
    #    Input, integer SEED, a seed for the random number generator.
    #
    #    Output, real X, a sample of the standard normal PDF.
    #
    #    Output, integer SEED, an updated seed for the random number generator.
    #

    r1, seed = r8_uniform_01(seed)
    r2, seed = r8_uniform_01(seed)

    x = np.sqrt(- 2.0 * np.log(r1)) * np.cos(2.0 * np.pi * r2)

    return x, seed

def r8vec_normal_01(n, seed):

    # *****************************************************************************80
    #
    # R8VEC_NORMAL_01 returns a unit pseudonormal R8VEC.
    #
    #  Licensing:
    #
    #    This code is distributed under the GNU LGPL license.
    #
    #  Modified:
    #
    #    04 March 2015
    #
    #  Author:
    #
    #    John Burkardt
    #
    #  Parameters:
    #
    #    Input, integer N, the number of entries in the vector.
    #
    #    Input, integer SEED, a seed for the random number generator.
    #
    #    Output, real X(N), the vector of pseudorandom values.
    #
    #    Output, integer SEED, an updated seed for the random number generator.
    #

    x = np.zeros(n)

    for i in range(0, n):
        x[i], seed = r8_normal_01(seed)

    return x, seed

def r8vec_normal_01_test():

    # *****************************************************************************80
    #
    # R8VEC_NORMAL_01_TEST tests R8VEC_NORMAL_01.
    #
    #  Licensing:
    #
    #    This code is distributed under the GNU LGPL license.
    #
    #  Modified:
    #
    #    04 March 2015
    #
    #  Author:
    #
    #    John Burkardt
    #

    n = 10
    seed = 123456789

    print('')
    print('R8VEC_NORMAL_01_TEST')
    print('  Python version: %s' % (platform.python_version()))
    print('  R8VEC_NORMAL_01 returns a vector of Normal 01 values')
    print('')
    print('  SEED = %d' % (seed))

    r, seed = r8vec_normal_01(n, seed)

    r8vec_print(n, r, '  Vector:')
#
#  Terminate.
#
    print('')
    print('R8VEC_NORMAL_01_TEST:')
    print('  Normal end of execution.')
    return


from io import BytesIO
from PIL import Image, ImageDraw, ImageFilter,ImageEnhance
import time
from time import sleep
from pynput.mouse import Button, Controller, Listener
import glob

import difflib

import pytesseract

import numpy as np
import pyscreenshot as ImageGrab
import cv2
import json
from types import SimpleNamespace

def listFile( path ):
        res = glob.glob(  path + "*")
        for i in range(len(res)):
                res[i] = res[i].replace("\\" , "/")
        return res

def on_click(x, y, button, pressed):
    global clickPos

    if not pressed:
        clickPos = (x,y)
        return False
# Collect events until released
def getNextClickPos():
    with Listener(on_click=on_click) as listener:
        listener.join()
        return clickPos

def moveTo( coord ):
    mouse = Controller()
    mouse.position = (coord[0],coord[1])

def moveToCoord( coord ):
    mouse = Controller()
    mouse.position = (coord['x'],coord['y'])

def moveThenClick( mouseBtn, coord ):
    mouse = Controller()
    mouse.position = (coord[0],coord[1])
    time.sleep(0.05)
    mouse.click( Button[mouseBtn],1)
    time.sleep(0.1)

def moveThenClickCoord( mouseBtn, coord ):
    mouse = Controller()
    mouse.position = (coord["x"],coord["y"])
    time.sleep(0.05)
    mouse.click( Button[mouseBtn],1)
    time.sleep(0.1)

def isPixelColorContainedInRange( begRangeRGB , endRangeRGB, auditedRGB ):
    isContained = True
    for ind in range(3):
        if( auditedRGB[ind] < begRangeRGB[ind] or auditedRGB[ind] > endRangeRGB[ind] ):
            return False

    return isContained

def findFirstPixePosInImgOnColor(im, boxRangeX, boxRangeY,targetColor ):
    for pX in range( boxRangeX ):
        for pY in range( boxRangeY ):
            color = im.getpixel( (pX ,pY) )
            if color == targetColor :
                return [pX,pY]
##replace outter circle by (0,0,0)
def mask_circle_solid(pil_img, background_color, blur_radius, offset=0):
    background = Image.new(pil_img.mode, pil_img.size, background_color)

    offset = blur_radius * 2 + offset
    mask = Image.new("L", pil_img.size, 0)
    draw = ImageDraw.Draw(mask)
    draw.ellipse((offset, offset, pil_img.size[0] - offset, pil_img.size[1] - offset), fill=255)
    mask = mask.filter(ImageFilter.GaussianBlur(blur_radius))

    return Image.composite(pil_img, background, mask)
# maybe try to create ^pixcel map to Optimize like image.load() ?
def getListOfPixelPosByColor(im, boxRangeX, boxRangeY, targetColor, blurArea ):
    targetColorBegRange = [ x - blurArea for x in targetColor]
    targetColorEndRange = [ x + blurArea for x in targetColor]
    imData = []
    for pX in range( boxRangeX ):
        for pY in range( boxRangeY ):
            colorVal = im.getpixel( (pX ,pY) )
            if isPixelColorContainedInRange( targetColorBegRange, targetColorEndRange, colorVal ) == False:
                continue

            imData.append( (pX ,pY) )
            # if colorVal in imData:
            #     oldVal = imData[colorVal]
            #     imData[colorVal] = oldVal+1
            # else :
            #     imData[ colorVal ] = 1

    return imData

################ IMG IN IMG // IMG TO TEXT // TEXT TO PRICE -- TODO LOAD GLOBAL VAR BY ENV VAR ( create .env )

# CONFIG
LTC_IMG_PATH = ['ancor/refs/items/leftTopItemBorder.png','ancor/refs/items/leftTopItemBorder2.png','ancor/refs/items/leftTopItemBorder3.png','ancor/refs/items/leftTopItemBorder4.png']
RTC_IMG_PATH =  ['ancor/refs/items/rightTopItemBorder.png','ancor/refs/items/rightTopItemBorder2.png','ancor/refs/items/rightTopItemBorder3.png','ancor/refs/items/rightTopItemBorder4.png']

GIDP_IMG_PATH = 'img/guessedItemDesription.png'
EIN_IMG_PATH = 'img/extractedItemName.png'

PRICING_JSON_PATH = 'json/items_pricing.json'
# -- tesseract config
pytesseract.pytesseract.tesseract_cmd = r'D:\Web_game_solo\OCR\tesseract'

# FUNCTIONS
def getItemList( jsonFilePath = PRICING_JSON_PATH ):
    input_file = open ( jsonFilePath )
    itemsData = json.load(input_file)

    itemList = []
    for index, item in enumerate(itemsData):
        itemList.append( item )

    return itemList , itemsData

def contrast( val , img ):
    #image brightness enhancer
    enhancer = ImageEnhance.Contrast(img)

    factor = val #gives original image
    im_output = enhancer.enhance(factor)
    return im_output

def getImgPosInImg( large_img_path , small_img_path , method = cv2.TM_SQDIFF_NORMED, debug = False ):
    # Read the images from the file
    large_image = cv2.imread(large_img_path)
    small_image = cv2.imread(small_img_path)
    result = cv2.matchTemplate(small_image, large_image, method)
    # We want the minimum squared difference
    mn,_,mnLoc,_ = cv2.minMaxLoc(result)
    # Draw the rectangle:
    # Extract the coordinates of our best match
    MPx,MPy = mnLoc
    # print( MPx,MPy )
    if debug :
        # - - - DEBUG  Step 2: Get the size of the template. This is the same size as the match.
        trows,tcols = small_image.shape[:2]
        # Step 3: Draw the rectangle on large_image
        cv2.rectangle(large_image, (MPx,MPy),(MPx+tcols,MPy+trows),(0,0,255),2)
        # Display the original image with the rectangle around the match.
        cv2.imshow('output',large_image)
        # The image is only displayed if we call this
        cv2.waitKey(0)

    return [MPx,MPy]

def extractItemNameAsImg( mousePos, screenArea , resultImgPath, debug = False, iter = 0 ):
    im = ImageGrab.grab( bbox=( mousePos['x']-screenArea, mousePos['y']-screenArea, mousePos['x']+screenArea, mousePos['y']+screenArea), backend="mss",childprocess=False )  # X1,Y1,X2,Y2
    im.save(GIDP_IMG_PATH)

    tlBorder = getImgPosInImg( GIDP_IMG_PATH, LTC_IMG_PATH[iter], debug = debug )
    trBorder = getImgPosInImg( GIDP_IMG_PATH, RTC_IMG_PATH[iter], debug = debug )
    # print( tlBorder,  trBorder )
    cropped = Image.open( GIDP_IMG_PATH )
    # Setting the points for cropped image'test shop

    left = tlBorder[0]+20
    right = trBorder[0]-20

    top = tlBorder[1] +15
    bottom = tlBorder[1] + 25
    # Cropped image of above dimension
    # (It will not change original image)

    if debug :
        print('imgSize before ' , cropped.size )
        print('left : ' ,left ,'top : ' ,top ,'right : ' ,right ,'bottom : ' ,bottom)

    cropped = cropped.crop((left, top, right, bottom))

    if debug :
        print('imgSize after ' , cropped.size )
    # # Shows the image in image viewer
    # cropped.show()

    try:
        cropped.save(resultImgPath)
    except:
        print('could not saved cropped img')
        return None

    # im = im.crop((tlBorder[0], tlBorder[1]+ 5, trBorder[0], trBorder[1] +5  ))
    return cropped

def getItemPriceByParsingMousePosImg( mousePos, nearRange = 220, fontAverageRangeColor = ((180,180,180),(255,255,255)), debug = False, iter = 0 ):

    moveToCoord( mousePos )
    sleep( 0.5 )

    nearRange = 220
    extractedImg = extractItemNameAsImg( mousePos, nearRange, EIN_IMG_PATH, debug = debug, iter = iter  )
    # try :
    #     extractedImg.save("img/tmpState.png")
    # except :
    #     print( 'imgSat' ,  extractedImg )

    if( extractedImg == None ):
        return None

    extractedImg = extractedImg.convert("RGBA")
    pixdata = extractedImg.load()
    imgsize = extractedImg.size

    for pX in range( imgsize[0] ):
        for pY in range( imgsize[1] ):
            colorVal = extractedImg.getpixel( (pX ,pY) )
            if isPixelColorContainedInRange(  fontAverageRangeColor[0], fontAverageRangeColor[1], colorVal ) == False:
                pixdata[pX, pY] = (0, 0, 0, 255)

    extractedImg.save( EIN_IMG_PATH )
    extractedText = pytesseract.image_to_string( EIN_IMG_PATH )
    parsedExtractedText = extractedText.strip()

    itemsList, itemData = getItemList()
    match = difflib.get_close_matches( parsedExtractedText , itemsList)

    if debug :
        print("extracted text => ",  parsedExtractedText  )
        print( "item => " , itemData )
        print( "match => ", match , len(match) )

    if len(match) == 0:
        return None

    pricingData = itemData[match[0]] if itemData.get(match[0]) else None

    return pricingData

# # getImgPosInImg( 'img/guessedItemDesription.png', "ancor/refs/items/leftTopItemBorder.png", method=cv2.TM_SQDIFF_NORMED ,  debug=True )

# getImgPosInImg( 'img/guessedItemDesription.png', "ancor/refs/items/rightTopItemBorder4.png", method=cv2.TM_SQDIFF_NORMED ,  debug=True )
# extractedText = pytesseract.image_to_string( 'img/extractedItemName.png' )
# parsedExtractedText = extractedText.strip()

# print( parsedExtractedText , extractedText )


r"""
    Processes the Excel file in:
        D:\data\NRSI\1033H
"""
import pandas as pd
import numpy as np
import os

# First - load all the folders
excelFileToValidate = (
    r"D:\data\NRSI\1033H\NRSI_1033H_Camera Data_2019_03_14_All Data.xlsx"
)

# Load the Excel file with the file paths to validate
df = pd.read_excel(excelFileToValidate, "Wildlife Camera Data_QAQC")
df = df.replace(np.nan, "", regex=True)

count = 0
taggedImagePaths: list[str] = []
for i, row in df.iterrows():
    count += 1
    # Guess the folder from the Excel file
    taggedImagePath: str = str(row["Picture File"]).strip()
    if os.path.isfile(taggedImagePath):
        print(taggedImagePath)
        taggedImagePaths.append(taggedImagePath)
    # else:
    #     print(f'Failed to find tagged image from row: {i} - "{taggedImagePath}"')

numTaggedImages = len(taggedImagePaths)
numMissingImages = count - numTaggedImages
print(
    f"Found a total of {numTaggedImages} tagged images - out of {count} (missing {numMissingImages})"
)


from datetime import datetime

from django.template import Library
from django.utils import timezone
from django.utils.dateparse import parse_datetime, parse_date, parse_time

register = Library() #pylint: disable=invalid-name

def _datetime(dtime):
    """Forces a variable to be a datetime (not date or time)"""
    now = datetime.now(timezone.utc)
    if isinstance(dtime, str):
        if ' ' in dtime or 'T' in dtime:
            dtime = parse_datetime(dtime)
        elif '-' in dtime:
            dtime = parse_date(dtime)
        elif ':' in dtime:
            dtime = parse_time(dtime)
        else:
            raise ValueError("Should be a datetime object, got string: %s" % dtime)
    if not isinstance(dtime, datetime) or not dtime.tzinfo:
        return datetime(
            getattr(dtime, 'year', now.year),
            getattr(dtime, 'month', now.month),
            getattr(dtime, 'day', now.day),
            getattr(dtime, 'hour', 0),
            getattr(dtime, 'minute', 0),
            getattr(dtime, 'second', 0),
            getattr(dtime, 'microsecond', 0),
            timezone.utc)
    return dtime or now

@register.filter("timedelta")
def _timedelta(dtime, other=None):
    """Returns the clean timedelta for this dt, other can be any date/time or None for now()"""
    return _datetime(other) - _datetime(dtime)

@register.filter("totalseconds")
def totalseconds(dtime, other=None):
    """Return the number of seconds in this delta, can be positive or negative"""
    return _timedelta(dtime, other).total_seconds()


from flask import *
from flaskext.mysql import MySQL
from random import *
from datetime import *
from datetime import datetime
from datetime import date
import os
import string
import requests
import math
import time
import requests
import json

app = Flask(__name__,template_folder ='template')

app.secret_key = os.urandom(34)

app.config['MYSQL_DATABASE_USER'] = 'root'
app.config['MYSQL_DATABASE_PASSWORD'] = 'lallantiwari'
app.config['MYSQL_DATABASE_DB'] = 'frappe'
app.config['MYSQL_DATABASE_HOST'] = 'localhost'
mysql = MySQL(app)

#--------------------------------------------------------------------------------------------------

#MySQL Query Driver function

#Query can be directly passed as an argument without setting the coonection and committing the output

def mysql_query(sql):
	connection = mysql.connect()
	cursor = connection.cursor()
	if sql.strip().split(' ')[0].lower() == "select" :
		print(sql)
		cursor.execute(sql)
		print(cursor._executed)

		columns = [column[0] for column in cursor.description]
		results = []
		for row in cursor.fetchall():
			results.append(dict(zip(columns, row)))
		data = results
		cursor.close()
		connection.close()
		return data
	if sql.strip().split(' ')[0].lower() != "select" :
		cursor.execute(sql)
		print(cursor._executed)
		connection.commit()
		cursor.close()
		connection.close()
		return None

# How to use this function
# --> mysql_query("Select * from user_master;")
# --> mysql_query(" select * from user_master where emailid='{}';".format(email))

#Mysql Function Ended

#--------------------------------------------------------------------------------------------

#---------------------------------------------------------------------------------------------

#Code For Library management

#----------------------------------------------------------------------------------------------

#********************************************************************************************

#Function to display and import book details

@app.route('/',methods=['GET','POST'])
def book():
	bdata=mysql_query("SELECT * from books")
	if request.method=="POST":
		#----------------------------------------------------------------------------------------
		#add button for importing data from api
		if 'add' in request.form:
			#using try-catch statement for catching any exception
			try:
				no=request.form['nbooks']
				#converting the string value to integer
				no=int(no)
				#--------------------------------------
				title=request.form['title']
				author=request.form['author']
				isbn=request.form['isbn']
				pub=request.form['publisher']
				full_data=[]
				#Calculating how many time api should run
				page=no/20
				bno=math.ceil(page)
				#----------------------------------------
				#loop for importing data as per requirement and appending it into a list
				for i in range(1,bno+1):
					data=[]
					req=requests.get("https://frappe.io/api/method/frappe-library?page={}&title={}&authors={}&isbn={}&publisher={}".format(i,title,author,isbn,pub))
					data=req.json()
					full_data.append(data)
				#loop for iterating through the data fetched from the api
				for x in full_data:
					for i in range(0,no):
						bid=x['message'][i]['bookID']
						print(bid)
						#checking if the imported value already exists in the database or not
						check=mysql_query("SELECT book_id from books where book_id={}".format(bid))
						#if the details does not exists in the database
						if len(check)==0:
							connection = mysql.connect()
							cursor = connection.cursor()
							#Using normal cursor connection instead of mysql function for escaping aphostrphes
							#---------------------------------------------------------------------------------
							sql="INSERT INTO books(book_id,title,authors,average_rating,isbn,isbn13,language_code,num_pages,ratings_count,text_reviews_count,publication_date,publisher) VALUES(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
							#Date converted into yyyy-mm-dd fromat
							time=datetime.strptime(x['message'][i]['publication_date'],'%m/%d/%Y')
							sqldt=(x['message'][i]['bookID'],x['message'][i]['title'],x['message'][i]['authors'],x['message'][i]['average_rating'],x['message'][i]['isbn'],x['message'][i]['isbn13'],x['message'][i]['language_code'],x['message'][i]['  num_pages'],x['message'][i]['ratings_count'],x['message'][i]['text_reviews_count'],time,x['message'][i]['publisher'])
							cursor.execute(sql,sqldt)
							connection.commit()
						#-------------------------------------------------------------------------------------
						#Stock Management is done through the api data :- Depending of the repeated details
						#If the details exists in the database
						else:
							#if the details exists then the stock of the book will be increamented by 1
							mysql_query("UPDATE books set stock=stock+1 where book_id={}".format(bid))
							mysql_query("UPDATE books set total=total+1 where book_id={}".format(bid))
					#flash is used to give notification or warning to the user by flashing the entered message with its category
					flash('Books Data fetched Successfully','success')
				return redirect(url_for('book'))
			except:
				flash('Sufficient data was not found','warning')
				return redirect(url_for('book'))
		#----------------------------------------------------------------------------------------
		#Del button for deleting data from database
		if 'del' in request.form:
			bid=request.form['del']
			#fetching return dates of issued books
			tdata=mysql_query("SELECT return_date from transaction where book_id={}".format(bid))
			#-------------------------------------
			#if the book is not reuturned than its details cannot be deleted
			if len(tdata)==0:
				flash('Cannot Delete ! Book is Already Issued ','warning')
			#if the book is returned then the details can be deleted
			else:
				mysql_query("DELETE from books where book_id={}".format(bid))
				flash('Book Data Deleted Successfully !','success')
			return redirect(url_for('book'))
		#----------------------------------------------------------------------------------------
		#Update button for updating books details
		if 'update' in request.form:
			bid=request.form['update']
			title=request.form['title']
			author=request.form['author']
			arating=request.form['rating']
			isbn=request.form['isbn']
			isbn13=request.form['isbn13']
			lcode=request.form['lcode']
			npage=request.form['pages']
			rcount=request.form['rcount']
			treview=request.form['treview']
			pdate=request.form['pdate']
			pub=request.form['publisher']
			connection = mysql.connect()
			cursor = connection.cursor()
			query="UPDATE books set title=%s,authors=%s,average_rating=%s,isbn=%s,isbn13=%s,language_code=%s,num_pages=%s,ratings_count=%s,text_reviews_count=%s,publication_date=%s,publisher=%s where book_id=%s"
			values=(title,author,arating,isbn,isbn13,lcode,npage,rcount,treview,pdate,pub,bid)
			cursor.execute(query,values)
			connection.commit()
			return redirect(url_for('book'))

	return render_template('book_details.html',bdata=bdata)

#**********************************************************************************************

#Function for displaying member details

@app.route('/member_details',methods=['GET','POST'])
def member():
	mdata=mysql_query("SELECT * from members")
	#----------------------------------------------------------------------------------------
	#del button for deleting the member data from the database
	if request.method=="POST":
		if 'del' in request.form:
			mid=request.form['del']
			check=mysql_query("SELECT book_id from transaction where member_id={} and return_date is Null".format(mid))
			if len(check)==0:
				mysql_query("DELETE from members where members.member_id={}".format(mid))
				flash('Member Delete Successfully !','success')
			else:
				flash('Cannot Delete Member ! Issued book is not returned','danger')
			return redirect(url_for('member'))
		#----------------------------------------------------------------------------------------
		#update for updating member Data into the database
		if 'update' in request.form:
			mid=request.form['update']
			name=request.form['name']
			phone=request.form['number']
			address=request.form['address']
			mysql_query("UPDATE members SET member_name='{}',member_phone={},member_address='{}' where member_id={}".format(name,phone,address,mid))
			flash('Member Details Updated Successfully !','success')
			return redirect(url_for('member'))
		#----------------------------------------------------------------------------------------
		#add button for adding new member into the database
		if 'add' in request.form:
			name=request.form['name']
			phone=request.form['number']
			email=request.form['email']
			address=request.form['address']
			#Checking if details are already available in the database or not
			edata=mysql_query("SELECT member_id from members where member_email='{}' OR member_phone='{}' ".format(email,phone))
			#---------------------------------------------------------------------
			#If details does not exists than new member will be added to the database
			if len(edata)==0:
				mysql_query("INSERT INTO members(member_name,member_phone,member_address,member_email) value('{}',{},'{}','{}')".format(name,phone,address,email))
				flash('Member Registered Successfully !','success')
			#if details already exists than it will give a warning
			else:
				flash('Member Already Exists !','warning')
			return redirect(url_for('member'))
		#----------------------------------------------------------------------------------------
		#Settle button to settle the outstanding amount of the member
		if 'settle' in request.form:
			amount=request.form['amount']
			mid=request.form['member']
			print(amount)
			mysql_query("UPDATE members set outstanding_amount=outstanding_amount-{},total_amount=total_amount+{} where member_id={}".format(amount,amount,mid))
			flash('Outstanding Amount Settled Successfully !', 'success')
			return redirect(url_for('transaction'))

	return render_template('member_details.html',mdata=mdata)

#************************************************************************************************

#Function For managing book issue and return

@app.route('/book_issued',methods=['GET','POST'])
def transaction():
	tdata=mysql_query("SELECT * from transaction join members using(member_id) join books using(book_id) order by transaction_id DESC")
	mdata=mysql_query("SELECT * from members")
	bdata=mysql_query("SELECT * from books")
	#----------------------------------------------------------------------------------------
	if request.method=="POST":
		#issueb button for issuing book to the members
		if "issueb" in request.form:
			name=request.form['name']
			book=request.form['book']
			tdate=date.today()
			#After fetching the details checking if the required book is in stock or not
			bstock=mysql_query("SELECT stock from books where book_id={}".format(book))
			#Checking the outstanding amount of the member who is issuing the book
			outstanding=mysql_query("SELECT outstanding_amount from members where member_id={}".format(name))
			#Checking if the earlier issued book is returned or not
			returnb=mysql_query("SELECT return_date from transaction where member_id={} order by transaction_id DESC limit 1".format(name))
			noissue=mysql_query("SELECT transaction_id from transaction where member_id={}".format(name))
			#condition to check if the book is in stock
			if bstock[0]['stock']>=1:
				#Earlier issued book is returned or not, or no book is issued yet
				if len(noissue)==0 or returnb[0]['return_date'] is not None:
					#if the oustanding amount is less than 500 or not
					if outstanding[0]['outstanding_amount']<500:
						#if the user meets all the condition then the book will be issued
						mysql_query("INSERT INTO transaction(book_id,member_id,issue_date) values({},{},'{}')".format(book,name,tdate))
						mysql_query("UPDATE books set stock=stock-1 where book_id={}".format(book))
						flash("Book Issued Successfully !",'success')
					#Flashing message for exceeding outstanding amount
					else :
						flash('Outstanding amount is exceeding Rs.500','warning')
				#Flashing message for book not returned
				else:
					flash('Prior issued book is not returned','warning')
			#Flashing message for book is out of stock
			else:
				flash('Book is out of stock', 'warning')
			return redirect(url_for('transaction'))
		#----------------------------------------------------------------------------------------
		#return button for returning the book
		if 'return' in request.form:
			tid=request.form['return']
			bid=request.form['book']
			mid=request.form['member']
			rdate=date.today()
			rent=request.form['rent']
			paid=request.form['paid']
			mid=request.form['member']
			#checking if the book rent is paid at the time of returning the book or not
			#--------------------------------------------------------------------------
			#If the rent is paid at the time of returning book
			if paid=="yes":
				#return date is set
				mysql_query("UPDATE transaction set return_date='{}',rent={},rent_paid='{}' where transaction_id={}".format(rdate,rent,paid,tid))
				#the total amount paid by user will be updated
				mysql_query("UPDATE members set total_amount=total_amount+{} where member_id={}".format(rent,mid))
				#updating the book stocks
				mysql_query("UPDATE books set stock=stock+1 where book_id={}".format(bid))
				flash('Book returned Successfully and rent is paid', 'success')
			#if the rent is not paid at the time of returning the book
			elif paid=="no":
				#outstanding amount is fechted from database
				amt=mysql_query("SELECT outstanding_amount from members where members.member_id={}".format(mid))
				rent1=int(rent)
				final_amt=rent1+amt[0]['outstanding_amount']
				#if the outstanding is getting greater the 500 when not paying the rent at the time
				#of the return then the book cannot be returned member has to settle the outstanding amount
				if final_amt<500:
					mysql_query("UPDATE transaction set return_date='{}',rent={} where transaction_id={}".format(rdate,rent,tid))
					mysql_query("UPDATE members set outstanding_amount=outstanding_amount+{} where member_id={}".format(rent,mid))
					flash('Book returned Successfully and rent is not paid', 'info')
					mysql_query("UPDATE books set stock=stock+1 where book_id={}".format(bid))
				else:
					flash('Cannot Return Book ! Outstanding amount is exceeding 500','danger')
			return redirect(url_for('transaction'))
		#----------------------------------------------------------------------------------------
		#settle button to settle the outstanding amount
		if 'settle' in request.form:
			amount=request.form['amount']
			tid=request.form['settle']
			mid=request.form['member']
			print(amount)
			mysql_query("UPDATE members set outstanding_amount=outstanding_amount-{},total_amount=total_amount+{} where member_id={}".format(amount,amount,mid))
			flash('Outstanding Amount Settled Successfully !','success')
			mysql_query("UPDATE transaction set rent_paid='yes' where member_id=(select member_id from members where outstanding_amount=0 and member_id={})".format(mid))
			return redirect(url_for('transaction'))

	return render_template('transaction_details.html',tdata=tdata,mdata=mdata,bdata=bdata)

#---------------------------------------------------------------------------------------------

#Code For Library management Ended

#----------------------------------------------------------------------------------------------

#**********************************************************************************************

#---------------------------------------------------------------------------------------------

#Code For Report generation

#----------------------------------------------------------------------------------------------

#Function for Generating reports

@app.route('/reports',methods=['GET','POST'])
def report():
	if request.method=="POST":
		if 'report1' in request.form:
			mname=[]
			tvalue=[]
			maxdata=mysql_query("SELECT * from members order by total_amount DESC")
			#converting values into list for the chart
			for x in maxdata:
				mname.append(x['member_name'])
				tvalue.append(x['total_amount'])
			return render_template('reports.html',maxdata=maxdata,mname=mname,tvalue=tvalue)
		#the most popular book is taken out on the total issued number
		if 'report2' in request.form:
			tissue=[]
			bname=[]
			bookdata=mysql_query("SELECT b.book_id,b.title,b.authors,b.publication_date,b.stock,b.total,b.publisher,count(t.book_id) from transaction t,books b where b.book_id = t.book_id group by t.book_id order by count(t.book_id) DESC")
			#converting values into list for the chart
			for i in bookdata:
				tissue.append(i['count(t.book_id)'])
				bname.append(i['title'])
			return render_template('reports.html',bookdata=bookdata,tissue=tissue,bname=bname)
	return render_template('reports.html')

#---------------------------------------------------------------------------------------------

#Code For Report generation Ended

#----------------------------------------------------------------------------------------------

#**********************************************************************************************

#--------------------------------------------------------------------------------------------

# For accessing the login page and to view book details use '/login' after the local host address

#---------------------------------------------------------------------------------------------
#Function for Guest view
@app.route('/login',methods=['GET','POST'])
def login():
	if request.method=="POST":
		if 'check' in request.form:
			email=request.form['email']
			data=mysql_query("SELECT member_id from members where member_email='{}'".format(email))
			if data:
				return redirect(url_for('checkbooks'))
			else:
				print("wrong data entered")
	return render_template('login.html')

#Function for showing book details for the guest view users
@app.route('/checkbooks',methods=['GET','POST'])
def checkbooks():
	bdata=mysql_query("SELECT * from books")
	return render_template('checkbooks.html',bdata=bdata)

#--------------------------------------------------------------------------------------------

# Login code ended

#---------------------------------------------------------------------------------------------

if __name__ == "__main__":
	app.run(debug = True)


from functools import reduce
from itertools import chain

def lmap(f, l):
	return list(map(f, l))

def split_on_nl(xs):
	stuff = [[]]
	for x in xs:
		if x == "\n":
			stuff.append([])
			continue
		stuff[-1].append(x)

	return stuff

def p_boards(bs):
	for b in bs:
		for l in b:
			print(l)
		print()

def mark_cell(cell, call):
	(num, res) = cell
	if num == call:
		return (num, True)
	return cell

def mark(bs, call):
	for i, _ in enumerate(bs):
		bs[i] = lmap(lambda col: lmap(lambda cel: mark_cell(cel, call), col), bs[i])

def check_if_wins(board):
	# horizontal
	for row in board:
		winning_row = True
		for c in row:
			if c[1] == False:
				winning_row = False
		if winning_row:
			# print("doublefuck")
			return True

	# list transpose nicked from so again
	for col in list(map(list, zip(*board))):
		winning_col = True
		for c in col:
			if c[1] == False:
				winning_col = False
		if winning_col:
			# print("fuck")
			return True
	return False

def num_if_false(cell):
	(num, res) = cell
	if res == False:
		return num
	return 0

def calc1(calls, boards):
	for c in calls:
		mark(boards, c)

		for board in boards:
			if check_if_wins(board):
				flatboard = chain(*board)
				total = reduce(lambda l, r: l + num_if_false(r), flatboard, 0)
				p_boards([board])
				# print(list(flatboard))
				# print(board)
				print(total, c)
				print(total * c)
				return

def calc2(calls, boards):
	final = None
	last = None
	for i, c in enumerate(calls):
		mark(boards, c)

		for board in boards.copy():
			if check_if_wins(board):
				boards.remove(board)
		if len(boards) == 1:
			final = boards[0]
			last = i
			break

	last += 1
	while not check_if_wins(boards[0]):
		mark(boards, calls[last])
		last += 1

	flatboard = chain(*boards[0])
	total = reduce(lambda l, r: l + num_if_false(r), flatboard, 0)
	print(total, calls[last-1])
	print(total * calls[last-1])

with open("ch.txt") as file:
	lines = file.readlines()

	calls = lmap(int, lines[0].split(","))
	rest = split_on_nl(lines[2:])
	rest = lmap(lambda s: lmap(lambda t: t.split(), s), rest)
	boards = lmap(lambda s: lmap(lambda t: lmap(lambda u: (int(u), False), t), s), rest)

	print(calls)
	print()

	# calc1(calls, boards)
	calc2(calls, boards)


import matplotlib.pyplot as plt
import numpy as np

np.set_printoptions(precision=5, suppress=True)

def helper():
    return f'''Newton's Polynomial Interpolation.

Output:
    D : Matrix array with the divided differences table.
    c : Coefficients of the Newton's polynomial.

Parameters: newtonPoly(x,y)

Parameters: newtonPoly(X, Y, plot=False, function=None)
    X, Y: Dataset to interpolate.
    plot: When True, it will display a plot with continuous graph of the corresponding Newton's polynomial with discrete points where it interpolates.
    function: When specified (either as Python or lambda function), it will display a comparison plot with the function, polynomial interpolation and discrete X, Y points.

'''

def newtonpoly(x, y):
    n = len(x)
    F = np.zeros((n, n))
    F[:, 0] = y

    for i in range(1, n):
        for j in range(1, i + 1):
            F[i, j] = (F[i, j - 1] - F[i - 1, j - 1]) / (x[i] - x[i - j])

    P = np.zeros(n)

    for i in range(n):
        P[i] = F[i, i]

        for j in range(i - 1, -1, -1):
            P[j] = F[j, j] + (x[i] - x[j]) * P[j + 1]

    return F, P


# Program to test/demonstrate consistency of results from getcal()
from array import array
from ds3231_pb import DS3231

# This takes 12.5 hours to run: to sve you the trouble here are results from one sample of Pyboard.

# Mean and standard deviation of RTC correction factors based on ten runs over different periods.
# Conclusion: for the best possible accuracy, run for 20 minutes. However a ten minute run gave
# a result within 2ppm (one minute/yr).
# >>> test()
# t =  5 -174 -175 -175 -172 -175 -175 -172 -174 -175 -172  avg -173.8 sd   1.3
# t = 10 -175 -175 -175 -175 -173 -175 -176 -175 -174 -175  avg -174.8 sd   0.7
# t = 20 -175 -175 -175 -175 -174 -175 -175 -175 -175 -174  avg -174.8 sd   0.4
# t = 40 -175 -175 -175 -174 -174 -175 -174 -174 -175 -174  avg -174.4 sd   0.5

def test():
    NSAMPLES = 10
    a = DS3231()
    for t in (5, 10, 20, 40):
        values = array('f', (0 for z in range(NSAMPLES)))
        print('t = {:2d}'.format(t), end = '')
        for x in range(NSAMPLES):
            cal = a.getcal(t)
            values[x] = cal
            print('{:5d}'.format(cal), end = '')
        avg = sum(values)/NSAMPLES
        sd2 = sum([(v -avg)**2 for v in values])/NSAMPLES
        sd = sd2 ** 0.5
        print('  avg {:5.1f} sd {:5.1f}'.format(avg, sd))


import os
from flask_wtf import FlaskForm

from wtforms import PasswordField, StringField, SubmitField, TextAreaField, SelectField
from wtforms.validators import DataRequired, Length, Email
from wtforms import ValidationError

from flask_wtf.file import FileField, FileRequired
import phonenumbers

from flask import current_app, render_template
from werkzeug.utils import secure_filename

from ..email import send_email_attachment, send_email

STATE_CHOICES = [('--Choose--', '--Choose--'), ("AL - Alabama", "AL - Alabama"), ("AK - Alaska", "AK - Alaska"), ("AZ - Arizona", "AZ - Arizona"), ("AR - Arkansas", "AR - Arkansas"), ("CA - California", "CA - California"), ("CO - Colorado", "CO - Colorado"),
                 ("CT - Connecticut", "CT - Connecticut"), ("DC - Washington DC", "DC - Washington DC"), ("DE - Deleware", "DE - Deleware"), ("FL - Florida", "FL - Florida"), ("GA - Georgia", "GA - Georgia"),
                 ("HI - Hawaii", "HI - Hawaii"), ("ID - Idaho", "ID - Idaho"), ("IL - Illinios", "IL - Illinios"), ("IN - Indiana", "IN - Indiana"), ("IA - Iowa", "IA - Iowa"), ("KS - Kansas", "KS - Kansas"), ("KY - Kentucky", "KY - Kentucky"), ("LA - Louisiana", "LA - Louisiana"), ("ME - Maine", "ME - Maine"), ("MD - Maryland", "MD - Maryland"), ("MO - Missouri", "MO - Missouri"), ("MT - Montana", "MT - Montana"), ("NE - Nebraska", "NE - Nebraska"), ("NV - Nevada", "NV - Nevada"), ("NH - New Hampshire", "NH - New Hampshire"),("MA - Massachusetts", "MA - Massachusetts"), ("MI - Michigan", "MI - Michigan"), ("MN - Minnesota", "MN - Minnesota"), ("MS - Mississippi", "MS - Mississippi"),("NJ - New Jersey", "NJ - New Jersey"), ("NM - New Mexico", "NM - New Mexico"), ("NY - New York", "NY - New York"), ("NC - North Carolina", "NC - North Carolina"),
                 ("ND - North Dakota", "ND - North Dakota"), ("OH - Ohio", "OH - Ohio"), ("OK - Oklahoma","OK - Oklahoma"), ("OR - Oregon", "OR - Oregon"), ("PA - Pennsylvania", "PA - Pennsylvania"),("RI - Rhode Island", "RI - Rhode Island"), ("SC - South Carolina","SC - South Carolina"), ("SD - South Dakota", "SD - South Dakota"), ("TN-Tennessee", "TN-Tennessee"),
                 ("TX - Texas", "TX - Texas"), ("UT - Utah", "UT - Utah"), ("VT - Vermont", "VT - Vermont"), ("VA - Virgina", "VA - Virgina"), ("WA - Washington", "WA - Washington"), ("WV - West Virginia", "WV - West Virginia"),
                 ("WI - Wisconsin", "WI - Wisconsin"), ("WY - Wyoming", "WY - Wyoming")]

class PostResumeForm(FlaskForm):
    first_name = StringField('First Name', validators=[DataRequired(message="Please enter first name.")])
    last_name = StringField('Last Name', validators=[DataRequired()])
    contact_number = StringField(
        'Contact Number', validators=[DataRequired(), Length(min=10,max=10)])
    alternate_contact_number = StringField(
        'Alternate Contact Number(if any)', validators=[Length(min=10, max=10)])
    email = StringField('Contact Email', validators=[DataRequired(), Email()])
    alternate_email = StringField('Alternate Contact Email(if any)', validators=[ Email()])
    city = StringField('City', validators=[DataRequired()])
    state = SelectField(
        'State', validators=[DataRequired()], choices=STATE_CHOICES)
    visa_status = SelectField('Visa Status', validators=[DataRequired()],
                              choices=[('--Choose--', '--Choose--'), ('ACTIVE', 'ACTIVE'),
                                 ('EXPIRED', 'EXPIRED'),
                                 ('INVALID', 'INVALID')])
    current_status = SelectField('Current Status (*): (Working or not ) :', validators=[DataRequired()],
                                 choices=[('--Choose--', '--Choose--'),('WORKING', 'WORKING'),
                                          ('NOT WORKING', 'NOT WORKING'),
                                       ('NOTICE PERIOD', 'NOTICE PERIOD')])
    job_title = StringField('Job Title', validators=[DataRequired()])
    available = SelectField('Availability to start the project (*) :', validators=[DataRequired()],
                            choices=[('--Choose--', '--Choose--'), ('YES', 'YES'),
                                          ('NO', 'NO'),
                                          ])
    cover_letter = FileField(validators=[FileRequired()])
    resume = FileField(validators=[FileRequired()])
    summary = TextAreaField('Summary')
    submit = SubmitField('Post Resume')

    def validate_contact_number(form, field):
        # print(f"Debug1 : Outside validate_contact_number")
        # print(f"Debug11 : {field.data}")
        if len(field.data) > 10:
            # print(f"Debug2 : Inside validate_contact_number")
            raise ValidationError('Phone number should be 10 digit long.')

    def validate_alternate_contact_number(form, field):
        # print(f"Debug1 : Outside validate_contact_number")
        # print(f"Debug11 : {field.data}")
        if len(field.data) > 10:
            # print(f"Debug2 : Inside validate_contact_number")
            raise ValidationError('Phone number should be 10 digit long.')

    def validate_state(form, field):
        # print(f"Debug3 : Outside validate_state")
        if field.data == '--Choose--':
            # print(f"Debug4 : Inside validate_state")
            raise ValidationError('Please choose atleast one.')
        # print(f"Debug12 : {field.data}")

    def validate_visa_status(form, field):
        # print(f"Debug5 : Outside validate_state")
        if field.data == '--Choose--':
            # print(f"Debug6 : Inside validate_state")
            raise ValidationError('Please choose atleast one.')
        # print(f"Debug13 : {field.data}")

    def validate_current_status(form, field):
        # print(f"Debug7 : Outside validate_current_status")
        if field.data == '--Choose--':
            # print(f"Debug8 : Inside validate_current_status")
            raise ValidationError('Please choose atleast one.')
        # print(f"Debug14 : {field.data}")

    def validate_available(form, field):
        # print(f"Debug9 : Outside validate_available")
        if field.data == '--Choose--':
            # print(f"Debug9 : Inside validate_available")
            raise ValidationError('Please choose atleast one.')
        # print(f"Debug15 : {field.data}")

    def allowed_image(self, filename):
        if not "." in filename:
            return False
        ext = filename.rsplit(".", 1)[1]
        if ext.upper() in current_app.config["ALLOWED_IMAGE_EXTENSIONS"]:
            return True
        else:
            return False

    def allowed_file(self, filename):
        if not "." in filename:
            return False
        ext = filename.rsplit(".", 1)[1]
        if ext.upper() in current_app.config["ALLOWED_FILE_EXTENSIONS"]:
            return True
        else:
            return False

    def upload_image(self, image):
        if self.allowed_image(image.filename):
            filename = secure_filename(image.filename)
            image.save(os.path.join(
                current_app.config["IMAGE_UPLOADS"], filename))
            print("Image saved")
        else:
            print("Image was not saved.")

    def upload_file(self, ifile):
        # Make instance directory
        if not os.path.exists(current_app.config["FILE_UPLOADS"]):
            os.makedirs(current_app.config["FILE_UPLOADS"])
        else:
            print(f"{current_app.config['FILE_UPLOADS']} already exists.")
        if self.allowed_file(ifile.filename):
            filename = secure_filename(ifile.filename)
            ifile.save(os.path.join(
                current_app.config["FILE_UPLOADS"], filename))
            print("File saved")
        else:
            print("File was not saved.")

    def post_mail(self, cover_letter, resume, form):
        base_dir = current_app.config["FILE_UPLOADS"]
        attachment_list = []
        attachment_list.append({'name': 'cover_letter', 'location': os.path.join(
            base_dir, secure_filename(cover_letter.filename))})
        attachment_list.append({'name': 'resume', 'location': os.path.join(
            base_dir, secure_filename(resume.filename))})
        print(f"In Post Mail..")
        for attachment in attachment_list:
            print(f"post mail >>>> {attachment}")
        # Send email
        send_email_attachment("We recieved Resume.", sender=current_app.config['MAIL_DEFAULT_SENDER'], recipients_list=['nandhu.misc@gmail.com'], text_body=render_template(
            'email/recieved_resume.txt', first_name="Nandha", recruiter_name='Dhamu', form=form), html_body=render_template('email/recieved_resume.html', first_name="Nandha", recruiter_name='Dhamu', form=form), attachment_list=attachment_list)

class ContactUsForm(FlaskForm):
    first_name = StringField('First Name (*)', validators=[
                             DataRequired(message="Please enter first name.")])
    contact_number = StringField(
        'Contact Number (*)', validators=[DataRequired(), Length(min=10, max=10)])
    email = StringField('Contact Email (*)',
                        validators=[DataRequired(), Email()])
    state = SelectField(
        'State (*)', validators=[DataRequired()], choices=STATE_CHOICES)
    city = StringField('City (*)', validators=[DataRequired()])
    comments = TextAreaField('Comments (If any):')
    submit = SubmitField('SEND')

    def validate_contact_number(form, field):
        if len(field.data) > 10:
            raise ValidationError('Phone number should be 10 digit long.')

    def validate_state(form, field):
        if field.data == '--Choose--':
            raise ValidationError('Please choose atleast one.')

    def post_greeting_mail(self, form):
        try:
            # Send Notification to NTech
            send_email("We got a customer Query!!", sender=current_app.config['MAIL_DEFAULT_SENDER'], recipients_list=[
                       'free2dhamu@gmail.com', 'nandhu.misc@gmail.com'], text_body=render_template('email/recieved_contact.txt', form=form), html_body=render_template('email/recieved_contact.html', form=form))

            # Send Greetings to Candidate
            send_email("Greetings from Ntech Global.", sender=current_app.config['MAIL_DEFAULT_SENDER'], recipients_list=[form.email.data], text_body=render_template(
                'email/greet_candidate.txt', form=form), html_body=render_template('email/greet_candidate.html', form=form))

        except:
            print(f"Exception occured, May be check the contact mail={form.email.data}")


"""
    Вводится строка.

    1. Вывести количество слов в введенной строке.
    2. Вывести самое длинное слово и его длину.
"""

string = input('Введите строку: ')
kol_slov = 0
temp = _ = 0

for i in string:
    _ += len(i)
    if temp < _:
        temp = _
    if i == ',' or i == ' ':
        kol_slov += 1
        _ = 0

print('naibolshee slovo: ', temp)
print('slov v stroke: ', kol_slov)


import json
import logging

from settings import DEFAULT_LANG

logger = logging.getLogger(__name__)

def translate(message_id: str, lang_code: str, placeholders=None) -> str:
    """
    Loads a specified translation and replaces the placeholders with the provided values.

    :param message_id: A string representing the message ID, in the format 'module.message_name'.
    :param lang_code: The language code (e.g., 'en', 'es') for the desired translation.
    :param placeholders: A dictionary containing the placeholders and their values.
                         Defaults to an empty dictionary if not provided.
    :return: The translated message as a string.
    """
    if placeholders is None:
        placeholders = {}

    trans = load_translation(lang_code)
    module, message_name = message_id.split('.')

    try:
        message_template = trans[module][message_name]
        for placeholder, value in placeholders.items():
            message_template = message_template.replace(f'{{{placeholder}}}', str(value))
        return message_template

    except (KeyError, TypeError) as e:
        if lang_code != DEFAULT_LANG:
            # Try falling back to default language
            logger.warning(f'Could not find translation for {message_id} in {lang_code}', exc_info=e)
            return translate(message_id, DEFAULT_LANG, placeholders)

        logger.error(f'Could not find translation for {message_id} in default {lang_code}', exc_info=e)
        return message_id

def load_translation(lang_code: str) -> dict:
    """
    Loads translations for the given language code from a JSON file.

    :param lang_code: The language code (e.g., 'en', 'es') for the desired translation.
    :return: A dictionary containing the translations.
    :raises ValueError: If the default translation file cannot be loaded.
    """
    try:
        filename = f'locales/translations/{lang_code}.json'.lower()
        with open(filename, 'r', encoding='utf-8') as f:
            return json.load(f)

    except Exception as e:
        if lang_code != DEFAULT_LANG:
            # Try falling back to default language
            logger.warning(f'Could not load translation {lang_code}', exc_info=e)
            return load_translation(DEFAULT_LANG)

        logger.error(f'Default translation {DEFAULT_LANG} could not be loaded', exc_info=e)
        raise ValueError(f'Default translation {DEFAULT_LANG} could not be loaded') from e


from django.conf.urls import url
from drf_yasg import openapi
from drf_yasg.views import get_schema_view
from rest_framework import permissions, routers

from django_scantron.api import views

# Create a router and register our viewsets with it.
# basename requirement: http://www.django-rest-framework.org/api-guide/routers/#usage
router = routers.DefaultRouter(trailing_slash=False)
router.register(r"configuration", views.ConfigurationViewSet, basename="configuration")
router.register(r"engines", views.EngineViewSet, basename="engines")
router.register(r"engine_pools", views.EnginePoolViewSet, basename="engine_pools")
router.register(r"globally_excluded_targets", views.GloballyExcludedTargetViewSet, basename="globally_excluded_targets")
router.register(r"scan_commands", views.ScanCommandViewSet, basename="scan_commands")
router.register(r"scans", views.ScanViewSet, basename="scans")
router.register(r"scheduled_scans", views.ScheduledScanViewSet, basename="scheduled_scans")
router.register(r"sites", views.SiteViewSet, basename="sites")

schema_view = get_schema_view(
    openapi.Info(
        title="Scantron API",
        default_version="v1",
        description="Scantron API documentation",
        terms_of_service="https://github.com/rackerlabs/scantron",
        contact=openapi.Contact(email="https://github.com/rackerlabs/scantron"),
        license=openapi.License(name="Apache License, Version 2.0"),
    ),
    public=False,
    permission_classes=(permissions.IsAuthenticated,),  # comma needed inside parenthesis.
)

urlpatterns = [
    url(r"^swagger(?P<format>\.json|\.yaml)$", schema_view.without_ui(cache_timeout=0), name="schema-json"),
    url(r"^swagger/$", schema_view.with_ui("swagger", cache_timeout=0), name="schema-swagger-ui"),
    url(r"^redoc/$", schema_view.with_ui("redoc", cache_timeout=0), name="schema-redoc"),
    url(r"^server_time$", views.get_server_time, name="server_time"),
]

urlpatterns += router.urls


from typing import List, Optional
from fastapi import APIRouter, Depends, HTTPException, Query
from pydantic import BaseModel
from sqlalchemy import select, insert, update
from sqlalchemy.ext.asyncio import AsyncSession
from src.database import get_async_session

from src.reviews.models import Review
from src.reviews.schemas import ReviewRead, ReviewCreate

router = APIRouter(
    prefix="/review",
    tags=["Reviews"]
)

@router.get("/", response_model=List[ReviewRead])
async def get_review_list(page: Optional[int] = Query(1, description="Номер страницы", ge=1),
                          page_size: Optional[int] = Query(10, description="Размер страницы", ge=1, le=100),
                          session: AsyncSession = Depends(get_async_session)):
    offset = (page - 1) * page_size
    query = select(Review).offset(offset).limit(page_size)
    result = await session.execute(query)
    return result.scalars().all()

@router.get("/{review_id}", response_model=ReviewRead)
async def get_review_detail(review_id: int, session: AsyncSession = Depends(get_async_session)):
    query = select(Review).filter_by(id=review_id)
    result = await session.execute(query)
    return result.scalars().first()

@router.post("/")
async def post_review_create(new_review: ReviewCreate, session: AsyncSession = Depends(get_async_session)):
    stmt = insert(Review).values(**new_review.dict())
    await session.execute(stmt)
    await session.commit()
    return {"status": "success"}

@router.put("/{review_id}", response_model=ReviewCreate)
async def put_review_update(review_id: int, product: ReviewCreate,
                            session: AsyncSession = Depends(get_async_session), ):
    stmt = (
        update(Review)
        .where(Review.id == review_id)
        .values(**product.dict())
        .returning(Review)
    )
    result = await session.execute(stmt)
    updated_review = result.scalar()
    if updated_review is None:
        raise HTTPException(status_code=404, detail="Review not found")

    await session.commit()
    return updated_review

@router.delete("/{review_id}", response_model=ReviewRead)
async def review_delete(review_id: int, session: AsyncSession = Depends(get_async_session)):
    stmt = (
        update(Review)
        .where(Review.id == review_id)
        .values({"is_deleted": True})
        .returning(Review)
    )
    result = await session.execute(stmt)
    delete_review = result.scalar()
    if delete_review is None:
        raise HTTPException(status_code=404, detail="Review not found")

    await session.commit()
    return delete_review