import argparse
import os
from datetime import datetime as dt
from time import sleep
import estClient.est.errors as est_errors
import estClient.est.client as est_client
import OpenSSL.crypto as openssl

NUM_TRY_LATER_ATTEMPTS = 2  # Number of times request should be resent on HTTP 202-Try Later

class bcolors:
    HEADER = '\033[95m'
    OKBLUE = '\033[94m'
    OKGREEN = '\033[92m'
    WARNING = '\033[93m'
    FAIL = '\033[91m'
    ENDC = '\033[0m'
    BOLD = '\033[1m'
    UNDERLINE = '\033[4m'

PASSED = bcolors.OKGREEN + 'Passed' + bcolors.ENDC
FAILED = bcolors.FAIL + 'Failed' + bcolors.ENDC

class NmosEst(object):
    def __init__(self, host, port,
                 cacert_path,
                 client_cert_path,
                 client_key_path):
        """
        Class used to provision an NMOS Node with the Root CA and TLS Server certificate, can also be used
        to renew both when expiring.
        If a valid TLS server certificate for the current domain is not present, the externally issued client
        certificate will be used for authentication with the EST server.
        """
        self.estClient = est_client.Client(host, port, implicit_trust_anchor_cert_path=False)
        self.cacert_path = cacert_path
        self.client_cert_path = client_cert_path
        self.client_key_path = client_key_path
        self.try_later_attempts = NUM_TRY_LATER_ATTEMPTS

    def isCertValid(self, cert_data):
        """Check that the TLS certificate is valid, by checking the expiry date and domain for server certificate

        Args:
            cert_data: String of certificate data

        Returns:
            True if certificate passes all tests
        """
        cert = openssl.load_certificate(openssl.FILETYPE_PEM, cert_data)

        if cert.has_expired():
            print('Certificate has expired')
            return False

        return True

    def verifyNmosCert(self, cert_data):
        """Check that the TLS certificate is valid for use as an NMOS Server certificate.
        Validates the date and domain and certificate usage

        Args:
            cert_data: String of certificate data

        Returns:
            True if certificate passes all tests
        """
        test_results = {
            "basic_validation": False,
            "extended_key_usage": False
        }

        test_results['basic_validation'] = self.isCertValid(cert_data)

        cert = openssl.load_certificate(openssl.FILETYPE_PEM, cert_data)

        for i in range(cert.get_extension_count()):
            if cert.get_extension(i).get_short_name() == b'extendedKeyUsage':
                print('Certificate Extended Key usage:\n \
                      {}'.format(cert.get_extension(i)))
                test_results['extended_key_usage'] = True
                # if str(cert.get_extension(i)) == 'TLS Web Server Authentication, TLS Web Client Authentication':
                #     test_results['extended_key_usage'] = True
                # else:
                #     print(f'Certificate does not support Extended Key usage for both Web Server and Web Clients: \
                #           {cert.get_extension(i)}')

        cert_is_valid = True
        for test in test_results:
            result = (PASSED if test_results[test] else FAILED)
            print('Test {}: {}'.format(test, result))
            if not test_results[test]:
                cert_is_valid = False

        return cert_is_valid

    def inspectCert(self, cert_data):
        """Print information about the certificate

        Args:
            cert_data: String of certificate data

        Returns:
            None
        """

        cert = openssl.load_certificate(openssl.FILETYPE_PEM, cert_data)

        print('CA Issuer: {}'.format(cert.get_issuer().get_components()[0][1]))
        print('Cert Subject: {}'.format(cert.get_subject()))

        expiry_date = cert.get_notAfter()
        expiry_date = self.convertAsn1DateToString(expiry_date)

        print('Expiry Date: {}'.format(expiry_date))
        print('Version Number: {}'.format(cert.get_version()))
        print('Extensions:')
        for i in range(cert.get_extension_count()):
            print('   {}'.format(cert.get_extension(i)))

    def inspectCsr(self, csr_data):
        """Print information about the Certificate Signing Request PKCS10

        Args:
            csr_data: String of CSR data

        Returns:
            None
        """
        csr = openssl.load_certificate_request(openssl.FILETYPE_PEM, csr_data)

        print('Cert Subject: {}'.format(csr.get_subject()))

        print('Version Number: {}'.format(csr.get_version()))
        print('Extensions:')
        for ext in csr.get_extensions():
            print('   {}: {}'.format(ext.get_short_name(), ext))

    def convertAsn1DateToString(self, asn1_date):
        """Convert ASN.1 formated date (YYYYMMDDhhmmssZ) to datatime object"""
        if isinstance(asn1_date, bytes):
            # Convert bytes to string
            asn1_date = asn1_date.decode('utf-8')

        # Strip tailing Z from string
        if asn1_date[-1:] == 'Z':
            asn1_date = asn1_date[:-1]

        # Covert to date object
        date = dt.strptime(asn1_date, '%Y%m%d%H%M%S')

        return date

    def _createCsr(self, common_name, subject_alt_name=None, cipher_suite='rsa_2048', private_key=None):
        """Create CSR and private key

        Args:
            common_name: Common name to be included in the certificate

            subject_alt_name: Subject alternative name to be included in the certificate
                eg. b'DNS:test.com'

            cipher_suite: Cipher suite to be used to sign the CSR. rsa_2048 and ecdsa supported

        Returns:
            private_key, csr
        """
        country = 'GB'
        city = 'Manchester'
        organization = 'AMWA'
        organizational_unit = 'ENG'
        email_address = 'test@workshop.nmos.tv'
        private_key, csr = self.estClient.create_csr(common_name,
                                                     country=country,
                                                     city=city,
                                                     organization=organization,
                                                     organizational_unit=organizational_unit,
                                                     email_address=email_address,
                                                     cipher_suite=cipher_suite,
                                                     subject_alt_name=subject_alt_name,
                                                     private_key=private_key)

        # Add OID extension for certificate profile
        # profile_ext = openssl.X509Extension(b'1.3.6.1.4.1.311.20.2', False, b'pc-client')
        # csr.add_extensions([profile_ext])

        self.inspectCsr(csr)

        return private_key, csr

    def setImplictTrustAnchor(self, path):
        self.estClient.implicit_trust_anchor_cert_path = path
        self.cacert_path = path

    def getCaCert(self, newCaPath):
        """Get CA Cert, but do not verify the authenticity of the EST server"""
        try:
            ca_cert = self.estClient.cacerts()
        except est_errors.RequestError as e:
            print("Failed to get Root CA from EST Server")
            print(e)
            return False

        self._writeDataToFile(ca_cert, newCaPath)

        # Use latest Root CA for future requests
        self.setImplictTrustAnchor(newCaPath)

        return True

    def getNewCert(self, hostname, newCertPath, newKeyPath, cipher_suite='rsa_2048'):
        """
        Get a new TLS certificate from EST, using externally issued certificate for authentication with EST server
        """

        # Get CSR attributes from EST server as an OrderedDict.
        # csr_attrs = self.estClient.csrattrs()

        private_key, csr = self._createCsr(hostname, cipher_suite=cipher_suite)

        client_cert = (self.client_cert_path, self.client_key_path)

        cert_response = self._request_cert(self.estClient.simpleenroll, csr, client_cert)
        if not cert_response:
            print('Failed to request new TLS certificate')
            print('for host: {} with cipher suite: {}'.format(hostname, cipher_suite))
            return False

        # Append Chain of trust
        with open(self.cacert_path) as f:
            cert_response += f.read()

        self._writeDataToFile(private_key, newKeyPath)
        self._writeDataToFile(cert_response, newCertPath)

        self.inspectCert(cert_response)
        self.verifyNmosCert(cert_response)

        return True

    def renewCert(self, hostname, newCertPath, newKeyPath, cipher_suite='rsa_2048'):
        """
        Renew existing TLS certificate, using current certificate for authentication with EST server
        """

        # Get CSR attributes from EST server as an OrderedDict.
        # csr_attrs = self.estClient.csrattrs()

        private_key, csr = self._createCsr(hostname, cipher_suite=cipher_suite)

        client_cert = (self.client_cert_path, self.client_key_path)

        cert_response = self._request_cert(self.estClient.simplereenroll, csr, client_cert)
        if not cert_response:
            print('Failed to renew TLS certificate')
            return False

        self._writeDataToFile(private_key, newKeyPath)
        self._writeDataToFile(cert_response, newCertPath)

        self.inspectCert(cert_response)
        self.verifyNmosCert(cert_response)

        return True

    def serverKeyGen(self, hostname, newCertPath, newKeyPath, cipher_suite='rsa_2048'):
        """
        Get new certificate with the EST server generating the key pair
        """

        private_key_unused, csr = self._createCsr(hostname, cipher_suite=cipher_suite)

        client_cert = (self.client_cert_path, self.client_key_path)

        cert_response, private_key = self._request_cert(self.estClient.serverkeygen, csr, client_cert)
        if not cert_response or not private_key:
            print('Failed to renew TLS certificate')
            return False

        self._writeDataToFile(private_key, newKeyPath)
        self._writeDataToFile(cert_response, newCertPath)

        self.inspectCert(cert_response)
        self.verifyNmosCert(cert_response)

        return True

    def _request_cert(self, method, *args):
        """Perform request and handle errors"""
        success = False
        for x in range(self.try_later_attempts):
            try:
                returned_cert = method(*args)
                success = True
                break
            except est_errors.TryLater as e:
                print('Try request certificate again in {} seconds'.format(e.seconds))
                sleep(e.seconds)
            except est_errors.RequestError as e:
                print("Failed to get TLS Certificate from EST Server")
                print(e)
                return False
        if not success:
            return False

        return returned_cert

    def _writeDataToFile(self, data, path, private=False):
        """Write data to file path"""
        if not isinstance(data, str) and not isinstance(data, bytes):
            print('Cert data is not a string or bytes, file: {}'.format(path))
            return False

        if isinstance(data, bytes):
            # Convert bytes to string
            data = data.decode('utf-8')

        with open(path, 'w') as f:
            f.write(data)

        if private:
            os.chmod(path, 0o400)

if __name__ == "__main__":

    """
    Example workflow of NMOS EST class
    1. Discover EST server (config file or DNS-SD)
    2. Request root CA
    3. Request RSA cert using external client cert
    4. Request ECDSA cert using external client cert
    4. Renew both certs
    """

    parser = argparse.ArgumentParser()
    parser.add_argument("--ip", default='bbc-0.workshop.nmos.tv')
    parser.add_argument("--port", type=int, default=8443)
    parser.add_argument("--cacert", default='cacert.pem')
    parser.add_argument("--cert", default='certs/man1.ecdsa.product1.cert.chain.pem')
    parser.add_argument("--key", default='certs/man1.ecdsa.product1.key.pem')
    args = parser.parse_args()

    # Location of EST Server
    host = args.ip
    port = args.port

    ca_cert_path = args.cacert
    client_cert_path = args.cert
    client_key_path = args.key

    print('Using EST Server {}:{}'.format(host, port))
    print('Root CA: {}'.format(ca_cert_path))
    print('External Certificate: {}'.format(client_cert_path))
    print('External Private Key: {}'.format(client_key_path))

    nmos_est_client = NmosEst(host, port, None, client_cert_path, client_key_path)

    # Get latest EST server CA certs.
    if not nmos_est_client.getCaCert(ca_cert_path):
        print('Exiting...')
        exit(1)

    # Request TLS Server certificate from EST server, using manufacturer issued client certificate for authentication
    if not nmos_est_client.getNewCert('camera-1.workshop.nmos.tv', f'rsa.test.pem.crt', f'rsa.test.pem.key',
                                      cipher_suite='rsa_2048'):
        print('Exiting...')
        exit(1)


