import os
import numpy as np
import matplotlib.pyplot as plt
import scipy.io
from PIL import Image
from tqdm import tqdm

import cmocean as cm

from utils import clear_dir, plot_dir, velocity_dir

def simulate(lx: int = 400, ly: int = 100, max_t: int = 800_000, obst_type: str = "cylinder"):
	obst_x = lx / 5 + 1             # position of the cylinder (exact
	obst_y = ly / 2 + 3             # y-symmetry is avoided)
	obst_r = ly / 10 + 1            # radius of the cylinder

	uMax = 0.1                      # maximum velocity of Poiseuille inflow
	Re = 100                        # Reynolds number
	nu = uMax * 2 * obst_r / Re     # kinematic viscosity
	omega = 1 / (3 * nu + 1 / 2)    # relaxation parameter

	tPlot = 1 * 50                  # cycles

	# up = np.zeros(max_t)

	# D2Q9 LATTICE CONSTANTS
	t = np.array([4/9, 1/9, 1/9, 1/9, 1/9, 1/36, 1/36, 1/36, 1/36])
	cx = np.array([0, 1, 0, -1, 0, 1, -1, -1, 1])
	cy = np.array([0, 0, 1, 0, -1, 1, 1, -1, -1])
	opp = [0, 3, 4, 1, 2, 7, 8, 5, 6]
	# col = [2:(ly - 1)]
	col = np.arange(1, ly-1)
	inlet = 0               # position of inlet
	outlet = lx - 1         # position of outlet

	# x is downstream
	y, x = np.meshgrid(np.arange(1, ly + 1), np.arange(1, lx + 1))

	# Mask of the location of the obstacle
	if obst_type == "square":
		obst = np.logical_and(np.abs(x - obst_x) <= obst_r, np.abs(y - obst_y) <= obst_r)
	else:   # Cylinder
		obst = (x - obst_x) ** 2 + (y - obst_y) ** 2 <= obst_r ** 2
	# Set location of top/bottom boundary
	obst[:, [0, ly - 1]] = True
	# Boolean mask for bounce-back cells
	bbRegion = np.where(obst)

	# INITIAL CONDITION: Poiseuille profile at equilibrium
	L = ly - 2
	y_phys = y - 1.5
	ux = 4 * uMax / (L * L) * (y_phys * L - y_phys * y_phys)
	uy = np.zeros((lx, ly))
	rho = 1
	fIn = np.zeros((9, lx, ly))

	for i in range(9):
		cu = 3 * (cx[i] * ux + cy[i] * uy)
		fIn[i] = rho * t[i] * (1 + cu + 1/2 * (cu * cu) - 3/2 * (ux ** 2 + uy ** 2))

	data = []

	# MAIN LOOP (TIME CYCLES)
	for cycle in tqdm(range(max_t), desc="Lattice Boltzmann Simulation", unit="step"):

		# MACROSCOPIC VARIABLES
		rho = np.sum(fIn, axis=0)
		fIn_reshape = np.reshape(fIn, (9, lx * ly), order="F")
		# Matlab is fortran style for reshape.
		ux = np.reshape(np.dot(cx, fIn_reshape), (lx, ly), order="F") / rho
		# uy is somewhat different from MATLAB. Assuming it is due to precision
		uy = np.reshape(np.dot(cy, fIn_reshape), (lx, ly), order="F") / rho
		# For some reason the first column as been put last compare to the matlab

		# MACROSCOPIC (DIRICHLET) BOUNDARY CONDITIONS
		# Inlet: Poiseuille profile
		y_phys = col - 0.5

		ux[inlet, col] = 4 * uMax / (L * L) * (y_phys * L - y_phys * y_phys)
		uy[inlet, col] = 0
		rho[inlet, col] = (
			1 / (1 - ux[inlet, col]) *
			(
				np.sum(fIn[np.ix_([0, 2, 4], [inlet], col)], axis=0) +
				2 * np.sum(fIn[np.ix_([3, 6, 7], [inlet], col)], axis=0)
			)
		)

		# Outlet: Constant pressure
		rho[outlet, col] = 1
		ux[outlet, col] = (
			-1 + 1 / (rho[outlet, col]) *
			(
				np.sum(fIn[np.ix_([0, 2, 4], [outlet], col)], axis=0) +
				2 * np.sum(fIn[np.ix_([1, 5, 8], [outlet], col)], axis=0)
			)
		)
		uy[outlet, col] = 0

		# MICROSCOPIC BOUNDARY CONDITIONS:
		# INLET (Zou/He BC)
		fIn[1, inlet, col] = fIn[3, inlet, col] + 2 / 3 * rho[inlet, col] * ux[inlet, col]
		fIn[5, inlet, col] = (
				fIn[7, inlet, col] +
				1 / 2 * (fIn[4, inlet, col] - fIn[2, inlet, col]) +
				1 / 2 * rho[inlet, col] * uy[inlet, col] +
				1 / 6 * rho[inlet, col] * ux[inlet, col]
		)
		fIn[8, inlet, col] = (
				fIn[6, inlet, col] +
				1 / 2 * (fIn[2, inlet, col] - fIn[4, inlet, col]) -
				1 / 2 * rho[inlet, col] * uy[inlet, col] +
				1 / 6 * rho[inlet, col] * ux[inlet, col]
		)

		# OUTLET (Zou/He BC)
		fIn[3, outlet, col] = fIn[1, outlet, col] - 2 / 3 * rho[outlet, col] * ux[outlet, col]
		fIn[7, outlet, col] = (
				fIn[5, outlet, col] +
				1 / 2 * (fIn[2, outlet, col] - fIn[4, outlet, col]) -
				1 / 2 * rho[outlet, col] * uy[outlet, col] -
				1 / 6 * rho[outlet, col] * ux[outlet, col]
		)
		fIn[6, outlet, col] = (
				fIn[8, outlet, col] +
				1 / 2 * (fIn[4, outlet, col] - fIn[2, outlet, col]) +
				1 / 2 * rho[outlet, col] * uy[outlet, col] -
				1 / 6 * rho[outlet, col] * ux[outlet, col]
		)

		# Initialize equilibrium distribution
		fEq = np.zeros((9, lx, ly))
		# Initialize output distribution
		fOut = np.zeros((9, lx, ly))

		# COLLISION STEP
		for i in range(9):
			cu = 3 * (cx[i] * ux + cy[i] * uy)
			fEq[i, :, :] = rho * t[i] * (1 + cu + 1/2 * (cu * cu) - 3/2 * (ux ** 2 + uy ** 2))
			fOut[i, :, :] = fIn[i, :, :] - omega * (fIn[i, :, :] - fEq[i, :, :])

		# OBSTACLE (BOUNCE-BACK)
		for i in range(9):
			fOut[i, bbRegion[0], bbRegion[1]] = fIn[opp[i], bbRegion[0], bbRegion[1]]

		# STREAMING STEP
		for i in range(9):
			fIn[i, :, :] = np.roll(fOut[i, :, :], shift=(cx[i], cy[i]), axis=(0, 1))
		data.append(np.hstack((ux.flatten(order="F"), uy.flatten(order="F"))))
		save_flow_png(ux, uy, lx, ly, bbRegion, cycle, max_t)

		save_velocity(ux, uy, lx, ly, cycle)

	data.append(np.hstack((ux.flatten(order="F"), uy.flatten(order="F"))))
	save_sym_mat(np.array(data).T, ux, uy, lx, ly, bbRegion, x, y, obst_x, obst_y, obst_r, nu, Re, uMax)

def plot(
		ux: np.ndarray,
		uy: np.ndarray,
		lx: int,
		ly: int,
		bbRegion: np.ndarray,
		cycle: int,
		maxT: int,
		cmap=cm.cm.speed,
		save: bool = False
) -> None:
	u = np.reshape(np.sqrt(ux ** 2 + uy ** 2), (lx, ly), order="F")
	u[bbRegion[0], bbRegion[1]] = np.NAN
	plt.imshow(u.conj().T, cmap=cmap)
	plt.axis("equal")
	plt.axis("off")
	# print("A")
	plt.show()
	if save:
		plt.savefig(
		os.path.join(
			plot_dir(),
			f"{str(cycle).zfill(len(str(maxT)))}.png"
		))

def save_flow_png(
		ux: np.ndarray,
		uy: np.ndarray,
		lx: int,
		ly: int,
		bbRegion: np.ndarray,
		cycle: int,
		maxT: int,
		cmap=cm.cm.ice
) -> None:
	u = np.reshape(np.sqrt(ux ** 2 + uy ** 2), (lx, ly), order="F")
	u[bbRegion[0], bbRegion[1]] = np.NAN

	# Scale the velocity field to 0-255 range
	u_scaled = (u - np.nanmin(u)) / (np.nanmax(u) - np.nanmin(u))
	u_scaled = cmap(u_scaled.T) * 255
	u_scaled = np.uint8(u_scaled)

	# Create PIL Image object
	img = Image.fromarray(u_scaled)

	scale = 10
	new_width = int(img.width * scale)
	new_height = int(img.height * scale)

	# Resize the image
	resized_image = img.resize((new_width, new_height), resample=Image.NEAREST)

	# Save the image
	resized_image.save(
		os.path.join(
			plot_dir(),
			f"{str(cycle).zfill(len(str(maxT)))}.png"
		)
	)

def save_velocity(ux: np.ndarray, uy: np.ndarray, lx: int, ly: int, cycle: int) -> None:
	# printf('%d of %d \n', cycle, maxT)
	vx = np.reshape(ux, (lx, ly), order="F")
	vy = np.reshape(uy, (lx, ly), order="F")
	filepath = os.path.join(
		velocity_dir(),
		f"Testvelocity_{cycle}.mat"
	)

	data = {"vx": vx, "vy": vy}
	scipy.io.savemat(filepath, data)

