import math
import sys
import six
import time

import numpy as np
import tensorflow as tf
import tf_extended as tfe
import tf_utils
from tensorflow.python.framework import ops

from datasets import dataset_factory
from nets import nets_factory
from preprocessing import preprocessing_factory
from nets import np_methods

slim = tf.contrib.slim
tf.enable_eager_execution()
# =========================================================================== #
# Some default EVAL parameters
# =========================================================================== #
# List of recalls values at which precision is evaluated.
LIST_RECALLS = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.85,
                0.90, 0.95, 0.96, 0.97, 0.98, 0.99]
DATA_FORMAT = 'NHWC'

# =========================================================================== #
# SSD evaluation Flags.
# =========================================================================== #
tf.app.flags.DEFINE_float(
    'select_threshold', 0.01, 'Selection threshold.')
tf.app.flags.DEFINE_integer(
    'select_top_k', 400, 'Select top-k detected bounding boxes.')
tf.app.flags.DEFINE_integer(
    'keep_top_k', 200, 'Keep top-k detected objects.')
tf.app.flags.DEFINE_float(
    'nms_threshold', 0.45, 'Non-Maximum Selection threshold.')
tf.app.flags.DEFINE_float(
    'matching_threshold', 0.5, 'Matching threshold with groundtruth objects.')
tf.app.flags.DEFINE_integer(
    'eval_resize', 4, 'Image resizing: None / CENTRAL_CROP / PAD_AND_RESIZE / WARP_RESIZE.')
tf.app.flags.DEFINE_integer(
    'eval_image_size', None, 'Eval image size.')
tf.app.flags.DEFINE_boolean(
    'remove_difficult', True, 'Remove difficult objects from evaluation.')

# =========================================================================== #
# Main evaluation flags.
# =========================================================================== #
tf.app.flags.DEFINE_integer(
    'num_classes', 21, 'Number of classes to use in the dataset.')
tf.app.flags.DEFINE_integer(
    'batch_size', 1, 'The number of samples in each batch.')
tf.app.flags.DEFINE_integer(
    'max_num_batches', None,
    'Max number of batches to evaluate by default use all.')
tf.app.flags.DEFINE_string(
    'master', '', 'The address of the TensorFlow master to use.')
tf.app.flags.DEFINE_string(
    'checkpoint_path', 'checkpoints/VGG_VOC0712_SSD_300x300_ft_iter_120000.ckpt',
    'The directory where the model was written to or an absolute path to a '
    'checkpoint file.')
tf.app.flags.DEFINE_string(
    'eval_dir', '/tmp/tfmodel/', 'Directory where the results are saved to.')
tf.app.flags.DEFINE_integer(
    'num_preprocessing_threads', 4,
    'The number of threads used to create the batches.')
tf.app.flags.DEFINE_string(
    'dataset_name', 'pascalvoc_2007', 'The name of the dataset to load.')
tf.app.flags.DEFINE_string(
    'dataset_split_name', 'test', 'The name of the train/test split.')
tf.app.flags.DEFINE_string(
    'dataset_dir', 'assets/PASCAL_VOC/', 'The directory where the dataset files are stored.')
tf.app.flags.DEFINE_string(
    'model_name', 'ssd_300_vgg', 'The name of the architecture to evaluate.')
tf.app.flags.DEFINE_string(
    'preprocessing_name', None, 'The name of the preprocessing to use. If left '
                                'as `None`, then the model_name flag is used.')
tf.app.flags.DEFINE_float(
    'moving_average_decay', None,
    'The decay to use for the moving average.'
    'If left as None, then moving averages are not used.')
tf.app.flags.DEFINE_float(
    'gpu_memory_fraction', 0.1, 'GPU memory fraction to use.')
tf.app.flags.DEFINE_boolean(
    'wait_for_checkpoints', False, 'Wait for new checkpoints in the eval loop.')

FLAGS = tf.app.flags.FLAGS

def main(_):
    if not FLAGS.dataset_dir:
        raise ValueError('You must supply the dataset directory with --dataset_dir')

    tf.logging.set_verbosity(tf.logging.INFO)
    with tf.Graph().as_default():
        tf_global_step = slim.get_or_create_global_step()

        # =================================================================== #
        # Dataset + SSD model + Pre-processing
        # =================================================================== #
        dataset = dataset_factory.get_dataset(
            FLAGS.dataset_name, FLAGS.dataset_split_name, FLAGS.dataset_dir)

        # Get the SSD network and its anchors.
        ssd_class = nets_factory.get_network(FLAGS.model_name)
        ssd_params = ssd_class.default_params._replace(num_classes=FLAGS.num_classes)
        ssd_net = ssd_class(ssd_params)

        # Evaluation shape and associated anchors: eval_image_size
        net_shape = (300, 300)
        ssd_shape = net_shape
        ssd_anchors = ssd_net.anchors(ssd_shape)

        # Select the preprocessing function.
        preprocessing_name = FLAGS.preprocessing_name or FLAGS.model_name
        image_preprocessing_fn = preprocessing_factory.get_preprocessing(
            preprocessing_name, is_training=False)

        tf_utils.print_configuration(FLAGS.__flags, ssd_params,
                                     dataset.data_sources, FLAGS.eval_dir)
        # =================================================================== #
        # Create a dataset provider and batches.
        # =================================================================== #
        with tf.device('/cpu:0'):
            with tf.name_scope(FLAGS.dataset_name + '_data_provider'):
                provider = slim.dataset_data_provider.DatasetDataProvider(
                    dataset,
                    common_queue_capacity=2 * FLAGS.batch_size,
                    common_queue_min=FLAGS.batch_size,
                    shuffle=False)
            # Get for SSD network: image, labels, bboxes.
            [image, shape, glabels, gbboxes] = provider.get(['image', 'shape',
                                                             'object/label',
                                                             'object/bbox'])
            if FLAGS.remove_difficult:
                [gdifficults] = provider.get(['object/difficult'])
            else:
                gdifficults = tf.zeros(tf.shape(glabels), dtype=tf.int64)

            # Pre-processing image, labels and bboxes.

            gpu_options = tf.GPUOptions(allow_growth=True)
            config = tf.ConfigProto(log_device_placement=False, gpu_options=gpu_options)
            isess = tf.InteractiveSession(config=config)

            net_shape = (300, 300)
            data_format = 'NHWC'
            img_input = tf.placeholder(tf.uint8, shape=(None, None, 3))

            image_pre, glabels, gbboxes, gbbox_img = \
                image_preprocessing_fn(image, glabels, gbboxes,
                                       out_shape=ssd_shape,
                                       data_format=DATA_FORMAT,
                                       resize=FLAGS.eval_resize,
                                       difficults=None)
            image_4d = tf.expand_dims(image_pre, 0)

            from nets import ssd_vgg_300

            ssd_net = ssd_vgg_300.SSDNet()
            with slim.arg_scope(ssd_net.arg_scope(data_format=data_format)):
                rpredictions, rlocalisations, _, _ = ssd_net.net(image_4d, is_training=False, reuse=tf.AUTO_REUSE)
            print('yes')
            ckpt_filename = 'checkpoints/ssd_300_vgg.ckpt'
            isess.run(tf.global_variables_initializer())
            saver = tf.train.Saver()
            saver.restore(isess, ckpt_filename)

            ssd_anchors = ssd_net.anchors(net_shape)
            bbox_img = gbbox_img

            select_threshold = 0.5
            nms_threshold = .45
            net_shape = (300, 300)
            # Run SSD network.

            rbbox_img = gbbox_img

            print(image_4d)
            # rimg, rpredictions, rlocalisations, rbbox_img = isess.run([image_4d, rpredictions, rlocalisations, gbbox_img])
            # rclasses, rscores, rbboxes = np_methods.ssd_bboxes_select(
            #     rpredictions, rlocalisations, ssd_anchors,
            #     select_threshold=select_threshold, img_shape=net_shape, num_classes=21, decode=True)
            #
            #
            # rbboxes = np_methods.bboxes_clip(rbbox_img, rbboxes)
            # rclasses, rscores, rbboxes = np_methods.bboxes_sort(rclasses, rscores, rbboxes, top_k=400)
            # rclasses, rscores, rbboxes = np_methods.bboxes_nms(rclasses, rscores, rbboxes, nms_threshold=nms_threshold)
            # # Resize bboxes to original image shape. Note: useless for Resize.WARP!
            # rbboxes = np_methods.bboxes_resize(rbbox_img, rbboxes)

def np_ssd_bboxes_select(rpredictions, rlocalisations, net_shape):
    return np_methods.ssd_bboxes_select(rpredictions, rlocalisations, ssd_anchors,
                                        select_threshold=FLAGS.select_threshold, img_shape=net_shape, num_classes=21,
                                        decode=True)