#! /usr/bin/env python3

from enum import Enum

class Cell(Enum):
    painted = '#'
    clear = '.'

class Surface:
    def __init__(self):
        self.rows = 0
        self.columns = 0
        self.matrix = {}
    def import_from_file(self, filename):
        with open('simple.in', 'r') as f:
            self.rows, self.columns = tuple(f.readline().split())
            self.rows = int(self.rows)
            self.columns = int(self.columns)
            for lineNb, line in enumerate(f.readlines()):
                if lineNb >= self.rows:
                    raise Exception("Line number out of bounds")
                line = line.rstrip('\n')
                self.matrix[lineNb] = {}
                for columnNb, cell in enumerate(line):
                    if columnNb >= self.columns:
                        raise Exception("Column number out of bounds")
                    self.matrix[lineNb][columnNb] = Cell(cell)
    def __str__(self):
        out = ""
        for i in range(self.rows):
            for j in range(self.columns):
                out += self.matrix[i][j].value
            out += '\n'
        return out

s = Surface()
s.import_from_file('simple.in')
print(s)


import torch
from torch import nn
import torch.nn.functional as F
import fps_cuda
import sys
sys.path.append('/mnt/Disk16T/chenhr/threed/utils')
from utils_func import ball_query_cuda2, knn_query_cuda2, index_points, index_gts, PEGenerator
from memory import Memory

class PointSetAbstractionLayer(nn.Module):
    def __init__(self, stride, radius, k, in_channels, mlp_units):
        super(PointSetAbstractionLayer, self).__init__()
        self.stride = stride
        self.radius = radius
        self.k = k

        mlp = [nn.Conv2d(in_channels, mlp_units[0], kernel_size=1, bias=False),
                    nn.BatchNorm2d(mlp_units[0]),
                    nn.ReLU(inplace=True)]
        for i in range(len(mlp_units) - 1):
            mlp += [nn.Conv2d(mlp_units[i], mlp_units[i + 1], kernel_size=1, bias=False),
                    nn.BatchNorm2d(mlp_units[i + 1]),
                    nn.ReLU(inplace=True)]

        self.mlp = nn.Sequential(*mlp)

    @torch.no_grad()
    def fps(self, points):
        """
        points.shape = (b, n, 3)
        return indices.shape = (b, self.nsamples)
        """
        b, n, _ = points.shape
        device = points.device
        dis = torch.ones((b, n), device=device) * 1e10
        indices = torch.zeros((b, self.nsamples), device=device, dtype=torch.long)

        fps_cuda.fps(points, dis, indices)
        return indices

    def group(self, points, features, centroids):
        """
        points.shape = (b, n, 3)
        features.shape = (b, n, c)
        centroids.shape = (b, self.nsamples, 3)
        return res.shape = (b, self.nsamples, k, 3+c)
        """
        group_points, group_point_features, _ = ball_query_cuda2(self.radius, self.k, centroids, points, features)

        group_points = group_points - centroids.transpose(1, 2).unsqueeze(dim=2)   # 要的是相对坐标

        res = torch.cat((group_points / self.radius, group_point_features), dim=1)
        return res

    def forward(self, points, features, gts=None):
        """
        points.shape = (b, n, 3)   坐标信息
        features.shape = (b, n, c)   特征信息
        gts.shape = (b, n)
        return centroids.shape = (b, self.nsamples, 3)
        return group_features.shape = (b, self.nsamples, c')
        return gts.shape = (b, self.nsamples)
        """
        self.nsamples = points.shape[1] // self.stride

        fps_indices = self.fps(points)

        centroids = index_points(points, fps_indices)
        if gts is not None:
            gts = index_gts(gts, fps_indices)

        group_features = self.group(points, features, centroids)

        group_features, _ = self.mlp(group_features).max(dim=2)
        group_features = group_features.transpose(1, 2)

        return centroids, group_features, gts

class PointFeaturePropagationLayer(nn.Module):
    def __init__(self, in_channels, mlp_units):
        super(PointFeaturePropagationLayer, self).__init__()
        mlp = [nn.Conv1d(in_channels, mlp_units[0], kernel_size=1, bias=False),
                    nn.BatchNorm1d(mlp_units[0]),
                    nn.ReLU(inplace=True)]
        for i in range(len(mlp_units) - 1):
            mlp += [nn.Conv1d(mlp_units[i], mlp_units[i + 1], kernel_size=1, bias=False),
                    nn.BatchNorm1d(mlp_units[i + 1]),
                    nn.ReLU(inplace=True)]

        self.mlp = nn.Sequential(*mlp)

    def forward(self, points_1, features_1, points_2, features_2):
        """
        points_1来自于更前面层的输出, 点更多
        points_1.shape = (b, n1, 3)
        features_1.shape = (b, n1, c1)
        points_2.shape = (b, n2, 3)
        features_2.shape = (b, n2, c2)
        return final_features.shape = (b, n1, c')
        """
        _, n1, _ = points_1.shape
        _, n2, _ = points_2.shape

        if n2 == 1:
            receive_features = features_2.expand(-1, n1, -1)
        else:
            _, correspond_features, distance = knn_query_cuda2(3, points_1, points_2, features_2)

            dist_recip = 1/ (distance + 1e-8)
            norm_term = dist_recip.sum(dim=-1, keepdim=True)
            weights = dist_recip / norm_term

            receive_features = torch.sum(weights.transpose(1, 2).unsqueeze(dim=1) * correspond_features, dim=2)

        final_features = torch.cat((receive_features, features_1.transpose(1, 2)), dim=1)

        final_features = self.mlp(final_features).transpose(1, 2)

        return final_features

class Pointnet2_Memory(nn.Module):
    def __init__(self, num_class, use_ddp):
        super().__init__()
        self.sa1 = PointSetAbstractionLayer(4, 0.05, 32, 7+3, [32, 32, 64])
        self.sa2 = PointSetAbstractionLayer(4, 0.1, 32, 64+3, [64, 64, 128])
        self.sa3 = PointSetAbstractionLayer(4, 0.2, 32, 128+3, [128, 128, 256])
        self.sa4 = PointSetAbstractionLayer(4, 0.4, 32, 256+3, [256, 256, 512])

        self.fp1 = PointFeaturePropagationLayer(512+256, [256, 256])
        self.pe_gen1 = PEGenerator(256)
        self.coarse_mlp1 = nn.Sequential(nn.Conv1d(256, 256, kernel_size=1, bias=False),
                                        nn.BatchNorm1d(256),
                                        nn.ReLU(inplace=True),
                                        nn.Conv1d(256, num_class, kernel_size=1))
        self.memory1 = Memory(num_class, 128, 256, 256, use_ddp=use_ddp)

        self.fp2 = PointFeaturePropagationLayer(256+128, [256, 256])
        self.pe_gen2 = PEGenerator(256)
        self.coarse_mlp2 = nn.Sequential(nn.Conv1d(256, 256, kernel_size=1, bias=False),
                                        nn.BatchNorm1d(256),
                                        nn.ReLU(inplace=True),
                                        nn.Conv1d(256, num_class, kernel_size=1))
        self.memory2 = Memory(num_class, 128, 256, 256, use_ddp=use_ddp)

        self.fp3 = PointFeaturePropagationLayer(256+64, [256, 128])
        self.fp4 = PointFeaturePropagationLayer(128+7, [128, 128])

        self.out_mlp = nn.Sequential(nn.Conv1d(256, 256, kernel_size=1, bias=False),
                                     nn.BatchNorm1d(256),
                                     nn.ReLU(inplace=True),
                                     nn.Dropout(0.5),
                                     nn.Conv1d(256, num_class, kernel_size=1))

    def forward(self, pos, color, normal, y=None, epoch_ratio=None):
        """
        pos.shape = (b, n, 3)
        color.shape = (b, n, 3)
        normal.shape = (b, n, 3)
        """
        n = pos.shape[1]
        height = pos[:, :, -1:]
        x = torch.cat((color, height, normal), dim=-1)

        pos1, x1, y1 = self.sa1(pos, x, y)
        pos2, x2, y2 = self.sa2(pos1, x1, y1)
        pos3, x3, y3 = self.sa3(pos2, x2, y2)
        pos4, x4, y4 = self.sa4(pos3, x3, y3)

        x3 = self.fp1(pos3, x3, pos4, x4)
        # 给x3加上pe
        x3 = self.pe_gen1(pos3, x3, 0.4, 32)
        coarse_pred1 = self.coarse_mlp1(x3.transpose(1, 2))
        coarse_seg_loss1 = 0
        if self.training:
            coarse_seg_loss1 = F.cross_entropy(coarse_pred1, y3, label_smoothing=0.2, ignore_index=20)
            self.memory1.update(x3, y3, coarse_pred1, epoch_ratio)
        x3, _ = self.memory1(x3, coarse_pred1, None)

        x2 = self.fp2(pos2, x2, pos3, x3)
        # 给x2加上pe
        x2 = self.pe_gen2(pos2, x2, 0.2, 32)
        coarse_pred2 = self.coarse_mlp2(x2.transpose(1, 2))
        coarse_seg_loss2 = 0
        if self.training:
            coarse_seg_loss2 = F.cross_entropy(coarse_pred2, y2, label_smoothing=0.2, ignore_index=20)
            self.memory2.update(x2, y2, coarse_pred2, epoch_ratio)
        x2, contrast_loss = self.memory2(x2, coarse_pred2, y2)

        x1 = self.fp3(pos1, x1, pos2, x2)
        x = self.fp4(pos, x, pos1, x1)

        x_max = x.max(dim=1, keepdim=True)[0].expand(-1, n, -1)
        x = torch.cat((x, x_max), dim=-1)

        y_pred = self.out_mlp(x.transpose(1, 2))
        coarse_seg_loss = coarse_seg_loss1 * 0.1 + coarse_seg_loss2 * 0.1

        return y_pred, coarse_seg_loss, contrast_loss * 0


import pandas as pd
import numpy as np
import math
import re
from datetime import date, datetime, timedelta
import copy

def open_neighborhoods():
    df = pd.read_csv('SF_neighborhoods.csv')
    print("Neighborhoods dataset opened.")
    return df