def save_sym_mat(
		data: np.ndarray,
		ux: np.ndarray,
		uy: np.ndarray,
		lx: int,
		ly: int,
		bbRegion: np.ndarray,
		x: np.array,
		y: np.array,
		obst_x: float,
		obst_y: float,
		obst_r: float,
		nu: float,
		Re: float,
		uMax: float,
) -> None:
	vx = np.reshape(ux, (lx, ly), order="F")
	vy = np.reshape(uy, (lx, ly), order="F")
	# # no idea what the values in vx(..,..) should be. Just picking as smaller than the overall window size
	# TODO: change this mess of indices
	u = np.sqrt(vx[(2 * 50) - 1, (2 * 25) - 1] ** 2 + vy[(2 * 50) - 1, (2 * 25) - 1] ** 2)
	# up[cycle] = u
	print(data.shape)
#
	data = {
		"bbRegion":  bbRegion,
		"x":  x,
		"y":  y,
		"obst_x":  obst_x,
		"obst_y":  obst_y,
		"obst_r":  obst_r,
		"nu":  nu,
		"Re":  Re,
		"uMax":  uMax,
		"lx":  lx,
		"ly":  ly,
		"DATA": data,
		# ans
		# j
		# DATA
	}
	scipy.io.savemat(
		"./TestSymVars.mat",
		data
	)

def main():
	clear_dir(target="./plots/", extension="png")
	simulate(max_t=400, lx=100, ly=50, obst_type="square")

if __name__ == '__main__':
	main()


from flask import Blueprint, request
from google.cloud import datastore
from helper import validate_mimetype
import constants
import json

bp = Blueprint('users', __name__, url_prefix='/users')
client = datastore.Client()

@bp.route('', methods=['GET'])
def get_users():
    if request.method == 'GET':
        # Checking to see if the request Accept Header is in a valid format.
        chk_content_type = validate_mimetype(None, None, request.accept_mimetypes, 'application/json')
        if chk_content_type is not None:
            return chk_content_type
        q = client.query(kind=constants.users)
        results = list(q.fetch())
        for el in results:
            el["id"] = el.key.id
        return json.dumps(results)
    else:
        return 'That is a bad method!'


import os
import requests
import pypandoc

def download_image(url):
    response = requests.get(url)
    return response.content

def convert_doc_to_md(doc_url, access_token):
    headers = {"Authorization": "Bearer " + access_token}
    response = requests.get(doc_url, headers=headers)
    response.raise_for_status()
    doc_json = response.json()
    title = doc_json["title"]
    content_blocks = doc_json["content"]
    md_text = f"# {title}\n\n"
    for block in content_blocks:
        block_type = block["type"]
        if block_type == "text":
            md_text += block["content"] + "\n\n"
        elif block_type == "image":
            image_url = block["url"]
            image_name = os.path.basename(image_url)
            image_content = download_image(image_url)
            with open(image_name, "wb") as f:
                f.write(image_content)
            md_text += f"![{image_name}]({image_name})\n\n"
    md_text = pypandoc.convert_text(md_text, "md", format="html")
    return md_text

if __name__ == "__main__":
    doc_url = "https://test.feishu.cn/docx/test"
    access_token = "xxxxxxxxxxxxxxxxxx"
    md_text = convert_doc_to_md(doc_url, access_token)
    with open("output.md", "w", encoding="utf-8") as f:
        f.write(md_text)


import math
import numpy as np

POINT_NUM = 8 # number of points, corresponding to 2 phones
TOUCHING_DISTANCE = 6.5 # resolution of screen / width of phone past detection
CELL_ERROR = 1 # used to compensate for inherent rectangle imprecision

# points is a list of (x, y) tuples
# finds the distances for all points in 2 sets: those adjacent to the starting
# point and all others
def findDistances(points, start_point, index):
    distancesPts = []
    distancesTuples = []
    distancesList = []
    allDistancesPts = []
    allDistancesTuples = []
    for i in range(0, POINT_NUM):
        if i != index:
            distancesPts.append((start_point, points[i]))
            distancesList.append(math.sqrt(math.pow(start_point[0] - points[i][0], 2) \
                                           + math.pow(start_point[1] - points[i][1], 2)))
            distancesTuples.append((abs(start_point[0] - points[i][0]), \
                                    abs(start_point[1] - points[i][1])))
    for i in range(0, POINT_NUM):
        for j in range (0, i + 1):
            pt1 = points[i]
            pt2 = points[j]
            # don't include start point
            if pt1 != start_point and pt2 != start_point and pt1 != pt2:
                allDistancesPts.append((pt1, pt2))
                allDistancesTuples.append((abs(pt1[0] - pt2[0]), \
                                           abs(pt1[1] - pt2[1])))
    distances = np.asarray(distancesList)
    return distancesPts, distancesTuples, distances, allDistancesPts, allDistancesTuples

# finds all possible parallelograms (possibly degenerate) out of lists of points
# and distances, while taking into account possible error
def findParallelograms(distancesPts, distancesTuples, allDistancesPts, \
                       allDistancesTuples, points, start_point, sortedIndices):
    pgramList = []
    for i in range(0, POINT_NUM - 1):
        for j in range(0, len(allDistancesTuples)):
            index = sortedIndices[i]
            distance = distancesTuples[index]
            t1 = allDistancesPts[j]
            if (abs(allDistancesTuples[j][0] - distance[0]) <= TOUCHING_DISTANCE and \
                abs(allDistancesTuples[j][1] - distance[1]) <= TOUCHING_DISTANCE and \
                t1[0] != points[index] and t1[1] != points[index] and \
                t1[0] != start_point and t1[1] != start_point and t1[0] != t1[1]):
                pgramList.append((t1[0], t1[1], distancesPts[index][0], \
                                  distancesPts[index][1]))
    return pgramList

# determines if 3 points are collinear, takes as argument 3 (x, y) tuples
# representing points
def isCollinear(p1, p2, p3):
    if p1[0] != p2[0] and p1[0] != p3[0]:
        slope1 = (p2[1] - p1[1]) / float(p2[0] - p1[0])
        slope2 = (p3[1] - p1[1]) / float(p3[0] - p1[0])
        if abs(slope1 - slope2) <= CELL_ERROR:
            return True
    else:
        if (abs(p1[0] - p2[0]) <= CELL_ERROR and abs(p1[0] - p3[0]) <= CELL_ERROR):
            return True
    return False

# determines whether an input is a rectangle, with allowance for error
# takes as argument a list of 4 points
# uses the mathematical logic that rectangle diagonals should be equal length
def isRectangle(pointsList):
    pointsList = sorted(pointsList)
    dx1 = abs(pointsList[0][0] - pointsList[3][0])
    dy1 = abs(pointsList[0][1] - pointsList[3][1])
    dx2 = abs(pointsList[1][0] - pointsList[2][0])
    dy2 = abs(pointsList[1][1] - pointsList[2][1])
    dis = math.sqrt(dx1 * dx1 + dy1 * dy1)

    errdx = 0 # compensation for inherent imprecision
    errdy = 0 # compensation for inherent imprecision
    if dx2 < CELL_ERROR:
        errdx = 0
    else:
        errdx = dx2 - CELL_ERROR
    if dy2 < CELL_ERROR:
        errdy = 0
    else:
        errdy = dy2 - CELL_ERROR
    # upper and lower bounds because of inherent imprecision
    lower = math.sqrt((errdx) * (errdx) + (errdy) * (errdy))
    upper = math.sqrt((dx2 + CELL_ERROR) * (dx2 + CELL_ERROR) + \
                      (dy2 + CELL_ERROR) * (dy2 + CELL_ERROR))
    if lower < dis and upper > dis and pointsList not in pointsList:
        return True
    return False

# determines whether a rectangle has another point inside it
# takes as arguments a list of tuples corresponding to the corners of a
# rectangle, as well as a list of all possible points
def hasPointIn(rect, points):
    for j in range(0, POINT_NUM):
        if points[j] not in rect:
            # calculations for dot product
            ABx = abs(-rect[0][0] + rect[1][0])
            ABy = abs(-rect[0][1] + rect[1][1])
            ADx = abs(-rect[0][0] + rect[2][0])
            ADy = abs(-rect[0][1] + rect[2][1])
            AB = ABx * ABx + ABy * ABy
            AD = ADx * ADx + ADy * ADy
            AMx = abs(-rect[0][0] + points[j][0])
            AMy = abs(-rect[0][1] + points[j][1])
            # M inside rectangle if 0 < AM * AB < AB * AB and
            # 0 < AM * AD < AD * AD
            # http://math.stackexchange.com/questions/190111/how-to-check-if-a-point-is-inside-a-rectangle
            if AMx * ABx + AMy * ABy >= 0 and AMx * ABx + AMy * ABy < AB:
                if AMx * ADx + AMy * ADy >= 0 and AMx * ADx + AMy * ADy < AD:
                    return True
    return False