def py_postprocess(rpredictions, rlocalisations, ssd_anchors, net_shape, rbbox_img):
    from nets import np_methods
    rclasses, rscores, rbboxes = np_methods.ssd_bboxes_select(
        rpredictions, rlocalisations, ssd_anchors,
        select_threshold=FLAGS.select_threshold, img_shape=net_shape, num_classes=21, decode=True)

    rbboxes = np_methods.bboxes_clip(rbbox_img, rbboxes)
    rclasses, rscores, rbboxes = np_methods.bboxes_sort(rclasses, rscores, rbboxes, top_k=400)
    rclasses, rscores, rbboxes = np_methods.bboxes_nms(rclasses, rscores, rbboxes, nms_threshold=FLAGS.nms_threshold)
    # Resize bboxes to original image shape. Note: useless for Resize.WARP!
    rbboxes = np_methods.bboxes_resize(rbbox_img, rbboxes)

    return rscores, rbboxes

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


import cv2, imutils, os
import numpy as np
import matplotlib.pyplot as plt

wait = 1

def stitch(prev, im, result, posx,posy, ratio=0.75, reprojThresh=4.0,
	show=False):

	offsetx,offsety,H = generate_homography(prev,im)

	posx+=offsetx
	posy-=offsety
	print(posx,posy)
	if(offsetx>0):
		print('right')
	elif(offsetx<0):
		print('left')
	if(offsety>0):
		print('down')
	elif(offsety<0):
		print('up')
	print()

	#prev[offsety:im.shape[0]+offsety, offsetx:im.shape[1]+offsetx] = im

	result = append_images(result,im,-offsetx,-offsety)

	if show:
		global wait
		cv2.imshow("result",result)
		cv2.imshow("current",im)
		k = cv2.waitKey(wait)
		if(k==27):
			cv2.destroyAllWindows()
			exit(1)
		if(k==32):
			wait = not wait

	return result,posx,posy

def analyze(imageA, imageB, ratio = 0.75,reprojThresh=4.0):
	(kpsA, featuresA) = detectAndDescribe(imageA)
	(kpsB, featuresB) = detectAndDescribe(imageB)
	M = matchKeypoints(kpsA, kpsB,
		featuresA, featuresB, ratio, reprojThresh)
	if M is None:
		return None
	(matches, H, status) = M
	return find_shift(kpsA, kpsB, matches, status)

def append_images(imageA,imageB,shift_x,shift_y):
	right,shift_x = (abs(shift_x),0) if shift_x<0 else (0,shift_x)
	down,shift_y = (abs(shift_y),0) if shift_y<0 else (0,shift_y)
	result = np.zeros((max(imageA.shape[0]+shift_y,imageB.shape[0]+down),max(imageA.shape[1]+shift_x,imageB.shape[1]+right),3))
	result[:,:]=-np.inf
	#print(imageA.shape,result.shape)
	result[shift_y:(imageA.shape[0]+shift_y),shift_x:(imageA.shape[1]+shift_x),:]=\
	np.where(result[shift_y:(imageA.shape[0]+shift_y),shift_x:(imageA.shape[1]+shift_x),:]==-np.inf,\
	imageA,result[shift_y:(imageA.shape[0]+shift_y),shift_x:(imageA.shape[1]+shift_x),:])
	result[down:(imageB.shape[0]+down),right:(imageB.shape[1]+right),:]= \
	np.where(result[down:(imageB.shape[0]+down),right:(imageB.shape[1]+right),:]==-np.inf, \
	imageB,result[down:(imageB.shape[0]+down),right:(imageB.shape[1]+right),:])
	result = result.astype(np.uint8)
	return result

def generate_homography(imageA, imageB, ratio=0.75, reprojThresh=4.0):
	grayA = cv2.cvtColor(imageA, cv2.COLOR_BGR2GRAY)
	grayB = cv2.cvtColor(imageB, cv2.COLOR_BGR2GRAY)
	descriptor = cv2.xfeatures2d.SIFT_create()
	(kpsA, featuresA) = descriptor.detectAndCompute(imageA, None)
	(kpsB, featuresB) = descriptor.detectAndCompute(imageB, None)
	kpsA = np.float32([kp.pt for kp in kpsA])
	kpsB = np.float32([kp.pt for kp in kpsB])

	M = matchKeypoints(kpsA, kpsB, featuresA, featuresB, ratio, reprojThresh)
	if M is None:
		return None
	(matches, H, status) = M
	H_inv = np.linalg.inv(H)
	ds = np.dot(H_inv, np.array([imageA.shape[1], imageA.shape[0], 1]))
	ds = ds/ds[-1]
	f1 = np.dot(H_inv, np.array([0,0,1]))
	f1 = f1/f1[-1]
	H_inv[0][-1] += abs(f1[0])
	H_inv[1][-1] += abs(f1[1])
	ds = np.dot(H_inv, np.array([imageA.shape[1], imageA.shape[0], 1]))
	offsety = int(f1[1])
	offsetx = int(f1[0])
	return offsetx, offsety, H

def matchKeypoints(kpsA, kpsB, featuresA, featuresB,
	ratio, reprojThresh):
	# compute the raw matches and initialize the list of actual
	# matches
	matcher = cv2.DescriptorMatcher_create("BruteForce")
	rawMatches = matcher.knnMatch(featuresA, featuresB, 2)
	matches = []

	# loop over the raw matches
	for m in rawMatches:
		# ensure the distance is within a certain ratio of each
		# other (i.e. Lowe's ratio test)
		if len(m) == 2 and m[0].distance < m[1].distance * ratio:
			matches.append((m[0].trainIdx, m[0].queryIdx))

	# computing a homography requires at least 4 matches
	if len(matches) > 4:
		# construct the two sets of points
		ptsA = np.float32([kpsA[i] for (_, i) in matches])
		ptsB = np.float32([kpsB[i] for (i, _) in matches])

		# compute the homography between the two sets of points
		(H, status) = cv2.findHomography(ptsA, ptsB, cv2.RANSAC,
			reprojThresh)

		# return the matches along with the homograpy matrix
		# and status of each matched point
		return (matches, H, status)

	# otherwise, no homograpy could be computed
	return None

def drawMatches(imageA, imageB, kpsA, kpsB, matches, status):
	# initialize the output visualization image
	(hA, wA) = imageA.shape[:2]
	(hB, wB) = imageB.shape[:2]
	vis = np.zeros((max(hA, hB), wA + wB, 3), dtype="uint8")
	vis[0:hA, 0:wA] = imageA
	vis[0:hB, wA:] = imageB

	# loop over the matches
	for ((trainIdx, queryIdx), s) in zip(matches, status):
		# only process the match if the keypoint was successfully
		# matched
		if s == 1:
			# draw the match
			ptA = (int(kpsA[queryIdx][0]), int(kpsA[queryIdx][1]))
			ptB = (int(kpsB[trainIdx][0]) + wA, int(kpsB[trainIdx][1]))
			cv2.line(vis, ptA, ptB, (0, 255, 0), 1)

	# return the visualization
	return vis

def find_shift(kpsA, kpsB, matches, status):
	avgA=[0,0]
	avgB=[0,0]

	maxxA = -np.inf
	maxyA = -np.inf
	minxA = np.inf
	minyA = np.inf

	maxxB = -np.inf
	maxyB = -np.inf
	minxB = np.inf
	minyB = np.inf
	# loop over the matches
	for ((trainIdx, queryIdx), s) in zip(matches, status):
		# only process the match if the keypoint was successfully
		# matched
		if s == 1:
			ptA = (int(kpsA[queryIdx][0]), int(kpsA[queryIdx][1]))
			ptB = (int(kpsB[trainIdx][0]), int(kpsB[trainIdx][1]))

			if(ptA[0]>maxxA):
				maxxA = ptA[0]
			if(ptA[0]<minxA):
				minxA = ptA[0]
			if(ptA[1]>maxyA):
				maxyA = ptA[1]
			if(ptA[1]<minyA):
				minyA = ptA[1]

			if(ptB[0]>maxxB):
				maxxB = ptB[0]
			if(ptB[0]<minxB):
				minxB = ptB[0]
			if(ptB[1]>maxyB):
				maxyB = ptB[1]
			if(ptB[1]<minyB):
				minyB = ptB[1]

			avgA[0]+=ptA[0]/len(kpsA)
			avgA[1]+=ptA[1]/len(kpsA)
			avgB[0]+=ptB[0]/len(kpsB)
			avgB[1]+=ptB[1]/len(kpsB)

	return (int(avgA[0]),int(avgA[1])),(int(avgB[0]),int(avgB[1])), ((maxxA - minxA),(maxyA - minyA)), ((maxxB - minxB),(maxyB - minyB))

if __name__ == '__main__':
	prev = None
	result = None
	posx = 0
	posy = 0
	count=-1
	lst = sorted(os.listdir(os.fsencode('../../../data/frames/continuous/ACHA UNH/')))
	while count < len(lst):
		file = lst[count]
		filename = os.fsdecode(file)
		if(filename.endswith('.jpg') == False):
			continue

		count+=1
		if(count%1==0):
			#print(str(float(count)/float(len(lst))*100)+"%")
			im = cv2.imread('../../../data/frames/continuous/ACHA UNH/'+filename)
			im = cv2.resize(im,(480, 320))
			if(prev is None):
				result = im
				prev = im
				continue

			result,posx,posy = stitch(prev, im, result, posx,posy, show=True)
			prev = im