def get_neighborhoods(df):
    neighborhoods = []
    num_neighborhoods = len(df.index)
    for x in range(0,num_neighborhoods):
        neighborhoods.append(df.iloc[x,2])
    return neighborhoods

def open_businesses():
    df = pd.read_csv('businesses_0.1.csv')
    print("Business dataset opened.")
    return df

def calculate_new_businesses(df):
    df['Location Start Date'] = pd.to_datetime(df['Location Start Date'])
    df = df[df['Location Start Date'].dt.year > 2017]
    df['New businesses'] = 1
    df = df.groupby(['Location Start Date','Neighborhood']).count()
    df = df.reset_index()
    return df

def check_for_missing_neighborhoods_business_openings(df,neighborhoods):
    new_rows = pd.DataFrame()
    num_records = len(df.index)
    current_date = df.iloc[0,0]
    zero_business_opening_neighborhoods = copy.deepcopy(neighborhoods)
    for record in range(0,num_records):
        zero_business_opening_neighborhoods.remove(df.iloc[record,1])
        if record != num_records-1:
            if df.iloc[record+1,0] != current_date:
                for neighborhood in zero_business_opening_neighborhoods:
                    new_row = {'Location Start Date' : current_date,
                               'Neighborhood' : neighborhood,
                               'New businesses' : 0}
                    new_rows = new_rows.append(new_row,ignore_index=True)
                zero_business_opening_neighborhoods = copy.deepcopy(neighborhoods)
                current_date = df.iloc[record+1,0]
    for neighborhood in zero_business_opening_neighborhoods:
        new_row = {'Location Start Date' : current_date,
                    'Neighborhood' : neighborhood,
                    'New businesses' : 0}
        new_rows = new_rows.append(new_row,ignore_index=True)
    frames = [df,new_rows]
    new_record = pd.concat(frames)
    new_record = new_record.sort_values(['Location Start Date','Neighborhood'])
    new_record = new_record.drop(columns=['DBA Name','Location End Date'])
    return new_record

def calculate_closed_businesses(df):
    df['Location End Date'] = pd.to_datetime(df['Location End Date'])
    df = df[df['Location End Date'].dt.year > 2017]
    df['Closed businesses'] = 1
    df = df.groupby(['Location End Date','Neighborhood']).count()
    df = df.reset_index()
    return df

def check_for_missing_neighborhoods_business_closures(df,neighborhoods):
    new_rows = pd.DataFrame()
    num_records = len(df.index)
    current_date = df.iloc[0,0]
    zero_business_closure_neighborhoods = copy.deepcopy(neighborhoods)
    for record in range(0,num_records):
        zero_business_closure_neighborhoods.remove(df.iloc[record,1])
        if record != num_records-1:
            if df.iloc[record+1,0] != current_date:
                for neighborhood in zero_business_closure_neighborhoods:
                    new_row = {'Location End Date' : current_date,
                               'Neighborhood' : neighborhood,
                               'Closed businesses' : 0}
                    new_rows = new_rows.append(new_row,ignore_index=True)
                zero_business_closure_neighborhoods = copy.deepcopy(neighborhoods)
                current_date = df.iloc[record+1,0]
    for neighborhood in zero_business_closure_neighborhoods:
        new_row = {'Location End Date' : current_date,
                    'Neighborhood' : neighborhood,
                    'Closed businesses' : 0}
        new_rows = new_rows.append(new_row,ignore_index=True)
    frames = [df,new_rows]
    new_record = pd.concat(frames)
    new_record = new_record.sort_values(['Location End Date','Neighborhood'])
    new_record = new_record.drop(columns=['DBA Name','Location Start Date'])
    return new_record

def combine_data(new_bus_df,closed_bus_df):
    new_bus_df = new_bus_df.reset_index()
    closed_bus_df = closed_bus_df.reset_index()
    new_bus_df['Closed businesses'] = closed_bus_df['Closed businesses']
    #closed_bus_df = closed_bus_df.drop(columns=[ 'Location End Date','Neighborhood'])
    #combined_open_close_data = pd.concat([new_bus_df, closed_bus_df], ignore_index=True, sort=False)
    return new_bus_df

df = open_neighborhoods()
neighborhoods = get_neighborhoods(df)
df = open_businesses()
new_bus_df = calculate_new_businesses(df)
new_bus_df = check_for_missing_neighborhoods_business_openings(new_bus_df,neighborhoods)
closed_bus_df = calculate_closed_businesses(df)
closed_bus_df = check_for_missing_neighborhoods_business_closures(closed_bus_df,neighborhoods)
combined_open_close_data = combine_data(new_bus_df,closed_bus_df)
combined_open_close_data.to_csv('new and closed businesses.csv', index = False)

Scripts pre-Jupyter transition/Business openings and closures.py


class Student:
    def __init__(self, name, surname, gender):
        self.name = name
        self.surname = surname
        self.gender = gender
        self.finished_courses = []
        self.courses_in_progress = []
        self.grades = {}

    def rate_lecturer(self, lecturer, course, grade):
        if isinstance(lecturer,
                      Lecturer) and course in lecturer.courses_attached and course in self.courses_in_progress:
            if course in lecturer.grades:
                lecturer.grades[course] += [grade]
            else:
                lecturer.grades[course] = [grade]
        else:
            return 'Ошибка'

    def avg_grade_hw(self, grades):
        sum_of_grades = 0
        for key, value in self.grades:
            sum_of_grades += sum(self.grades.values()) / len(self.grades.values())
        return round(sum_of_grades / len(grades), 2)

    def __str__(self):
        info = f'Имя: {self.name} \nФамилия: {self.surname} \nСредняя оценка за домашние задания:\nКурсы в процессе изучения: {self.courses_in_progress}\nЗавершенные курсы:{self.finished_courses}'
        return info

class Mentor:
    def __init__(self, name, surname):
        self.name = name
        self.surname = surname
        self.courses_attached = []

class Lecturer(Mentor):
    def __init__(self, name, surname, ):
        super().__init__(name, surname, )
        self.grades = {}

    def __str__(self):
        info = f'Имя: {self.name} \nФамилия: {self.surname} \nСредняя оценка за лекции:'
        return info

class Reviewer(Mentor):

    def __init__(self, name, surname,):
        super().__init__(name, surname,)

    def rate_hw(self, student, course, grade):
        if isinstance(student, Student) and course in self.courses_attached and course in student.courses_in_progress:
            if course in student.grades:
                student.grades[course] += [grade]
            else:
                student.grades[course] = [grade]
        else:
            return 'Ошибка'

    def __str__(self):
        res = f'Имя: {self.name} \nФамилия: {self.surname}'
        return res

    def avg_grade_hw(self, grades):
        sum_of_grades = 0
        for key, value in self.grades:
            sum_of_grades += sum(self.grades.values()) / len(self.grades.values())
        return round(sum_of_grades / len(grades), 2)

ivan_ivanov = Student('Иван', 'Иванов', 'мужчина')
ivan_ivanov.courses_in_progress += ['Python']
ivan_ivanov.courses_in_progress += ['Git']
ivan_ivanov.finished_courses += ['Введение в программирование']

nikita_nikitin = Student('Никита', 'Никитин', 'мужчина')
nikita_nikitin.courses_in_progress += ['Python']
nikita_nikitin.courses_in_progress += ['Git']
nikita_nikitin.finished_courses += ['Введение в программирование']

denis_denisov = Reviewer('Денис', 'Денисов')
denis_denisov.courses_attached += ['Python']

vasily_petrovich = Reviewer('Василий', 'Петрович')
vasily_petrovich.courses_attached += ['Git']

ruslan_ruslanovich = Lecturer('Руслан', 'Русланович')
ruslan_ruslanovich.courses_attached += ['Python']

olya_olegovna = Lecturer('Оля', 'Олеговна')
olya_olegovna.courses_attached += ['Git']

vasily_petrovich.rate_hw(ivan_ivanov, 'Git', 10)
denis_denisov.rate_hw(ivan_ivanov, 'Python', 9.5)
vasily_petrovich.rate_hw(nikita_nikitin, 'Git', 8)
denis_denisov.rate_hw(nikita_nikitin, 'Python', 9)

ivan_ivanov.rate_lecturer(ruslan_ruslanovich, 'Python', 8.5)
ivan_ivanov.rate_lecturer(olya_olegovna, 'Git', 10)
nikita_nikitin.rate_lecturer(ruslan_ruslanovich, 'Python', 9)
nikita_nikitin.rate_lecturer(olya_olegovna, 'Git', 10)

#print(ivan_ivanov)
# print(nikita_nikitin)
# print(vasily_petrovich)
# print(denis_denisov)
# print(ruslan_ruslanovich)
# print(olya_olegovna)


import urllib.parse
import json
import random

def encode_url(url):
    return urllib.parse.quote(url)

def get_random_header():
    UA_LIST = [
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36"
    ]

    HEADER = {
        "referer": "referer: https://www.google.com",
        "user-agent": random.choice(UA_LIST)
    }
    return HEADER


from threading import Thread
import paho.mqtt.client as mqtt

class MQTTClient(Thread):
    def __init__(self, pipeline):
        Thread.__init__(self)

        self.pipeline = pipeline
        self.daemon = True
        self.client = mqtt.Client()
        self.client.on_connect = self._on_connect
        self.client.on_message = self._on_message

    def run(self):
        self.client.connect('127.0.0.1', 1883, 60)
        self.client.loop_forever()

    def _on_connect(self, client, userdata, flags, rc):
        client.subscribe("/nodes/+/state")
        client.subscribe("/nodes/+/get/#")

    def _on_message(self, client, userdata, message):
        try:
            print(f"MQTT message: ({message.topic}): {message.payload}")
            topic = message.topic.split('/')[1:]
            node_id = int(topic[1], 16)
            msg = message.payload.decode('ascii')

            if topic[2] == 'state':
               self._on_state(node_id, msg)

            elif topic[2] == 'get':
                if topic[3] == 'volume':
                    self._on_volume(node_id, int(msg))

                elif topic[3] == 'bass':
                    self._on_bass(node_id, float(msg))

                elif topic[3] == 'mid':
                    self._on_mid(node_id, float(msg))

                elif topic[3] == 'treble':
                    self._on_treble(node_id, float(msg))

        except Exception as e:
            print(f"MQTT message handling error: {e}")

    def _on_state(self, node_id, ip):
        if len(ip) < 2: # '0' or '' or something else that's invalid
            self.pipeline.remove_node(node_id)
        else:
            self.pipeline.add_node(node_id, ip)

    def _on_volume(self, node_id, volume):
        __class__._check_range(volume, 0, 100, "Volume")
        self.pipeline.set_volume(node_id, volume)

    def _on_bass(self, node_id, bass):
        __class__._check_range(bass, -24, 12, "Bass")
        self.pipeline.set_bass(node_id, bass)

    def _on_mid(self, node_id, mid):
        __class__._check_range(mid, -24, 12, "Mid")
        self.pipeline.set_mid(node_id, mid)

    def _on_treble(self, node_id, treble):
        __class__._check_range(treble, -24, 12, "Treble")
        self.pipeline.set_treble(node_id, treble)

    def _check_range(value, min_value, max_value, comment):
        if value < min_value or value > max_value:
            raise ValueError(f"{comment}({value}) not between {min_value} and {max_value}")


