# Author: ROHIT KADAM

import requests
import json
import subprocess as sp
fp = open('C:\\Users\\rokadam\\Desktop\\Book1.csv')

x = fp.read()
y = x.split('\n')
# print (y)

for item in y:
    if len(item) == 0:
        y.pop(y.index(item))

z = []
for item in y:
    z.append(item.split('\t'))     #In case sometimes in the output you see /t instead of ',' replace ',' with '/t' in this line
print (z)

a = []
for j in z:
    a.append(j[1])

a.remove('Site')
#print(a)

m = ['fpi-main','spi-main','rpi-wan']
n=[]
for item in a:
    for jtem in m:
        n.append('{}-{}'.format(item, jtem))
#print (n)                     #list of all devices that need to be checked in NB
print ("\n")
p=','.join(n)                #editing list to be passed to be passed as strings to get method
print ("Complete list of devices to be checked in NB:\n",p)

print ("\n")
#print ("Complete list of devices to be checked in netbrain database\n",len(p))

####################################### Checking status of these devices in netbrain through api   ##################################################

headers = {'NetOps-API-Key': ''}
r = requests.get("http://your-netbrain-server?host={}".format(p), headers=headers)

q = r.json()
#print (q)

k=[]
#count=0
for item in q["output"]:
    if item["status_code"] == 404:
        k.append(item["object"])
    else:
        pass
        #r.append(q.index(item))
print ("List of devices not present in Netbrain:\n",k)
print ("\n")
#print ("No. of devices not present in NB:\n",len(k))

############################################ ckeck if devices are reachable ########################################################

l=[]
not_reachable=[]
cannot_ping=[]
for device in k:
    status,result = sp.getstatusoutput("ping -n 3 -w 5 " + str(device))
    #print (result)

    if "unreachable" in result:
        #print("System " + str(device) + " is UNREACHABLE !")
        not_reachable.append(device)
        pass
    elif status == 0:
        #print("System " + str(device) + " is UP !")
        l.append(device)
    else:
        #print ("System " + str(device) + " is DOWN !")
        cannot_ping.append(device)                                                   # saving to further reolve the name and check for reachability using IP address! :)
print ("List of devices which can be reached and need to be added to NB:\n",l)       #devices that are reachable and not present in netbrain!
print ("\n")
#print ("No. of devices which are reachable:\n",len(l))

print ("Destination Unreachable Devices:\n",not_reachable)
print ("\n")
print ("Other devices that cannot be reached due to some other reason:\n",cannot_ping)
print ("\n")

########################################### Write the devices to be added to the new csv file ###########################################
def add_to_file():
    fp = open('C:\\Users\\rokadam\\Desktop\\Book1.csv','r')

    x = fp.read()
    y = x.split('\n')
    #print (y)

    z = []
    for item in y:
        z.append(item.split('\t'))
    #print (z[0])

    z[0].append("Missing reachable Devices added to NB")
    #print(z[0])

    count=0
    for items in range(len(z)):
        if items == 0:
            pass
        else:
            z[items].append(l[count])
            count+=1
            if count == (len(l)):
                break
            else:
                continue
    resultz= []
    for element in z:
        resultz.append(",".join(element))

    final = "\n".join(resultz)

    fp.close()                    ####### the file open in read need to be closed

    write_to_file = open('C:\\Users\\rokadam\\Desktop\\Book3.csv','w')      ###write operation performed on a completely new file!!!

    write_to_file.write(final)          #### the write operation can be performed only once, meaning if we execute the same code again,
                                              # the module conatining write operation will give an error stating that the permission is denied

########################################### Add reachable devices to Netbrain through API #############################################

t=','.join(l)
payload=[{"hostlist":"{}".format(t)}]
s = requests.post("http://your-netbrain-server", json=payload, headers=headers)
u = s.json()
print (u)

add_to_file()      ######## call to add to the new file the complete list missing and added devices


from datetime import datetime, timedelta

from flask import abort, request
from flask_restx import Namespace, Resource, reqparse
from flask_restx.inputs import datetime_from_iso8601

from c3po.api.dto import FeedDto
from c3po.api.service.feed_service import FeedService

feed_ns = FeedDto.ns

parser = reqparse.RequestParser()
parser.add_argument('limit', type=int, default=10)
parser.add_argument('genre', type=str)
parser.add_argument('from', type=datetime_from_iso8601, help="Inclusive")
parser.add_argument('to', type=datetime_from_iso8601, help="Exclusive")

@feed_ns.route('/interval')
class FeedPopular(Resource):
    """ User Login Resource """
    @feed_ns.doc('Popular songs (most liked)')
    @feed_ns.expect(parser)
    def get(self):
        args = parser.parse_args()
        if(args['from'] and args['to']):
            response, status = FeedService.get_posts_in_interval(
                args['from'], args['to'])
        else:
            response, status = FeedService.get_posts_in_interval()

        if status != 200:
            abort(403, response)
        else:
            return response, status

@feed_ns.route('/latest')
class FeedLatest(Resource):
    @feed_ns.doc('Latest feed')
    @feed_ns.expect(parser)
    def get(self):
        args = parser.parse_args()
        response, status = FeedService.get_latest_posts(args['limit'])
        if status != 200:
            abort(403, response)
        else:
            return response, status

@feed_ns.route('/popular')
class FeedLatest(Resource):
    popular_parser = parser
    popular_parser.add_argument('past', type=int, help='Days in the past')

    @feed_ns.doc('Latest popular songs')
    @feed_ns.expect(parser)
    def get(self):
        args = parser.parse_args()
        response, status = FeedService.get_popular_posts(
            args['to'], args['past'])
        if status != 200:
            abort(403, response)
        else:
            return response, status

@feed_ns.route('/frequent')
class FeedFrequent(Resource):
    @feed_ns.doc('Most frequent songs')
    @feed_ns.expect(parser)
    def get(self):
        args = parser.parse_args()
        response, status = FeedService.get_frequent_posts(args['limit'])
        if status != 200:
            abort(403, response)
        else:
            return response, status


from bs4 import BeautifulSoup       # download BeautifulSoup first: https://www.crummy.com/software/BeautifulSoup/bs4/doc/
from random import randint
import re
import string
                                    # REMEMBER TO CHANGE THIS LINE TO RIGHT DIRECTORY
soup = BeautifulSoup(open("/path-to/<facebook's_unzipped_folder>/html/messages.htm"), "html.parser")
arr = soup.find_all("p")
nametags = soup.find_all("span", "user")
timetags = soup.find_all("span", "meta")                    # get all useful data (returns list with tags still included)
aliases = {"Mr. Bean": "Person: 0"}

long_p = ""
for l in xrange(len(arr)-1, -1, -1):                        # backwards since chats printed in reverse order
    real = nametags[l].get_text(' ', strip=True)
    if real not in aliases:
        aliases[real] = "Person: " + str(len(aliases))      # put all useful data into 1 large string
    fake = real                     # UNCOMMENT LINE BELOW FOR NAME HIDING
    # fake = aliases[real]
    timestamp = timetags[l].get_text(' ', strip=True)
    str3 = arr[l].get_text(' ', strip=True)                 # format: Person, Time, Message, EOM → 1 per line
    long_p += fake + "\nTime: " + timestamp + "\n" + str3 + "\n"
    long_p += "--------------------------------------------- EOM ---------------------------------------------\n"

long_talk = re.sub('</?(p|span.*)>', '', long_p)            # remove all tags, turn IDs into random 9 digit number
long_talk = re.sub('[^0-9][0-9]{9}[^0-9]', '\n'+str(randint(100000000, 999999999))+'\n', long_talk)
printable = set(string.printable)                           # remove non-ASCII characters
long_talk = filter(lambda x: x in printable, long_talk)

f = open("/path-to/preferred/directory/test.txt", "w")      # create text document of all chats: test.txt
f.write(long_talk)
f.close()


from directicus.layer import *
import pygame,directicus
directicus.event.debugging = False

if __name__=='__main__':
    class Gun(directicus.sprite.Sprite):
        image = pygame.image.load('media/howitzer.png')

        def __init__(self,pos=(0,0)):
            directicus.sprite.Sprite.__init__(self)
            self.rect.center = pos

    class LayerDemo(directicus.engine.State):
        def start(self):
            directicus.engine.State.start(self)
            pygame.display.set_caption('Directicus Layering Demo')

            bg1 = pygame.display.get_surface().copy()
            bg2 = pygame.Surface((300,200))
            bg2.fill((100,100,100))
            sprites = [
                Gun((150,100)),
                Gun((145,90)),
                Gun((155,110)),
            ]
            self.layer = IsometricLayer(background_image=bg1,size=(640,480),*sprites)
            disp = pygame.display.get_surface()
            self.layer.start(disp)
            pygame.display.flip()

        def onTick(self,event):
            directicus.engine.State.onTick(self,event)
            disp = pygame.display.get_surface()
            disp.fill((0,0,0))
            self.layer.update()
            disp.blit(self.layer.image,self.layer.rect)
            pygame.display.flip()

    e = directicus.engine.Engine()
    e.size = (300,200)
    e.DEFAULT = LayerDemo
    e.run()


#This sample, non-production-ready template .
#© 2022 Amazon Web Services, Inc. or its affiliates. All Rights Reserved.
#This AWS Content is provided subject to the terms of the AWS Customer Agreement available at
#http://aws.amazon.com/agreement or other written agreement between Customer and either
#Amazon Web Services, Inc. or Amazon Web Services EMEA SARL or both.

#
# Dump all replication events from a remote mysql server
# pip install mysql-replication boto3
#
import boto3
import json
from pymysqlreplication import BinLogStreamReader
from pymysqlreplication.row_event import (
    DeleteRowsEvent,
    UpdateRowsEvent,
    WriteRowsEvent,
)

MYSQL_SETTINGS = {
"host": "hostname",
      "port": 3306,
      "user": "repl",
      "passwd": "******"
      }

def main():

    kinesis = boto3.client("kinesis")

    # server_id is your slave identifier, it should be unique.
    # set blocking to True if you want to block and wait for the next event at
    # the end of the stream
    stream = BinLogStreamReader(connection_settings=MYSQL_SETTINGS,
                                server_id=1012598212,
                                blocking=True,
                                resume_stream=True,
                                only_events=[DeleteRowsEvent, WriteRowsEvent, UpdateRowsEvent])
    for binlogevent in stream:
        for row in binlogevent.rows:
            print(">>> start event")
            event = {"schema": binlogevent.schema,
                    "table": binlogevent.table,
                    "type": type(binlogevent).__name__,
                    "row": row
                    }
            print(">>>event",event)
            output = kinesis.put_record(StreamName="mysql_data", Data=json.dumps(event), PartitionKey="default")
            print(">>kinasis output",output)

            #binlogevent.dump()

    stream.close()