# determines the cells which correspond to the lines through the 4 vertices
# of a rectangle
def findBresenhamLines(rect):
    points1 = []
    x = 0.0
    y = 0.0
    error = 0.0
    deltax = 0.0
    deltay = 0.0
    for k in range(0, len(rect)):
        for j in range(0, k):
            if k != j:
                p1 = rect[k]
                p2 = rect[j]
                deltay = p2[1] - p1[1]
                deltax = p2[0] - p1[0]
                # positive slope cases
                # 1st octant of plane
                if (deltax >= 0 and deltay >= 0 and deltax >= deltay):
                    y = p1[1]
                    for i in range(int(p1[0]), int(p2[0]) + 1):
                        points1.append((i, y))
                        error += deltay
                        if 2 * error >= deltax:
                            error -= deltax
                            y += 1
                # 2nd octant of plane
                elif (deltax >= 0 and deltay >= 0 and deltax < deltay):
                    x = p1[0];
                    for i in range(int(p1[1]), int(p2[1]) + 1):
                        points1.append((x, i))
                        error += deltax; # increase error
                        if (2 * error >= deltay):
                            error -= deltay
                            x += 1
                # 5th octant of plane
                elif (deltax <= 0 and deltay <= 0 and deltax <= deltay):
                    y = p2[1];
                    for i in range(int(p2[0]), int(p2[0]) + 1):
                        points1.append((i, y))
                        error -= deltay
                        if (2 * error >= -deltax):
                            error += deltax # decrease error appropriately
                            y += 1
                # 6th octant of plane, increment by y
                elif (deltax <= 0 and deltay <= 0 and deltax > deltay):
                    x = p2[0];
                    for i in range(int(p2[1]), int(p1[1]) + 1):
                        points1.append((x, i))
                        error -= deltax; # increase error
                        if (2 * error >= -deltay): # if change in x is >= 0.5
                            error += deltay # decrease error appropriately
                            x += 1 # increase next x-coordinate

                # negative slope cases
                # 3rd octant of plane, increment by y
                elif (deltax <= 0 and deltay >= 0 and -deltax <= deltay):
                    x = p1[0];
                    for i in range(int(p1[1]), int(p2[1]) + 1):
                        points1.append((x, i)) # add point to list to be drawn
                        error += deltax; # decrease error
                        if (2 * error <= -deltay): # if change in x is <= -0.5
                            error += deltay; # increase error appropriately
                            x -= 1; # decrease next x-coordinate
                # 4th octant of plane, increment by x
                elif (deltax <= 0 and deltay >= 0 and -deltax > deltay):
                    y = p2[1];
                    for i in range(int(p2[0]), int(p1[0]) + 1):
                        points1.append((i, y)) # add point to list to be drawn
                        error -= deltay; # decrease error
                        if (2 * error <= deltax): # if change in y is <= -0.5
                            error -= deltax # increase error appropriately
                            y -= 1 # decrease next y-coordinate
                # 7th octant of plane, increment by y
                elif (deltax >= 0 and deltay <= 0 and deltax < -deltay):
                    x = p2[0];
                    for i in range(int(p2[1]), int(p1[1]) + 1):
                        points1.append((x, i)) # add point to list to be drawn
                        error -= deltax; # decrease error
                        if (2 * error <= deltay): # if change in x is <= -0.5
                            error -= deltay # increase error appropriately
                            x -= 1 # decrease next y-coordinate
                # 8th octant of plane, increment by x
                elif (deltax >= 0 and deltay <= 0 and deltax >= -deltay):
                    y = p1[1];
                    for i in range(p1[0], p2[0] + 1):
                        points1.append((i, y)) # add point to list to be drawn
                        error += deltay; # decrease error
                        if (2 * error <= -deltax): # if change in y is <= -0.5
                            error += deltax; # increase error appropriately
                            y -= 1; # decrease next x-coordinate
    return points1

# finds the points belonging to each set of tuples (x, y) that represent points
# on the border between them
def findTouchingLines(points1, points2):
    touchpoints1 = []
    touchpoints2 = []
    found = False
    for i in range(0, len(points1)):
        found = False
        point1 = points1[i]
        minx = point1[0] - TOUCHING_DISTANCE
        maxx = point1[0] + TOUCHING_DISTANCE
        miny = point1[1] - TOUCHING_DISTANCE
        maxy = point1[1] + TOUCHING_DISTANCE
        for j in range(0, len(points2)):
            point2 = points2[j]
            if (point2[0] >= minx and point2[0] <= maxx and \
               point2[1] >= miny and point2[1] <= maxy):
                found = True
                touchpoints2.append(point2)
        if found == True:
            touchpoints1.append(point1)

    touchpoints1 = sorted(list(set(touchpoints1)))
    touchpoints2 = sorted(list(set(touchpoints2)))
    return touchpoints1, touchpoints2

# takes a list of 4 vertices representing a rectangle, and determines which
# vertex corresponds to which on a rectangular phone
def findCorners(phone1):
    tL1 = [0, 0]
    tR1 = [0, 0]
    bL1 = [0, 0]
    bR1 = [0, 0]

    if(len(phone1) < 2):
        return None

    phone1 = sorted(phone1)

    if math.pow(phone1[0][0] - phone1[1][0], 2) + math.pow(phone1[0][1] - phone1[1][1], 2) > \
        math.pow(phone1[0][0] - phone1[2][0], 2) + math.pow(phone1[0][1] - phone1[2][1], 2):
        if phone1[0][0] != phone1[1][0]: # if distance to 1 > distance to 2
            if phone1[0][1] > phone1[1][1]: # assuming y increasing downwards
                tL1 = phone1[1]
                tR1 = phone1[3]
                bL1 = phone1[0]
                bR1 = phone1[2]
            else:
                tL1 = phone1[0]
                tR1 = phone1[2]
                bL1 = phone1[1]
                bR1 = phone1[3]
        else:
            tL1 = phone1[0]
            tR1 = phone1[2]
            bL1 = phone1[1]
            bR1 = phone1[3]
    else:
        if phone1[0][0] != phone1[1][0]:
            if phone1[0][1] > phone1[1][1]: # assuming y increasing downwards
                tL1 = phone1[0]
                tR1 = phone1[1]
                bL1 = phone1[2]
                bR1 = phone1[3]
            else:
                tL1 = phone1[2]
                tR1 = phone1[3]
                bL1 = phone1[0]
                bR1 = phone1[1]
        else:
            tL1 = phone1[2]
            tR1 = phone1[3]
            bL1 = phone1[0]
            bR1 = phone1[1]
    return tL1, tR1, bL1, bR1


#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import six
import sys
import csv
import json
import yaml
import codecs
import logging
import archieml
import validictory
import frontmatter
from django.apps import apps
from datetime import datetime
from django.core.serializers.base import DeserializationError
from bigbuild.exceptions import MissingRecommendedMetadataWarning
from django.core.serializers.json import Serializer as JSONSerializer
from django.core.serializers.pyyaml import Serializer as YAMLSerializer
from django.core.serializers.python import Deserializer as PythonDeserializer
logger = logging.getLogger(__name__)

class BigBuildJSONSerializer(JSONSerializer):
    """
    A custom JSON serializer for bigbuild models.
    """
    pass

def BigBuildJSONDeserializer(stream_or_string, **options):
    """
    Deserialize a stream or string of JSON data.
    """
    if not isinstance(stream_or_string, (bytes, six.string_types)):
        stream_or_string = stream_or_string.read()
    if isinstance(stream_or_string, bytes):
        stream_or_string = stream_or_string.decode('utf-8')
    try:
        objects = json.loads(stream_or_string)
        for obj in PythonDeserializer(objects, **options):
            yield obj
    except GeneratorExit:
        raise
    except Exception as e:
        # Map to deserializer error
        six.reraise(DeserializationError, DeserializationError(e), sys.exc_info()[2])

class BigBuildFrontmatterSerializer(YAMLSerializer):
    """
    A custom YAML frontmatter serializer for bigbuild models.
    """
    def get_dump_object(self, obj):
        # Restructure to YAML schema preferred by frontmatter
        obj.metadata = self.get_metadata(obj)
        # Pass it out
        return obj

    def end_serialization(self):
        # Dump each object into the stream as as frontmatter
        content = [frontmatter.dumps(o) for o in self.objects]
        # Write out as text to the stream in a safe string format
        [self.stream.write(six.text_type(chunk)) for chunk in content]

    def get_metadata(self, obj):
        """
        Returns the structured "metadata" associated with this page expected by Jekyll's frontmatter.
        """
        # Structure the metadata
        d = dict([
            ('headline', obj.headline),
            ('byline', obj.byline),
            ('description', obj.description),
            ('image_url', obj.image_url),
            ('pub_date', obj.pub_date),
            ('published', obj.published),
            ('show_in_feeds', obj.show_in_feeds),
        ])
        if obj.extra:
            d['extra'] = obj.extra
        if obj.data:
            d['data'] = obj.data

        # Make sure the page is valid
        if not self.is_metadata_valid(d):
            raise ValueError("Metadata is not valid for %s" % obj)

        return d

    def is_metadata_valid(self, metadata):
        """
        Tests if the metadata is valid and returns True or False.
        """
        schema = {
            "type": "object",
            "properties": {
                'headline': {"type": "string", "blank": True},
                'byline': {"type": "string", "blank": True},
                'description': {"type": "string", "blank": True},
                'image_url': {"type": "any", "blank": True},
                'pub_date': {"type": "any"},
                'published': {"type": "boolean"},
                'show_in_feeds': {"type": "boolean"},
            }
        }
        try:
            validictory.validate(metadata, schema)
            if not isinstance(metadata['pub_date'], datetime):
                return False
            return True
        except Exception:
            return False

class BaseBigBuildFrontmatterDeserializer(object):
    """
    Abstract method for deserializing YAML data from Jekyll's frontmatter format.
    """
    def deserialize(self, slug):
        """
        Retrieves the provided slug and returns a bigbuild object
        """
        logger.debug("Retrieving {} as {} object".format(
            slug,
            self.model.__name__
        ))
        obj = self.model.create(slug=slug, skip_create_directory=True)
        try:
            # Sync the metadata from the YAML frontmatter with the object
            obj = self.set_metadata(obj)
            # Pass it out
            return obj
        except Exception as e:
            # Map to deserializer error
            six.reraise(DeserializationError, DeserializationError(e), sys.exc_info()[2])

    def set_metadata(self, obj):
        """
        Syncs metadata with YAML frontmatter with provided bigbuild model object.
        """
        stream = open(obj.frontmatter_path, 'r')
        post = frontmatter.load(stream)

        # Set the basic frontmatter metadata
        obj.headline = post.metadata['headline']
        obj.byline = post.metadata['byline']
        obj.description = post.metadata['description']
        obj.image_url = post.metadata['image_url']
        obj.pub_date = post.metadata['pub_date']
        obj.published = post.metadata['published']
        obj.show_in_feeds = post.metadata['show_in_feeds']

        # Attach any extra stuff
        try:
            obj.extra = post.metadata['extra']
        except KeyError:
            obj.extra = {}

        try:
            obj.data = post.metadata['data']
        except KeyError:
            obj.data = {}

        # Pull in the content as is
        obj.content = post.content

        # Render it out as flat HTML
        obj.content = obj.rendered_content

        # Make sure the page has recommended metadata
        # ... if it's ready to publish
        if obj.pub_status in ['live', 'pending']:
            if not obj.has_recommended_metadata():
                logger.warn(MissingRecommendedMetadataWarning(obj))

        # Pass it back out
        return obj