from floodsystem.stationdata import build_station_list, update_water_levels
from floodsystem import flood
import matplotlib
from floodsystem.datafetcher import fetch_measure_levels
import datetime
from floodsystem.analysis import polyfit

def get_at_risk_towns(risk_thresholds,predictionAmount,N):
    """Print a list of towns that are predicted to have a increase in relative water level
    N - amount of towns considered
    predictionAmount - days into future predicted
    risk_thresholds - adjusts wording
    """
    #criteria: towns with stations that:
    # are in the top 60 highest relative level
    # and are predicted to have a rise in relative water level

        # Build list of stations
    stations = build_station_list()
    update_water_levels(stations)

    # Setting the time interval to 2 days
    dt = 2

    # Run curve fitting with degree of 4
    p = 4

    shortlist = flood.stations_highest_rel_level(stations, N)

    # First find the stations at risk
    risk_stations = []

    for station in shortlist:
        dates, levels = fetch_measure_levels(station.measure_id,
                                             dt=datetime.timedelta(days=dt))
        if len(dates) < 1 or len(levels) < 1:
            # if there is no data, fitting will throw an error
            continue

        # calculate the fitting polynomial
        poly, d0 = polyfit(dates, levels, p)

        #get the list in date as float format
        x = matplotlib.dates.date2num(dates)

        # get the latest date
        latestDate = max(x - d0)

        #amount of days to predict into the future
        predictionAmount = 2

        # predict the water level two days later
        prediction = poly(latestDate + predictionAmount)

        #get current relative water level
        r_level = station.relative_water_level()

        #get predicted water level
        predicted_r_level = predicted_relative_water_level(station, prediction)

        # calculate the predicted rise in relative water level
        rise = predicted_r_level - r_level

        #if relative level will rise add to at risk stations list
        if predicted_r_level > r_level:
            if station.town:
                risk_stations.append([station.town, rise])
            else:
                risk_stations.append(["Missing town name: at risk station is " +station.name, rise]) #fallback to station name if nearest town cannot be found

    at_risk_towns = []

    for i, station_i in enumerate(risk_stations): #loop through all stations at risk
        at_risk_towns.append(station_i[:]) # append town name and rise of station at risk

    # sort at_risk_towns by risks in descending order
    at_risk_towns.sort(key=lambda x: x[1], reverse=True)

    print("\nThe following warnings are for the top {} towns at risk, based on predictions for the next {} days".format(N,predictionAmount))
    print("Warnings will not be generated for towns already underwater\n")

    print("Current risk thresholds: \n ")

    ratings = ['low', 'moderate', 'high', 'severe']

    for i, threshold in enumerate(risk_thresholds):
        print("{} rating: {}".format(ratings[i+1],threshold))

    print('\nThe towns where the risk of flooding is assessed to be the greatest:')

    for town, relative_rise in at_risk_towns:
        rating_factor = 0  # low
        if relative_rise > risk_thresholds[0]:
            rating_factor = 1  # moderate
        if relative_rise > risk_thresholds[1]:
            rating_factor = 2  # high
        if relative_rise > risk_thresholds[2]:
            rating_factor = 3  # severe
        print('{}:\n\t{}'.format(town, ratings[rating_factor]))

def predicted_relative_water_level(station, prediction):
    """return predicted water level as fraction of the typical range"""

    #default case if data is not avaliable or inconsistent
    relative_level = None

    if station.typical_range_consistent():
        try:
            #should only work if data is consistent and avaliable
            relative_level = (prediction - station.typical_range[0]) / (
                station.typical_range[1] - station.typical_range[0])
        except:
            #if data is consistent but not present return None
            relative_level = None

    return relative_level

def run():
    thresholds=[0.5,5,10]
    get_at_risk_towns(thresholds,2,60)
if __name__ == "__main__":
    print("*** Task 2G final ***")

    run()


#!/usr/bin/env python3
# -*- coding: utf-8 -*-

'''
产生全部的网格
从左下开始
'''

from gridMap import varGlobal
import json

from gridMap import gridmap
import csv

# 纬度从上到下变小，经度从左往右变大
# 1存的是小值，2存的是大值
def generateGrid():
    l = []
    for i in range(1,varGlobal.COUNTCELL+1):
        r = gridmap.getBorderByGridId(i)
        newgrid = gridmap.Grid(i, r[0], r[1], r[2], r[3])
        l.append(gridmap.grid2dict(newgrid))
    #with open('app/static/GuiYangGrid.js', 'w') as f:
    with open('app/static/GuiYangGrid4836.js', 'w') as f:
        f.write('var GuiYangGrid = ')
        json.dump(l, f)#把Python object写入到.js文件
        f.write(';')

def generateGridTxt():
    l = []
    for i in range(1,varGlobal.COUNTCELL+1):
        r = gridmap.getBorderByGridId(i)
        newgrid = [i,r[0], r[1], r[2], r[3]]
        l.append(newgrid)
    #with open('data/grid4836.csv', 'w', newline='') as f:   #python3
    with open('data/grid4836.csv', 'w') as f:
        write = csv.writer(f)
        write.writerow(['id','lat_down', 'lat_up', 'lng_left', 'lng_right'])
        write.writerows(l)

if __name__=="__main__" :
    generateGrid()
    generateGridTxt()


# program to store the content thats loaded from various server
#into a local binary file knows as pickle

import pandas as pd
import quandl
import pickle
import matplotlib.pyplot as plt
from matplotlib import style
style.use('fivethirtyeight')

house_data_list = ['GICHSGFIN','GANESHHOUC','IBULHSGFIN']

#store the api key in the text file
api_key  = open('apiKey.txt','r').read()
#
# df = quandl.get("NSE/GICHSGFIN", authtoken=api_key)
# print(df['Open'].head())

# create a main dataframe which will store all the queried dataframe
HPI = pd.DataFrame()
def grab_initial_state():
    main_df = pd.DataFrame()
    for data in house_data_list:
        # Build a query
        query = "NSE/" + str(data)
        # Create a dataframe from the above query to quandl database
        df = quandl.get(query, authtoken=api_key)
        df = df[['Close']]
        df.columns = [data]
        print(df.head())
        print("..........................")

        # start the join process
        if main_df.empty:
            main_df = df
        else:
            main_df = main_df.join(df, how="inner")

    pickle_out = open('quandl.pickle','wb')
    pickle.dump(main_df, pickle_out)
    pickle_out.close()

# grab_initial_state()

#Load dataframe from pickle
pickle_in = open('quandl.pickle','rb')
HPI_data = pickle.load(pickle_in)
#HPI data is for the whole year.
print(HPI_data)

# Produce a monthly sample for the HPI data

GIC  = HPI_data['GICHSGFIN'].resample('M').mean()
print(GIC.head())

# DataFrame  to store the percentage in value
# HPI = HPI_data.pct_change()

HPI_data['GICHSGFIN'].plot()
GIC.plot()

plt.legend()
plt.show()


import pandas as pd
import numpy as np

# Load Data
data_dir = f"./data/raw/ratings.dat"
data = pd.read_csv(
    data_dir,
    sep="::",
    header=None,
    names=["uid", "mid", "rating", "timestamp"],
    engine="python",
)

# Reindex
user_id = data[["uid"]].drop_duplicates().reindex()
user_id["userId"] = np.arange(len(user_id))
data = pd.merge(data, user_id, on=["uid"], how="left")

item_id = data[["mid"]].drop_duplicates().reindex()
item_id["itemId"] = np.arange(len(item_id))
data = pd.merge(data, item_id, on=["mid"], how="left")

data = data[["userId", "itemId", "rating", "timestamp"]]

print(f"Range of userId is [{data.userId.min()}, {data.userId.max()}]")
print(f"Unique userIds {data.userId.nunique()}")

print(f"Range of itemId is [{data.itemId.min()}, {data.itemId.max()}]")
print(f"Unique itemIds {data.itemId.nunique()}")

data.to_csv("./data/processed/ratings.csv")


import random

class MapGenerator:

    def __init__(self):
        self.block_no = 0
        self.block_mid = 1
        self.block_bottom_top = 2
        self.block_top_bottom = 3

        self.height = 10
        self.min_space = 4

    def generate_row_empty(self):
        return [self.block_no for _ in range(self.height)]

    def generate_row(self):

        limit_downwards = int(self.height * (self.height - self.min_space) / 10)
        limit_above = random.randint(-1, limit_downwards)
        limit_upwards = limit_above + self.min_space
        limit_below = random.randint(limit_upwards, self.height)

        row = []
        if limit_above > 0:
            for i in range(0, limit_above):
                if i < limit_above - 1:
                    row.append(self.block_mid)  # mid
                else:
                    row.append(self.block_top_bottom)  # end of top block

        for _ in range(limit_above, limit_below):
            row.append(self.block_no)

        if limit_below < self.height:
            for i in range(limit_below, self.height):
                if i == limit_below:
                    row.append(self.block_bottom_top)
                else:
                    row.append(self.block_mid)

        return row


import unittest
from HeapWithClassModule import *