from __future__ import annotations

import itertools
import logging
import re

from requests import Response
from typing import TYPE_CHECKING, Union
from collections import defaultdict

from dkutils.constants import (
    API_DELETE,
    API_GET,
    API_POST,
    API_PUT,
)

from dkutils.datakitchen_api.vault import Vault

if TYPE_CHECKING:
    from .datakitchen_client import DataKitchenClient

logger = logging.getLogger(__name__)

class Kitchen:

    def __init__(self, client: DataKitchenClient, name: str) -> None:
        """
        Kitchen object for performing kitchen related API requests.

        Parameters
        ----------
        client : DataKitchenClient
            Client for making requests.
        name : str
            Name of existing kitchen.
        """
        self._client = client
        self._name = name
        self._parent_name = None

    @property
    def name(self) -> str:
        """
        Kitchen name
        """
        return self._name

    @property
    def parent_name(self) -> str:
        """
        Parent kitchen name
        """
        if self._parent_name is None:
            self._parent_name = self._get_settings()['kitchen']['parent-kitchen']
        return self._parent_name

    def is_ingredient(self) -> bool:
        """
        Return true if this is an ingredient kitchen, False otherwise.

        Returns
        -------
        bool
            True if this kitchen is an ingredient kitchen, False otherwise.
        """
        match = re.match(pattern=r'(?P<parent_name>\w+)_(?P<uuid>\w{32})', string=self._name)
        return match.group('parent_name') == self.parent_name if match else False

    @staticmethod
    def create(
            client: DataKitchenClient,
            parent_kitchen_name: str,
            new_kitchen_name: str,
            description: str = ''
    ) -> Kitchen:
        """
        Create a new kitchen and return a kitchen object

        Parameters
        ----------
        client : DataKitchenClient
        parent_kitchen_name : str
            New kitchen will be a child of this parent kitchen
        new_kitchen_name : str
            New kitchen name
        description : str
            New kitchen description

        Returns
        -------
        Kitchen
            :class:`Kitchen <Kitchen>` object

        Raises
        ------
        HTTPError
            If the request fails.
        """
        logger.debug(f'Creating child kitchen of {parent_kitchen_name} named {new_kitchen_name}...')
        client._api_request(
            API_PUT,
            'kitchen',
            'create',
            parent_kitchen_name,
            new_kitchen_name,
            description=description,
        )
        return Kitchen(client, new_kitchen_name)

    def delete(self) -> Response:
        """
        Delete the current kitchen.

        Returns
        -------
        requests.Response
            :class:`Response <Response>` object

        Raises
        ------
        HTTPError
            If the request fails.
        """
        logger.debug(f'Deleting kitchen: {self._name}...')
        return self._client._api_request(API_DELETE, 'kitchen', 'delete', self._name)

    def _get_settings(self) -> dict:
        """
        Retrieve kitchen settings JSON.

        Returns
        -------
        settings : dict

        Raises
        ------
        HTTPError
            If the request fails.
        """
        logger.debug(f'Retrieving settings for kitchen: {self._name}...')
        response = self._client._api_request(API_GET, 'kitchen', self._name)
        return response.json()

    def _update_settings(self, settings: dict) -> Response:
        """
        Update kitchen settings JSON.

        Parameters
        ----------
        settings : dict
            Kitchen settings JSON with updated values.

       Returns
        -------
        requests.Response
            :class:`Response <Response>` object

        Raises
        ------
        HTTPError
            If the request fails.
        ValueError
            If the name in the given settings does not match that of the current kitchen.
        """
        kitchen_name = settings['kitchen']['name']
        if kitchen_name != self._name:
            raise (
                ValueError(
                    f'Name in settings: {kitchen_name} does not match current kitchen: {self._name}'
                )
            )

        response = self._client._api_request(
            API_POST, 'kitchen', 'update', self._name, json={"kitchen.json": settings['kitchen']}
        )
        return response.json()

    def _get_roles(self, settings: dict = None) -> dict:
        """
        Retrieve the staff and their associated roles assigned to this kitchen.

        Parameters
        ----------
        settings : dict, optional
            Dictionary representing kitchen_settings.json.

        Raises
        ------
        HTTPError
            If the request fails.

        Returns
        -------
        roles : dict
            Dictionary of current kitchen staff and their associated roles of the form::

                {
                    'Admin': ['admin@gmail.com'],
                    'Developer': ['developer1@gmail.com', 'developer2@gmail.com'],
                }
        """
        kitchen_settings = settings if settings else self._get_settings()
        kitchen_roles = kitchen_settings['kitchen']['kitchen-roles']
        result = defaultdict(list)
        for email, permission in kitchen_roles.items():
            result[permission].append(email)
        return result

    def _get_staff_set(self, settings: dict = None) -> set:
        """
        Retrieve the set of staff usernames assigned to this kitchen.

        Parameters
        ----------
        settings : dict, optional
            Dictionary representing kitchen_settings.json.

        Raises
        ------
        HTTPError
            If the request fails.

        Returns
        -------
        roles : list
            set of current kitchen staff usernames of the form::

                {
                    'admin@gmail.com',
                    'developer1@gmail.com',
                    'developer2@gmail.com',
                }
        """
        _settings = settings if settings else self._get_settings()
        return set(_settings['kitchen']['kitchen-staff'])

    def _ensure_admin(self, roles: dict = None, settings: dict = None) -> None:
        """
        Ensure the user in the provided client has Admin privileges in this kitchen. Otherwise,
        raise a PermissionError.

        Parameters
        ----------
        roles : dict, optional
            Dictionary keyed by role and valued by list of associated usernames.
        settings : dict, optional
            Dictionary representing kitchen_settings.json.

        Raises
        ------
        HTTPError
            If the request fails.
        PermissionError
            If the client user is not an Admin in this kitchen.
        """
        if not roles:
            roles = self._get_roles(settings=settings)

        current_user = self._client._username
        if current_user not in roles['Admin']:
            raise PermissionError(f'Current user ({current_user}) not an Admin. Permission denied.')

    def _ensure_disjoint(self, lists: list) -> bool:
        """
        Return True if all the provided lists (converted to sets) are disjoint, False otherwise.

        Parameters
        ----------
        lists : list
            List of lists. Each list will be converted to a set to ensure they are all disjoint.

        Returns
        -------
        bool
            True if provided lists are disjoint, False otherwise.
        """
        if len(lists) > 1:
            merged_set = set(lists[0])
            for l in lists[1:]:
                if not merged_set.isdisjoint(set(l)):
                    return False
                merged_set = merged_set | set(l)
        return True

    def get_alerts(self) -> dict:
        """
        Retrieve alerts set on this kitchen.

        Returns
        -------
        alerts : dict
            Dictionary of current kitchen alerts of the form::
                {
                    'Start': ['foo@gmail.com'],
                    'Warning': None,
                    'OverDuration': ['foo@gmail.com', 'bar@gmail.com'],
                    'Success': None,
                    'Failure': ['foo@gmail.com'],
                }
        """
        alerts = self._get_settings()['kitchen']['settings']['alerts']
        return {
            'Start': alerts['orderrunStart'],
            'Warning': alerts['orderrunWarning'],
            'OverDuration': alerts['orderrunOverDuration'],
            'Success': alerts['orderrunSuccess'],
            'Failure': alerts['orderrunError'],
        }

    def add_alerts(self, alerts: dict) -> None:
        """
        Add the provided alerts to the kitchen.

        Parameters
        ----------
        alerts : dict
            Alerts to add in the form::

                {
                    'Start': ['foo@gmail.com'],
                    'Warning': None,
                    'OverDuration': ['foo@gmail.com', 'bar@gmail.com'],
                    'Success': None,
                    'Failure': ['foo@gmail.com'],
                }

        Raises
        ------
        KeyError
            If an unrecognized alert field is provided - valid fields are Start, Warning,
            OverDuration, Success, and Failure
        """

        settings = self._get_settings()
        existing_alerts = settings['kitchen']['settings']['alerts']
        for k, v in alerts.items():
            k = 'orderrunError' if k == 'Failure' else f'orderrun{k}'
            if k not in existing_alerts:
                raise KeyError(
                    'Unrecognized alert field: {k}. Expected fields are Start, Warning, OverDuration, Success, and Failure'  # noqa: E501
                )

            if isinstance(v, str):
                v = [v]

            alert_emails = set(existing_alerts[k]) if existing_alerts[k] else set()
            alert_emails = list(alert_emails.union(set(v)))
            existing_alerts[k] = alert_emails

        self._update_settings(settings)

    def delete_alerts(self, alerts: dict) -> None:
        """
        Delete the provided kitchen alerts.

        Parameters
        ----------
        alerts : dict
            Alerts to delete in the form::

                {
                    'Start': ['foo@gmail.com'],
                    'Warning': None,
                    'OverDuration': ['foo@gmail.com', 'bar@gmail.com'],
                    'Success': None,
                    'Failure': ['foo@gmail.com'],
                }

        Raises
        ------
        KeyError
            If an unrecognized alert field is provided - valid fields are Start, Warning,
            OverDuration, Success, and Failure
        """
        settings = self._get_settings()

        existing_alerts = settings['kitchen']['settings']['alerts']
        for k, v in alerts.items():
            k = 'orderrunError' if k == 'Failure' else f'orderrun{k}'
            if k not in existing_alerts:
                raise KeyError(
                    'Unrecognized alert field: {k}. Expected fields are Start, Warning, OverDuration, Success, and Failure'  # noqa: E501
                )

            if isinstance(v, str):
                v = [v]

            if existing_alerts[k] is not None:
                alert_emails = list(set(existing_alerts[k]) - set(v))
                existing_alerts[k] = alert_emails

        self._update_settings(settings)

    def get_staff(self) -> dict:
        """
        Retrieve the staff and their associated roles assigned to this kitchen.

        Raises
        ------
        HTTPError
            If the request fails.
        PermissionError
            If the current user is not an Admin

        Returns
        -------
        staff : dict
            Dictionary of current kitchen staff and their associated roles of the form::

                {
                    'Admin': ['admin@gmail.com'],
                    'Developer': ['developer1@gmail.com', 'developer2@gmail.com'],
                }
        """
        return self._get_roles()

    def ensure_users_is_part_of_staff(
            self, users_to_check: Union[set, list], current_staff: Union[set, list] = None
    ) -> None:
        """
        Ensure a list of users is part of Kitchen Staff. Otherwise, raise a ValueError.

        Parameters
        ----------
        users_to_check : set or list
            List or set of emails of the users to check if they are part of the staff.
        current_staff : set or list
            List or set of the current staff.
        Raises
        ------
        ValueError
            If the users to check are not part of the Kitchen Staff.

        """
        if not current_staff:
            current_staff = self._get_staff_set()

        if not users_to_check.issubset(current_staff):
            raise ValueError(
                f'The following staff do not already exist in kitchen: {users_to_check - current_staff}'
            )
        pass

    def delete_staff(self, staff_to_delete: Union[set, list]) -> Response:
        """
        Delete the provided staff from this kitchen.

        Parameters
        ----------
        staff_to_delete : set or list
            List or set of usernames to delete from this kitchen's staff.

        Raises
        ------
        HTTPError
            If the request fails.
        PermissionError
            If the current user is not an Admin

        Returns
        -------
        requests.Response
            :class:`Response <Response>` object
        """
        if not isinstance(staff_to_delete, set):
            staff_to_delete = set(staff_to_delete)

        settings = self._get_settings()
        self._ensure_admin(settings=settings)

        current_staff = self._get_staff_set(settings)
        self.ensure_users_is_part_of_staff(staff_to_delete, current_staff)

        # Remove staff from list
        settings['kitchen']['kitchen-staff'] = list(current_staff - staff_to_delete)

        # Remove staff from roles
        for staff in staff_to_delete:
            if staff in settings['kitchen']['kitchen-roles']:
                del settings['kitchen']['kitchen-roles'][staff]

        return self._update_settings(settings)

    def add_staff(self, staff_to_add: dict) -> Response:
        """
        Add the provided staff to this kitchen.

        Parameters
        ----------
        staff_to_add : dict
            Dictionary keyed by role and valued with list of users to add to that role in the form::

                {
                    'Admin': ['admin@gmail.com'],
                    'Developer': ['developer1@gmail.com', 'developer2@gmail.com'],
                }

        Raises
        ------
        HTTPError
            If the request fails.
        PermissionError
            If the current user is not an Admin
        ValueError
            If the provided staff are not new or unique across roles.

        Returns
        -------
        requests.Response
            :class:`Response <Response>` object
        """
        if not self._ensure_disjoint(list(staff_to_add.values())):
            raise ValueError(f'Staff lists for each role must be unique.')

        settings = self._get_settings()
        self._ensure_admin(settings=settings)

        # Add staff to list
        current_staff = self._get_staff_set(settings)
        new_staff = set(itertools.chain.from_iterable(staff_to_add.values()))

        if not current_staff.isdisjoint(new_staff):
            raise ValueError(
                f'The following staff already exist in kitchen: {current_staff & new_staff}'
            )

        settings['kitchen']['kitchen-staff'] = list(current_staff | new_staff)

        # Add staff to roles
        for role, list_of_staff_to_add in staff_to_add.items():
            for staff_to_add in list_of_staff_to_add:
                settings['kitchen']['kitchen-roles'][staff_to_add] = role

        return self._update_settings(settings)

    def update_staff(self, staff_to_update: dict) -> Response:
        """
        Update roles for the provided staff to this kitchen.

        Parameters
        ----------
        staff_to_update : dict
            Dictionary keyed by role and valued with list of users to update to that role in the form::

                {
                    'Admin': ['admin@gmail.com'],
                    'Developer': ['developer1@gmail.com', 'developer2@gmail.com'],
                }

        Raises
        ------
        HTTPError
            If the request fails.
        PermissionError
            If the current user is not an Admin
        ValueError
            If the provided staff are not new or unique across roles.

        Returns
        -------
        requests.Response
            :class:`Response <Response>` object
        """
        if not self._ensure_disjoint(list(staff_to_update.values())):
            raise ValueError(f'Staff lists for each role must be unique.')

        settings = self._get_settings()
        self._ensure_admin(settings=settings)

        # Add staff to list
        current_staff = self._get_staff_set(settings)
        updated_staff = set(itertools.chain.from_iterable(staff_to_update.values()))

        self.ensure_users_is_part_of_staff(updated_staff, current_staff)

        # Update staff to roles
        for role, list_staff in staff_to_update.items():
            for staff in list_staff:
                settings['kitchen']['kitchen-roles'][staff] = role

        return self._update_settings(settings)

    def get_vault(self):
        return Vault(self._client, self._name)