if __name__ == "__main__":
    main()


import inspect
import urwid
import os

def main():
	# http://urwid.org/tutorial/index.html

	# txt = urwid.Text("Hello World")
	#
	# fill = urwid.Filler(txt, "top")
	# loop = urwid.MainLoop(fill)
	#
	# loop.run()

	print("\n", "-" * 4, " ", inspect.getframeinfo(inspect.currentframe()).lineno, " ", "-" * 4, "\n", sep = "")

	def exit_on_q(key):
		if key in ("q", "Q"):
			raise urwid.ExitMainLoop()

	palette = [("banner", "black", "light gray"), ("streak", "black", "dark red"), ("bg", "black", "dark blue"), ]

	txt = urwid.Text(("banner", " Hello World "), align = "center")

	map1 = urwid.AttrMap(txt, "streak")
	fill = urwid.Filler(map1)

	map2 = urwid.AttrMap(fill, "bg")
	loop = urwid.MainLoop(map2, palette, unhandled_input = exit_on_q)

	loop.run()

	print("\n", "-" * 4, " ", inspect.getframeinfo(inspect.currentframe()).lineno, " ", "-" * 4, "\n", sep = "")

if __name__ == '__main__':
	main()


import numpy as np
from scipy.stats import norm
from statsmodels.distributions.empirical_distribution import ECDF

class OnlineTransformFunction():
    def __init__(self, cont_indices, ord_indices, X=None, window_size=100):
        """
        Require window_size to be positive integers.

        To initialize the window,
        for continuous columns, sample standatd normal with mean and variance determined by the first batch of observation;
        for ordinal columns, sample uniformly with replacement among all integers between min and max seen from data.

        """
        self.cont_indices = cont_indices
        self.ord_indices = ord_indices
        p = len(cont_indices)
        self.window_size = window_size
        self.window = np.array([[np.nan for x in range(p)] for y in range(self.window_size)]).astype(np.float64)
        self.update_pos = np.zeros(p).astype(np.int)#更新位置
        if X is not None:
            self.partial_fit(X)

    '''
    Idea.
    The input data is the corresponding masked batch data
    Construct a window size, which is filled in two ways.
    1、Order value
    2, non-sequential values
    For ordinal values
        a. For the nan value, random filling between 0 and 1 is used.
        b. If it is not a nan value, use the range of mean and standard deviation to fill randomly
    For non-sequential values
        a. For nan values, directly fill to 0
        b. If the value is not nan, use the maximum value and minimum value to fill randomly

    After filling the window as above
    To update the window (corresponding to the size of the batch), the non-nan value of the batch corresponding to X_masked should be updated to the window
    '''
    def partial_fit(self, X_batch):
        """
        Update the running window used to estimate marginals with the data in X
        """
        # Initialization
        if np.isnan(self.window[0, 0] ):
            # Continuous columns: normal initialization
            mean_cont = np.nanmean(X_batch[:, self.cont_indices])# Ignore the nan in this to find the average
            std_cont = np.nanstd(X_batch[:, self.cont_indices])
            if np.isnan(mean_cont):# The standard normal distribution is generated if the continuous series is empty, otherwise it is generated based on the mean and variance
                self.window[:, self.cont_indices] = np.random.normal(0, 1, size=(self.window_size, np.sum(self.cont_indices)))
            else:
                self.window[:, self.cont_indices] = np.random.normal(mean_cont, std_cont, size=(self.window_size, np.sum(self.cont_indices)))
            # Ordinal columns: uniform initialization
            for j,loc in enumerate(self.ord_indices):
                if loc:
                    min_ord = np.nanmin(X_batch[:, j])
                    max_ord = np.nanmax(X_batch[:,j])
                    if np.isnan(min_ord):
                        self.window[:,j].fill(0) #  If the list of ordinal numbers is empty, fill with 0
                    else:# Randomly select the element in the middle of the maximum and minimum values
                        self.window[:, j] = np.random.randint(min_ord, max_ord+1, size = self.window_size)
        # update for new data update window
        for row in X_batch:
            for col_num in range(len(row)):
                data = row[col_num]
                if not np.isnan(data):
                    self.window[self.update_pos[col_num], col_num] = data
                    self.update_pos[col_num] += 1
                    if self.update_pos[col_num] >= self.window_size:
                        self.update_pos[col_num] = 0

    def partial_evaluate_cont_latent(self, X_batch):
        """
        Obtain the latent continuous values corresponding to X_batch
        """
        X_cont = X_batch[:,self.cont_indices]
        window_cont = self.window[:,self.cont_indices]
        Z_cont = np.empty(X_cont.shape)
        Z_cont[:] = np.nan
        for i in range(np.sum(self.cont_indices)):
            # INPUT THE WINDOW FOR EVERY COLUMN
            missing = np.isnan(X_cont[:,i])
            Z_cont[~missing,i] = self.get_cont_latent(X_cont[~missing,i], window_cont[:,i])
        return Z_cont

    def partial_evaluate_ord_latent(self, X_batch):
        """
        获取与 X_batch 对应的潜在序数值
        Obtain the latent ordinal values corresponding to X_batch
        """
        X_ord = X_batch[:,self.ord_indices]
        window_ord = self.window[:,self.ord_indices]
        Z_ord_lower = np.empty(X_ord.shape) #Returns a one-dimensional or multi-dimensional array, the elements of which are not empty and are randomly generated data
        Z_ord_lower[:] = np.nan
        Z_ord_upper = np.empty(X_ord.shape)
        Z_ord_upper[:] = np.nan
        for i in range(np.sum(self.ord_indices)):
            missing = np.isnan(X_ord[:,i])
            # INPUT THE WINDOW FOR EVERY COLUMN
            Z_ord_lower[~missing,i], Z_ord_upper[~missing,i] = self.get_ord_latent(X_ord[~missing,i], window_ord[:,i])
        return Z_ord_lower, Z_ord_upper

    def partial_evaluate_cont_observed(self, Z_batch, X_batch=None):
        """
        Transform the latent continous variables in Z_batch into corresponding observations
        """
        Z_cont = Z_batch[:,self.cont_indices]
        if X_batch is None:
            X_batch = np.zeros(Z_batch.shape) * np.nan
        X_cont = X_batch[:,self.cont_indices]
        X_cont_imp = np.copy(X_cont)
        window_cont = self.window[:,self.cont_indices]
        for i in range(np.sum(self.cont_indices)):
            # if X_batch is not provided, missing will be 1:n
            missing = np.isnan(X_cont[:,i])
            if np.sum(missing)>0:
                X_cont_imp[missing,i] = self.get_cont_observed(Z_cont[missing,i], window_cont[:,i])
        return X_cont_imp

    def partial_evaluate_ord_observed(self, Z_batch, X_batch=None):
        """
        Transform the latent ordinal variables in Z_batch into corresponding observations
        """
        Z_ord = Z_batch[:,self.ord_indices]
        if X_batch is None:
            X_batch = np.zeros(Z_batch.shape) * np.nan
        X_ord = X_batch[:, self.ord_indices]
        X_ord_imp = np.copy(X_ord)
        window_ord = self.window[:,self.ord_indices]
        for i in range(np.sum(self.ord_indices)):
            missing = np.isnan(X_ord[:,i])
            if np.sum(missing)>0:
                X_ord_imp[missing,i] = self.get_ord_observed(Z_ord[missing,i], window_ord[:,i])
        return X_ord_imp

    def get_cont_latent(self, x_batch_obs, window):
        """
        Return the latent variables corresponding to the continuous entries of
        self.X. Estimates the CDF columnwise with the empyrical CDF 累积标准正态分布函数
        """
        ecdf = ECDF(window)
        l = len(window)
        q = (l / (l + 1.0)) * ecdf(x_batch_obs)
        q[q==0] = l/(l+1)/2
        if any(q==0):
            print("In get_cont_latent, 0 quantile appears")
        # print("q",q)
        return norm.ppf(q)

    def get_cont_observed(self, z_batch_missing, window):
        """
        Applies marginal scaling to convert the latent entries in Z corresponding
        to continuous entries to the corresponding imputed oberserved value
        """
        quantiles = norm.cdf(z_batch_missing)
        return np.quantile(window, quantiles)

    def get_ord_latent(self, x_batch_obs, window):
        """
        get the cdf at each point in X_batch
        """
        # the lower endpoint of the interval for the cdf
        ecdf = ECDF(window)
        unique = np.unique(window)
        if unique.shape[0] > 1:
            threshold = np.min(np.abs(unique[1:] - unique[:-1]))/2.0
            z_lower_obs = norm.ppf(ecdf(x_batch_obs - threshold))
            z_upper_obs = norm.ppf(ecdf(x_batch_obs + threshold))
        else:
            z_upper_obs = np.inf
            z_lower_obs = -np.inf
            # If the window at j-th column only has one unique value,
            # the final imputation will be the unqiue value regardless of the EM iteration.
            # In offline setting, we don't allow this happen.
            # In online setting, when it happens,
            # we use -inf to inf to ensure tha EM iteration does not break down due to singularity
            #print("window contains a single value")
        return z_lower_obs, z_upper_obs

    def get_ord_observed(self, z_batch_missing, window, DECIMAL_PRECISION = 3):
        """
        Gets the inverse CDF of Q_batch
        returns: the Q_batch quantiles of the ordinals seen thus far
        """
        n = len(window)
        x = norm.cdf(z_batch_missing)
        # round to avoid numerical errors in ceiling function
        quantile_indices = np.ceil(np.round_((n + 1) * x - 1, DECIMAL_PRECISION))
        quantile_indices = np.clip(quantile_indices, a_min=0,a_max=n-1).astype(int)
        sort = np.sort(window)
        return sort[quantile_indices]


import json
import os
import re
from urllib.parse import quote

import requests

new_content = """# [{}. {}]({})

[English Version]({})

## 题目描述

<!-- 这里写题目描述 -->

{}

"""

new_content_en = """# [{}. {}]({})

[中文文档]({})

## Description

{}

"""