class PageFrontmatterDeserializer(BaseBigBuildFrontmatterDeserializer):
    """
    Deserializes Jekyll frontmatter from YAML to a bigbuild Page object.
    """
    def __init__(self):
        self.model = apps.get_app_config('bigbuild').get_model('Page')

    def set_metadata(self, obj):
        """
        Extends the base deserialization with techniques for syncing data files.
        """
        obj = super(PageFrontmatterDeserializer, self).set_metadata(obj)

        # Reopen the YAML frontmatter
        stream = open(obj.frontmatter_path, 'r')
        post = frontmatter.load(stream)

        # Loop through any data files
        for key, path in post.metadata.get('data', {}).items():

            # Generate the path if it's stored in the default `data` directory
            data_dir = os.path.join(obj.page_directory_path, 'data')
            p = os.path.join(data_dir, path)
            # If it doesn't exist, see if it's in another folder
            if not os.path.exists(p):
                p = os.path.join(obj.page_directory_path, path)
                # If it's not there either, throw an error
                if not os.path.exists(p):
                    logging.debug("Data file could not be found at %s" % p)

            # Open the file
            with codecs.open(p, 'r') as f:
                # If it's a CSV file open it that way...
                if p.endswith(".csv"):
                    obj.data_objects[key] = list(csv.DictReader(f))
                # If it's a JSON file open it this way ...
                elif p.endswith(".json"):
                    obj.data_objects[key] = json.load(f)
                # If it's a YAML file open it t'other way ...
                elif (p.endswith(".yml") or p.endswith(".yaml")):
                    obj.data_objects[key] = yaml.load(f)
                elif p.endswith(".aml"):
                    obj.data_objects[key] = archieml.load(f)
                # If it's none of those throw an error.
                else:
                    logging.debug("Data file at %s not recognizable type" % path)

        # Pass it back out
        return obj

class ArchivedPageFrontmatterDeserializer(BaseBigBuildFrontmatterDeserializer):
    """
    Deserializes Jekyll frontmatter from YAML to a bigbuild ArchivedPage object.
    """
    def __init__(self):
        self.model = apps.get_app_config('bigbuild').get_model('ArchivedPage')

#
# Lookups
#

deserializers = {
    'Page': PageFrontmatterDeserializer,
    'ArchivedPage': ArchivedPageFrontmatterDeserializer
}


#!/usr/bin/env python
import rospy
from std_msgs.msg import String
from std_msgs.msg import UInt8
from std_msgs.msg import Float32

#need to check these
import cv2
import math
import time
from board import SCL, SDA
import busio
import os
from adafruit_pca9685 import PCA9685
from adafruit_motor import servo

channel_motor = 15
i2c = busio.I2C(SCL, SDA)
pca = PCA9685(i2c)
pca.frequency = 100
channel_num = 14
servo7 = servo.Servo(pca.channels[channel_num])
steer_ref = 94
servo7.angle = steer_ref

from adafruit_motor import servo
from adafruit_pca9685 import PCA9685

found_pole = 0
ref_row = 1
def callback(data):
    global found_pole
    global ref_row
    global pca
    global channel_motor
    global first_time
    rospy.loginfo(data.data)
    pole = data.data
#    servo7.angle = steer_ref
#   adding time delay in order to get lidar to agree again
    if pole == 1 and found_pole == 1 and time.time() > first_time:
        print("stopping")
        #pca.channels[channel_motor].duty_cycle = math.floor(.15*65535)
        #pca.channels[channel_motor].duty_cycle = math.floor(.15*65535)

#    if pole == 1 and found_pole == 0:
    elif pole == 1 and found_pole == 0:
        first_time = time.time() + 6
        time.sleep(0.5)
        print("turning")
        servo7.angle = 110
        time.sleep(3.8)
        servo7.angle = steer_ref
#        time.sleep(2)
        found_pole = 1

def motor():

    # In ROS, nodes are uniquely named. If two nodes with the same
    # name are launched, the previous one is kicked off. The
    # anonymous=True flag means that rospy will choose a unique
    # name for our 'listener' node so that multiple listeners can
    # run simultaneously.
    rospy.init_node('motor', anonymous=True)

    rospy.Subscriber("pole_detection", UInt8, callback)

    # spin() simply keeps python from exiting until this node is stopped
    rospy.spin()

if __name__ == '__main__':
    motor()


"""
Calibrate smoth rssi for the analysis
"""

from datetime import datetime, timedelta
import logging
import time
from common.telnet import Telnet
from programs.info_connected_stations import get_connected_stations, parse_telnet_output

logger = logging.getLogger(__name__)

COMMANDS = {
    "get station info": "echo -n 'EE''EE '; wl -i BAND sta_info MAC_ADDRESS; echo 'FF''FF'",
}

VALUES_TO_CALIBRATE = ["smoothed rssi"]

def run_calibrate_station(
    telnet: Telnet,
    station_mac: str,
):
    """Entry point for initial calibrate stations program"""

    logger.info(
        f"RUNNING PROGRAM: initial calibrate station MAC: {station_mac}")

    now = datetime.now()

    while True:
        next_sample_at = now + timedelta(seconds=1)

        # Get number of connected stations
        total_connections, connected_stations_2_4GHz, connected_stations_5GHz = get_connected_stations(
            telnet)

        connected_stations = connected_stations_2_4GHz + connected_stations_5GHz
        if total_connections > 0:
            # Check if station to calibrate is connected
            if station_mac in connected_stations:
                connected_to_band = "5GHz" if station_mac in connected_stations_5GHz else "2.4GHz"
                # retrieve station info
                sta_info_command = COMMANDS["get station info"].replace(
                    "MAC_ADDRESS", station_mac)
                if connected_to_band == "5GHz":
                    sta_info_command = sta_info_command.replace("BAND", "wl0")
                elif connected_to_band == "2.4GHz":
                    sta_info_command = sta_info_command.replace("BAND", "wl2")
                else:
                    sta_info_command = sta_info_command.replace("BAND", "wl1")
                station_info_result_brut = telnet.send_command_and_read_result(
                    sta_info_command)
                _raw_station_info = str(parse_telnet_output(
                    station_info_result_brut)).split("\r\n")[1:-1]

                # create entry
                for key in VALUES_TO_CALIBRATE:
                    for line in _raw_station_info:
                        if key in line:
                            value = line.split(key)[1][1:].replace("= ", "")
                            logger.info(f"{key}: {value}")
            else:
                logger.error(f"The station {station_mac} is not connected")
        else:
            logger.error(f"The station {station_mac} is not connected")

        now = datetime.now()

        while now < next_sample_at:
            time.sleep(0.1)
            now = datetime.now()


# Day 11: - Sets

# Sets are a little different to the collections we've looked at so far, in that they're not reliably ordered
# If we create a list or a tuple and print it, we know that the items will show up in the order we defined them.
# This isn't the case for a set.
# Sets can also only contain unique elements, much like we saw with dictionary keys.
# In fact, we can really think of a set as a dictionary which only contains keys.
# They're therefore very useful for filtering values, and it's also extremely efficient to perform these
# kinds of membership tests for sets

# Defining a set : set()
vegetables = {"carrot", "lettuce", "broccoli", "onion", "carrot"}

# nested_sets = {{1,  2,  3},  {"a",  "b",  "c"}}  # TypeError: unhashable type: 'set'
vegetables.add("potato")
print(vegetables)  # {'lettuce', 'broccoli', 'onion', 'potato', 'carrot'}

# The union of two sets is essentially the combination of the two sets
letters = {"a", "b", "c"}
numbers = {1, 2, 3}
letters_and_numbers = letters.union(numbers)
print(letters_and_numbers)  # {'a', 'c', 1, 2, 3, 'b'}

# When we find the intersection of two sets, we get a new set containing the elements common to both sets
mod_2 = {2, 4, 6, 8, 10, 12, 14, 16, 18}
mod_3 = {3, 6, 9, 12, 15, 18}
mod_6 = mod_2.intersection(mod_3)
print(mod_6)  # {18, 12, 6}

# We have to be a little bit careful when using difference, because unlike the other set operations we've mentioned,
# with difference the order of the sets matters
bundle_1 = {"Resident Evil 3", "Final Fantasy VII", "Cyberpunk 2077"}
bundle_2 = {"Doom Eternal", "Halo Infinite", "Resident Evil 3"}
print(bundle_1.difference(bundle_2))  # {'Final Fantasy VII', 'Cyberpunk 2077'}
print(bundle_2.difference(bundle_1))  # {'Halo Infinite', 'Doom Eternal'}

# symmetric_difference gives us all of the items which only feature in one of the sets.
# Unlike difference the order of the sets doesn't matter.
bundle_1 = {"Resident Evil 3", "Final Fantasy VII", "Cyberpunk 2077"}
bundle_2 = {"Doom Eternal", "Halo Infinite", "Resident Evil 3"}
print(
    bundle_1.symmetric_difference(bundle_2))  # {'Cyberpunk 2077', 'Final Fanstay VII', 'Halo Infinite', 'Doom Eternal'}

# We can only call the set operator methods on sets, but we can actually pass in any collection we like into the method
# Checking if items are in collections
print("j" in "Python")  # False
print("n" in "Python")  # True