import socket
import threading

PORT = 7777
# SERVER = socket.gethostbyname(socket.gethostname())
SERVER = "192.168.10.17"
ADDR = (SERVER, PORT)
PAYLOAD_LEN = 64 # Bytes
DISCONNECT_MESSAGE = "QUIT\n"

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(ADDR)

def findAllNumbers(n):
    cb = int(pow(n, 1.0 / 3))
    num_list = []
    s = set()
    for i in range(1, cb - 1):
        for j in range(i + 1, cb + 1):
            sum = (i*i*i) + (j*j*j)
            if sum in s:
                num_list.append(sum)
            else:
                s.add(sum)

    return num_list

def handleClient(conn, addr):
    print(f"New connection, {addr} is connected")

    conn.send("\nHardy-Ramanujan numbers are the numbers that can be represented as the sum of two cubes for two different pairs.\n\nEnter a number to see Hardy-Ramanujan numbers up until to that number\n\n Type QUIT to disconnect\n\n".encode("utf-8"))

    while True:
        msg = conn.recv(PAYLOAD_LEN).decode("utf-8")
        print(f"{addr} sent the message {msg}, message length: {PAYLOAD_LEN}")
        print(msg)

        if msg == DISCONNECT_MESSAGE:
            print("Client requested to disconnect")
            break

        if (findAllNumbers(int(msg))):
            conn.send("\nHardy-Ramanujan numbers: ".encode("utf-8"))
            for each in findAllNumbers(int(msg)):
                conn.send((str(each)+" ").encode("utf-8"))
            conn.send("\n\n".encode("utf-8"))

    conn.send("Disconnecting from the server\n".encode("utf-8"))
    conn.close()

def start():
    server.listen()
    print(f"Server is listening - {SERVER}")

    while True:
        conn, addr = server.accept()
        thread = threading.Thread(target=handleClient, args=(conn,addr))
        thread.start()
        print(f"Active Connections: {threading.activeCount() - 1}")

start()


class Solution:
    def maxNumber(self, nums1: List[int], nums2: List[int], k: int) -> List[int]:
        res = [0 for i in range(k)]

        m, n = len(nums1), len(nums2)
        start = max(0, k - n)
        end = min(k, m)

        for i in range(start, end + 1):
            s1 = self.getMax(nums1, i)
            s2 = self.getMax(nums2, k - i)
            s = self.merge(s1, s2)
            if self.compare(s, res) > 0:
                res = s

        return res

    def getMax(self, nums: List[int], k: int) -> List[int]:
        '''
        获取从 nums 选取 k 个数能拼成的最大序列
        '''
        stack = [0] * k
        top = -1
        unuse = len(nums) - k # 可以不使用的数目个数

        for num in nums:
            while top >= 0 and stack[top] < num and unuse > 0:
                # 把栈顶比当前数小的都删掉
                # 尽可能保持高位最大（贪心）
                top -= 1
                unuse -= 1
            if top < k - 1:
                # 插入当前数
                top += 1
                stack[top] = num
            else:
                # 当前数未被使用
                unuse -= 1

        return stack

    def merge(self, s1: List[int], s2: List[int]) -> List[int]:
        '''
        将两个序列拼接
        '''
        l1 = len(s1)
        l2 = len(s2)
        i1 = 0
        i2 = 0
        pos = 0

        res = [0 for i in range(l1+l2)]
        while pos < l1+l2:
            if self.use1(s1,s2,i1,i2):
                res[pos] = s1[i1]
                i1 += 1
            else:
                res[pos] = s2[i2]
                i2 += 1
            pos +=1
        return res

    def use1(self, s1: List[int], s2:List[int], i1: int, i2:int)->bool:
        '''
        在拼接序列时，是否应该从 s1 选取下一个值
        '''
        l1 = len(s1)
        l2 = len(s2)

        if i1>=l1 and i2>=l2:
            # s1 s2 都已经用完了，随便用谁返回下
            return True
        elif i1<l1 and i2>=l2:
            # s1 没用完，s2 用完，所以用 s1
            return True
        elif i1>=l1 and i2<l2:
            # s1 用完了，s2 没用完，所以用 s2
            return False

        if s1[i1] == s2[i2]:
            # 两个值一样，比较下一个
            return self.use1(s1, s2, i1+1, i2+1)
        elif s1[i1] > s2[i2]:
            # s1 的值更大，用 s1
            return True
        else:
            # s2 的值更大，用 s2
            return False

    def compare(self, s1: List[int], s2: List[int]) -> bool:
        '''
        比较序列大小
        '''
        for i in range(len(s1)):
            c1 = s1[i]
            c2 = s2[i]
            if c1 != c2:
                return c1 - c2
        return 0


"""Disposable module with temporary work-arounds until upstream changes are made in Dask/Xarray"""
import warnings
import xarray as xr
import dask.array as da
from dask.dataframe import DataFrame
from dask.array import Array
from dask.array.overlap import overlap, trim_internal
from numbers import Integral
# pylint: disable=no-name-in-module
from tlz import merge, pipe, concat, partial, get