class LCSpider:
    graph_url = 'https://leetcode-cn.com/graphql'
    user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' \
                 'Chrome/77.0.3865.120 Safari/537.36'

    def __init__(self):
        self.session = requests.session()

        # ['0000-0099', '0100-0199', ..., '9900-9999']
        self.sub_folders = [str(i * 100).zfill(4) + '-' + str(i * 100 + 99).zfill(4) for i in range(100)]
        self.difficulty_mapper = dict(Easy='简单', Medium='中等', Hard='困难')

        self.result = []

    def get_question_detail(self, question_title_slug):
        """fetch question detail from lc's api"""
        form_data = {
            'operationName': 'globalData',
            'query': 'query globalData {\n  feature {\n    questionTranslation\n    subscription\n    signUp\n    '
                     'discuss\n    mockInterview\n    contest\n    store\n    book\n    chinaProblemDiscuss\n    '
                     'socialProviders\n    studentFooter\n    cnJobs\n    enableLsp\n    enableWs\n    '
                     'enableDebugger\n    enableDebuggerAdmin\n    enableDarkMode\n    tasks\n    '
                     'leetbook\n    __typename\n  }\n  userStatus {\n    isSignedIn\n    isAdmin\n    '
                     'isStaff\n    isSuperuser\n    isTranslator\n    isPremium\n    isVerified\n    '
                     'isPhoneVerified\n    isWechatVerified\n    checkedInToday\n    username\n    '
                     'realName\n    userSlug\n    groups\n    avatar\n    optedIn\n    '
                     'requestRegion\n    region\n    activeSessionId\n    permissions\n    notificationStatus {\n      '
                     'lastModified\n      numUnread\n      __typename\n    }\n    completedFeatureGuides\n    '
                     'useTranslation\n    accountStatus {\n      isFrozen\n      inactiveAfter\n      __typename\n    '
                     '}\n    __typename\n  }\n  siteRegion\n  chinaHost\n  websocketUrl\n  userBannedInfo {\n    '
                     'bannedData {\n      endAt\n      bannedType\n      __typename\n    }\n    __typename\n  }\n}\n',
            'variables': {}
        }
        headers = {
            'User-Agent': LCSpider.user_agent,
            'Connection': 'keep-alive',
            'Content-Type': 'application/json',
            'Referer': 'https://leetcode-cn.com/problems/' + question_title_slug,
            # cookie here
            # 'cookie': ''
        }
        self.session.post(url=LCSpider.graph_url,
                          data=json.dumps(form_data),
                          headers=headers,
                          timeout=10)

        form_data = {
            'operationName': 'questionData',
            'variables': {
                'titleSlug': question_title_slug
            },
            'query': """query questionData($titleSlug: String!) {\n  question(titleSlug: $titleSlug) {\n
            questionId\n    questionFrontendId\n    boundTopicId\n    title\n    titleSlug\n    content\n
            translatedTitle\n    translatedContent\n    isPaidOnly\n    difficulty\n    likes\n    dislikes\n
            isLiked\n    similarQuestions\n    contributors {\n      username\n      profileUrl\n
            avatarUrl\n      __typename\n    }\n    langToValidPlayground\n    topicTags {\n      name\n
            slug\n      translatedName\n      __typename\n    }\n    companyTagStats\n    codeSnippets {\n
            lang\n      langSlug\n      code\n      __typename\n    }\n    stats\n    hints\n    solution {\n
            id\n      canSeeDetail\n      __typename\n    }\n    status\n    sampleTestCase\n    metaData\n
            judgerAvailable\n    judgeType\n    mysqlSchemas\n    enableRunCode\n    envInfo\n    book {\n
            id\n      bookName\n      pressName\n      source\n      shortDescription\n      fullDescription\n
            bookImgUrl\n      pressImgUrl\n      productUrl\n      __typename\n    }\n    isSubscribed\n
            isDailyQuestion\n    dailyRecordStatus\n    editorType\n    ugcQuestionId\n    style\n
            __typename\n  }\n}\n"""
        }

        # get question detail
        resp = self.session.post(url=LCSpider.graph_url,
                                 data=json.dumps(form_data).encode('utf-8'),
                                 headers=headers,
                                 timeout=10)
        res = resp.json()
        return res['data']['question']

    def get_all_questions(self):
        """fetch all question from lc's api"""
        headers = {
            'accept': 'application/json, text/javascript, */*; q=0.01',
            'content-type': 'application/json',
            'user-agent': LCSpider.user_agent,
            'x-requested-with': 'XMLHttpRequest'
        }
        resp = self.session.get(url='https://leetcode.com/api/problems/all/',
                                headers=headers,
                                allow_redirects=False,
                                timeout=10)
        questions = resp.json()['stat_status_pairs']

        for question in questions:
            question_title_slug = question['stat']['question__title_slug']
            question_detail = self.get_question_detail(question_title_slug)
            if not question_detail:
                continue

            frontend_question_id = str(question['stat']['frontend_question_id']).zfill(4)
            no = int(frontend_question_id) // 100

            question_title_en = question['stat']['question__title']
            question_title_en = re.sub(r'[\\/:*?"<>|]', '', question_title_en).strip()

            url_cn = f'https://leetcode-cn.com/problems/{question_title_slug}'
            url_en = f'https://leetcode.com/problems/{question_title_slug}'

            path_cn = f'/solution/{self.sub_folders[no]}/{frontend_question_id}.{quote(question_title_en)}/README.md'
            path_en = f'/solution/{self.sub_folders[no]}/{frontend_question_id}.{quote(question_title_en)}/README_EN.md'

            print(f'{frontend_question_id}. {question_title_en}')
            topic_tags = question_detail.get('topicTags')
            item = {
                'question_id': str(question['stat']['question_id']).zfill(4),
                'frontend_question_id': frontend_question_id,
                'paid_only': question['paid_only'],
                'paid_only_cn': question_detail.get('isPaidOnly'),
                'url_cn': url_cn,
                'url_en': url_en,
                'relative_path_cn': path_cn,
                'relative_path_en': path_en,
                'title_cn': question_detail.get('translatedTitle') or '',
                'title_en': question_title_en or '',
                'question_title_slug': question_title_slug,
                'content_en': question_detail.get('content'),
                'content_cn': question_detail.get('translatedContent'),
                'tags_en': [e['name'] for e in topic_tags if e['name']] or [],
                'tags_cn': [e['translatedName'] for e in topic_tags if e['translatedName']] or [],
                'difficulty_en': question_detail.get('difficulty'),
                'difficulty_cn': self.difficulty_mapper.get(question_detail.get('difficulty')),
                'code_snippets': question_detail.get('codeSnippets') or [],
            }

            col1_cn = f'[{frontend_question_id}]({url_cn})'
            col2_cn = f'[{item["title_cn"]}]({path_cn})'
            col3_cn = ','.join([f'`{tag}`' for tag in item['tags_cn']])
            col3_cn = '' if (col3_cn == 'None' or not col3_cn) else col3_cn
            col4_cn = item['difficulty_cn']
            col5_cn = '🔒' if item['paid_only_cn'] else ''
            col1_en = f'[{frontend_question_id}]({url_en})'
            col2_en = f'[{item["title_en"]}]({path_en})'
            col3_en = ','.join([f'`{tag}`' for tag in item['tags_en']])
            col3_en = '' if (col3_en == 'None' or not col3_en) else col3_en
            col4_en = item['difficulty_en']
            col5_en = '🔒' if item['paid_only'] else ''
            item['md_table_row_cn'] = [col1_cn, col2_cn, col3_cn, col4_cn, col5_cn]
            item['md_table_row_en'] = [col1_en, col2_en, col3_en, col4_en, col5_en]

            self.result.append(item)

    def save_result(self):
        with open('result.json', 'w', encoding='utf-8') as f:
            f.write(json.dumps(self.result))

    @staticmethod
    def generate_readme():
        """generate readme files"""
        with open('./result.json', 'r', encoding='utf-8') as f:
            result = f.read()
            result = json.loads(result)

        md_table_cn = [item['md_table_row_cn'] for item in result]
        md_table_en = [item['md_table_row_en'] for item in result]

        # generate README.md
        items = []
        table_cn = "\n|  题号  |  题解  |  标签  |  难度  | 备注 |\n| --- | --- | --- | --- | --- |"
        for item in sorted(md_table_cn, key=lambda x: x[0]):
            items.append("\n|  {}  |  {}  |  {}  |  {}  |  {}  |".format(item[0], item[1], item[2], item[3], item[4]))
        table_cn += "".join(items)

        with open('./readme_template.md', 'r', encoding='utf-8') as f:
            readme_cn = f.read()
        with open('./README.md', 'w', encoding='utf-8') as f:
            f.write(readme_cn.format(table_cn))

        # generate README_EN.md
        items = []
        table_en = "\n|  #  |  Solution  |  Tags  |  Difficulty  |  Remark |\n| --- | --- | --- | --- | --- |"
        for item in sorted(md_table_en, key=lambda x: x[0]):
            items.append(
                "\n|  {}  |  {}  |  {}  |  {}  |  {}  |".format(item[0], item[1], item[2], item[3], item[4]))
        table_en += "".join(items)
        with open('./readme_template_en.md', 'r', encoding='utf-8') as f:
            readme_en = f.read()
        with open('./README_EN.md', 'w', encoding='utf-8') as f:
            f.write(readme_en.format(table_en))

    def generate_question_readme(self):
        with open('./problem_readme_template.md', 'r', encoding='utf-8') as f:
            readme_cn = f.read()
        with open('./problem_readme_template_en.md', 'r', encoding='utf-8') as f:
            readme_en = f.read()

        with open('./result.json', 'r', encoding='utf-8') as f:
            result = f.read()
            result = json.loads(result)
            for item in result:
                if not item['content_cn'] and not item['content_en']:
                    continue
                no = int(item['frontend_question_id']) // 100
                path = f'./{self.sub_folders[no]}/{item["frontend_question_id"]}.{item["title_en"]}'
                path = path.replace(":", " ")
                if os.path.isdir(path):
                    continue
                os.makedirs(path)

                # generate lc problem readme cn
                with open(f'{path}/README.md', 'w', encoding='utf-8') as f1:
                    f1.write(readme_cn.format(int(item['frontend_question_id']),
                                              item["title_cn"],
                                              item['url_cn'],
                                              item['relative_path_en'],
                                              item['content_cn']))

                # generate lc problem readme en
                with open(f'{path}/README_EN.md', 'w', encoding='utf-8') as f2:
                    f2.write(readme_en.format(int(item['frontend_question_id']),
                                              item["title_en"],
                                              item['url_en'],
                                              item['relative_path_cn'],
                                              item['content_en']))

    @staticmethod
    def generate_summary():
        """generate summary files"""
        summary_cn = ""
        summary_en = ""
        for file in os.listdir("./"):
            if os.path.isdir("./" + file) and file != '__pycache__':
                summary_cn += ("\n- " + file + "\n")
                summary_en += ("\n- " + file + "\n")
                for sub in os.listdir("./" + file):
                    enc = quote(sub)
                    summary_cn += f'  - [{sub}](/solution/{file}/{enc}/README.md)\n'
                    summary_en += f'  - [{sub}](/solution/{file}/{enc}/README_EN.md)\n'

        # generate summary.md
        with open('./summary.md', 'w', encoding='utf-8') as f:
            f.write(summary_cn)

        # generate summary_en.md
        with open('./summary_en.md', 'w', encoding='utf-8') as f:
            f.write(summary_en)

    @staticmethod
    def remove_empty_folders():
        """remove empty sub folders"""
        sub_folders = [str(i * 100).zfill(4) + '-' + str(i * 100 + 99).zfill(4) for i in range(100)]

        for item in sub_folders:
            if not os.path.isdir(f'./{item}'):
                continue
            files = os.listdir(f'./{item}')
            for f in files:
                if os.path.isdir(f'./{item}/{f}'):
                    if not os.listdir(f'./{item}/{f}'):
                        os.rmdir(f'./{item}/{f}')

    @staticmethod
    def replace_content():
        with open('./result.json', 'r', encoding='utf-8') as f:
            result = f.read()
            result = json.loads(result)
            mapper = {item['frontend_question_id']: item for item in result}
        sub_folders = [str(i * 100).zfill(4) + '-' + str(i * 100 + 99).zfill(4) for i in range(100)]
        for item in sub_folders:
            if not os.path.isdir(f'./{item}'):
                continue
            files = os.listdir(f'./{item}')
            for f in files:
                if os.path.isdir(f'./{item}/{f}'):
                    with open(f'./{item}/{f}/README.md', 'r', encoding='utf-8') as f1:
                        readme = f1.read()
                    with open(f'./{item}/{f}/README_EN.md', 'r', encoding='utf-8') as f2:
                        readme_en = f2.read()
                    question = mapper[f[:4]]
                    b = new_content.format(int(question['frontend_question_id']),
                                           question["title_cn"],
                                           question['url_cn'],
                                           question['relative_path_en'],
                                           question['content_cn'])
                    index_cn = readme.index("## 解法")
                    a = b + readme[index_cn:]
                    with open(f'./{item}/{f}/README.md', 'w', encoding='utf-8') as f1:
                        f1.write(a)
                    index_en = readme_en.index("## Solutions")
                    b = new_content_en.format(int(question['frontend_question_id']),
                                              question["title_en"],
                                              question['url_en'],
                                              question['relative_path_cn'],
                                              question['content_en'])
                    a = b + readme_en[index_en:]
                    with open(f'./{item}/{f}/README_EN.md', 'w', encoding='utf-8') as f2:
                        f2.write(a)

    @staticmethod
    def download_image():
        sub_folders = [str(i * 100).zfill(4) + '-' + str(i * 100 + 99).zfill(4) for i in range(100)]
        for item in sub_folders:
            if not os.path.isdir(f'./{item}'):
                continue
            files = os.listdir(f'./{item}')
            for f in files:
                if os.path.isdir(f'./{item}/{f}'):
                    with open(f'./{item}/{f}/README.md', 'r', encoding='utf-8') as f1:
                        readme = f1.read()
                    with open(f'./{item}/{f}/README_EN.md', 'r', encoding='utf-8') as f2:
                        readme_en = f2.read()

                    res_cn = re.findall(r'src="(.*?)"', readme, re.S) or []
                    for url in res_cn:
                        file_name = os.path.basename(url)
                        new_url = f'https://cdn.jsdelivr.net/gh/doocs/leetcode@main/solution/{item}/{quote(f)}/images/{file_name}'
                        readme = readme.replace(url, new_url)
                    with open(f'./{item}/{f}/README.md', 'w', encoding='utf-8') as f1:
                        f1.write(readme)

                    res_en = re.findall(r'src="(.*?)"', readme_en, re.S) or []
                    for url in res_en:
                        file_name = os.path.basename(url)
                        new_url = f'https://cdn.jsdelivr.net/gh/doocs/leetcode@main/solution/{item}/{quote(f)}/images/{file_name}'
                        readme_en = readme_en.replace(url, new_url)
                    with open(f'./{item}/{f}/README_EN.md', 'w', encoding='utf-8') as f1:
                        f1.write(readme_en)