#
# In many path-finding applications, a natural scoring function is
# "lexicographic ordering".  That is, there is one attribute of the
# path (say cost) that is the most important thing to minimize.
# However, all things being equal, if you have two paths with the same
# cost, you might prefer one with a shorter total flight time.
#
# A recent example of lexicographic ordering: In the Olympics Medal
# Tracker website, countries are sorted from most total medals to
# least total medals.  If two countries have the same number of total
# medals, the one with more gold medals is listed first.  If they have
# the same total medals and the same number of gold medals, the one
# with more silver medals is listed first.
#
# We want you to take the list of flights, given below, and create a
# graph.  Then, write a modified Dijkstra's algorithm to find the best
# combination of flights to get between two cities, where flights `x`
# is better than flights `y` if `x` has lower cost *or* if they are
# tied in cost, `x` has shorter total flight time.
#
# Concretely, to get from Broome to Fitroy Crossing,
# flights [530, 112] are better than flights [526, 622]
# because, since they both cost 110, the first flights are
# shorter - 5 hours and 52 minutes compared to
# 6 hours and 23 minutes. There maybe be even better flights, but
# you'll have to search the graph to find them.
#
def get_time(timestring):
    (hourstring, minutesstring) = timestring.split(':')
    return int(hourstring) * 60 + int(minutesstring)

class flight_info:
    def __init__(self, FlightNumber, DepartureTime, ArrivalTime, Cost):
        self.flightNumber = FlightNumber
        self.departureTime = DepartureTime
        self.arrivalTime = ArrivalTime
        self.cost = Cost
    def __add__(self, another):
        # extend the flight number, departure is still the same, arrival is the arrival of the second flight, cost is the sum
        flights = []
        deptime = self.departureTime
        if len(self.flightNumber) > 0:
            flights.extend(self.flightNumber)
        else:
            deptime = another.departureTime
        flights.extend(another.flightNumber)
        return flight_info(flights, deptime, another.arrivalTime, self.cost + another.cost)
    def __gt__(self, another):
        return (self.cost > another.cost)
    def __ge__(self, another):
        return (self.cost >= another.cost)
    def __lt__(self, another):
        return (self.cost < another.cost)
    def total_flight_time(self):
        return self.arrivalTime - self.departureTime
    def laterThen(self, another):
        return self.arrivalTime > another.departureTime

def make_link(G, node1, node2, w):
    if node1 not in G:
        G[node1] = {}
    (G[node1])[node2] = w
    return G

def build_graph(flights):
    G = {}
    for FlightNumber, Origin, Destination, DepartureTime, ArrivalTime, Cost in flights:
        make_link(G, Origin, FlightNumber, flight_info([FlightNumber], get_time(DepartureTime), 0, Cost))
        make_link(G, FlightNumber, Destination, flight_info([], 0, get_time(ArrivalTime), 0))
    return G

# extended Dijkstra, keeps the path to each node
def dijkstra_shortest_path_flights(G, start_node, end_node):
    # distances so far
    dist_so_far = []
    # final list of distances
    final_dist = {}

    # structures for keeping the path sa well
    possible_paths = []

    # create the initial node with distance 0
    node = heap_node(start_node, flight_info([], 0, 0, 0))

    # add it to the heap and to the dictionary
    dist_so_far.append(node)

    while len(dist_so_far) > 0:

        # find the closes node
        wNode = dist_so_far.pop()

        w = wNode.name
        # remove it from the dictionary for good measure
        # lock it down!
        final_dist[w] = wNode.value

        for x in G[w]:
            # only need the nodes that are not over and done
            #if x in final_dist:
            #    continue
            # is it feasible to reach this flight
            if final_dist[w].laterThen(G[w][x]):
                continue

            # calculate the new distance
            new_value = (final_dist[w] + G[w][x])

            # we have found one possible path
            if x == end_node:
                possible_paths.append(new_value)
            else:
                # if the node is not in the heap, add it to both heap and dictionary
                node = heap_node(x, new_value)
                dist_so_far.append(node)

    if len(possible_paths) == 0:
        return None

    path = possible_paths[0]
    for p in possible_paths[1:]:
        if p < path:
            path = p
        elif p == path and p.total_flight_time() < path.total_flight_time():
            path = p
    return path

def find_best_flights(flights, origin, destination):
    G = build_graph(flights)
    cost = dijkstra_shortest_path_flights(G, origin, destination)
    if(cost is None):
        return None
    # your code here
    return cost.flightNumber