def map_overlap(
    func, *args, depth=None, boundary=None, trim=True, align_arrays=True, **kwargs
):
    """ Map a function over blocks of arrays with some overlap

    We share neighboring zones between blocks of the array, map a
    function, and then trim away the neighboring strips.

    Parameters
    ----------
    func: function
        The function to apply to each extended block
    args : dask arrays
    depth: int, tuple, dict or list
        The number of elements that each block should share with its neighbors
        If a tuple or dict then this can be different per axis.
        If a list then each element of that list must be an int, tuple or dict
        defining depth for the corresponding array in `args`.
        Asymmetric depths may be specified using a dict value of (-/+) tuples.
        Note that asymmetric depths are currently only supported when
        ``boundary`` is 'none'.
        The default value is 0.
    boundary: str, tuple, dict or list
        How to handle the boundaries.
        Values include 'reflect', 'periodic', 'nearest', 'none',
        or any constant value like 0 or np.nan.
        If a list then each element must be a str, tuple or dict defining the
        boundary for the corresponding array in `args`.
        The default value is 'reflect'.
    trim: bool
        Whether or not to trim ``depth`` elements from each block after
        calling the map function.
        Set this to False if your mapping function already does this for you
    align_arrays: bool
        Whether or not to align chunks along equally sized dimensions when
        multiple arrays are provided.  This allows for larger chunks in some
        arrays to be broken into smaller ones that match chunk sizes in other
        arrays such that they are compatible for block function mapping. If
        this is false, then an error will be thrown if arrays do not already
        have the same number of blocks in each dimensions.
    **kwargs:
        Other keyword arguments valid in ``map_blocks``

    Examples
    --------
    >>> import numpy as np
    >>> import dask.array as da

    >>> x = np.array([1, 1, 2, 3, 3, 3, 2, 1, 1])
    >>> x = da.from_array(x, chunks=5)
    >>> def derivative(x):
    ...     return x - np.roll(x, 1)

    >>> y = x.map_overlap(derivative, depth=1, boundary=0)
    >>> y.compute()
    array([ 1,  0,  1,  1,  0,  0, -1, -1,  0])

    >>> x = np.arange(16).reshape((4, 4))
    >>> d = da.from_array(x, chunks=(2, 2))
    >>> d.map_overlap(lambda x: x + x.size, depth=1).compute()
    array([[16, 17, 18, 19],
           [20, 21, 22, 23],
           [24, 25, 26, 27],
           [28, 29, 30, 31]])

    >>> func = lambda x: x + x.size
    >>> depth = {0: 1, 1: 1}
    >>> boundary = {0: 'reflect', 1: 'none'}
    >>> d.map_overlap(func, depth, boundary).compute()  # doctest: +NORMALIZE_WHITESPACE
    array([[12,  13,  14,  15],
           [16,  17,  18,  19],
           [20,  21,  22,  23],
           [24,  25,  26,  27]])
    """
    # Look for invocation using deprecated single-array signature
    # map_overlap(x, func, depth, boundary=None, trim=True, **kwargs)
    if isinstance(func, Array) and callable(args[0]):
        warnings.warn(
            "Detected use of signature map_overlap(x, func) rather than "
            "map_overlap(func, *args) for multi-array support. Arguments "
            "will be swapped in this case but such an exception will not "
            "be made in a future release.",
            FutureWarning,
        )
        sig = ["func", "depth", "boundary", "trim"]
        depth = get(sig.index("depth"), args, depth)
        boundary = get(sig.index("boundary"), args, boundary)
        trim = get(sig.index("trim"), args, trim)
        func, args = args[0], [func]

    if not callable(func):
        raise TypeError(
            "First argument must be callable function, not {}\n"
            "Usage:   da.map_overlap(function, x)\n"
            "   or:   da.map_overlap(function, x, y, z)".format(type(func).__name__)
        )
    if not all(isinstance(x, Array) for x in args):
        raise TypeError(
            "All variadic arguments must be arrays, not {}\n"
            "Usage:   da.map_overlap(function, x)\n"
            "   or:   da.map_overlap(function, x, y, z)".format(
                [type(x).__name__ for x in args]
            )
        )

    # Coerce depth and boundary arguments to lists of individual
    # specifications for each array argument
    def coerce(xs, arg, fn):
        if not isinstance(arg, list):
            arg = [arg] * len(xs)
        return [fn(x.ndim, a) for x, a in zip(xs, arg)]

    depth = coerce(args, depth, coerce_depth)
    boundary = coerce(args, boundary, coerce_boundary)

    # Align chunks in each array to a common size
    if align_arrays:
        # Reverse unification order to allow block broadcasting
        inds = [list(reversed(range(x.ndim))) for x in args]
        _, args = da.core.unify_chunks(*list(concat(zip(args, inds))), warn=False)

    for i, x in enumerate(args):
        for j in range(x.ndim):
            if isinstance(depth[i][j], tuple) and boundary[i][j] != "none":
                raise NotImplementedError(
                    "Asymmetric overlap is currently only implemented "
                    "for boundary='none', however boundary for dimension "
                    "{} in array argument {} is {}".format(j, i, boundary[i][j])
                )

    def assert_int_chunksize(xs):
        assert all(type(c) is int for x in xs for cc in x.chunks for c in cc)

    assert_int_chunksize(args)
    args = [overlap(x, depth=d, boundary=b) for x, d, b in zip(args, depth, boundary)]
    assert_int_chunksize(args)
    x = da.map_blocks(func, *args, **kwargs)
    assert_int_chunksize([x])
    if trim:
        # Find index of array argument with maximum rank and break ties by choosing first provided
        i = sorted(enumerate(args), key=lambda v: (v[1].ndim, -v[0]))[-1][0]
        # Trim using depth/boundary setting for array of highest rank
        return trim_internal(x, depth[i], boundary[i])
    else:
        return x

def coerce_depth(ndim, depth):
    default = 0
    if depth is None:
        depth = default
    if isinstance(depth, Integral):
        depth = (depth,) * ndim
    if isinstance(depth, tuple):
        depth = dict(zip(range(ndim), depth))
    if isinstance(depth, dict):
        for i in range(ndim):
            if i not in depth:
                depth.update({i: 0})
    return depth

def coerce_boundary(ndim, boundary):
    default = "reflect"
    if boundary is None:
        boundary = default
    if not isinstance(boundary, (tuple, dict)):
        boundary = (boundary,) * ndim
    if isinstance(boundary, tuple):
        boundary = dict(zip(range(ndim), boundary))
    if isinstance(boundary, dict):
        for i in range(ndim):
            if i not in boundary:
                boundary.update({i: default})
    return boundary

def dataframe_to_dataset(df: DataFrame, dim, compute_lengths=True, add_coord=False):
    # Watch: https://github.com/pydata/xarray/issues/3929
    data_vars = {}
    for c in df:
        # Convert Dask Series to xr.DataArray with no coordinates
        # Use lengths=True to include chunk size calculations
        arr = df[c].to_dask_array(lengths=True if compute_lengths else None)
        data_vars[c] = xr.DataArray(arr, dims=dim)
    coords = {dim: da.arange(len(df))} if add_coord else None
    return xr.Dataset(data_vars, coords=coords)


import os

from dotenv import load_dotenv

load_dotenv()

TOKEN = os.getenv('TOKEN')

HEROKU_APP_NAME = os.getenv('HEROKU_APP_NAME')

PORT = os.getenv('PORT')

DATABASE_URL = os.getenv('DATABASE_URL', '')

if DATABASE_URL.startswith('postgres://'):
    DATABASE_URL = DATABASE_URL.replace('postgres', 'postgresql')

API_BASE_URL = os.getenv('API_BASE_URL')

API_TOKEN = os.getenv('API_TOKEN')


from aawedha.io.base import DataSet
from aawedha.paradigms.erp import ERP
from aawedha.paradigms.subject import Subject
from aawedha.utils.network import download_file
from mne import Epochs, pick_types, events_from_annotations
from mne import set_log_level
from mne.io import concatenate_raws, read_raw_edf
import pandas as pd
import numpy as np
import glob
import os