if __name__ == '__main__':
    spider = LCSpider()

    spider.get_all_questions()
    spider.save_result()

    spider.generate_readme()
    spider.generate_question_readme()
    spider.generate_summary()
    # spider.replace_content()
    # spider.download_image()


from random import randint, choice
from typing import List, Dict

from dialogflow_backend.dialogflow.intent_handlers.elicitation.architecture import elicitation_architecture_handler
from dialogflow_backend.dialogflow.response_types import ActionResponse, TextResponse, FormattingResponse, CardResponse, \
    QuickReplyResponse
from dialogflow_backend.dialogflow.util import get_context, is_in_context, set_context_parameters
from util.log import error
from util.text.ids import INTENT_ELICITATION_COMPONENT_MISSING_TEXT, INTENT_ELICITATION_COMPONENT_TEXT, \
    INTENT_ELICITATION_COMPONENT_SERVICE_TEXT, INTENT_ELICITATION_COMPONENT_OPERATION_TEXT
from util.text.text import text

async def get_nodes(nodes):
    nodes = {k: v[1] for k, v in sorted(nodes.items())}
    return {k: v for k, v in sorted(nodes.items(), key=lambda o: o[1], reverse=True)}

async def get_edges(edges):
    edges = {k: v[1] for k, v in sorted(edges.items())}
    return {k: v for k, v in sorted(edges.items(), key=lambda o: o[1], reverse=True)}

async def elicitation_component_handler(result) -> List[Dict]:
    try:
        conversation = []

        elicitation = get_context('c-elicitation', result)
        graph_context = get_context('c-graph', result)
        config_context = get_context('c-config', result)

        # Component name was given as text.
        if is_in_context('component-name', config_context):
            component_type = config_context.parameters['component-type']
            component_name = config_context.parameters['component-name']

            # Check against available operations.
            if component_type == 'operation' or component_name in graph_context.parameters['arch']['edges']:
                return [ActionResponse.create('command', ['select-element', 'edge', component_name])]

            # Check against available services.
            elif component_type == 'service' or component_name in graph_context.parameters['arch']['nodes']:
                return [ActionResponse.create('command', ['select-element', 'node', component_name])]

            # Prompt the user to try again.
            missing = text(INTENT_ELICITATION_COMPONENT_MISSING_TEXT)
            return [TextResponse.create(missing.format(component_type, component_name))]

        # Provide the user with a selection of services and operations.
        conversation.append(FormattingResponse.create('divider'))
        content = text(INTENT_ELICITATION_COMPONENT_TEXT)
        response = CardResponse.create(title=content['title'].format(elicitation.parameters['arch']),
                                       text=content['text'], spoiler=content['spoiler'])
        conversation.append(response)

        # Services
        services = TextResponse.create(text(INTENT_ELICITATION_COMPONENT_SERVICE_TEXT))
        service_replies = QuickReplyResponse()

        nodes = await get_nodes(graph_context.parameters['arch']['nodes'])
        for i, node in enumerate(nodes):
            if i == 5:
                break
            service_replies.add_reply(node, 'select-element', ['node', node])

        conversation.append(services)
        conversation.append(service_replies.__repr__())

        # Operations
        operations = TextResponse.create(text(INTENT_ELICITATION_COMPONENT_OPERATION_TEXT))
        operation_replies = QuickReplyResponse()

        edges = await get_edges(graph_context.parameters['arch']['edges'])
        for i, edge in enumerate(edges):
            if i == 5:
                break
            operation_replies.add_reply(edge, 'select-element', ['edge', edge])

        conversation.append(operations)
        conversation.append(operation_replies.__repr__())

        return conversation

    except Exception as e:
        error(e)
        return await elicitation_architecture_handler(result)

async def elicitation_component_followup_handler(result) -> List[Dict]:
    return await elicitation_component_handler(result)

async def elicitation_component_default_handler(result) -> List[Dict]:
    graph_context = get_context('c-graph', result)
    if graph_context:
        if not randint(0, 10) < 6:
            edges = await get_edges(graph_context.parameters['arch']['edges'])
            name = choice(list(edges.keys()))
            result = set_context_parameters(result, 'c-config', {'component-name': name, 'component-type': 'operation'})
        else:
            nodes = await get_nodes(graph_context.parameters['arch']['nodes'])
            name = choice(list(nodes.keys()))
            result = set_context_parameters(result, 'c-config', {'component-name': name, 'component-type': 'service'})

    return await elicitation_component_handler(result)


import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
import torchvision
import torchvision.transforms as transforms

class Model:
    def __init__(self, net, cost, optimist):
        self.net = net
        self.cost = self.create_cost(cost)
        self.optimizer = self.create_optimizer(optimist)
        pass

    @staticmethod
    def create_cost(cost):
        support_cost = {
            'CROSS_ENTROPY': nn.CrossEntropyLoss(),
            'MSE': nn.MSELoss()
        }

        return support_cost[cost]

    def create_optimizer(self, optimist, **rests):
        #
        """
        self.net.parameters()：这是一个传递给优化器的参数列表，parameters() 方法用于获取模型中所有可学习的参数。
        lr=0.001：学习率（learning rate）是控制参数更新步幅的超参数，表示每次参数更新的幅度大小。这里设置学习率为 0.001。
        **rests：这是额外的参数，用于传递其他可选的优化器参数，例如权重衰减（weight decay）、动量（momentum）等。**rests 表示将额外的参数以关键字参数的形式传递给 RMSprop 优化器。
        """
        support_optim = {
            'SGD': optim.SGD(self.net.parameters(), lr=0.1, **rests),
            'ADAM': optim.Adam(self.net.parameters(), lr=0.01, **rests),
            'RMSP': optim.RMSprop(self.net.parameters(), lr=0.001, **rests)
        }

        return support_optim[optimist]

    def train(self, loader, epoches=3):
        for epoch in range(epoches):
            running_loss = 0.0
            for i, data in enumerate(loader, 0):
                inputs, labels = data

                self.optimizer.zero_grad()

                # forward + backward + optimize
                outputs = self.net(inputs)
                loss = self.cost(outputs, labels)
                loss.backward()
                self.optimizer.step()

                running_loss += loss.item()
                if i % 100 == 0:
                    print('[epoch %d, %.2f%%] loss: %.3f' % (epoch + 1, (i + 1) * 1. / len(loader), running_loss / 100))
                    running_loss = 0.0

        print('Finished Training')

    def evaluate(self, loader):
        print('Evaluating ...')
        correct = 0
        total = 0
        with torch.no_grad():  # no grad when test and predict
            for data in loader:
                images, labels = data

                outputs = self.net(images)
                predicted = torch.argmax(outputs, 1)
                total += labels.size(0)
                correct += (predicted == labels).sum().item()

        print('Accuracy of the network on the test images: %d %%' % (100 * correct / total))

class MnistNet(torch.nn.Module):
    def __init__(self):
        super(MnistNet, self).__init__()
        self.fc1 = torch.nn.Linear(28 * 28, 512)
        self.fc2 = torch.nn.Linear(512, 512)
        self.fc3 = torch.nn.Linear(512, 10)

    def forward(self, x):
        x = x.view(-1, 28 * 28)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = F.softmax(self.fc3(x), dim=1)
        return x