student = {
    "name": "Eric Cartman",
    "age": 10,
    "school": "South Park Elementary"
}

print("grades" in student)  # False
print("school" in student)  # True

"""Exercises

1) Create an empty set and assign it to a variable.

2) Add three items to your empty set using either several add calls, or a single call to update.

3) Create a second set which includes at least one common element with the first set.

4) Find the union, symmetric difference, and intersection of the two sets. Print the results of each operation.

5) Create a sequence of numbers using range, then ask the user to enter a number. Inform the user whether or not their
number was within the range you specified."""

# 1) Create an empty set and assign it to a variable
set = set()

# for number in range(0,4):
#     set.add(number)
#     print(set)

# 2) Add three items to your empty set using either several add calls, or a single call to update
set.update(range(1, 4))
print(set)

# 3) Create a second set which includes at least one common element with the first set.
second_set = {2, 3}

# 4) Find the union, symmetric difference, and intersection of the two sets. Print the results of each operation.
union = set.union(second_set)
print(f'The union of the 2 sets is : {union}')

intersection = set.intersection(second_set)
print(f'The intersection of the 2 sets is : {intersection}')

symetric_diff = set.symmetric_difference(second_set)
print(f'The symetric difference of the 2 sets is : {symetric_diff}')

# Or this way:
# set2 = set()
# set2.update(range(1, 4))
#
# random_values = {"r", 1, ("Python", "C", "Rust")}
#
# print(set2.union(random_values))
# print(set2.symmetric_difference(random_values))
# print(set2.intersection(random_values))

# 5) Create a sequence of numbers using range, then ask the user to enter a number. Inform the user whether or not their
# number was within the range you specified.

sequence = range(0,20)
number = int(input("Please enter a number : "))

if number in sequence :
    print("The number you choose is in the sequence!")
else:
    print("The number you choose is not in the sequence!")

# Or :
numbers = range(27, 54)
user_number = int(input("Enter a number: "))

if user_number in numbers:
    print("Your number is in the valid range.")
else:
    if user_number < numbers[0]:
        print("Your number is too low.")
    else:
        print("Your number is too high.")


class node:
    def __init__(self, x):
        self.k = x
        self.l = None
        self.r = None
        self.p = None
        self.h = 1

class tree:
    def __init__(self):
        self.root = None

    def insert(self, x):
        if self.root is None:
            self.root = node(x)

        tmp = self.root
        while tmp:
            if x<tmp.k:
                if tmp.l:
                    tmp = tmp.l
                else:
                    tmp.l = node(x)
                    tmp.l.p = tmp
                    return
            elif x>tmp.k:
                if tmp.r:
                    tmp = tmp.r
                else:
                    tmp.r = node(x)
                    tmp.r.p = tmp
                    return
            else:
                return
        return

    def height_set(self, x):
        tmp = self.root
        while tmp:
            if x<tmp.k:
                tmp = tmp.l
            elif x>tmp.k:
                tmp = tmp.r
            else:
                break

        while tmp.p:
            if tmp.p.h <= tmp.h:
                tmp.p.h = tmp.h + 1
            tmp = tmp.p

    def rotateleft(self,el):
        tmp = el.r
        el.r = tmp.l
        tmp.l = el
        if self.hi(el.r) > self.hi(el.l):
            el.h = self.hi(el.r) + 1
        else:
            el.h = self.hi(el.l) + 1
        if self.hi(tmp.r) > self.hi(tmp.l):
            tmp.h = self.hi(tmp.r) + 1
        else:
            tmp.h = self.hi(tmp.l) + 1
        self.root = tmp

    def rotateright(self, el):
        tmp = el.l
        el.l = tmp.r
        tmp.r = el
        if self.hi(el.r) > self.hi(el.l):
            el.h = self.hi(el.r) + 1
        else:
            el.h = self.hi(el.l) + 1
        if self.hi(tmp.r) > self.hi(tmp.l):
            tmp.h = self.hi(tmp.r) + 1
        else:
            tmp.h = self.hi(tmp.l) + 1

        self.root.r = tmp

    def hi(self, el):
        if el:
            return el.h
        else:
            return 0

    def bal(self, el):
        return self.hi(el.r) - self.hi(el.l)

    def balance(self):
        if self.hi(self.root.r) > self.hi(self.root.l):
            self.root.h = self.hi(self.root.r) + 1
        else:
            self.root.h = self.hi(self.root.l) + 1

        if self.bal(self.root) >= 2:
            if self.bal(self.root.r) < 0:
                self.rotateright(self.root.r)
            self.rotateleft(self.root)
            return

def output(el):
    if el is None:
        return

    out.append(el.k)

    if el.l:
        lo[el.k] = len(out) + 1
    else:
        lo[el.k] = 0

    output(el.l)

    if el.r:
        ro[el.k] = len(out) + 1
    else:
        ro[el.k] = 0

    output(el.r)

fi = open("rotation.in")
fo = open("rotation.out", "w")

n = int(fi.readline())
data = [None for _ in range(n+1)]
left = [None for _ in range(n + 1)]
right = [None for _ in range(n + 1)]
i = 1
for line in fi:
    tmp = [int(_) for _ in line.split()]
    data[i] = tmp[0]
    left[i] = tmp[1]
    right[i] = tmp[2]
    i+=1

T = tree()
T.root = node(data[1])
for i in range(1,n+1):
    if left[i]:
        T.insert(data[left[i]])
    if right[i]:
        T.insert(data[right[i]])
    if left[i]+right[i] == 0:
        T.height_set(data[i])

out = []
lo = {}
ro = {}
T.balance()
output(T.root)
print(len(out), file=fo)
for i in range(1, n+1):
    print(out[i-1], lo[out[i-1]], ro[out[i-1]], file=fo)

fi.close()
fo.close()


from consolemenu import *
from consolemenu.items import *
import psutil
import os
import random
import json
import xml.etree.ElementTree as ET
import zipfile

def print_disk_info():
  disk_info = []

  for part in psutil.disk_partitions(all=False):
    if os.name == 'nt':
      if 'cdrom' in part.opts or part.fstype == '':
        continue

    usage = psutil.disk_usage(part.mountpoint)

    print("device:", part.device)
    print("total:", usage.total)
    print("used:", usage.used)
    print("free:", usage.free)
    print("percent:", usage.percent)
    print("fstype:", part.fstype)
    print("mountpoint:", part.mountpoint)
    print()

  input()

def create_file():
  f = open(input("Enter filename: "), "w+")
  f.close()

def write_to_file():
  f = open(input("Enter filename: "), "w+")
  f.write(input("Enter text: "))
  f.close()

def read_all_file():
  f = open(input("Enter filename: "), "r")
  print(f.read())
  f.close()
  input()

def delete_file():
  os.remove(input("Enter filename: "))

def create_text_file_menu():
  text_file_menu = ConsoleMenu("Security soft", "Text file")

  create_file_function_item = FunctionItem("Create file", create_file)
  write_text_to_file_function_item = FunctionItem("Write text", write_to_file)
  read_text_from_file_function_item = FunctionItem("Read text", read_all_file)
  delete_file_function_item = FunctionItem("Delete file", delete_file)

  text_file_menu.append_item(create_file_function_item)
  text_file_menu.append_item(write_text_to_file_function_item)
  text_file_menu.append_item(read_text_from_file_function_item)
  text_file_menu.append_item(delete_file_function_item)

  return text_file_menu

class some_struct():
  def __init__(self, id, name, some_doubles):
    self.id = id
    self.name = name
    self.some_doubles = some_doubles

def get_some_struct():
  id = int(input("id = "))
  name = input("name = ")
  some_doubles = []
  for i in range(0, 5):
    some_doubles.append(random.random())

  return some_struct(id, name, some_doubles)

def write_json_obj_to_file():
  ss = get_some_struct()

  f = open(input("Enter filename: "), "w+")
  f.write(json.dumps(ss.__dict__))
  f.close()

def create_json_file_menu():
  json_file_menu = ConsoleMenu("Security soft", "Json file")

  create_file_function_item = FunctionItem("Create file", create_file)
  write_obj_to_file_function_item = FunctionItem("Write json object", write_json_obj_to_file)
  read_text_from_file_function_item = FunctionItem("Read text", read_all_file)
  delete_file_function_item = FunctionItem("Delete file", delete_file)

  json_file_menu.append_item(create_file_function_item)
  json_file_menu.append_item(write_obj_to_file_function_item)
  json_file_menu.append_item(read_text_from_file_function_item)
  json_file_menu.append_item(delete_file_function_item)

  return json_file_menu

def write_xml_obj_to_file():
  ss = get_some_struct()

  data = ET.Element("some_struct")

  id_element = ET.SubElement(data, "id")
  id_element.text = str(ss.id)

  name_element = ET.SubElement(data, "name")
  name_element.text = ss.name

  some_doubles_element = ET.SubElement(data, "some_doubles")
  for some_double in ss.some_doubles:
    some_double_element = ET.SubElement(some_doubles_element, "some_double")
    some_double_element.text = str(some_double)

  f = open(input("Enter filename: "), "w+")
  f.write(ET.tostring(data).decode())
  f.close()

def create_xml_file_menu():
  xml_file_menu = ConsoleMenu("Security soft", "Xml file")

  create_file_function_item = FunctionItem("Create file", create_file)
  write_obj_to_file_function_item = FunctionItem("Write xml object", write_xml_obj_to_file)
  read_text_from_file_function_item = FunctionItem("Read text", read_all_file)
  delete_file_function_item = FunctionItem("Delete file", delete_file)

  xml_file_menu.append_item(create_file_function_item)
  xml_file_menu.append_item(write_obj_to_file_function_item)
  xml_file_menu.append_item(read_text_from_file_function_item)
  xml_file_menu.append_item(delete_file_function_item)

  return xml_file_menu

def create_zip_archive():
  f = zipfile.ZipFile(input("Enter filename: "), "w")
  f.close()