class Essex(DataSet):
    """P300 Amplitude Dataset

    [1] L. Citi, R. Poli, C. Cinel, Documenting, modelling and exploiting P300 amplitude
    changes due to variable target delays in Donchin’s speller, J. Neural Eng. 7 (2010).
    doi:10.1088/1741-2560/7/5/056006.
    """
    def __init__(self):
        super().__init__(title='Essex_P300',
                         ch_names=['Fp1', 'AF7', 'AF3', 'F1', 'F3', 'F5', 'F7',
                                    'FT7', 'FC5', 'FC3', 'FC1','C1', 'C3', 'C5',
                                    'T7', 'TP7', 'CP5', 'CP3', 'CP1', 'P1', 'P3',
                                    'P5', 'P7', 'P9', 'PO7', 'PO3', 'O1', 'Iz',
                                    'Oz', 'POz', 'Pz', 'CPz', 'Fpz', 'Fp2', 'AF8',
                                    'AF4', 'AFz', 'Fz', 'F2', 'F4', 'F6', 'F8',
                                    'FT8', 'FC6', 'FC4', 'FC2', 'FCz', 'Cz', 'C2',
                                    'C4', 'C6', 'T8', 'TP8', 'CP6', 'CP4', 'CP2',
                                    'P2', 'P4', 'P6', 'P8', 'P10', 'PO8', 'PO4', 'O2'],
                         fs=2048,
                         doi='http://dx.doi.org/10.1088/1741-2560/7/5/056006',
                         url="https://archive.physionet.org/pn4/erpbci"
                         )
        self.phrase = []

    def generate_set(self, load_path=None, download=False, channels=None, epoch=[0., .7],
                     band=[1.0, 10.0], order=2,  downsample=None,
                     save=True, save_folder=None, fname=None,
                     ):
        """Main method for creating and saving DataSet objects and files:
            - sets train and test (if present) epochs and labels
            - sets dataset information : subjects, paradigm
            - saves DataSet object as a serialized pickle object

        Parameters
        ----------
        load_path : str
            raw data folder path
        download : bool,
            if True, download raw data first. default False.
        channels : list, optional
            default : None, keep all channels
        epoch : list
            epoch window start and end in seconds relative to trials' onst
            default : [0, .7]
        band : list
            band-pass filter frequencies, low-freq and high-freq
            default : [1., 10.]
        order : int
            band-pass filter order
            default: 2
        downsample: int, optional
            down-sampling factor
            default : None
        save : bool,
            it True save DataSet, default True.
        save_folder : str
            DataSet object saving folder path
        fname: str, optional
            saving path for file, specified when different versions of
            DataSet are saved in the same folder
            default: None
        """
        if downsample:
            self.fs = self.fs // int(downsample)

        if download:
            self.download_raw(load_path)

        self.epochs, self.y, events, phrase = self.load_raw(load_path, channels,
                                                    epoch, band, order,
                                                    downsample
                                                    )
        if channels:
            self.ch_names = [self.ch_names[ch] for ch in self._get_channels(channels)]

        self.subjects = self._get_subjects()
        self.paradigm = self._get_paradigm()
        self.events = events
        self.phrase = phrase
        if save:
            self.save_set(save_folder, fname)

    def load_raw(self, path=None, channels=None, epoch=[0., .7],
                     band=[1.0, 5.0], order=2,  downsample=None):
        """Read and process raw data into structured arrays

        Parameters
        ----------
        path : str
            raw data folder path
        channels : list of str
            list of channels to keep, default None, select all channels.
        epoch : list
            epoch duration window start and end in seconds relative to trials' onset
            default : [0., .7]
        band : list
            band-pass filter frequencies, low-freq and high-freq
            default : [1., 10.]
        ch : list, optional
            default : None, keep all channels
        order : int
            band-pass filter order
            default: 2
        downsample: int, optional
            down-sampling factor
            default : 4
        Returns
        -------
        X : list of nd array (samples x channels x trials_per_subject)
            epoched EEG data for the entire set or train/test phase
        Y : list of 1d array (trials_per_subject)
            class labels for the entire set or train/test phase
        ev : list of 1d array (trials_per_subject)
            frequency stimulation of each class
        """
        set_log_level(verbose=False)
        subjects = range(1, 13)
        X, Y , ev, phrase = [], [], [], []
        flashes = []
        ev_id = {'AGMSY5': 1, 'BHNTZ6': 2, 'CIOU17': 3, 'DJPV28': 4,
                 'EKQW39': 5, 'FLRX4_': 6, 'ABCDEF': 7, 'GHIJKL': 8,
                 'MNOPQR': 9, 'STUVWX': 10, 'YZ1234':11, '56789_': 12
                 }

        for subj in subjects:
            if subj < 10:
                subj = '0'+str(subj)
            raw_names = sorted(glob.glob(f"{path}/s{subj}/*.edf"))
            raw = concatenate_raws([read_raw_edf(f, preload=True) for f in raw_names])
            s = pd.Series(raw.annotations.description)
            targets = s[s.str.startswith("#Tgt")]
            targets = [tar[4] for tar in targets]
            # FROM SUBJECT 3, ANNOTATIONS DON'T CONTAIN #start
            # THE DATE OF RECORDING REPLACES #start
            # AND CONTAIN A NEW count: #counted20of20
            #starts = s[s.str.startswith("#start")]
            # targets = s[s.str.startswith("#Tgt")].str.split("_")
            # targets = [tar[0][-1] for tar in targets]
            # starts = s[s.str.startswith("#start")]
            #if starts.size == 0:
            starts = s[s.str.startswith("#Tgt")]
            ends = s[s.str.startswith("#end")]
            counts = s[s.str.startswith("#counted")]
            if counts.empty:
                start_index = np.where("#start" == raw.annotations.description)
                end_index = np.where("#end" == raw.annotations.description)
                diff = (end_index[0]- start_index[0] -1) / 6
                counts = diff.tolist()
            else:
                counts = [int(c[12:14]) for c in counts]
            desc = list(np.unique(raw.annotations.description))
            desc = [dc for dc in desc if len(dc)==6 and dc != '#start']
            event_keys = list(ev_id.keys())
            if sorted(desc) != sorted(event_keys):
                # subjects : 6 to 12, character '_' is replace by '#'
                old_keys = sorted(list(set(event_keys).difference(desc)))
                new_keys = sorted(list(set(desc).difference(event_keys)))
                evs = ev_id.copy()
                for idx, key in enumerate(new_keys):
                    evs[key] = evs.pop(old_keys[idx])
                events, _ = events_from_annotations(raw, event_id=evs)
            else:
                # subjects: 1 to 5
                events, _ = events_from_annotations(raw, event_id=ev_id)
            r = [ev_id[key] if key in ev_id else key for key in raw.annotations.description]
            ss = pd.Series(r)
            y = self._get_labels(targets, ss, starts, ends, ev_id)
            if channels:
                eeg_channels = channels
            else:
                eeg_channels = raw.info.ch_names[:64]

            raw.pick_channels(eeg_channels)
            raw.filter(band[0], band[1], method='iir', iir_params=dict(order=order, ftype='butter'))
            picks = pick_types(raw.info, meg=False, eeg=True, stim=False, eog=False,
                               exclude='bads')

            # epos = Epochs(raw, events, ev_id, epoch[0], epoch[1], proj=True, picks=picks,
            #               baseline=(-0.2, 0), preload=True)
            epos = Epochs(raw, events, ev_id, -0.2, epoch[1], proj=True, picks=picks,
                           baseline=(-0.2, 0), preload=True)
            epos.crop(epoch[0], epoch[1])
            if downsample:
                epos.decimate(downsample)
            epos = np.transpose(epos.get_data(), (2, 1, 0))
            X.append(epos*1e6)
            Y.append(y)
            ev.append(events[:, -1])
            phrase.append(targets)
            flashes.append(counts)
            del raw, epos, y, events, targets, counts, s, ss, picks

        #X = np.array(X)
        #Y = np.array(Y).squeeze()
        #ev = np.array(ev).squeeze()
        self.flashes = flashes
        return X, Y, ev, phrase

    def download_raw(self, store_path=None):
        """Download raw data from dataset repo url and stored it in a folder.

        Parameters
        ----------
        store_path : str,
            folder path where raw data will be stored, by default None. data will be stored in working path.
        """
        record_file = f"{self.url}/RECORDS"
        download_file(record_file, store_path)
        urls = self._get_files_urls(store_path)
        for i in range(12):
            # mkdir for subject
            if i < 10:
                subj_folder = f"{store_path}/s0{i+1}"
            else:
                subj_folder = f"{store_path}/s{i+1}"
            if not os.path.isdir(subj_folder):
                os.mkdir(subj_folder)
            # download edf and edf.event file for subject
            for subj_urls in urls[i]:
                download_file(subj_urls, subj_folder)

    @staticmethod
    def _get_labels(targets, events, starts, ends, ev_id):
        """Extract labels from description.
        Returns
        -------
        1d array
            trials labels 0/1 : 0 non target, 1 target
        """
        y = []
        for idx, tr in enumerate(targets):
            '''
            if events[ends.index[idx]-1] != '#end':
                trial_events = events[starts.index[idx]+2:ends.index[idx]-1]
            else:
                trial_events = events[starts.index[idx]+2:ends.index[idx]]
            '''
            if type(events[ends.index[idx]-1]) is int:
                trial_events = events[starts.index[idx]+2:ends.index[idx]]
            else:
                trial_events = events[starts.index[idx]+2:ends.index[idx]-1]
            trial_target = [ev_id[key]for key in ev_id if tr in key]
            y_trial = np.zeros(len(trial_events))
            target_indices = np.logical_or(trial_events==trial_target[0], trial_events==trial_target[1])
            y_trial[target_indices] = 1.
            y.append(y_trial)
        return np.hstack(y)

    def _get_paradigm(self):
        return ERP(title='Essex_P300', stimulation=100,
                   break_duration=50, repetition=20,
                   stimuli=12, phrase='',
                   flashing_mode='RC',
                   speller=[])

    def get_path(self):
        NotImplementedError

    def _get_files_urls(self, store_path):
        """Return each subject files url by reading RECORDS file.

        Parameters
        ----------
        store_path : str
            folder path where record file is stored

        Returns
        -------
        list of lists
            each list contains subject file urls
        """
        with open(f"{store_path}/RECORDS", "r") as f:
            recs = f.read()
        files = recs.split('\n')
        urls = []
        for i in range(1,13):
            tmp = []
            for f in files:
                if i < 10:
                    ptrn = f"s0{i}"
                else:
                    ptrn = f"s{i}"
                if f.startswith(ptrn):
                    tmp.extend([f"{self.url}/{f}", f"{self.url}/{f}.event"])
            urls.append(tmp)
        return urls


from unicodedata import name
from django.urls import path

from . import views

urlpatterns = [
    path("", views.index, name="index"),
    path("wiki/<str:title>/", views.entry, name="entry"),
    path("wiki/create", views.create, name="create"),
    path("wiki/randompage", views.randompage, name="randompage"),
    path("edit", views.edit, name="edit"),
    path("search", views.search, name="search")
]


import arcpy
import os
class Toolbox(object):
    def __init__(self):
        """Define the toolbox (the name of the toolbox is the name of the
        .pyt file)."""
        self.label = "HydroMeteoData Toolbox"
        self.alias = "HydroMeteoData"
        self.tools = [HydroMeteoData]