def gen_data():
    # 把图片转换成张量，并把像素标准化到[0-1]范围内
    transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize([0, ], [1, ])])

    train_set = torchvision.datasets.MNIST(root='./data', train=True, download=True, transform=transform)
    train_l = torch.utils.data.DataLoader(train_set, batch_size=32, shuffle=True, num_workers=2)

    test_set = torchvision.datasets.MNIST(root='./data', train=False, download=True, transform=transform)
    test_l = torch.utils.data.DataLoader(test_set, batch_size=32, shuffle=True, num_workers=2)
    return train_l, test_l

if __name__ == '__main__':
    # train for mnist
    net = MnistNet()
    model = Model(net, 'CROSS_ENTROPY', 'RMSP')
    train_loader, test_loader = gen_data()
    model.train(train_loader)
    model.evaluate(test_loader)


"""Abstract class defining tables of different datatypes in a Dataset

Description:

asdf.

"""

# Where imports
from midgard.dev import console

from where.lib import cache
from where.lib import enums

class Table(object):
    datatype = None

    def __init__(self, name, num_obs, dataset):
        self._name = name
        self._num_obs = num_obs
        self._dataset = dataset
        self._data = None
        self._fields = list()
        self._units = dict()
        self._write_levels = dict()

    @classmethod
    def get_default_tablename(cls, fieldname):
        """Default name of table

        This is the table name that will be used when adding a field with this datatype unless another one is specified
        (see Dataset._add). This default implementation sets the default table name to be <fieldname> which means that
        each field will be stored in its own table. Different Tables are free to override this method, for instance to
        by default store all fields in one table with a name like <cls.datatype>_data.

        Args:
            fieldname:   String, the name of the field.

        Returns:
            String with default name of table.
        """
        return fieldname

    def add(self, fieldname, write_level=None, **_kwargs):
        """Add a field to a data table

        This method will be called once for each field added to this table from a dataset (using the
        add_datatype-method). See Dataset._add for details.

        The implementation of this method is responsible for adding the field to self._data and self._fields. It is
        also possible to add extra fields that typically will be calculated from the given field. These extra fields
        should be added to the self._fields-list as <fieldname>.<extra_field> (see PositionTable for an example of
        this).

        Note that the docstring of this function is copied to the corresponding add_datatype-method so args should
        include fieldnames (plural) and table as below, as well as any other arguments explicitly defined by the
        add-method. The docstring does not need to define a return value as that is eaten up by the
        add_datatype-method.

        Args:
            fieldnames:  String or list of strings with names of fields to be added.
            table:       String, name of table where fields are added (optional).
        """
        write_level = max(enums.get_enum("write_level")).name if write_level is None else write_level
        self._write_levels[fieldname] = enums.get_value("write_level", write_level)

    def read(self, json_data, hdf5_data):
        """Read a data table from file

        This method is called from Dataset.read.

        This method is responsible for recovering its data from the json_data and hdf5_data structures, that were
        written by write(). Just like add(), read needs to register all fields in its self._fields dictionary so that
        the fields can be calles as attributes on the Table-object.

        Args:
            json_data:  Dict, data read from JSON-file.
            hdf5_data:  HDF5 dataset, data read from HDF5-file.
        """
        self._units.update(json_data.get("_units", dict()).get(self.name, dict()))
        write_levels = json_data.get("_write_levels", dict()).get(self.name, dict())
        self._write_levels.update({f: enums.get_value("write_level", wl) for f, wl in write_levels.items()})

    def write(self, json_data, hdf5_data):
        """Write a data table to file

        This method is called from Dataset.write.

        This method is responsible for adding its data to the json_data and hdf5_data structures in such a way that the
        data can be recovered later by read(). Note that it is enough to store the data in the data structures.
        Actually storing the data to file is done by Dataset.write.

        Args:
            json_data:  Dict, data to be stored in JSON-file.
            hdf5_data:  HDF5 dataset, data to be stored in HDF5-file.
        """
        import sys

        class_name = type(self).__name__
        method_name = sys._getframe().f_code.co_name
        raise NotImplementedError(
            "'{}' class has not implemented method '{}'" "".format(class_name, method_name)
        ) from None

    def copy_from(self, other_table):
        """Copy data from another table

        This method is called from Dataset.copy_from.

        This method is reponsible for copying data from other_table to itself. It should take care to do an actual copy
        of the data, and not just copy references (i.e. it must do a proper deep copy).

        Args:
            other_table:  Table-object. Table to copy data from.
        """
        self._data = other_table._data.copy()
        self._fields = other_table._fields.copy()
        self._units = other_table._units.copy()
        self._write_levels = other_table._write_levels.copy()

    def subset(self, idx):
        """Remove observations from table based on idx

        This method is called from Dataset.subset.

        This method should modify the contents of self._data such that only the observations for which idx == True are
        kept. It must also update the num_obs-property (by updating self._num_obs) so that it returns the correct
        number of observations.

        Args:
            idx:   Array of booleans with shape (num_obs, ). True means observation is kept, False means removed.
        """
        import sys

        class_name = type(self).__name__
        method_name = sys._getframe().f_code.co_name
        raise NotImplementedError(
            "'{}' class has not implemented method '{}'" "".format(class_name, method_name)
        ) from None

    def extend(self, other_table):
        """Add observations from another table at the end of this table

        This method is called from Dataset.extend.

        This method should modify the contents of self._data such that it adds the contents of the `other_table` at the
        end of the table. It must also update the num_obs-property (by updating self._num_obs) so that it returns the
        correct number of observations.

        Args:
            other_table (Table):   The other table.
        """
        import sys

        class_name = type(self).__name__
        method_name = sys._getframe().f_code.co_name
        raise NotImplementedError(
            "'{}' class has not implemented method '{}'" "".format(class_name, method_name)
        ) from None

    def filter_field(self, field, filter_value):
        """Filter observations in one field

        This method is called from Dataset.filter.

        This method should return a boolean numpy-array of shape (num_obs, ). The values of the array should be True
        for each observation with value equal to filter_value, False otherwise.

        Args:
            field:        String, name of field.
            filter_value: Scalar, value to compare to.

        Returns:
            Numpy array of booleans with shape (num_obs, ).
        """
        import sys

        class_name = type(self).__name__
        method_name = sys._getframe().f_code.co_name
        raise NotImplementedError(
            "'{}' class has not implemented method '{}'" "".format(class_name, method_name)
        ) from None

    def plot_values(self, field):
        """Return values of a field in a form that can be plotted

        Args:
            field:   String, the field name.

        Returns:
            Numpy-array that can be plotted by for instance matplotlib.
        """
        return getattr(self, field.split(".")[-1])

    def as_dict(self, use_plot_values=False, fields=None):
        """Return a representation of the table as a dict

        The dictionary should also be able to be used to initialize a Pandas Dataframe.

        Args:
            use_plot_values (Boolean):  Use the plot_values instead of regular values for each field.
            fields (List):              Field names that should be included, default is to include all fields.

        Returns:
            Dict: A representation of the dataset as a dictionary.
        """
        table_dict = dict()
        fields = self.fields if fields is None else fields
        for field_name in fields:
            field = field_name.split(".")[-1]
            try:
                values = self.plot_values(field) if use_plot_values else getattr(self, field)
                if values.ndim == 1:
                    table_dict[field_name.replace(".", "_")] = values
                else:
                    for i, val in enumerate(values.T):
                        table_dict["{}_{}".format(field_name.replace(".", "_"), i)] = val
            except (AttributeError, TypeError):
                continue

        return table_dict

    @property
    def data(self):
        """Actual data stored in table

        Returns:
            Table data. The datatype will depend on the table.
        """
        return self._data

    @property
    def fields(self):
        """List names of fields in table

        Returns:
            List: Strings with names of fields.
        """
        return sorted(self._fields)

    def get_fields(self, write_level=None):
        """List names of fields in table with write level at or above `write_level`

        Args:
            write_level (String):  Lowest write level allowed for fields.

        Returns:
            List:  Strings with names of fields.
        """
        if write_level is None:
            level = min(enums.get_enum("write_level"))
        else:
            level = enums.get_value("write_level", write_level)

        return sorted(f for f, wl in self._write_levels.items() if wl >= level)

    @property
    def _write_level_strings(self):
        """List write levels of fields in table

        Returns:
            List:  Strings with write levels of fields.
        """
        return {f: wl.name for f, wl in self._write_levels.items()}

    @property
    def name(self):
        """Name of table

        Returns:
            String: name of table.
        """
        return self._name

    @property
    def num_obs(self):
        """Number of observations (= rows) in table

        Returns:
            Int: number of observations in table.
        """
        return self._num_obs

    def unit(self, field):
        """Unit of values in a field in table

        Args:
            field (String):  The field name.

        Returns:
            String:  The unit used for data in the field.
        """
        return self._units.get(field, None)

    @property
    def _properties(self):
        """List names of properties in table

        Dynamically looks up all properties that does not start with an underscore. Properties are defined on the
        class, not the instance, so we need to look up __class__ on self. Use issubclass to catch special properties
        like for instance those defined in lib.cache.

        One use of this property is to determine available fields at runtime as is done in PositionTable.add.

        Returns:
            List of strings with names of properties.
        """
        s_type = type(self)
        return sorted(
            k
            for k in dir(s_type)
            if issubclass(type(getattr(s_type, k)), (property, cache.property)) and not k.startswith("_")
        )

    def __getitem__(self, key):
        """Get a field from the table using dict-notation

        This method is called when a field is accessed using square brackets, e.g. table['station']. The implementation
        of __getattr__ also calls this method when accessing fields using the dot-notation.

        Args:
            key:   String, the name of the field.

        Returns:
            Field data. The datatype will depend on the table.
        """
        import sys

        class_name = type(self).__name__
        method_name = sys._getframe().f_code.co_name
        raise NotImplementedError(
            "'{}' class has not implemented method '{}'" "".format(class_name, method_name)
        ) from None

    def __getattr__(self, key):
        """Get a field from the table using attribute-notation

        This method is called when a field is accessed using a dot, e.g. table.station. This is done by forwarding the
        call to __getitem__.

        Args:
            key:   String, the name of the field.

        Returns:
            Field data. The datatype will depend on the table.
        """
        try:
            return self.__getitem__(key)
        except KeyError:
            raise AttributeError("'{}' object has no attribute '{}'".format(type(self).__name__, key)) from None

    def __delitem__(self, key):
        """Delete a field in the table

        This method is called by the del keyword when the field is specified using the square bracket notation, e.g.
        `del data['station']`. If the key is one of the fields we delete it from the field list.

        Args:
            key:   String, the name of the field.
        """
        if key in self._fields:
            del self._fields[key]
        else:
            raise KeyError("{} '{}' has no field '{}'".format(type(self).__name__, self.dataset_name, key))

    def __delattr__(self, key):
        """Delete a field in the table

        This method is called by the del keyword when a field is specified using the attribute notation, e.g.
        `del data.station`. If the key is one of the fields we delete it from the field list.

        Args:
            key:   String, the name of the field.
        """
        try:
            self.__delitem__(key)
        except KeyError:
            raise AttributeError("'{}' object has no attribute '{}'".format(type(self).__name__, key)) from None

    def __len__(self):
        """The length of the table is the number of observations

        Returns:
            Int: The number of observations in the table.
        """
        return self.num_obs

    def __dir__(self):
        """List all fields and attributes on the table

        Overridden so that fields are included in the list. This is especially useful when exploring the table
        interactively in an environment that supports tab-completion, e.g. ipython.

        Returns:
            List of strings, representing attributes and fields on the dataset.
        """
        return super().__dir__() + [f for f in self.fields if "." not in f]

    def __repr__(self):
        """A string representing the table

        The string should equal a python call that creates the table. Note that this call will only initialize the
        table, not create all fields.

        Returns:
            A string representing the table.
        """
        cls_name_full = ".".join([self.__class__.__module__.split(".")[-1], self.__class__.__name__])
        return "{cls}('{name}', {num_obs})".format(cls=cls_name_full, name=self.name, num_obs=self.num_obs)

    def __str__(self):
        """A string describing the table

        The string describes the table, including listing the table name, datatype and all the fields. This string is
        mainly meant to be read by humans.

        Returns:
            A string describing the table.
        """
        name_and_type = "  {} ({}): ".format(self.name, self.datatype)
        return console.fill(name_and_type + ", ".join(self.fields), hanging=len(name_and_type))