def add_file_to_zip():
  f = zipfile.ZipFile(input("Enter archive name: "), "a")
  path_to_file = input("Enter filename: ")
  f.write(path_to_file, os.path.basename(path_to_file))
  f.close()

def get_file_from_zip():
  archive = zipfile.ZipFile(input("Enter archive name: "), "r")

  filename = input("Enter filename: ")
  data = archive.read(filename)
  archive.close()

  f = open(filename, "w+b")
  f.write(data)
  f.close()

  print("size:", os.path.getsize(filename))
  print("modify timestamp:", os.path.getmtime(filename))
  input()

def create_zip_file_menu():
  zip_file_menu = ConsoleMenu("Security soft", "Zip file")

  create_file_function_item = FunctionItem("Create zip archive", create_zip_archive)
  add_file_to_zip_function_item = FunctionItem("Add file to zip archive", add_file_to_zip)
  get_file_from_zip_function_item = FunctionItem("Get file from zip archive", get_file_from_zip)
  delete_file_function_item = FunctionItem("Delete zip archive", delete_file)

  zip_file_menu.append_item(create_file_function_item)
  zip_file_menu.append_item(add_file_to_zip_function_item)
  zip_file_menu.append_item(get_file_from_zip_function_item)
  zip_file_menu.append_item(delete_file_function_item)

  return zip_file_menu

def create_menu():
  menu = ConsoleMenu("Security soft", "Lab2")

  menu.append_item(FunctionItem("Get logic disks info", print_disk_info))
  menu.append_item(SubmenuItem("Text file", create_text_file_menu()))
  menu.append_item(SubmenuItem("Json file", create_json_file_menu()))
  menu.append_item(SubmenuItem("Xml file", create_xml_file_menu()))
  menu.append_item(SubmenuItem("Zip file", create_zip_file_menu()))

  return menu

def main():
  menu = create_menu()
  menu.show()

if __name__ == "__main__":
  main()


import datetime

from pytz import timezone

from processors import NexusTileProcessor

EPOCH = timezone('UTC').localize(datetime.datetime(1970, 1, 1))

class NormalizeTimeBeginningOfMonth(NexusTileProcessor):
    def process_nexus_tile(self, nexus_tile):
        the_tile_type = nexus_tile.tile.WhichOneof("tile_type")

        the_tile_data = getattr(nexus_tile.tile, the_tile_type)

        time = the_tile_data.time

        timeObj = datetime.datetime.utcfromtimestamp(time)

        timeObj = timeObj.replace(day=1)

        timeObj = timezone('UTC').localize(timeObj)

        the_tile_data.time = int((timeObj - EPOCH).total_seconds())

        yield nexus_tile


# -*- coding: utf-8 -*-
from django.http import Http404
from ..models import UserSocialProfile, Poll
from ..forms import PollForm
from django.conf import settings
from django.http import Http404

class polls_help():

    def is_party_manager(self, request):
        '''To find out if user manager of the app or not'''
        manager_social_id = settings.PARTY_MANAGER_VK_SOCIAL_ID
        user = request.user
        # find the profile
        try:
            social_user = UserSocialProfile.objects.get(user=user)
        except:
            raise Http404("Такого профиля социальной сети ВКонтакте нет в базе.")

        if social_user.social_id == manager_social_id:
            return True
        else:
            return None

    def arrange_poll_form(self, request, form):
        '''To arrange params for the poll form'''
        user = request.user
        try:
            vk_social_user = UserSocialProfile.objects.get(user=user)
        except:
            raise Http404("Такого профиля социальной сети ВКонтакте нет в базе.")
        return {'form': form, 'vk_social_user': vk_social_user}


import random
from words import words
import string

def get_word(words, mode):
    word = random.choice(words)
    l = 1 + mode * 2
    while '-' in word or ' ' in word or len(word) < l:
        word = random.choice(words)
    return word

def hangman():

    print(f"\nWelcome to Hangman Game, choosing difficulty and start the game.\n")
    mode = -1
    while mode < 0 or mode > 3:
        mode = int(input("\
 1.Easy         \n\
 2.Medium       \n\
 3.Hard         \n\n\
Your choice: "))
    # print(mode)
    if mode == 1:
        print(f"Easy Mode\n")
        lives = 10
    elif mode == 2:
        print(f"Medium Mode\n")
        lives = 6
    elif mode == 3:
        print(f"Hard Mode\n")
        lives = 3
    else:
        print(f"Hardcore\n")
        mode = 4
        lives = 2

    word = get_word(words, mode).upper()
    word_set = set(word)
    print(word)
    guess = ''
    letters = set(string.ascii_uppercase)
    print(letters)
    attempt = set()
    while lives > 0 and len(word_set) > 0:
        print(f"You have {lives} lives, and you tried these letters:", ' '.join(attempt))

        word_list = [l if l in attempt else '-' for l in word]

        print(f"Current word: ", ' '.join(word_list))
        print(" ")

        guess = input("Make a guess: ").upper()

        if guess in letters - attempt:
            attempt.add(guess)
            if guess in word_set:
                word_set.remove(guess)
            else:
                lives -= 1
        elif guess in attempt:
            print(f"\nYou have already try {guess}. Try again.\n")
        else:
            print(f"\nInvalid input. Try again.\n")
    if lives > 0:
        print(f"\n You made it! The answer is ", word.lower())
    else:
        print(f"\n Fail! The answer is ", word.lower())
hangman()


from fastapi import FastAPI, Request, Response, status
from fastapi.middleware.cors import CORSMiddleware

from src import __version__
from src.settings import init_db
from src.utils import get_features_from_db, get_feature_from_nominatim
from src.validators import authenticate, validate_zoom_level

app = FastAPI(version=__version__)

app.add_middleware(
    CORSMiddleware,
    allow_credentials=True,
    allow_headers=["*"],
    allow_methods=["*"],
    allow_origins=["*"],
)

@app.on_event("startup")
async def start_db():
    await init_db()

@app.get("/")
def home():
    return {"version": app.version}

@app.get("/polygons")
async def polygons(zoom_level: str, codes: str, request: Request):
    authenticate(request)

    validate_zoom_level(zoom_level)

    return await get_features_from_db(zoom_level, codes)

@app.post("/add_polygon", status_code=201)
async def add_polygon(zoom_level: str, code: str, request: Request, response: Response):
    authenticate(request)

    validate_zoom_level(zoom_level)

    feature, from_db = await get_feature_from_nominatim(zoom_level, code)

    if from_db:
        response.status_code = status.HTTP_200_OK

    return feature


import pandas as pd
from bs4 import BeautifulSoup
import re

f = open('AS_publications2019-21.txt', 'r')

i=0
j=0
k=0
l=0
m=0
n=0
titles = []
authors_list = []
biblio_codes = []
keywords = []
abstracts = []
urls = []

a_re = "[A-Z][a-zA-Z]+\s?[a-zA-Z0-9.]+\s?[+-]?\s?[0-9]?[0-9]+"
b_re = "[M][0-9]?[0-9]+"
c_re = "[0-9][A-Z][+]?\s?[0-9]+[+-.]?[0-9]+"
d_re = "[A-Z][0-9]+\s?[A-Z][a-z]+"
e_re = "[A-Z][0-9]+\s?[A-Z][a-z]+"

source_names = []

source_set = None

a=False
b=False
c=False

for line in f.readlines():
    if line.__contains__("Title:"):
        title = line.split("Title:")[-1].strip()
        print(title)
        titles.append(title)
        i+=1

        x = re.findall(a_re, title)
        source_set = set(x)
        y = re.findall(b_re, title)
        source_set.update(set(y))
        z = re.findall(c_re, title)
        source_set.update(set(z))
        w = re.findall(d_re, title)
        source_set.update(set(w))
        v = re.findall(e_re, title)
        source_set.update(set(v))

        a=True

    elif line.__contains__("Authors:"):
        authors = line.split("Authors:")[-1].strip()
        print(authors)
        authors_list.append(authors)
        j+=1

    elif line.__contains__("Bibliographic Code:"):
        code = line.split("Bibliographic Code:")[-1].strip()
        print(code)
        biblio_codes.append(code)
        k+=1

    elif line.__contains__("Keywords:"):
        keyword = line.split("Keywords:")[-1].strip()
        print(keyword)
        l+=1
        keywords.append(keyword)

        x = re.findall(a_re, keyword)
        source_set.update(set(x))
        y = re.findall(b_re, keyword)
        source_set.update(set(y))
        z = re.findall(c_re, keyword)
        source_set.update(set(z))
        w = re.findall(d_re, keyword)
        source_set.update(set(w))
        v = re.findall(e_re, keyword)
        source_set.update(set(v))

        c=True

    elif line.__contains__("Abstract:"):
        abstract = line.split("Abstract:")[-1].strip()
        print(abstract)
        abstracts.append(abstract)
        m+=1

        x = re.findall(a_re, abstract)
        source_set.update(set(x))
        y = re.findall(b_re, abstract)
        source_set.update(set(y))
        z = re.findall(c_re, abstract)
        source_set.update(set(z))
        w = re.findall(d_re, abstract)
        source_set.update(set(w))
        v = re.findall(e_re, abstract)
        source_set.update(set(v))

        b=True

    elif line.__contains__("URL:"):
        url_line = BeautifulSoup(line)
        for tag in url_line.findAll('a', href=True):
            url = tag['href']
        print(url)
        urls.append(url)
        n+=1

    elif a and b and c:
        source_names.append(list(source_set))
        b=False
        c=False

print(i)
print(j)
print(k)
print(l)
print(m)
print(n)
print(len(source_names))

df = pd.DataFrame({'Title':titles, 'URL':urls, 'Sources':source_names, 'Authors':authors_list, 'Keywords':keywords, 'Abstract':abstracts})

df.to_csv('publications.csv')


import af
import glb