class HydroMeteoData(object):
    def __init__(self):
        """Define the tool (tool name is the name of the class)."""

        self.label = "HydroMeteoData"
        self.description = "Generate archival hydrological and meteorological data for Poland from 2010-2020."
        self.canRunInBackground = False

    def getParameterInfo(self):
        """Define parameter definitions"""

        yearList = [2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020]

        dane = arcpy.Parameter(
            displayName = "Output Data Class",
            name = "in_value",
            datatype = "String",
            parameterType = "Required",
            direction = "Input"
        )

        dane.filter.type = "ValueList"
        dane.filter.list = ["Dane hydrologiczne", 'Dane meteorologiczne']

        data1 = arcpy.Parameter(
            displayName = "From year",
            name = "year1",
            datatype = "GPLong",
            parameterType = "Required",
            direction = "Input"
        )

        data1.filter.type = "ValueList"
        data1.filter.list = yearList

        data2 = arcpy.Parameter(
            displayName = "To year",
            name = "year2",
            datatype = "GPLong",
            parameterType = "Required",
            direction = "Input"
        )

        data2.filter.type = "ValueList"
        data2.filter.list = yearList

        save = arcpy.Parameter(
            displayName = "Output Features",
            name = "out_features",
            datatype = "GPFeatureLayer",
            parameterType = "Required",
            direction = "Output"
        )

        params = [dane, data1, data2, save]
        return params

    def isLicensed(self):
        """Set whether tool is licensed to execute."""
        return True

    def updateParameters(self, parameters):
        """Modify the values and properties of parameters before internal
        validation is performed.  This method is called whenever a parameter
        has been changed."""

        # tutaj robię tak, że jezeli bedzie wybrany rok OD którego mają być dane to żeby nie dało się wybrać wcześniejszego roku DO którego mają być dane
        # np. jeżeli ROK OD będzie 2013 to żeby nie można było wybrać ROK DO 2011, bo by wyszło od 2013 do 2011 czyli data wsteczna
        if parameters[1].value:
            year1 = parameters[1].value
            yearList = [year for year in range(year1, 2021)]
            parameters[2].filter.list = yearList

        # tu analogicznie, jeżeli będzie wybrany rok DO którego mają być dane to żeby nie dało się wybrać roku późniejszego OD którego mają być dane
        if parameters[2].value:
            year2 = parameters[2].value
            yearList2 = [year for year in range(2010, year2+1)]
            parameters[1].filter.list = yearList2

        return

    def updateMessages(self, parameters):
        """Modify the messages created by internal validation for each tool
        parameter.  This method is called after internal validation."""
        return

    def execute(self, parameters, messages):
        """The source code of the tool."""

        # arcpy.env.workspace = "d:/geoinformatyka/SEMESTRV/programowanie_gis/zaliczenie"
        # arcpy.AddMessage(arcpy.env.workspace)

        out = parameters[3].valueAsText.split('\\')
        out_folder = parameters[3].valueAsText.split(out[-1])[0]
        out_name = out[-1]

        out_name0 = out_name.split('.')

        first_year = parameters[1].valueAsText
        last_year = parameters[2].valueAsText

        years = [year for year in range(int(first_year), int(last_year)+1)]
        arcpy.AddMessage(years)

        if parameters[0].valueAsText == "Dane hydrologiczne":
            for year in years:
                out_name = out_name0[0] + str(year) + "." + out_name0[1]

                fc = arcpy.CreateFeatureclass_management(out_folder, out_name, "POINT")

                arcpy.AddField_management(fc, "KOD", "LONG", field_is_required=True)
                arcpy.AddField_management(fc, "NAZWA", "TEXT", field_is_required=True)
                arcpy.AddField_management(fc, "CIEK", "TEXT", field_is_required=True)
                arcpy.AddField_management(fc, "ROK", "SHORT", field_is_required=True)
                arcpy.AddField_management(fc, "MIES_H", "SHORT", field_is_required=True)
                arcpy.AddField_management(fc, "DZIEN", "SHORT", field_is_required=True)

                arcpy.AddField_management(fc, "STAN_WODY", "FLOAT", field_is_nullable = True, field_is_required=False)
                arcpy.AddField_management(fc, "PRZEPLYW", "FLOAT", field_is_nullable = True, field_is_required=False)
                arcpy.AddField_management(fc, "TEMP_WODY", "FLOAT", field_is_nullable = True, field_is_required=False)
                arcpy.AddField_management(fc, "MIES_K", "SHORT", field_is_required=True)
                arcpy.AddField_management(fc, "x", "FLOAT", field_is_required=True)
                arcpy.AddField_management(fc, "y", "FLOAT", field_is_required=True)

                with open("d:/geoinformatyka/SEMESTRV/programowanie_gis/zaliczenie/hydro_test.csv", 'r') as plik:
                    columns = plik.readline().split(";")
                    line = plik.readline()

                    cur = arcpy.InsertCursor(fc)

                    while line:
                        line = line.split(';')
                        if int(line[3]) == year:

                            row = cur.newRow()

                            row.KOD = line[0]
                            row.NAZWA = line[1]
                            row.CIEK = line[2]
                            row.ROK = line[3]
                            row.MIES_H = line[4]
                            row.DZIEN = line[5]
                            row.STAN_WODY = None if line[6] == '' else line[6]
                            row.PRZEPLYW = None if line[7] == '' else line[7]
                            row.TEMP_WODY = None if line[8] == '' else line[8]
                            row.MIES_K = line[9].strip()
                            row.x = line[10].strip()
                            row.y = line[11].strip()

                            cur.insertRow(row)

                        line = plik.readline()

                dbf = out_name.split('.')[0] + ".dbf"
                xyname = out_name.split('.')[0]
                arcpy.MakeXYEventLayer_management(out_folder + dbf, "x" , "y", xyname)
                arcpy.SaveToLayerFile_management(xyname, out_folder + xyname)

                mxd = arcpy.mapping.MapDocument("CURRENT") # pobiera aktualny projekt z arcmapy
                df = arcpy.mapping.ListDataFrames(mxd)[0] # pobiera ramki danych z arcmapy
                add1 = arcpy.mapping.Layer(out_folder + xyname + ".lyr") # wybiera warstwę do dodania po ścieżce
                arcpy.mapping.AddLayer(df, add1) # dodaje warstwę do ramki czyli do ToC
                arcpy.RefreshTOC() # odświeża tabelę z zawartością
                arcpy.RefreshActiveView() # odświeża widok

        if parameters[0].valueAsText == "Dane meteorologiczne":

            for year in years:
                out_name = out_name0[0] + str(year) + "." + out_name0[1]

                fc = arcpy.CreateFeatureclass_management(out_folder, out_name, "POINT")

                arcpy.AddField_management(fc, "KOD", "LONG", field_is_required=True)
                arcpy.AddField_management(fc, "NAZWA", "TEXT", field_is_required=True)
                arcpy.AddField_management(fc, "ROK", "SHORT", field_is_required=True)
                arcpy.AddField_management(fc, "MIES", "SHORT", field_is_required=True)
                arcpy.AddField_management(fc, "DZIEN", "SHORT", field_is_required=True)

                arcpy.AddField_management(fc, "SUMA_OPAD", "FLOAT", field_is_nullable = True, field_is_required=False)
                arcpy.AddField_management(fc, "RODZ_OPAD", "TEXT", field_is_nullable = True, field_is_required=False)
                arcpy.AddField_management(fc, "WYS_POKR", "FLOAT", field_is_nullable = True, field_is_required=False)
                arcpy.AddField_management(fc, "WYS_SW_SN", "FLOAT", field_is_nullable = True, field_is_required=False)
                arcpy.AddField_management(fc, "GAT_SNIEG", "TEXT", field_is_nullable = True, field_is_required=False)
                arcpy.AddField_management(fc, "RODZ_POKR", "TEXT", field_is_nullable = True, field_is_required=False)
                arcpy.AddField_management(fc, "x", "FLOAT", field_is_required=True)
                arcpy.AddField_management(fc, "y", "FLOAT", field_is_required=True)

                with open("d:/geoinformatyka/SEMESTRV/programowanie_gis/zaliczenie/meteo_test.csv", 'r') as plik:
                    status = ['8', '9']
                    columns = plik.readline().split(";")
                    line = plik.readline()

                    cur = arcpy.InsertCursor(fc)

                    while line:
                        line = line.split(';')
                        if int(line[2]) == year:

                            row = cur.newRow()

                            row.KOD = line[0]
                            row.NAZWA = line[1]
                            row.ROK = line[2]
                            row.MIES = line[3]
                            row.DZIEN = line[4]
                            row.SUMA_OPAD = None if line[6] in status else line[5]
                            row.RODZ_OPAD = None if line[7] == '' else line[7]
                            row.WYS_POKR = None if line[9] in status else line[8]
                            row.WYS_SW_SN = None if line[11] in status else line[10]
                            row.GAT_SNIEG = None if line[13] in status else line[12]
                            row.RODZ_POKR = None if line[15] in status else line[14]
                            row.x = line[16]
                            row.y = line[17].strip()

                            cur.insertRow(row)

                        line = plik.readline()

                dbf = out_name.split('.')[0] + ".dbf"
                xyname = out_name.split('.')[0]
                arcpy.MakeXYEventLayer_management(out_folder + dbf, "x" , "y", xyname)
                arcpy.SaveToLayerFile_management(xyname, out_folder + xyname)

                mxd = arcpy.mapping.MapDocument("CURRENT")
                df = arcpy.mapping.ListDataFrames(mxd)[0]
                add1 = arcpy.mapping.Layer(out_folder + xyname + ".lyr")
                arcpy.mapping.AddLayer(df, add1)
                arcpy.RefreshTOC()
                arcpy.RefreshActiveView()

        return


# David Wylie
# DA_1

# This program reads an unspecified number of integers, determines how many even
# and odd values have been read, and displays the count for the number of even and
# odd integers. If a 0 or negative number is initially inputted it displays the following
# message: No numbers were entered except a zero or a negative number.
# The program ends when a zero or a negative integer is inputted.

# Prompt user to enter an integer
number = int(input("Enter an integer, the input ends if a zero or a a negative number is entered: "))  # Corrected int

count_even = 0
count_odd = 0  # Changed variable to zero

# While loop to read and count numbers
while number > 0:  # Changed operator
    if number % 2 == 0:  # Changed modulus to 2
        count_even += 1
    else:
        count_odd += 1

# Prompt user to enter another integer
    number = int(input("Enter an integer, the input ends if a zero or a a negative number is entered: "))  # Indented

# Display output
if count_even + count_odd == 0:  # Corrected condition
    print("No numbers were entered except a zero or a negative number")
else:
    print(f"The number of even numbers is {count_even}")
    print(f"The number of odd numbers is {count_odd}")


from flask import Flask
import os
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, login_manager
from flask_bcrypt import Bcrypt
from flask_session import Session

# gives current directory of this file
basedir = os.path.abspath(os.path.dirname(__file__))
# instance of the Flask class
myapp_obj = Flask(__name__)

myapp_obj.config["UPLOAD_FOLDER"] = "uploads"

myapp_obj.config['SECRET_KEY'] = 'secret'
myapp_obj.config['SESSION_TYPE'] = 'filesystem'
Session(myapp_obj)

myapp_obj.config['SECRET_KEY'] = '6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe'

myapp_obj.config.from_mapping(
    SECRET_KEY = 'milestone2team6',
    SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'app.db'),
    SQLALCHEMY_TRACK_MODIFICATIONS = False
)

db = SQLAlchemy(myapp_obj) # Initialize flask SQLAlchemy instance
login_manager = LoginManager(myapp_obj)
login_manager.login_view = 'login'
login_manager.login_message_category = 'info'

bcrypt = Bcrypt(myapp_obj)

# making the database for the flash cards
def _update_db(obj):
    db.session.add(obj)
    db.session.commit()
    return obj
from myapp import routes, models


# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

class Migration(migrations.Migration):

    dependencies = [
        ('Factz', '0018_auto_20150923_2251'),
    ]

    operations = [
        migrations.AddField(
            model_name='message',
            name='sheet_id',
            field=models.IntegerField(default=None),
            preserve_default=False,
        ),
        migrations.AlterUniqueTogether(
            name='message',
            unique_together=set([('sheet_id', 'subscription')]),
        ),
    ]


'''
Created on 2013-11-25

@author: Joel
'''

import time
import random

# Part A
marks = [78, 81, 45, 91, 85, 79, 63, 86, 67, 96, 52, 60, 81, 83, 71, 90]

def insertion_sort(L):
    for n in range (1, len(L)):
        for i in range(0, n):
            if L[n] < L[i]:
                L.insert(i, L.pop(n))
    return L;

sorted_marks = insertion_sort(marks)
print(sorted_marks)

# Part B
marks = [78, 81, 45, 91, 85, 79, 63, 86, 67, 96, 52, 60, 81, 83, 71, 90]

def merge_sort(L):

    length = len(L)

    if length <= 1:
        return L

    a = merge_sort(L[0:int(length / 2)])
    b = merge_sort(L[int(length / 2):length])

    return merge(a, b)

def merge (a, b):

    merged_list = []

    i = 0;
    while (len(a) > 0 and len(b) > 0):
        if (a[0] < b[0]):
            merged_list.append(a.pop(0))
        else:
            merged_list.append(b.pop(0))
        i += 1

    return merged_list + a + b

sorted_marks = merge_sort(marks)
print(sorted_marks)

# Part C
start_time = time.time()
marks = [78, 81, 45, 91, 85, 79, 63, 86, 67, 96, 52, 60, 81, 83, 71, 90]
sorted_marks = insertion_sort(marks)
end_time = time.time()
print(end_time - start_time)

start_time = time.time()
marks = [78, 81, 45, 91, 85, 79, 63, 86, 67, 96, 52, 60, 81, 83, 71, 90]
sorted_marks = merge_sort(marks)
end_time = time.time()
print(end_time - start_time)

# Part D
def generate_random_test_case(N):
    return [random.randint(0,N) for x in range(N)]

def time_sorts(N, runs):

    total_time = 0

    for x in range(runs):
        list = generate_random_test_case(N)
        start_time = time.time()
        sorted_marks = insertion_sort(list)
        end_time = time.time()
        total_time += end_time - start_time
    print(total_time)
    print(total_time / (N * runs))

    total_time = 0

    for x in range(runs):
        list = generate_random_test_case(N)
        start_time = time.time()
        sorted_marks = merge_sort(list)
        end_time = time.time()
        total_time += end_time - start_time
    print(total_time)
    print(total_time / (N * runs))

time_sorts(10000,1)
time_sorts(100000,10)
time_sorts(100000,100)
time_sorts(1000000,1)
time_sorts(1000000,10)
time_sorts(1000000,100)
time_sorts(10000000,1)
time_sorts(10000000,10)
time_sorts(10000000,100)