#
# Here is a fictious flight schedule that is roughly based on routes
# flown by Skipper, a regional airline in Australia
# (http://www.skippers.com.au/).
#
# Each tuple contains six items:
#   Flight Number, Origin, Destination, Departure Time, Arrival Time, Cost
# (Don't worry about any time zone issues; assume everything happens
# in the same time zone)
# Also note that overnight layovers are not allowed.
#
all_flights = [(523, 'Broome', 'Derby', '07:17', '08:57', 60),
               (526, 'Broome', 'Derby', '08:41', '10:30', 50),
               (527, 'Broome', 'Derby', '11:46', '13:24', 200),
               (530, 'Broome', 'Derby', '14:23', '15:59', 50),
               (540, 'Broome', 'Derby', '17:49', '19:40', 50),
               (546, 'Broome', 'Derby', '20:34', '22:09', 20),
               (547, 'Broome', 'Perth', '06:41', '08:44', 30),
               (549, 'Broome', 'Perth', '17:16', '19:18', 100),
               (559, 'Carnarvon', 'Geraldton', '09:05', '10:57', 50),
               (561, 'Carnarvon', 'Geraldton', '11:14', '13:03', 30),
               (578, 'Carnarvon', 'Geraldton', '14:56', '16:48', 150),
               (582, 'Carnarvon', 'Geraldton', '17:05', '18:46', 50),
               (598, 'Carnarvon', 'Geraldton', '22:08', '23:49', 20),
               (599, 'Carnarvon', 'Perth', '07:04', '09:46', 200),
               (100, 'Carnarvon', 'Perth', '10:53', '13:38', 60),
               (604, 'Carnarvon', 'Perth', '14:50', '17:16', 200),
               (612, 'Carnarvon', 'Perth', '19:54', '22:38', 50),
               (107, 'Derby', 'Broome', '08:44', '10:36', 160),
               (108, 'Derby', 'Broome', '21:18', '23:04', 30),
               (622, 'Derby', 'Fitzroy Crossing', '13:59', '15:04', 60),
               (112, 'Derby', 'Fitzroy Crossing', '19:24', '20:15', 60),
               (113, 'Derby', 'Geraldton', '07:00', '08:10', 20),
               (115, 'Derby', 'Geraldton', '10:00', '11:07', 200),
               (118, 'Derby', 'Geraldton', '13:24', '14:31', 50),
               (121, 'Derby', 'Geraldton', '14:41', '15:52', 50),
               (122, 'Derby', 'Geraldton', '17:05', '18:09', 60),
               (635, 'Derby', 'Geraldton', '18:59', '20:18', 60),
               (638, 'Fitzroy Crossing', 'Derby', '09:18', '10:08', 50),
               (131, 'Fitzroy Crossing', 'Derby', '13:59', '14:51', 160),
               (226, 'Fitzroy Crossing', 'Derby', '14:34', '15:34', 110),
               (139, 'Fitzroy Crossing', 'Derby', '18:43', '19:36', 50),
               (654, 'Fitzroy Crossing', 'Halls Creek', '07:55', '09:48', 180),
               (143, 'Fitzroy Crossing', 'Halls Creek', '09:45', '11:39', 20),
               (280, 'Fitzroy Crossing', 'Halls Creek', '15:10', '17:07', 110),
               (660, 'Fitzroy Crossing', 'Halls Creek', '18:41', '20:24', 30),
               (661, 'Fitzroy Crossing', 'Halls Creek', '20:35', '22:19', 200),
               (663, 'Geraldton', 'Carnarvon', '08:30', '10:24', 30),
               (152, 'Geraldton', 'Carnarvon', '12:52', '14:42', 50),
               (153, 'Geraldton', 'Carnarvon', '15:24', '17:15', 30),
               (154, 'Geraldton', 'Carnarvon', '18:07', '19:53', 180),
               (671, 'Geraldton', 'Derby', '06:01', '07:10', 120),
               (676, 'Geraldton', 'Derby', '10:46', '12:09', 20),
               (165, 'Geraldton', 'Derby', '11:29', '12:45', 30),
               (683, 'Geraldton', 'Derby', '14:17', '15:23', 50),
               (174, 'Geraldton', 'Derby', '16:45', '17:58', 180),
               (175, 'Geraldton', 'Derby', '18:31', '19:47', 20),
               (179, 'Halls Creek', 'Fitzroy Crossing', '06:32', '08:22', 200),
               (187, 'Halls Creek', 'Fitzroy Crossing', '13:19', '15:03', 200),
               (702, 'Halls Creek', 'Fitzroy Crossing', '14:04', '15:45', 20),
               (192, 'Halls Creek', 'Fitzroy Crossing', '20:08', '21:59', 160),
               (195, 'Halls Creek', 'Kalbarri', '06:43', '09:01', 110),
               (709, 'Halls Creek', 'Kalbarri', '08:45', '11:04', 200),
               (199, 'Halls Creek', 'Kalbarri', '13:21', '15:39', 20),
               (209, 'Halls Creek', 'Kalbarri', '15:45', '18:01', 100),
               (723, 'Halls Creek', 'Kalbarri', '16:04', '18:10', 50),
               (724, 'Halls Creek', 'Kalbarri', '19:52', '22:07', 160),
               (216, 'Kalbarri', 'Halls Creek', '06:15', '08:34', 100),
               (217, 'Kalbarri', 'Halls Creek', '14:57', '17:14', 200),
               (730, 'Kalbarri', 'Halls Creek', '21:05', '23:24', 20),
               (731, 'Kalbarri', 'Perth', '06:18', '08:50', 50),
               (734, 'Kalbarri', 'Perth', '12:23', '14:59', 120),
               (735, 'Kalbarri', 'Perth', '12:59', '15:19', 30),
               (738, 'Kalbarri', 'Perth', '18:41', '21:10', 60),
               (739, 'Kalbarri', 'Perth', '19:42', '22:18', 60),
               (740, 'Laverton', 'Leonora', '07:39', '08:53', 180),
               (745, 'Laverton', 'Leonora', '12:20', '13:32', 20),
               (748, 'Laverton', 'Leonora', '13:44', '15:08', 30),
               (751, 'Laverton', 'Leonora', '18:00', '19:11', 200),
               (240, 'Laverton', 'Leonora', '20:34', '21:40', 110),
               (754, 'Laverton', 'Perth', '07:21', '08:21', 180),
               (247, 'Laverton', 'Perth', '20:11', '21:22', 160),
               (248, 'Leinster', 'Perth', '08:37', '11:16', 180),
               (249, 'Leinster', 'Perth', '13:44', '16:12', 110),
               (763, 'Leinster', 'Perth', '16:29', '19:06', 160),
               (765, 'Leinster', 'Perth', '19:17', '21:47', 20),
               (981, 'Leinster', 'Wiluna', '10:51', '13:03', 200),
               (770, 'Leinster', 'Wiluna', '16:02', '18:17', 50),
               (259, 'Leinster', 'Wiluna', '19:44', '22:09', 60),
               (772, 'Leonora', 'Laverton', '10:39', '11:59', 110),
               (987, 'Leonora', 'Laverton', '15:56', '17:13', 110),
               (264, 'Leonora', 'Laverton', '21:39', '22:48', 200),
               (779, 'Leonora', 'Perth', '10:29', '11:59', 50),
               (780, 'Leonora', 'Perth', '11:26', '12:58', 50),
               (783, 'Leonora', 'Perth', '19:48', '21:25', 30),
               (278, 'Meekatharra', 'Mt Magnet', '07:40', '08:42', 60),
               (792, 'Meekatharra', 'Mt Magnet', '08:35', '09:35', 60),
               (793, 'Meekatharra', 'Mt Magnet', '11:50', '12:44', 110),
               (796, 'Meekatharra', 'Mt Magnet', '14:32', '15:26', 30),
               (798, 'Meekatharra', 'Mt Magnet', '16:56', '17:52', 160),
               (288, 'Meekatharra', 'Mt Magnet', '19:38', '20:27', 60),
               (289, 'Meekatharra', 'Perth', '08:12', '09:28', 50),
               (803, 'Meekatharra', 'Perth', '09:12', '10:25', 30),
               (805, 'Meekatharra', 'Perth', '12:10', '13:16', 50),
               (298, 'Meekatharra', 'Perth', '13:33', '14:40', 50),
               (391, 'Meekatharra', 'Perth', '16:45', '17:50', 30),
               (815, 'Meekatharra', 'Perth', '20:17', '21:29', 110),
               (817, 'Monkey Mia', 'Perth', '08:26', '10:51', 20),
               (393, 'Monkey Mia', 'Perth', '13:12', '15:51', 30),
               (825, 'Monkey Mia', 'Perth', '21:01', '23:37', 180),
               (314, 'Mt Magnet', 'Meekatharra', '06:29', '07:30', 30),
               (827, 'Mt Magnet', 'Meekatharra', '08:56', '10:00', 50),
               (829, 'Mt Magnet', 'Meekatharra', '13:09', '14:14', 30),
               (832, 'Mt Magnet', 'Meekatharra', '14:10', '15:09', 30),
               (833, 'Mt Magnet', 'Meekatharra', '17:39', '18:41', 180),
               (322, 'Mt Magnet', 'Meekatharra', '19:51', '20:55', 160),
               (333, 'Mt Magnet', 'Perth', '07:53', '08:38', 120),
               (846, 'Mt Magnet', 'Perth', '15:45', '16:29', 20),
               (967, 'Mt Magnet', 'Perth', '18:04', '18:49', 20),
               (336, 'Mt Magnet', 'Wiluna', '07:34', '09:08', 200),
               (338, 'Mt Magnet', 'Wiluna', '13:35', '15:17', 30),
               (856, 'Mt Magnet', 'Wiluna', '14:54', '16:27', 50),
               (345, 'Mt Magnet', 'Wiluna', '18:03', '19:35', 50),
               (859, 'Perth', 'Broome', '07:21', '09:14', 50),
               (348, 'Perth', 'Broome', '10:37', '12:46', 60),
               (349, 'Perth', 'Broome', '12:56', '14:57', 20),
               (350, 'Perth', 'Broome', '15:01', '17:11', 110),
               (356, 'Perth', 'Broome', '18:03', '20:03', 60),
               (364, 'Perth', 'Broome', '18:45', '20:54', 150),
               (880, 'Perth', 'Carnarvon', '07:39', '10:09', 50),
               (884, 'Perth', 'Carnarvon', '10:33', '13:11', 30),
               (374, 'Perth', 'Carnarvon', '12:04', '14:31', 50),
               (375, 'Perth', 'Carnarvon', '13:59', '16:32', 30),
               (378, 'Perth', 'Carnarvon', '17:04', '19:38', 50),
               (299, 'Perth', 'Carnarvon', '19:27', '22:09', 50),
               (383, 'Perth', 'Kalbarri', '06:41', '09:12', 120),
               (384, 'Perth', 'Kalbarri', '12:42', '15:03', 20),
               (898, 'Perth', 'Kalbarri', '19:13', '21:38', 30),
               (390, 'Perth', 'Laverton', '10:20', '11:23', 60),
               (321, 'Perth', 'Laverton', '14:08', '15:03', 60),
               (905, 'Perth', 'Laverton', '19:58', '20:53', 100),
               (395, 'Perth', 'Leinster', '06:59', '09:28', 200),
               (396, 'Perth', 'Leinster', '10:17', '12:48', 100),
               (401, 'Perth', 'Leinster', '14:24', '16:50', 50),
               (914, 'Perth', 'Leinster', '18:54', '21:34', 160),
               (404, 'Perth', 'Leonora', '11:03', '12:40', 30),
               (918, 'Perth', 'Leonora', '12:37', '14:17', 150),
               (408, 'Perth', 'Leonora', '20:42', '22:10', 100),
               (923, 'Perth', 'Meekatharra', '06:21', '07:35', 110),
               (927, 'Perth', 'Meekatharra', '10:25', '11:26', 20),
               (933, 'Perth', 'Meekatharra', '14:27', '15:24', 50),
               (934, 'Perth', 'Meekatharra', '17:49', '18:50', 200),
               (941, 'Perth', 'Meekatharra', '21:56', '23:08', 30),
               (430, 'Perth', 'Monkey Mia', '06:18', '08:48', 30),
               (943, 'Perth', 'Monkey Mia', '12:11', '14:48', 180),
               (432, 'Perth', 'Monkey Mia', '17:32', '20:13', 50),
               (433, 'Perth', 'Monkey Mia', '19:48', '22:23', 100),
               (947, 'Perth', 'Mt Magnet', '06:43', '07:23', 100),
               (948, 'Perth', 'Mt Magnet', '13:59', '14:54', 20),
               (954, 'Perth', 'Mt Magnet', '15:44', '16:26', 120),
               (955, 'Perth', 'Mt Magnet', '19:34', '20:26', 200),
               (475, 'Perth', 'Wiluna', '07:34', '09:57', 60),
               (959, 'Perth', 'Wiluna', '09:44', '12:22', 50),
               (455, 'Perth', 'Wiluna', '12:22', '14:45', 60),
               (969, 'Perth', 'Wiluna', '14:26', '16:59', 50),
               (458, 'Perth', 'Wiluna', '17:19', '19:38', 60),
               (459, 'Perth', 'Wiluna', '19:09', '21:35', 30),
               (461, 'Wiluna', 'Leinster', '07:54', '10:16', 20),
               (462, 'Wiluna', 'Leinster', '08:35', '10:50', 200),
               (463, 'Wiluna', 'Leinster', '11:50', '14:01', 200),
               (976, 'Wiluna', 'Leinster', '13:54', '16:15', 50),
               (469, 'Wiluna', 'Leinster', '17:24', '19:43', 30),
               (984, 'Wiluna', 'Leinster', '19:58', '22:13', 200),
               (847, 'Wiluna', 'Mt Magnet', '07:13', '08:42', 30),
               (478, 'Wiluna', 'Mt Magnet', '11:48', '13:14', 50),
               (993, 'Wiluna', 'Mt Magnet', '13:00', '14:27', 20),
               (483, 'Wiluna', 'Mt Magnet', '17:20', '18:57', 60),
               (422, 'Wiluna', 'Mt Magnet', '21:40', '23:21', 60),
               (494, 'Wiluna', 'Perth', '08:28', '11:07', 160),
               (253, 'Wiluna', 'Perth', '11:17', '13:41', 150),
               (498, 'Wiluna', 'Perth', '13:53', '16:13', 60),
               (501, 'Wiluna', 'Perth', '17:59', '20:27', 20),
               (505, 'Wiluna', 'Perth', '20:21', '22:41', 180)]