default = 17777.0

class Print (af.Print):

	def __init__ (self, rnglist,
			start = default,
			end = default,
			frm = default,
			scale = default,
			desc=default):

		pl = glb.sch.GetPrintList ()
		self.this = af.Print (pl.Add())
		rl = af.TList (self.SetRangeList())
		for i in rnglist:
			rl.Add (i)
		pl = af.TList (self.SetParameterList())
		if start != default:
			dt = af.TReal (pl.Add())
			dt.SetName ('START')
			dt.SetValue (start)
		if end != default:
			dt = af.TReal (pl.Add())
			dt.SetName ('END')
			dt.SetValue (end)
		if frm != default:
			dt = af.TReal (pl.Add())
			dt.SetName ('FROM')
			dt.SetValue (frm)
		if scale != default:
			dt = af.TReal (pl.Add())
			dt.SetName ('SCALE')
			dt.SetValue (scale)
		if desc != default:
			self.SetDescription(desc)


from flask import jsonify, request, abort
from flask_sqlalchemy import SQLAlchemy

from routes import routes
import views

db = SQLAlchemy

# GET /api/search?kw={kw}
@routes.route("/api/search", methods=['GET'])
def get_search():
    kw = request.args.get('kw', type=str, default='')  # 검색어
    page = request.args.get('page', type=int, default=1)
    try:
        if kw:
            puppies, meta = views.get_search(kw, page)
            return jsonify({
                'success': True,
                'data': puppies,
                'meta': meta
            })

    except:
        abort(500, "Something wrong in database")


# Definition for singly-linked list.
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

class Solution:
    def add_all(self, result, ln):
        if not ln:
            return
        result.append(ln.val)
        if ln.next == None:
            return
        else:
            self.add_all(result, ln.next)

    def create_list(self, result):
        if len(result) != 0:
            ln = ListNode(result[0])
            result.remove(result[0])
            next = self.create_list(result)
            ln.next = next
            return ln
        else:
            return None

    def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode:
        result = []
        self.add_all(result, l1)
        self.add_all(result, l2)
        result.sort()
        # result.reverse()
        ln = self.create_list(result)
        return ln

def print_all(ln):
    if ln:
        print(ln.val)
        print_all(ln.next)

if __name__ == '__main__':
    s = Solution()
    # l1 = [1, 2, 4]
    # l2 = [1, 3, 4]
    l1 = ListNode(1, ListNode(2, ListNode(4)))
    l2 = ListNode(1, ListNode(3, ListNode(4)))

    result = s.mergeTwoLists(l1, l2)
    print_all(result)


import subprocess
import sys

try:
    import prompt_toolkit
except ImportError:
    subprocess.run([f"{sys.executable} -m pip install prompt-toolkit"], shell=True)

from prompt_toolkit.shortcuts import (checkboxlist_dialog, input_dialog,
                                      message_dialog, radiolist_dialog)
from prompt_toolkit.shortcuts.dialogs import yes_no_dialog
from prompt_toolkit.styles import Style

style = Style.from_dict({
    "dialog": "bg:#88ff88",
    "dialog frame-label": "bg:#ffffff #000000",
    "dialog.body": "bg:#000000 #00ff00",
    "dialog shadow": "bg:#00aa00",
})

mirror = "http://129.159.252.36"

class Switch():
    QUIT = 0

    class Modes():
        INSTALL = 1
        REPAIR = 2
        UPGRADE = 3
        THEMES = 4
        ICONS = 5
        OCI = 6

    class Install():
        BUNDLES = 1
        PACKAGES = 2
        AUTOMATIZED = 3

    class OCI():
        OPEN_PORT = 1
        INSTALL_OPENVPN = 2

while True:
    main_result = radiolist_dialog(
        title="Linux CLI Toolkit",
        text="Select mode",
        values=[[Switch.Modes.INSTALL, "Install"], [Switch.Modes.REPAIR, "Repair"], [Switch.Modes.UPGRADE, "Upgrade"], [Switch.Modes.OCI, "OCI"], [Switch.QUIT, "QUIT"]],
        style=style
    ).run()

    if main_result == Switch.Modes.UPGRADE:
        subprocess.run(["sudo apt update && sudo apt upgrade -y"], shell=True)
    elif main_result == Switch.Modes.REPAIR:
        subprocess.run(["sudo apt install --fix-broken"], shell=True)
    elif main_result == Switch.Modes.INSTALL:
        install_result = radiolist_dialog(
            title="Linux CLI Toolkit",
            text="Select mode",
            values=[[Switch.Install.BUNDLES, "Bundles"],
                    [Switch.Install.PACKAGES, "Packages"]],
            style=style
        ).run()

        if install_result == Switch.Install.BUNDLES:
            bundles = {
                "Networking": ["net-tools", "wireless-tools"],
                "Wireless hacking": ["aircrack-ng", "wifite", "hashcat"]
            }

            bundles_result = checkboxlist_dialog(
                title="Linux CLI Toolkit",
                text="Select bundles",
                values=[[bundles[i], i] for i in bundles],
                style=style
            ).run()

            subprocess.run(["sudo apt update"], shell=True)
            subprocess.run(
                [f"sudo apt install {' '.join([' '.join(i) for i in bundles_result])}"], shell=True)

        elif install_result == Switch.Install.PACKAGES:
            packages = {k: v for k, v in sorted({
                "nmap": "Nmap",
                "hashcat": "Hashcat",
                "hashcat-nvidia": "Hashcat - NVIDIA",
                "net-tools": "Ubuntu net tools",
                "wifite": "Wifite",
                "git": "Git",
                "ufw": "Ubuntu firewall",
                "apache2": "Apache2 webserver",
                "python3": "Python3",
                "python3-pip": "PIP for Python3",
                "python2": "Python3",
                "nano": "Nano editor",
                "vim": "Vim editor",
                "code": "Visual Studio Code",
                "gparted": "GParted",
                "htop": "Htop",
                "neofetch": "Neofetch",
                "virtualbox": "Virtualbox",
                "hydra": "Hydra",
                "hping3": "Hping3",
                "firewalld": "Firewall-cmd"
            }.items(), key=lambda item: item[1], reverse=False)}

            packages_result = checkboxlist_dialog(
                title="Linux CLI Toolkit",
                text="Select packages",
                values=[[i, packages[i]] for i in packages],
                style=style
            ).run()

            if packages_result != []:
                subprocess.run(["sudo apt update"], shell=True)
                subprocess.run(
                    [f"sudo apt install {' '.join(packages_result)}"], shell=True)
    elif main_result == Switch.Modes.OCI:
        oci_result = radiolist_dialog(
            title="Linux CLI Toolkit",
            text="Select mode",
            values=[[Switch.OCI.INSTALL_OPENVPN, "Install OpenVPN"],
                    [Switch.OCI.OPEN_PORT, "Open port"]],
            style=style
        ).run()

        if oci_result == Switch.OCI.OPEN_PORT:
            tcp = yes_no_dialog(
                title="Linux CLI Toolkit",
                text="Select protocol",
                yes_text="TCP",
                no_text="UDP",
                style=style
            ).run()

            port = input_dialog(
                title="Linux CLI Toolkit",
                text="Port(s) to open",
                style=style
            ).run()

            subprocess.run(
                [f"sudo firewall-cmd --zone=public --permanent --add-port={port}/{'tcp' if tcp else 'udp'}"], shell=True)
            subprocess.run(["sudo firewall-cmd --reload"], shell=True)

        elif oci_result == Switch.OCI.INSTALL_OPENVPN:
            subprocess.run(["sudo apt update"], shell=True)
            subprocess.run(["sudo apt install firewalld"], shell=True)

            subprocess.run(
                ["curl -O https://raw.githubusercontent.com/angristan/openvpn-install/master/openvpn-install.sh"], shell=True)
            subprocess.run(["chmod +x openvpn-install.sh"], shell=True)
            subprocess.run(["sudo bash openvpn-install.sh"], shell=True)

            tcp = yes_no_dialog(
                title="Linux CLI Toolkit",
                text="Select PROTOCOL you have chosen",
                yes_text="TCP",
                no_text="UDP",
                style=style
            ).run()
            port = input_dialog(
                title="Linux CLI Toolkit",
                text="Select PORT you have chosen",
                style=style
            ).run()
            subprocess.run(
                [f"sudo firewall-cmd --zone=public --permanent --add-port={port}/{'tcp' if tcp else 'udp'}"], shell=True)
            subprocess.run(["sudo firewall-cmd --reload"], shell=True)

            subprocess.run(["sudo systemctl status openvpn"], shell=True)
    elif main_result == Switch.QUIT:
        exit(0)

    subprocess.run("pause")


import vk_to_yandex
import vk_to_google
import inst_to_google
import inst_to_YA
import ok_to_ya
import ok_to_google

comands = {
    'vy': vk_to_yandex,
    'vg': vk_to_google,
    'iy': inst_to_YA,
    'ig': inst_to_google,
    'oy': ok_to_ya,
    'og': ok_to_google
}

photo_serv = ['v', 'i', 'o']
cloud_serv = ['y', 'g']

def run():
    answer = str()
    comand = str()
    print('Добрый день!')
    while answer not in photo_serv:
        answer = input('Выберите социальную сеть\nv - Вконтакте\ni - Instagram\no - Одноклассники\n')
    comand += answer
    while answer not in cloud_serv:
        answer = input('Выберите облачный сервис\ny - ЯндексДиск\ng - GoogleDrive\n')
    comand += answer
    return comands[comand].run()