#!/usr/bin/env python3
# pylint: disable=too-many-locals, too-many-branches, too-many-statements, line-too-long, unnecessary-lambda-assignment
# noqa: E501
"""
Peering Buddy - Helping you dig data from internet for better decisions!
"""

import sys
import argparse
import json

from pbuddy.pbuddy import PBuddy

def main():
    """Peering Buddy main"""
    formatter = lambda prog: argparse.HelpFormatter(prog, max_help_position=88)
    parser = argparse.ArgumentParser(
        description="Peering Buddy - Helping you dig data from internet for better decisions!",
        formatter_class=formatter,
    )
    parser.add_argument(
        "-av",
        "--asn-visibility",
        action="store",
        dest="asn_visibility",
        metavar="ASN",
        help="[RIPE] Check ASN visibility RIPE RIS sensors.",
    )
    parser.add_argument(
        "-ap",
        "--asn-announced-pfxs",
        action="store",
        dest="asn_announcedpfxs",
        metavar="ASN",
        help="[RIPE] Check ASN announced prefixes to internet.",
    )
    parser.add_argument(
        "-ar",
        "--asn-roa-validation",
        action="store",
        dest="asn_roavalidation",
        metavar="ASN",
        help="[RIPE] Check ASN RPKI/ROA validation for announced prefixes.",
    )
    parser.add_argument(
        "-lg",
        "--looking-glass",
        action="store",
        dest="pfx_rislg",
        metavar="PREFIX",
        help="[RIPE] Get prefix using RIPE RIS as Looking Glass.",
    )
    parser.add_argument(
        "-al",
        "--aspath-length-overview",
        action="store",
        dest="asn_aspathoverview",
        metavar="ASN",
        help="[RIPE] Check AS-Path length overview.",
    )
    parser.add_argument(
        "-as",
        "--aspath-lenghth-stripped",
        action="store",
        dest="asn_aspathstripped",
        metavar="ASN",
        help="[RIPE] Check AS-Path length stripped [no as-prepend].",
    )
    parser.add_argument(
        "-au",
        "--aspath-lenghth-unstripped",
        action="store",
        dest="asn_aspathunstripped",
        metavar="ASN",
        help="[RIPE] Check AS-Path length unstripped [with as-prepend].",
    )
    parser.add_argument(
        "-tm",
        "--threshold-max",
        action="store",
        dest="asn_aspaththresholdmax",
        metavar="INTEGER",
        help="[RIPE][as|au] Threshold [>=] to be used with -as and -au for max.",
    )
    parser.add_argument(
        "-ti",
        "--threshold-min",
        action="store",
        dest="asn_aspaththresholdmin",
        metavar="INTEGER",
        help="[RIPE][as|au] Threshold [>=] to be used with -as and -au for min.",
    )
    parser.add_argument(
        "-ta",
        "--threshold-avg",
        action="store",
        dest="asn_aspaththresholdavg",
        metavar="INTEGER",
        help="[RIPE][as|au] Threshold [>=] to be used with -as and -au for avg.",
    )
    parser.add_argument(
        "-ao",
        "--asn-overview",
        action="store",
        dest="asn_overview",
        metavar="ASN",
        help="[RIPE] Check ASN public resources overview.",
    )
    parser.add_argument(
        "-ac",
        "--asn-announce-consistency",
        action="store",
        dest="asn_announcesconsistency",
        metavar="ASN",
        help="[RIPE][BGPView][IPInfo] Check ASN announces consistency.",
    )
    parser.add_argument(
        "-pa",
        "--asn-pfxs-aspath-length",
        action="store",
        dest="asn_asnpfxaspathlength",
        metavar=("ASN", "THRESHOLD", "PREPEND[y|n]"),
        help="[RIPE][BGPView] Check ASN prefixes where as-path length >= threshold.",
        nargs=3,
    )
    parser.add_argument(
        "-tu",
        "--asn-upstreams-transient",
        action="store",
        dest="asn_upstreamtransient",
        metavar="ASN",
        help="[RIPE][BGPView] Check ASN upstreams on transient paths.",
    )
    parser.add_argument(
        "-gu",
        "--asn-upstreams",
        action="store",
        dest="upstreams",
        metavar="ASN",
        help="[BGPView] Get ASN upstreams.",
    )
    parser.add_argument(
        "-gd",
        "--asn-downstreams",
        action="store",
        dest="downstreams",
        metavar="ASN",
        help="[BGPView] Get ASN downstreams.",
    )
    parser.add_argument(
        "-gw",
        "--whois",
        action="store",
        dest="whois",
        metavar="[ASN|PREFIX]",
        help="[BGPView] Get ASN/Prefix whois information.",
    )
    parser.add_argument(
        "-wi",
        "--whois-ip",
        action="store",
        dest="ipwhois",
        metavar="IP",
        help="[IPInfo] Get IP whois information.",
    )
    parser.add_argument(
        "-ip",
        "--pdb-ixp-pfxs",
        action="store_true",
        dest="pdb_ip",
        help="[PeeringDB] Get IXPs prefixes.",
    )
    parser.add_argument(
        "-ai",
        "--pdb-asn-info",
        action="store",
        dest="asninfo",
        metavar="ASN",
        help="[PeeringDB] Get ASN information on PeeringDB.",
    )
    parser.add_argument(
        "-ii",
        "--pdb-asn-ips",
        action="store",
        dest="ixpips",
        metavar="ASN",
        help="[PeeringDB] Get ASN IPS allocated on IXPs.",
    )
    parser.add_argument(
        "-gc",
        "--pdb-asn-contact",
        action="store",
        dest="asncontact",
        metavar="ASN",
        help="[PeeringDB] Get ASN contact.",
    )
    parser.add_argument(
        "-cc",
        "--pdb-ixp-bycc",
        action="store",
        dest="ixpcc",
        metavar="ASN",
        help="[PeeringDB] Get IXPs by Country Code [iso-3166-1 alpha-2].",
    )
    parser.add_argument(
        "-gl",
        "--lgs",
        action="store_true",
        dest="lgs",
        help="[Team Cymrus] Check a list of public LookingGlass.",
    )
    parser.add_argument(
        "-bo",
        "--bogons",
        action="store_true",
        dest="bogonspfx4",
        help="[Team Cymrus] Get ip4 bogons list.",
    )
    parser.add_argument(
        "-b4",
        "--bogons-v4",
        action="store_true",
        dest="fbogonspfx4",
        help="[Team Cymrus] Get ip4 full (+unallocated) bogons list.",
    )
    parser.add_argument(
        "-b6",
        "--bogons-v6",
        action="store_true",
        dest="fbogonspfx6",
        help="[Team Cymrus] Get ip6 full (+unallocated) bogons list.",
    )
    parser.add_argument(
        "-ba",
        "--bogons-asn",
        action="store_true",
        dest="bogonsasn",
        help="[NTT] Get ASN bogons list/examples.",
    )
    parser.add_argument(
        "-aa",
        "--asset",
        action="store",
        dest="asset",
        metavar="ASN",
        help="[NLNOG] Check ASN AS-SET and expand it.",
    )
    parser.add_argument(
        "-rh",
        "--resource-health-check",
        action="store",
        dest="resourcehealthcheck",
        metavar="ASN|PREFIX",
        help="[NLNOG] ASN or Prefix health check.",
    )
    parser.add_argument(
        "-nv",
        "--non-verbose",
        action="store_true",
        dest="nonverbose",
        help="Remove human-like text to the output.",
    )

    args = parser.parse_args()
    options = all(value is True for value in vars(args).values())
    pbuddy = PBuddy()

    re_asn = "^[0-9]{0,9}$"
    re_cc = "^[a-zA-Z]{0,2}$"
    re_int = "^[0-9]{0,2}$"
    re_yn = "^[yYnN]$"
    asn_invalid = "Invalid ASN, please type the ASN without the suffix AS."
    pfx_invalid = "Invalid prefix (v4/v6), please type prefix/mask."
    separator = "=" * 80

    if args.asn_visibility is not None:
        reasn = pbuddy.regex_validation(re_asn, args.asn_visibility)
        if reasn is False:
            print(asn_invalid)
            sys.exit(1)
        result = pbuddy.ripe_asn_visibility(args.asn_visibility)
        if args.nonverbose is False:
            print(separator)
            print(
                "=> Visibilit percentage (RIS point of view)",
                args.asn_visibility,
                ":",
            )
            print(separator)
        for afi, perc in result.items():
            print(f"Visibility for {afi}: {perc}%")
        if args.nonverbose is False:
            print(separator)
    if args.asn_announcedpfxs is not None:
        regexp_asn = pbuddy.regex_validation(re_asn, args.asn_announcedpfxs)
        if regexp_asn is False:
            print(asn_invalid)
            sys.exit(1)
        pfxs = pbuddy.ripe_asn_announced_pfx(args.asn_announcedpfxs)
        if args.nonverbose is False:
            print(separator)
            print(
                "=> We are seeing the prefixes being announced to the internet for the ASN",
                args.asn_announcedpfxs,
                ":",
            )
            print(separator)
        print(json.dumps(pfxs, indent=4))
        if args.nonverbose is False:
            print(separator)
    if args.asn_roavalidation is not None:
        regexp_asn = pbuddy.regex_validation(re_asn, args.asn_roavalidation)
        if regexp_asn is False:
            print(asn_invalid)
            sys.exit(1)
        if args.nonverbose is False:
            print(separator)
            print(
                "=> We are validating the prefixes announced by the ASN",
                args.asn_roavalidation,
                ":",
            )
            print(separator)
        prefixes = pbuddy.ripe_asn_announced_pfx(args.asn_roavalidation)
        for prefix in prefixes:
            result = pbuddy.ripe_vrp_check(args.asn_roavalidation, prefix)
            print("Prefix", prefix, "is", result)
        if args.nonverbose is False:
            print(separator)
    if args.pfx_rislg is not None:
        repfx = pbuddy.pfx_validation(args.pfx_rislg)
        if repfx is False:
            print(pfx_invalid)
            sys.exit(1)
        field = None
        result = pbuddy.ripe_ris_lg(args.pfx_rislg, field)
        if args.nonverbose is False:
            print(separator)
            print("=> Looking glass results for the prefix", args.pfx_rislg, ":")
            print(separator)
        print(json.dumps(result, indent=4))
        if args.nonverbose is False:
            print(separator)
    if args.asn_aspathoverview is not None:
        reasn = pbuddy.regex_validation(re_asn, args.asn_aspathoverview)
        if reasn is False:
            print(asn_invalid)
            sys.exit(1)
        result = pbuddy.ripe_aspth_length_overview(args.asn_aspathoverview)
        aspath_s_max = result[0]
        aspath_s_min = result[1]
        aspath_s_avg = result[2]
        aspath_u_max = result[3]
        aspath_u_min = result[4]
        aspath_u_avg = result[5]
        print(separator)
        print("=> AS-Path length overview for the ASN", args.asn_aspathoverview, ":")
        print(separator)
        print("Maximum AS-PATH Stripped [ignore as-prepend] => ", aspath_s_max)
        print("Minimum AS-PATH Stripped [ignore as-prepend] => ", aspath_s_min)
        print("Average AS-PATH Stripped [ignore as-prepend] => ", aspath_s_avg)
        print("Maximum AS-PATH Unstripped [considering as-prepend] => ", aspath_u_max)
        print("Minimum AS-PATH Unstripped [considering as-prepend] => ", aspath_u_min)
        print("Average AS-PATH Unstripped [considering as-prepend] => ", aspath_u_avg)
        print(separator)
    if args.asn_aspathstripped is not None:
        reasn = pbuddy.regex_validation(re_asn, args.asn_aspathstripped)
        if reasn is False:
            print(asn_invalid)
            sys.exit(1)
        if (
            args.asn_aspaththresholdmax is not None
            or args.asn_aspaththresholdmin is not None
            or args.asn_aspaththresholdavg is not None
        ):
            func = ["max", "min", "avg"]
            values = [
                args.asn_aspaththresholdmax,
                args.asn_aspaththresholdmin,
                args.asn_aspaththresholdavg,
            ]
            for value in values:
                if value:
                    regex_int = pbuddy.regex_validation(re_int, str(value))
                    if regex_int is False:
                        print(
                            "That's not a valid integer, please type an integer from 1 to 2 digits."
                        )
                        sys.exit(1)
            threshold = dict(zip(func, values))
            result = pbuddy.ripe_aspath_length(
                args.asn_aspathstripped, "stripped", func, threshold
            )
        else:
            result = pbuddy.ripe_aspath_length(
                args.asn_aspathstripped, "stripped", None, None
            )
        if args.nonverbose is False:
            print(separator)
            print(
                "=> AS-Path length (min, max and avg - stripping as-prepends) for the ASN",
                args.asn_aspathstripped,
                ":",
            )
            print(separator)
        print(json.dumps(result, indent=4))
        if args.nonverbose is False:
            print(separator)
    if args.asn_aspathunstripped is not None:
        reasn = pbuddy.regex_validation(re_asn, args.asn_aspathunstripped)
        if reasn is False:
            print(asn_invalid)
            sys.exit(1)
        if (
            args.asn_aspaththresholdmax is not None
            or args.asn_aspaththresholdmin is not None
            or args.asn_aspaththresholdavg is not None
        ):
            func = ["max", "min", "avg"]
            values = [
                args.asn_aspaththresholdmax,
                args.asn_aspaththresholdmin,
                args.asn_aspaththresholdavg,
            ]
            for value in values:
                if value:
                    regex_int = pbuddy.regex_validation(re_int, str(value))
                    if regex_int is False:
                        print(
                            "That's not a valid integer, please type an integer from 1 to 2 digits."
                        )
                        sys.exit(1)
            threshold = dict(zip(func, values))
            result = pbuddy.ripe_aspath_length(
                args.asn_aspathunstripped, "unstripped", func, threshold
            )
        else:
            result = pbuddy.ripe_aspath_length(
                args.asn_aspathunstripped, "unstripped", None, None
            )
        if args.nonverbose is False:
            print(separator)
            print(
                "=> AS-Path length (min, max and avg - unstripping as-prepends) for the ASN",
                args.asn_aspathunstripped,
                ":",
            )
            print(separator)
        print(json.dumps(result, indent=4))
        if args.nonverbose is False:
            print(separator)
    if args.asn_overview is not None:
        reasn = pbuddy.regex_validation(re_asn, args.asn_overview)
        if reasn is False:
            print(asn_invalid)
            sys.exit(1)
        result = pbuddy.ripe_asn_resources_overview(args.asn_overview)
        if args.nonverbose is False:
            print(separator)
            print(
                "=> Public Internet resources overview for the ASN",
                args.asn_overview,
                ":",
            )
            print(separator)
        print(json.dumps(result, indent=4))
        if args.nonverbose is False:
            print(separator)
    if args.asn_announcesconsistency is not None:
        reasn = pbuddy.regex_validation(re_asn, args.asn_announcesconsistency)
        if reasn is False:
            print(asn_invalid)
            sys.exit(1)
        if args.nonverbose is False:
            print(separator)
            print(
                "=> ASN announces consistency for the ASN",
                args.asn_announcesconsistency,
                ":",
            )
            print(separator)
        result = pbuddy.ripe_asn_announces_consistency(args.asn_announcesconsistency)
        for item in result:
            print("".join(map(str, item)))
        if args.nonverbose is False:
            print(separator)
    if args.lgs is True:
        result = pbuddy.tc_public_lg()
        if args.nonverbose is False:
            print(separator)
            print("=> List of public looking glass.")
            print(separator)
        for key, value in result.items():
            print(key, "=>", value[0])
        if args.nonverbose is False:
            print(separator)
    if args.asset is not None:
        reasn = pbuddy.regex_validation(re_asn, args.asset)
        if reasn is False:
            print(asn_invalid)
            sys.exit(1)
        result = pbuddy.pdb_asn_asset(args.asset)
        asset = result[0]
        expanded = pbuddy.nlnog_expand_asset(asset[args.asset])
        if args.nonverbose is False:
            print(separator)
        print(json.dumps(expanded, indent=4))
        if args.nonverbose is False:
            print(separator)

    if args.resourcehealthcheck is not None:
        reasn = pbuddy.regex_validation(re_asn, args.resourcehealthcheck)
        repfx = pbuddy.pfx_validation(args.resourcehealthcheck)
        if reasn is False and repfx is False:
            print(
                "That's not a valid ASN or prefix, please type the ASN without the suffix AS."
            )
            sys.exit(1)
        if reasn is True:
            resource_type = "asn"
        elif repfx is True:
            resource_type = "prefix"
        rhc = pbuddy.nlnog_resource_health_check(
            args.resourcehealthcheck, resource_type
        )
        if args.nonverbose is False:
            print(separator)
        print(json.dumps(rhc, indent=4))
        if args.nonverbose is False:
            print(separator)

    if args.pdb_ip is True:
        if args.nonverbose is False:
            print(separator)
            print("=> IXPs prefixes:")
            print(separator)
        result = pbuddy.pdb_ixps_pfxs()
        for item in result:
            print("".join(map(str, item)))
        if args.nonverbose is False:
            print(separator)
    if args.asninfo is not None:
        reasn = pbuddy.regex_validation(re_asn, args.asninfo)
        if reasn is False:
            print(asn_invalid)
            sys.exit(1)
        if args.nonverbose is False:
            print(separator)
            print("=> ASN ", args.asninfo, " info/summary:")
            print(separator)
        result = pbuddy.pdb_asn_info(args.asninfo)
        print(json.dumps(result, indent=4))
        if args.nonverbose is False:
            print(separator)
    if args.ixpips is not None:
        reasn = pbuddy.regex_validation(re_asn, args.ixpips)
        if reasn is False:
            print(asn_invalid)
            sys.exit(1)
        if args.nonverbose is False:
            print(separator)
            print("=> Allocated IXPs IPs for the ASN ", args.ixpips, ":")
            print(separator)
        result = pbuddy.pdb_asn_ixps_ips(args.ixpips)
        for item in result:
            print("".join(map(str, item)))
        if args.nonverbose is False:
            print(separator)
    if args.asncontact is not None:
        reasn = pbuddy.regex_validation(re_asn, args.asncontact)
        if reasn is False:
            print(asn_invalid)
            sys.exit(1)
        if args.nonverbose is False:
            print(separator)
            print("=> ASN ", args.asncontact, " contacts:")
            print(separator)
        result = pbuddy.pdb_asn_contacts(args.asncontact)
        print(json.dumps(result, indent=4))
        if args.nonverbose is False:
            print(separator)
    if args.ixpcc is not None:
        reasn = pbuddy.regex_validation(re_cc, args.ixpcc)
        if reasn is False:
            print(
                "That's not a valid Country Code, please type the CC with two letters (IBAN Alpha-2)."
            )
            sys.exit(1)
        if args.nonverbose is False:
            print(separator)
            print("=> IXPs available on ", args.ixpcc, ":")
            print(separator)
        result = pbuddy.pdb_ixps_by_cc(args.ixpcc)
        print(json.dumps(result, indent=4))
        if args.nonverbose is False:
            print(separator)
    if args.bogonspfx4 is True:
        if args.nonverbose is False:
            print(separator)
            print("=> IPv4 bogons list:")
            print(separator)
        result = pbuddy.tc_bogons_pfxs(
            "https://www.team-cymru.org/Services/Bogons/bogon-bn-nonagg.txt"
        )
        for item in result:
            print("".join(map(str, item)))
        if args.nonverbose is False:
            print(separator)
    if args.fbogonspfx4 is True:
        if args.nonverbose is False:
            print(separator)
            print("=> IPv4 full (+unallocated) bogons list:")
            print(separator)
        result = pbuddy.tc_bogons_pfxs(
            "https://www.team-cymru.org/Services/Bogons/fullbogons-ipv4.txt"
        )
        for item in result:
            print("".join(map(str, item)))
        if args.nonverbose is False:
            print(separator)
    if args.fbogonspfx6 is True:
        if args.nonverbose is False:
            print(separator)
            print("=> IPv6 full (+unallocated) bogons list:")
            print(separator)
        result = pbuddy.tc_bogons_pfxs(
            "https://www.team-cymru.org/Services/Bogons/fullbogons-ipv6.txt"
        )
        for item in result:
            print("".join(map(str, item)))
        if args.nonverbose is False:
            print(separator)
    if args.upstreams is not None:
        reasn = pbuddy.regex_validation(re_asn, args.upstreams)
        if reasn is False:
            print(asn_invalid)
            sys.exit(1)
        if args.nonverbose is False:
            print(separator)
            print("=> ASN ", args.upstreams, " upstreams are:")
            print(separator)
        result = pbuddy.bv_asn_upstreams(args.upstreams)
        print(json.dumps(result, indent=4))
        if args.nonverbose is False:
            print(separator)
    if args.downstreams is not None:
        reasn = pbuddy.regex_validation(re_asn, args.downstreams)
        if reasn is False:
            print(asn_invalid)
            sys.exit(1)
        if args.nonverbose is False:
            print(separator)
            print("=> ASN ", args.downstreams, " downstreams are:")
            print(separator)
        result = pbuddy.bv_asn_downstreams(args.downstreams)
        print(json.dumps(result, indent=4))
        if args.nonverbose is False:
            print(separator)
    if args.whois is not None:
        reasn = pbuddy.regex_validation(re_asn, args.whois)
        repfx = pbuddy.pfx_validation(args.whois)
        if reasn is False and repfx is False:
            print(
                "That's not a valid ASN or prefix, please type the ASN without the suffix AS."
            )
            sys.exit(1)
        if reasn is True:
            if args.nonverbose is False:
                print(separator)
                print("=> ASN ", args.whois, " information:")
                print(separator)
            result = pbuddy.bv_asn_whois(args.whois)
            print(json.dumps(result, indent=4))
            if args.nonverbose is False:
                print(separator)
        elif repfx is True:
            if args.nonverbose is False:
                print(separator)
                print("=> Prefix ", args.whois, " information:")
                print(separator)
            result = pbuddy.bv_pfx_whois(args.whois)
            print(json.dumps(result, indent=4))
            if args.nonverbose is False:
                print(separator)
    if args.ipwhois is not None:
        reip = pbuddy.ip_validation(args.ipwhois)
        if reip is False:
            print("That's not a valid IP, please type the IP without the network mask.")
            sys.exit(1)
        if args.nonverbose is False:
            print(separator)
            print("=> Prefix ", args.ipwhois, " information:")
            print(separator)
        result = pbuddy.ii_ip_whois(args.ipwhois)
        print(json.dumps(result, indent=4))
        if args.nonverbose is False:
            print(separator)
    if args.bogonsasn is True:
        if args.nonverbose is False:
            print(separator)
            print("=> Bogons ASN list:")
            print(separator)
        result = pbuddy.ntt_bogons_asn()
        print(result)
        if args.nonverbose is False:
            print(separator)
    if args.asn_asnpfxaspathlength is not None:
        asn = args.asn_asnpfxaspathlength[0]
        threshold = args.asn_asnpfxaspathlength[1]
        asprepend = args.asn_asnpfxaspathlength[2]
        reasn = pbuddy.regex_validation(re_asn, args.asn_asnpfxaspathlength[0])
        repfx = pbuddy.regex_validation(re_int, args.asn_asnpfxaspathlength[1])
        reprep = pbuddy.regex_validation(re_yn, args.asn_asnpfxaspathlength[2])
        if reasn is False:
            print(asn_invalid)
            sys.exit(1)
        if repfx is False:
            print(
                "That's not a valid integer, please type an integer from 1 to 2 digits."
            )
            sys.exit(1)
        if reprep is False:
            print("That's not a valid option, please type an y [yes] or n [no].")
            sys.exit(1)
        if args.nonverbose is False:
            answer = None
            if asprepend == "y":
                answer = "considering as-prepend"
            elif asprepend == "n":
                answer = "not considering as-prepend"
            print(separator)
            print(
                "=> Getting prefixes for the ASN",
                asn,
                "where the AS-Path is greater than",
                threshold,
                "and",
                answer,
                ":",
            )
            print(separator)
        result = pbuddy.ripe_bv_pfxs_aspath_length(asn, threshold, asprepend)
        tuple_lpa = result[0]
        first_asns = result[1]
        second_asns = result[2]
        third_asns = result[3]
        nontransit = result[4]
        transit = result[5]
        direct = result[6]
        summary = pbuddy.ripe_bv_pfxs_aspath_length_summary(
            tuple_lpa, first_asns, second_asns, third_asns, nontransit, transit, direct
        )
        locations_d = summary[0]
        first_asn_d = summary[1]
        second_asn_d = summary[2]
        third_asn_d = summary[3]
        nontransit_d = summary[4]
        transit_d = summary[5]
        if args.nonverbose is False:
            print(separator)
        if args.nonverbose is False:
            print(separator)
            print("Summary => format [ ASN:COUNTER ]: ")
            print(separator)
        if int(threshold) <= 2:
            print(
                "First ASN (the other end ASN): ",
                [(":".join(map(str, item))) for item in first_asn_d],
            )
            print("")
            print(
                "Non transit peers directly attached to ASN",
                asn,
                ":",
                [(":".join(map(str, item))) for item in nontransit_d],
            )
            print("")
            print(
                "Transit upstreams for the ASN",
                asn,
                ":",
                [(":".join(map(str, item))) for item in transit_d],
            )
            print("")
            print("By locations:")
            for place in locations_d:
                print((":".join(map(str, place))))
        elif int(threshold) == 3:
            print(
                "First ASN (the other end ASN): ",
                [(":".join(map(str, item))) for item in first_asn_d],
            )
            print("")
            print(
                "Second ASN (the other end upstream): ",
                [(":".join(map(str, item))) for item in second_asn_d],
            )
            print("")
            print(
                "Non transit peers directly attached to ASN",
                asn,
                ":",
                [(":".join(map(str, item))) for item in nontransit_d],
            )
            print("")
            print(
                "Transit upstreams for the ASN",
                asn,
                ":",
                [(":".join(map(str, item))) for item in transit_d],
            )
            print("")
            print("By locations:")
            for place in locations_d:
                print((":".join(map(str, place))))
        elif int(threshold) >= 4:
            print(
                "First ASN (the other end ASN): ",
                [(":".join(map(str, item))) for item in first_asn_d],
            )
            print("")
            print(
                "Second ASN (the other end upstream): ",
                [(":".join(map(str, item))) for item in second_asn_d],
            )
            print("")
            print(
                "Third ASN (trying to find a common ASN on the path): ",
                [(":".join(map(str, item))) for item in third_asn_d],
            )
            print("")
            print(
                "Non transit peers directly attached to ASN",
                asn,
                ":",
                [(":".join(map(str, item))) for item in nontransit_d],
            )
            print("")
            print(
                "Transit upstreams for the ASN",
                asn,
                ":",
                [(":".join(map(str, item))) for item in transit_d],
            )
            print("")
            print("By locations:")
            for place in locations_d:
                print((": ".join(map(str, place))))
        if args.nonverbose is False:
            print(separator)
    if args.asn_upstreamtransient is not None:
        reasn = pbuddy.regex_validation(re_asn, args.asn_upstreamtransient)
        if reasn is False:
            print(asn_invalid)
            sys.exit(1)
        if args.nonverbose is False:
            print(separator)
            print(
                "=> Checking for upstreams on transient paths for the ASN",
                args.asn_upstreamtransient,
                ":",
            )
            print(separator)
        result = pbuddy.ripe_bv_upstreams_transient_path(args.asn_upstreamtransient)
        transient_paths = result[0]
        transient_ups = result[1]
        aspaths = result[2]
        full_aspaths = result[3]
        all_locations = result[4]
        locations = []
        transient_upstreams = {}
        for item in transient_paths:
            print("".join(map(str, item)))
            locations.append(item[0])
        locations_u = pbuddy.list_unique(locations)
        locations_dict = {}
        for location in locations_u:
            loc = locations.count(location)
            locations_dict[location] = loc
        asns_u = pbuddy.list_unique(transient_ups)
        for each in asns_u:
            rcount = aspaths.count(each[0])
            transient_upstreams[each[0]] = rcount
        transient_upstreams_d = sorted(
            transient_upstreams.items(), reverse=True, key=lambda x: x[1]
        )
        locations_d = sorted(locations_dict.items(), reverse=True, key=lambda x: x[1])
        if args.nonverbose is False:
            print(separator)
        print(
            "Transient upstreams for the ASN",
            args.asn_upstreamtransient,
            "[ Upstream transient ASN => Number of times this ASN was matched on the AS-Path => Total AS-Paths number seeing this ASN => Percentage ]:",
        )
        for item in transient_upstreams_d:
            upstreams_asn = item[0]
            upstreams_count = item[1]
            total_upstreams_count = full_aspaths.count(upstreams_asn)
            upstreams_percentage = round(
                100 * upstreams_count / total_upstreams_count, 2
            )
            print(
                "AS",
                upstreams_asn,
                "=>",
                upstreams_count,
                "=>",
                total_upstreams_count,
                "=>",
                upstreams_percentage,
                "%",
            )
        print("")
        print(
            "By locations [ Location => Number of transient upstreams ASNs on this location  => Total NLRI number seeing this location => Percentage ]:"
        )
        for place in locations_d:
            location = place[0]
            location_count = place[1]
            total_location_count = all_locations.count(location)
            location_percentage = round(100 * location_count / total_location_count, 2)
            print(
                location,
                "=>",
                location_count,
                "=>",
                total_location_count,
                "=>",
                location_percentage,
                "%",
            )
        if args.nonverbose is False:
            print(separator)

    if options is False:
        if len(sys.argv) == 1:
            parser.print_help(sys.stderr)
            sys.exit(0)

if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        print("Interrupted")


# Python program to calculate number of days between two dates.

# My solution...

from datetime import date

dateFrom = date(2021, 12, 8)
dateTo = date(2021, 12, 17)
daysBetween = dateTo - dateFrom
print("There are " + str(daysBetween.days) + " days between " + str(dateFrom.strftime("%B ")) + str(dateFrom.day) + " and " + str(dateTo.strftime("%B ")) + str(dateTo.day) + ".")

# It works!

# Example solution...

from datetime import date
f_date = date(2014, 7, 2)
l_date = date(2014, 7, 11)
delta = l_date - f_date
print(delta.days)