class test_bestflight(unittest.TestCase):
    def test(self):
        flights = find_best_flights(all_flights, 'Mt Magnet', 'Fitzroy Crossing')
        self.assertEqual(flights, [314, 803, 348, 530, 112])

        flights = find_best_flights(all_flights, 'Leonora', 'Fitzroy Crossing')
        self.assertEqual(flights, None)

        flights = find_best_flights(all_flights, 'Meekatharra', 'Wiluna')
        self.assertEqual(flights, [391, 459])


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

def solve(nums, target):
    nums = sorted(nums, reverse=True)
    min_value = min(nums)
    if target < min_value: return -1

    def dfs(nums, target, path, ans):
        if ans[0] != float('inf'):
            return

        if target == 0:
            # print(path)
            ans[0] = min(ans[0], len(path))

        for num in nums:
            if target - num < 0: continue
            path.append(num)
            dfs(nums, target - num, path, ans)
            path.pop()

    ans = [float('inf')]
    dfs(nums, target, [], ans)
    if ans[0] == float('inf'):
        return -1
    else:
        return ans[0]

if __name__ == '__main__':
    # nums = [10, 20, 50]
    # target = 110
    nums = list(map(int, input().split()))
    target = int(input())
    ans = solve(nums, target)
    print(ans)


import logging
from datetime import datetime

from apscheduler.schedulers.blocking import BlockingScheduler
from apscheduler.triggers.cron import CronTrigger
from django.conf import settings
from django.core.mail import mail_managers, EmailMultiAlternatives
from django.core.management.base import BaseCommand
from django_apscheduler import util
from django_apscheduler.jobstores import DjangoJobStore
from django_apscheduler.models import DjangoJobExecution

from django.contrib.auth.models import User
from news.models import Post, Category, Subscription

from news.email_sending import mass_email_sending

logger = logging.getLogger(__name__)

# last_send_date = None

def get_last_send_date():
    executions = DjangoJobExecution.objects.filter(job_id="new_post_mass_notification").filter(status="Executed").order_by("-run_time").values_list("run_time", flat=True)[:1]
    if executions.count() > 0:
        return executions[0]
    else:
        return None

def new_post_mass_notification_func():
    mass_email_sending()

@util.close_old_connections
def delete_old_job_executions(max_age=604_800):
    DjangoJobExecution.objects.delete_old_job_executions(max_age)

class Command(BaseCommand):
    help = "Runs APScheduler."

    def handle(self, *args, **options):
        scheduler = BlockingScheduler(timezone=settings.TIME_ZONE)
        scheduler.add_jobstore(DjangoJobStore(), "default")

        scheduler.add_job(
            new_post_mass_notification_func,
            trigger=CronTrigger(day_of_week="fri", hour="18", minute="00"),
            # trigger=CronTrigger(second="*/5"),  # Every 10 seconds
            id="new_post_mass_notification",  # The `id` assigned to each job MUST be unique
            max_instances=1,
            replace_existing=True,
        )
        logger.info("Added job 'new_post_mass_notification'.")

        scheduler.add_job(
            delete_old_job_executions,
            trigger=CronTrigger(
                day_of_week="mon", hour="00", minute="00"
            ),
            id="delete_old_job_executions",
            max_instances=1,
            replace_existing=True,
        )
        logger.info("Added weekly job: 'delete_old_job_executions'.")

        try:
            logger.info("Starting scheduler...")
            scheduler.start()
        except KeyboardInterrupt:
            logger.info("Stopping scheduler...")
            scheduler.shutdown()
            logger.info("Scheduler shut down successfully!")


from pathlib import Path

import matplotlib.pyplot as plt

def set_matplotlib_dpi(dpi: int = 300):
    plt.rcParams['figure.dpi'] = dpi
    plt.rcParams['savefig.dpi'] = dpi

def save_figure(fig: plt.Figure, output_filepath: Path):
    set_matplotlib_dpi()
    output_filepath.parent.mkdir(parents=True, exist_ok=True)
    current_figure = plt.gcf()
    plt.figure(fig)
    plt.tight_layout()
    plt.savefig(output_filepath)
    plt.figure(current_figure)


"""
Nhập số nguyên dương N (1 < N < 10000).
Viết chương trình tính tổng:
    S = 1 + 1/3 + 1/5 + … + 1/N nếu N lẻ
    S = 1/2 + 1/4 + 1/6 + … + 1/N nếu N chẵn
Kết quả được in ra với 6 chữ số phần thập phân.
Input: 10
Output: 1.141667
- Co 3 cach de format:
C1: round(sum,6)
C2: "{0:.6f}".format(sum)
C3: '%.6f' % sum
"""

if __name__ == "__main__":
    t = int(input())
    for _ in range(t):
        n = int(input())
        if n % 2 == 0:
            sum = 0
            for i in range(2,n+1,2):
                sum += 1/i
            print('%.6f' % sum)
        else:
            sum = 0
            for i in range(1, n + 1, 2):
                sum += 1 / i
            print("{0:.6f}".format(sum))


from src.config import config_service

__output_path = config_service.configuration['configuration']['paths']['output_path']

def create_and_write(name, content):
  with open(__output_path + name, 'w', encoding='utf-8') as file:
    file.write(content)
    file.close()


t = int(input())
for i in range(t):
    l = input()
    x = list(map(int, input().split(" ")))
    s = True
    for a, b in zip(sorted(x), x):
        if a != b:
            s = False
            break
    print("Yes" if s else "No")


#!/usr/bin/env python

""" CONTROL DE UN ROBOT MOVIL UTILIZANDO LOCALIZACION POR QR

Carmen Ballester Bernabeu

Grupo Aurova
Universidad de Alicante

"""

from sys import exit
import numpy as np
import math
import matplotlib.pyplot as plt
import cv2

# Libraries for ROS
import rospy
from geometry_msgs.msg import Pose
from nav_msgs.msg import Odometry
from gazebo_msgs.msg import ModelStates
# Personalized services
from qr_robot_localization.srv import *

# Define classes
class pose:
	"""
	Representation of the pose of the robot
	"""

	def __init__(self, x=0.0, y=0.0, theta=0.0):
		self.x = x
		self.y = y
		self.theta = theta

# Create the publisher for the odometry
#reset_odom = rospy.Publisher('/mobile_base/commands/reset_odometry', Empty, queue_size=10)

# Define the dictionary wich contains the equivalence between a qr id and its coordinates in 3D
graph = {'O':[0.5,0.0],
		 'A':[0.5, 2.0],
		 'B':[-0.5, 3.5],
		 'C':[-1.0, -3.0],
		 'D':[2.0, 0.0],
		 'E':[4.0, 1.0],
		 'F':[3.5, -1.5],
		 'G':[1.5, -2.5],
		 'H':[6.5, 0.0],
		 'I':[6.5, -3.5],
		 'J':[5.0, -3.0]}

# Define program variables
qr_received = False

# Define representation variables
odom_data = [[],[],[]]
corrected_odom_data = [[],[],[]]
qr_data = [[],[],[]]
gazebo_data = [[],[],[]]
#trajectory_data = [[],[],[]]

def euler_from_quaternion(x, y, z, w):
	"""Convert the angle given in quaternion form to euler angles.

	Parameters
	----------
	x:
	  component x of the quaternion.
	y:
	  component y of the quaternion.
	z:
	  component z of the quaternion.
	w:
	  component w of the quaternion.
	"""

	# Apply formula and get roll
	t0 = +2.0 * (w*x+y*z)
	t1 = +1.0 - 2.0 * (x*x+y*y)
	roll_x = math.atan2(t0, t1)

	# Apply formula and get pitch
	t2 = +2.0 * (w*y-z*x)
	t2 = +1.0 if t2 > +1.0 else t2
	t2 = -1.0 if t2 < -1.0 else t2
	pitch_y = math.asin(t2)

	# Apply formula and get yaw
	t3 = +2.0 * (w*z+x*y)
	t4 = +1.0 - 2.0 * (y*y+z*z)
	yaw_z = math.atan2(t3, t4)

	return roll_x, pitch_y, yaw_z

def callback_qr(msg):
	"""Callback executed everytime a pose is published in the topic /qr_location

	Parameters
	----------
	msg:
	  pose of the robot in the current time.
	"""

	global qr_data
	global qr_added

	# Define the pose of the robot from the message received
	pos_rob = pose(msg.position.x, msg.position.y, msg.orientation.z)

	# Add the new data
	qr_data[0].append(pos_rob.x)
	qr_data[1].append(pos_rob.y)
	qr_data[2].append(pos_rob.theta)