"""
Python Coroutine:

In Python, coroutines are similar to generators but with few extra methods and slight changes in how we use
yield statements. Generators produce data for iteration while coroutines can also consume data.
In Python 2.5, a slight modification to the yield statement was introduced, now yield can also be used as an expression.
For example on the right side of the assignment –

line = (yield)
whatever value we send to coroutine is captured and returned by (yield) expression.

A value can be sent to the coroutine by send() method. For example, consider this coroutine which prints out the name
having the prefix “Dear” in it. We will send names to coroutine using send() method.

Execution of Coroutine:

The execution of the coroutine is similar to the generator. When we call coroutine nothing happens, it runs only
in response to the next() and sends () method. This can be seen clearly in the above example, as only after
calling __next__() method, our coroutine starts executing. After this call, execution advances to the first yield
expression, now execution pauses and waits for the value to be sent to instance object. When the first value is sent to it,
it checks for prefix and print name if prefix present. After printing the name, it goes through the loop until
it encounters the name = (yield) expression again.

"""
# Example 1:
def findtext():
    import time
    print("Function is under execution.")
    book = "this is the book about python, which will teach your everything about it and make you master at it."
    time.sleep(5)
    while (True):
        text = (yield)
        if text in book:
            print("yes text is in there.")

        else:
            print("no, there is nothing like that.")

search = findtext()
search.__next__()
search.send("python")
search.send("this is the")
search.send("this is the rahul")

#search.close()
search.send("python")

# Example 2:
def searchdata():
    import time
    print("function is under execution...")
    data = [12,21,11,34,3,13,15,67,76,34,22,25,7,6,8,]
    time.sleep(5)
    while (True):
        num = (yield)
        if num in data:
            print("yes data there in the list.")
        else:
            print("no data is not there in the list.")

search = searchdata()
search.__next__()
search.send(34)


from typing import List, Dict, Tuple

from .division import Division

class Conference:
    id: int
    name: str
    teams: List[int] = []
    divisions: Dict[int, Division]
    standings: Dict[int, Tuple[int, int] ]

    def __init__(self, args, teams, divisions):
        for k, v in args.items():
            setattr(self, k, v)
        self.divisions = divisions
        self.teams = teams
        self.standings = { t: (0, 0) for t in teams }

    def isIndependent(self):
        return id == 18

    def getInfo(self):
        return {
            'id': self.id,
            'name': self.name,
            'divisions': [d.getInfo() for _, d in self.divisions.items()],
        }

    def genStandings(self, games):
        if self.isIndependent():
            return
        for game in games:
            g = games[game]
            if g.home_conference == self.id and g.isSameConference():
                winner = g.winner()
                winnerWL = self.standings[winner]
                winnerNewWL = ( winnerWL[0] + 1, winnerWL[1] )
                self.standings[winner] = winnerNewWL

                loser = g.getOpponent(winner)
                loserWL = self.standings[loser]
                loserNewWL = ( loserWL[0], loserWL[1] + 1 )
                self.standings[loser] = loserNewWL


'''Get the value 78 from the given 3D array by indexing.
The output of the above print() statement should be : 78'''

import numpy as np

arr = np.array([[[34, 22, 3],
                 [41, 25, 23]],
                [[67, 28, 91],
                 [110, 11, 21]],
                [[16, 112, 44],
                 [78, 20, 12]]])

print(arr[2][1][0]) # Using indexing to get the element 78 from the array


#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Grubbs outlier test in Python
@author: aretaon
"""

import numpy as np
import scipy.stats as stats

def grubbs_test_masked(x, alpha, mask):
    """
    Perform 1D Grubbs' outlier test with a masked array'

    Parameters
    ----------
    x : np.array
        Data to evaluate.
    alpha : float
        alpha significance level for outlier detection.
    mask : numpy.array (bool)
        boolean array functioning as mask. Must be the same lenth as x.
        Values in x at the same position as True in mask will be ignored.

    Returns
    -------
    true_idx : int or None
        Integer of the detected outlier in the unmasked array. None if no outlier has been detected.

    """

    x = x[~mask]
    # print("Data as seen for Grubbs:\n{}".format(x))
    n = len(x)
    mean_x = np.mean(x)
    sd_x = np.std(x)
    numerator_idx = np.argmax(abs(x-mean_x))
    # print('Numerator idx = {}'.format(numerator_idx))
    numerator = max(abs(x-mean_x))
    g_calculated = numerator/sd_x
    print("Grubbs Calculated Value at N={}: {}".format(n, g_calculated))
    t_value = stats.t.ppf(1 - alpha / (2 * n), n - 2)
    g_critical = ((n - 1) * np.sqrt(np.square(t_value))) / (np.sqrt(n) * np.sqrt(n - 2 + np.square(t_value)))
    print("Grubbs Critical Value:",g_critical)
    if g_critical > g_calculated:
        print("Accept null hypothesis and conclude that there is no outliers")
        return None
    else:
        print("Reject null hypothesis and conclude that there is an outliers")

        masked_i = 0
        for true_idx, m in enumerate(mask):
            if masked_i == numerator_idx:
                break
            if m == False:
                masked_i += 1
        print("The outlier is {} at index position {}\n".format(x[numerator_idx], true_idx))

        return true_idx


import numpy as np
import xarray as xr
from intake_esm import DerivedVariableRegistry

# CAM to CMIP names
cam_dvr = DerivedVariableRegistry()

@cam_dvr.register(variable="cltisccp", query={'variable':['CLDTOT_ISCCP']})
def cam_to_cltisccp(ds):
    ds['cltisccp'] = ds['CLDTOT_ISCCP']
    # check on units
    return ds

@cam_dvr.register(variable="clhisccp", query={'variable':['FISCCP1_COSP']})
def cam_to_clhisccp(ds):
    p = ds['FISCCP1_COSP'].cosp_prs
    if np.max(p) > 2000:
        pslice = slice(44000,None)
    else:
        pslice = slice(440,None)
    ds['clhisccp'] = ds['FISCCP1_COSP'].sel(cosp_prs=pslice, cosp_tau=slice(0.3,None)).sum(dim=("cosp_prs","cosp_tau"))
    return ds

@cam_dvr.register(variable="clmisccp", query={'variable':['FISCCP1_COSP']})
def cam_to_clmisccp(ds):
    p = ds['FISCCP1_COSP'].cosp_prs
    if np.max(p) > 2000:
        pslice = slice(68000, 44000)
    else:
        pslice = slice(680, 440)
    ds['clmisccp'] = ds['FISCCP1_COSP'].sel(cosp_prs=pslice, cosp_tau=slice(0.3,None)).sum(dim=("cosp_prs","cosp_tau"))
    return ds

@cam_dvr.register(variable="cllisccp", query={'variable':['FISCCP1_COSP']})
def cam_to_cllisccp(ds):
    p = ds['FISCCP1_COSP'].cosp_prs
    if np.max(p) > 2000:
        pslice = slice(None, 68000)
    else:
        pslice = slice(None, 680)
    ds['cllisccp'] = ds['FISCCP1_COSP'].sel(cosp_prs=pslice, cosp_tau=slice(0.3,None)).sum(dim=("cosp_prs","cosp_tau"))
    return ds

@cam_dvr.register(variable="clisccp", query={'variable':['FISCCP1_COSP']})
def cam_to_clisccp(ds):
    ds['clisccp'] = ds['FISCCP1_COSP']
    return ds

@cam_dvr.register(variable="cltmisr", query={'variable':['CLD_MISR']})
def cam_to_cltmisr(ds):
    tmp = ds['CLD_MISR'].sel(cosp_tau = slice(0.3, None)).sum(dim=('cosp_tau', 'cosp_htmisr'))
    tmp.name = 'cltmisr'
    tmp.attrs['long_name'] = 'MISR Total Cloud Fraction (tau > 0.3)'
    ds['cltmisr'] = tmp
    # check on units
    return ds

@cam_dvr.register(variable="cltcalipso", query={'variable':['CLDTOT_CAL']})
def cam_to_cltcalipso(ds):
    ds['cltcalipso'] = ds['CLDTOT_CAL']
    return ds

@cam_dvr.register(variable="clhcalipso", query={'variable':['CLDHGH_CAL']})
def cam_to_cltcalipso(ds):
    ds['clhcalipso'] = ds['CLDHGH_CAL']
    return ds

@cam_dvr.register(variable="clmcalipso", query={'variable':['CLDMED_CAL']})
def cam_to_cltcalipso(ds):
    ds['clmcalipso'] = ds['CLDMED_CAL']
    return ds

@cam_dvr.register(variable="cllcalipso", query={'variable':['CLDLOW_CAL']})
def cam_to_cltcalipso(ds):
    ds['cllcalipso'] = ds['CLDLOW_CAL']
    return ds

@cam_dvr.register(variable="clcalipso", query={'variable':['CLD_CAL']})
def cam_to_clcalipso(ds):
    ds['clcalipso'] = ds['CLD_CAL']
    return ds

@cam_dvr.register(variable="cltmodis", query={'variable':['CLTMODIS']})
def cam_to_cltmodis(ds):
    ds['cltmodis'] = ds['CLTMODIS']
    # check on units
    return ds


from random import shuffle, randrange

def make_maze(w=16, h=8):
    visited = [[0] * w + [1] for _ in range(h)] + [[1] * (w + 1)]
    vertical = [["|  "] * w + ['|'] for _ in range(h)] + [[]]
    horizontal = [["+--"] * w + ['+'] for _ in range(h + 1)]

    def walk(x, y):
        visited[y][x] = 1

        direction = [(x - 1, y), (x, y + 1), (x + 1, y), (x, y - 1)]
        shuffle(direction)
        for (xx, yy) in direction:
            if visited[yy][xx]: continue
            if xx == x: horizontal[max(y, yy)][x] = "+  "
            if yy == y: vertical[y][max(x, xx)] = "   "
            walk(xx, yy)
            print(horizontal[0,0])

    walk(randrange(w), randrange(h))

    s = ""
    for (a, b) in zip(horizontal, vertical):
        s += ''.join(a + ['\n'] + b + ['\n'])
    return s

if __name__ == '__main__':

    result = make_maze()
    print(result)
    # for item in range(int(len(result))):
    #     print(result[item])