#	print("QR added! Total data: {}".format(len(qr_data[0])))

def callback_odom(msg):
	""" Callback executed everytime a pose is published in the topic /odom

	Parameters
	----------
	msg:
	  pose of the robot in the current time.
	"""

	global odom_data

	# Convert the orientation received to eulers angles
	euler = euler_from_quaternion(msg.pose.pose.orientation.x, msg.pose.pose.orientation.y, msg.pose.pose.orientation.z, msg.pose.pose.orientation.w)

	# Define the pose of the robot from the message received
	pos_rob = pose(msg.pose.pose.position.x, msg.pose.pose.position.y, euler[2])

	# Add the new data
	odom_data[0].append(pos_rob.x)
	odom_data[1].append(pos_rob.y)
	odom_data[2].append(pos_rob.theta)

def callback_gazebo(msg):
	""" Callback executed everytime a pose is published in the topic /gazebo/model_states. It is used to know the real path followed by the robot.

	Parameters
	----------
	msg:
	  pose of the robot in the current time.
	"""

	global gazebo_data

	# Get the mobile_base (robot) information
	for cont in range(len(msg.name)):
		i = cont if msg.name[cont]=='mobile_base' else -1

	# Add the positions to the global data
	if i != -1:
		gazebo_data[0].append(msg.pose[i].position.x)
		gazebo_data[1].append(msg.pose[i].position.y)
		gazebo_data[2].append(msg.pose[i].orientation.z)

def trajectory_plot():
	""" Function representing the calculated trajectory and the diferent received positions.

	Parameters
	----------
	qr_data:
	  positions of the robot from qr localization.
	odom_data:
	  positions of the robot from odometry.
	gazebo_data:
	  positions of the robot from Gazebo (the real positions).
	"""

	global corrected_odom_data
	global gazebo_data
	global odom_data
	global qr_data

	# Get the QR coordinates
	qr_mark = [[],[]]
	for qr in graph:
		qr_mark[0].append(graph[qr][0])
		qr_mark[1].append(graph[qr][1])

	# Create a figure and represent the data
	with plt.style.context('seaborn-pastel'):
		fig, ax = plt.subplots()
		# Set the axis
		ax.set_xlim([-2, 7])
		ax.set_ylim([-4, 3])

		# Plot the calculated the QR localizations
		ax.plot(qr_mark[0], qr_mark[1], 'kx', markersize=15,)

		# Plot the positions data
		ax.plot(odom_data[0], odom_data[1], linewidth=2, label='Position-odom')
		ax.plot(gazebo_data[0], gazebo_data[1], linewidth=2, label='Position-Gazebo')
#		ax.plot(corrected_odom_data[0], corrected_odom_data[1], linewidth=2, label='Position-corrected-odom')
#		ax.plot(odom_data[0], odom_data[1], '.', markersize=5, label='Position-odom')
		ax.plot(corrected_odom_data[0], corrected_odom_data[1], '.', markersize=4, label='Position-corrected-odom')
		ax.plot(qr_data[0], qr_data[1], '.', markersize=7, label='Position-QR')

		# Set the information
		ax.set_xlabel('X axis')
		ax.set_ylabel('Y axis')
		ax.set_title('Robot position')
		ax.legend()

	plt.savefig("okase.png")
	plt.show()
	cv2.waitKey(0)

def detecting_qr_client():
	""" Client that request the id of the qr which is being seen the to the service location.
	"""

	# Wait until the service is operative
	rospy.wait_for_service('detecting_qr')
	try:
		# Define the service proxy for using it
		detecting_qr = rospy.ServiceProxy('detecting_qr', DetectingQR)
		# Get the value of the last qr and return it to the main function
		resp = detecting_qr()
		return resp.node

	except rospy.ServiceException as e:
		print("Service call failed: %s"%e)

def main():

	global odom_data
	global qr_data
	global corrected_odom_data

	# Initialize ROS params
	rospy.init_node('loc_controller', anonymous=True)
	rospy.Subscriber("/odom", Odometry, callback_odom)
	rospy.Subscriber("/qr_location", Pose, callback_qr)
	rospy.Subscriber("/gazebo/model_states", ModelStates, callback_gazebo)

	loc_pub = rospy.Publisher("/robot_location", Pose, queue_size=10)
	loc_msg = Pose()

	pos_rob = pose()
	correction = pose()
	qr_received_ant = "-1"
	errs = [[],[],[]]

	while(not rospy.is_shutdown()):
		# Location service call for actual localization
		qr_received = detecting_qr_client()

		# Check if there is position information
		if qr_received == "-1" and qr_received_ant != "-1":
			for e in errs[0]:
				errs[0].remove(e)
			for e in errs[1]:
				errs[1].remove(e)
			for e in errs[2]:
				errs[2].remove(e)

		if qr_received == "-1":
			if len(odom_data[0]) > 0:
				pos_rob.x = odom_data[0][len(odom_data[0])-1] - correction.x
				pos_rob.y = odom_data[1][len(odom_data[1])-1] - correction.y
				pos_rob.theta = odom_data[2][len(odom_data[2])-1] - correction.theta

				# Add the new data
				corrected_odom_data[0].append(pos_rob.x)
				corrected_odom_data[1].append(pos_rob.y)
				corrected_odom_data[2].append(pos_rob.theta)

		else:
			if len(qr_data[0]) > 0 and len(odom_data[0]) > 0:
				err_x = odom_data[0][len(odom_data[0])-1] - qr_data[0][len(qr_data[0])-1]
				err_y = odom_data[1][len(odom_data[1])-1] - qr_data[1][len(qr_data[1])-1]
				err_t = odom_data[2][len(odom_data[2])-1] - qr_data[2][len(qr_data[2])-1]

				errs[0].append(err_x)
				errs[1].append(err_y)
				errs[2].append(err_t)

				correction.x = sum(errs[0])/len(errs[0])
				correction.y = sum(errs[1])/len(errs[1])
				correction.theta = sum(errs[2])/len(errs[2])

				print("--------------------------------------------")
				print("CORR  x: {}, y: {}, t: {}".format(correction.x, correction.y, correction.theta))
				print("ERROR x: {}, y: {}, t: {}".format(err_x, err_y, err_t))
				print("ODOM  x: {}, y: {}, t: {}".format(odom_data[0][len(odom_data[0])-1], odom_data[1][len(odom_data[1])-1], odom_data[2][len(odom_data[2])-1]))
				print("QR    x: {}, y: {}, t: {}".format(qr_data[0][len(qr_data[0])-1], qr_data[1][len(qr_data[1])-1], qr_data[2][len(qr_data[2])-1]))
				print("--------------------------------------------")
				print("")

				pos_rob.x = qr_data[0][len(qr_data[0])-1]
				pos_rob.y = qr_data[1][len(qr_data[1])-1]
				pos_rob.theta = qr_data[2][len(qr_data[2])-1]

#				# Add the new data
				corrected_odom_data[0].append(pos_rob.x)
				corrected_odom_data[1].append(pos_rob.y)
				corrected_odom_data[2].append(pos_rob.theta)

			qr_received_ant = qr_received

		# 3. Publicar el valor de la posicion
#		print("{:6f},{:6f},{:6f}".format(pos_rob.x, pos_rob.y, pos_rob.theta))
		loc_msg.position.x = pos_rob.x
		loc_msg.position.y = pos_rob.y
		loc_msg.orientation.z = pos_rob.theta

#		print(loc_msg)

		loc_pub.publish(loc_msg)

	trajectory_plot()

if __name__ == '__main__':
	try:
		main()
	except rospy.ROSInterruptException: pass


#User function Template for python3

class Solution:
    #Function to merge k sorted arrays.
    def mergeKArrays(self, arr, K):
        # code here
        # return merged list
        import heapq
        heap = []
        for i in range(0, len(arr)):
            heapq.heappush(heap, (arr[i][0], i, 0))

        count = 0
        final = []
        while count < K * K:
            magnitude, i, j = heapq.heappop(heap)
            final.append(magnitude)
            if (j + 1) < len(arr):
                heapq.heappush(heap, (arr[i][j+1], i, j + 1))
            count += 1
        return final

#{
#  Driver Code Starts
#Initial Template for Python 3

if __name__=="__main__":
    t=int(input())
    for _ in range(t):
        n=int(input())
        numbers=[[ 0 for _ in range(n) ] for _ in range(n) ]
        line=input().strip().split()
        for i in range(n):
            for j in range(n):
                numbers[i][j]=int(line[i*n+j])
        ob = Solution();
        merged_list=ob.mergeKArrays(numbers, n)
        for i in merged_list:
            print(i,end=' ')
        print()
# } Driver Code Ends

Merge k Sorted Arrays - GFG/merge-k-sorted-arrays.py


import unittest

sample_set = [[1,1],[2,3],[4,3],[3,2],[5,5]]

class Test_Test_LinearRegression(unittest.TestCase):
    def test_A(self):
        self.fail("Not implemented")

if __name__ == '__main__':
    unittest.main()


"""

给定一个 N 叉树，返回其节点值的 后序遍历 。
N 叉树 在输入中按层序遍历进行序列化表示，每组子节点由空值 null 分隔（请参见示例）。

进阶：
递归法很简单，你可以使用迭代法完成此题吗?

示例 1：
输入：root = [1,null,3,2,4,null,5,6]
输出：[5,6,3,2,4,1]

示例 2：
输入：root = [1,null,2,3,4,5,null,null,6,7,null,8,null,9,10,null,null,11,null,12,null,13,null,null,14]
输出：[2,6,14,11,7,3,12,8,4,13,9,10,5,1]

"""

"""
递归
"""

class Solution:
    def preorder(self, root: 'Node') -> List[int]:
        #保存节点值
        result = []
        #后序遍历
        def pre_order(root):
            #跟节点非空入队列递归遍历
            if root:
                #递归遍历
                for node in root.children:
                    pre_order(node)
                #节点值入队列
                result.append(root.val)
        pre_order(root)
        return result

"""
迭代
"""
class Solution:
    def postorder(self, root: 'Node') -> List[int]:
        if not root:
            return []
        res = []
        stack = []
        stack.append(root)
        while stack:
            node = stack.pop()
            res.append(node.val)
            stack.extend(node.children)
        return res[::-1]

590、N 叉树的后序遍历.py

590、N 叉树的后序遍历.py


import http.server
import socketserver
import subprocess
import urllib.parse

PORT = 2728

class MyHandler(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            self.send_response(200)
            self.send_header('Content-type', 'text/html')
            self.end_headers()
            with open('index.html', 'rb') as f:
                self.wfile.write(f.read())
        else:
            self.send_response(404)
            self.end_headers()
            self.wfile.write(b'Not Found')

    def do_POST(self):
        if self.path == '/process':
            content_length = int(self.headers['Content-Length'])
            post_data = self.rfile.read(content_length).decode('utf-8')
            query = urllib.parse.parse_qs(post_data)
            user_name = query['name'][0]

            php_script_output = self.run_php_script(user_name)

            self.send_response(200)
            self.send_header('Content-type', 'text/html')
            self.end_headers()
            self.wfile.write(b'<!DOCTYPE html>')
            self.wfile.write(f'
Hello, {user_name}!
'.encode('utf-8'))
            self.wfile.write(f'
PHP Output:

{php_script_output}
'.encode('utf-8'))
            self.wfile.write(b'')
        else:
            self.send_response(404)
            self.end_headers()
            self.wfile.write(b'Not Found')

    def run_php_script(self, user_name):
        php_script = f'php -r "$html_content = \'Hello, {user_name}!\'; include(\'php_script.php\');"'
        try:
            php_output = subprocess.check_output(php_script, shell=True)
            return php_output.decode('utf-8')
        except subprocess.CalledProcessError as e:
            return f'Error: {e}'

if __name__ == '__main__':
    with socketserver.TCPServer(("", PORT), MyHandler) as httpd:
        print(f"Serving at port {PORT}")
        httpd.serve_forever()


#!/usr/bin/env python3

import sys, struct, re, math, decimal, csv

class RegPattern:
	ADDRESS_SPACE = "address_space_name\s*\[\s*\]\s*=\s*\{[^};]*\};"
	SUB_SPACE = "sub_space_name\s*\[\s*\]\s*=\s*\{[^};]*\};"
	SLAVE_COMP = "slave_component_name\s*\[\s*\]\s*=\s*\{[^};]*\};"
	MASTER_COMP = "master_component_name\s*\[\s*\]\s*=\s*\{[^};]*\};"
	ACCESS_TYPE = "access_type_name\s*\[\s*\]\s*=\s*\{[^};]*\};"
	REGPTN_ELEMENT_NAME = "\s*\"(.*)\""
	SOURCE_HEADER_END = "volatile float result_buf[AS_NUM][SS_NUM][SC_NUM][MC_NUM][AT_NUM][6];"

class SimulatorCycleToCsv:
	LATENCY_CACHE_HIT_RATIO = 0.95
	LATENCY_CACHE_NOT_FOUND_PROBABILITY = 0.05
	PITCH_CACHE_HIT_RATIO = 0.95
	PITCH_CACHE_NOT_FOUND_PROBABILITY = 0.05

	def __init__(self):
		pass

	def prepare(self):
		self.src = sys.argv[1]
		self.res = sys.argv[2]
		self.loop = sys.argv[3]
		self.csv = sys.argv[4]
		srcbuff = ""

		with open(self.src, 'r') as fp:
			buff = fp.readlines()
			for i in buff:
				mat = re.match(RegPattern.SOURCE_HEADER_END, i)
				if mat is None:
					srcbuff += i
					continue
				else:
					break

		buff = re.findall(RegPattern.ADDRESS_SPACE, srcbuff)
		self.addrSpace = re.findall(RegPattern.REGPTN_ELEMENT_NAME, buff[0])
		buff = re.findall(RegPattern.SUB_SPACE, srcbuff)
		self.subSpace = re.findall(RegPattern.REGPTN_ELEMENT_NAME, buff[0])
		buff = re.findall(RegPattern.SLAVE_COMP, srcbuff)
		self.slaveComp = re.findall(RegPattern.REGPTN_ELEMENT_NAME, buff[0])
		buff = re.findall(RegPattern.MASTER_COMP, srcbuff)
		self.masterComp = re.findall(RegPattern.REGPTN_ELEMENT_NAME, buff[0])
		buff = re.findall(RegPattern.ACCESS_TYPE, srcbuff)
		self.accessType = re.findall(RegPattern.REGPTN_ELEMENT_NAME, buff[0])

	def loadloopnum(self):
		with open(self.loop, 'rb') as fp:
			data = fp.read(24)
			buff = struct.unpack('<IIIIII', data)
			self.loopnum = []
			for i in buff:
				if i <= 0:
					i = 1
				self.loopnum.append(i);

	def calcWeight(self):
		self.weightTbl = [0, 0, 0, 0, 0]
		self.weightTbl[4] = len(self.accessType)
		self.weightTbl[3] = self.weightTbl[4] * len(self.masterComp)
		self.weightTbl[2] = self.weightTbl[3] * len(self.slaveComp)
		self.weightTbl[1] = self.weightTbl[2] * len(self.subSpace)
		self.weightTbl[0] = self.weightTbl[1] * len(self.addrSpace)

	def calcElementPosition(self, count):
		pos = [0, 0, 0, 0, 0]
		remain = count
		pos[0] = int(remain / self.weightTbl[1])
		remain = int(remain % self.weightTbl[1])
		pos[1] = int(remain / self.weightTbl[2])
		remain = int(remain % self.weightTbl[2])
		pos[2] = int(remain / self.weightTbl[3])
		remain = int(remain % self.weightTbl[3])
		pos[3] = int(remain / self.weightTbl[4])
		remain = int(remain % self.weightTbl[4])
		pos[4] = remain
		return pos

	def convert(self):
		self.calcWeight()

		dataList = []
		csvdata = []

		with open(self.res, 'rb') as resfp:
			while 1:
				data = resfp.read(16)
				if data == b'':
					break;
				buff = struct.unpack('<HHHHHHI', data)
				dataList.append(buff)

		# print (dataList)

		dataDict = {}

		dataList = sorted(dataList, key=lambda x:(x[0], x[1], x[2], x[3], x[4], x[5]))

		for i in dataList:
			list = [str(i[x]) for x in range(5)]
			key = '-'.join(list)
			if key in dataDict:
				result = dataDict[key]
			else:
				result = [0, 0, 0, 0, 0, 0]
			result[i[5]] = i[6]
			dataDict[key] = result

		for i in dataDict.items():
			keys = [int(key) for key in i[0].split('-')]
			vals = i[1]
			bw = []

			bw.append(self.addrSpace[keys[0]])
			bw.append(self.subSpace[keys[1]])
			bw.append(self.slaveComp[keys[2]])
			bw.append(self.masterComp[keys[3]])
			bw.append(self.accessType[keys[4]])

			f = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
			for j in range(6):
				f[j] = vals[j] / self.loopnum[j]

			f[2] = (f[0] * self.LATENCY_CACHE_HIT_RATIO) + (f[1] * self.LATENCY_CACHE_NOT_FOUND_PROBABILITY)
			f[5] = (f[3] * self.PITCH_CACHE_HIT_RATIO) + (f[4] * self.PITCH_CACHE_NOT_FOUND_PROBABILITY)

			ch = False
			for j in range(6):
				s = "{0:.2f}".format(f[j])
				bw.append(s)
				if f[j] > 0.00:
					ch = True
			if ch:
				csvdata.append(bw)

		count = 0;
		with open(self.csv, 'w') as outfp:
			wr = csv.writer(outfp, delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL)
			for r in csvdata:
				#print(r)
				wr.writerow(r)

	def convertSimlatorCycleToCsv(self):
		self.prepare()
		self.loadloopnum()
		self.convert()

def main():
	if len(sys.argv) != 5:
		exit()

	sim = SimulatorCycleToCsv()
	sim.convertSimlatorCycleToCsv()

if __name__ == '__main__':
	main()