from pcse.base_classes import SimulationObject, StatesTemplate
from pcse.traitlets import AfgenTrait, Instance, List

from .phenology_simulator import GenericBBCHPhenology
from .management_alerts_simulator import ManagementRules
from .weather_alerts_simulator import WeatherAlerts
from . import signals

class MainSimulator(SimulationObject):
    """Defines the top-level simulator that integrates the phenology, management alerts and weather alerts.
    """
    phenology = Instance(SimulationObject)
    management = Instance(SimulationObject)
    weatheralert = Instance(SimulationObject)

    class StateVariables(StatesTemplate):
        """Development stage state variables class"""
        WEATHER_MESSAGES = List()
        MANAGEMENT_MESSAGES = List()

    def initialize(self, day, kiosk, parameters):
        """Initializes the SimulationObject with given parametervalues.

        :param self: this SimulationObject
        :param day: start date of the simulation
        :param kiosk: variable kiosk of this PCSE instance
        :param parameters: ParameterProvider object
        """

        self._connect_signal(self._on_TMAX_STRESS, signal=signals.TMAX_STRESS)
        self._connect_signal(self._on_RAIN_STRESS, signal=signals.RAIN_STRESS)
        self._connect_signal(self._on_RH_STRESS, signal=signals.RHMAX_STRESS)
        self._connect_signal(self._on_TMIN_STRESS, signal=signals.TMIN_STRESS)
        self._connect_signal(self._on_FOG_STRESS, signal=signals.FOG_STRESS)

        self._connect_signal(self._on_MANAGEMENT_EVENT, signal=signals.MANAGEMENT_EVENT)
        self.states = self.StateVariables(kiosk, WEATHER_MESSAGES=[], MANAGEMENT_MESSAGES=[])

        self.phenology = GenericBBCHPhenology(day, kiosk, parameters)
        self.management = ManagementRules(day, kiosk, parameters)
        self.weatheralert = WeatherAlerts(day, kiosk, parameters)

    def calc_rates(self, day, drv):
        """Calculate the rates of change given the current states and driving
        variables (drv).

        :param day: current day of pcse simulation
        :param drv: dict with drivers
        """
        self.phenology.calc_rates(day, drv)
        self.management.calc_rates(day, drv)
        self.weatheralert.calc_rates(day, drv)

    def integrate(self, day, delt=1):
        """Integrate the rates of change on the current state variables multiplied by the time-step

        :param day: current day of pcse simulation
        :param delt: integer for calculating every delt days; in this case 1
        """
        self.phenology.integrate(day, delt)
        self.management.integrate(day, delt)
        self.weatheralert.integrate(day, delt)

    # Weather alerts
    def _on_TMAX_STRESS(self, day=None, signal=None, crop_no=None,
                        variety_no=None, message_no=None,
                        mday=None, message=None):
        self.states.WEATHER_MESSAGES.append(day.strftime('{"day":"%Y-%m-%d",') + '"msg_id":'+'"'+str(message_no)+'",' + '"msg":' + '"'+message+'"}')

    def _on_RAIN_STRESS(self, day=None, signal=None, crop_no=None,
                        variety_no=None, message_no=None,
                        mday=None, message=None):
        self.states.WEATHER_MESSAGES.append(day.strftime('{"day":"%Y-%m-%d",') + '"msg_id":'+'"'+str(message_no)+'",' + '"msg":' + '"'+message+'"}')

    def _on_RH_STRESS(self, day=None, signal=None, crop_no=None,
                        variety_no=None, message_no=None,
                        mday=None, message=None):
        self.states.WEATHER_MESSAGES.append(day.strftime('{"day":"%Y-%m-%d",') + '"msg_id":'+'"'+str(message_no)+'",' + '"msg":' + '"'+message+'"}')

    def _on_TMIN_STRESS(self, day=None, signal=None, crop_no=None,
                        variety_no=None, message_no=None,
                        mday=None, message=None):
        self.states.WEATHER_MESSAGES.append(day.strftime('{"day":"%Y-%m-%d",') + '"msg_id":'+'"'+str(message_no)+'",' + '"msg":' + '"'+message+'"}')

    def _on_FOG_STRESS(self, day=None, signal=None, crop_no=None,
                        variety_no=None, message_no=None,
                        mday=None, message=None):
        self.states.WEATHER_MESSAGES.append(day.strftime('{"day":"%Y-%m-%d",') + '"msg_id":'+'"'+str(message_no)+'",' + '"msg":' + '"'+message+'"}')

    # Management alerts
    def _on_MANAGEMENT_EVENT(self, day=None, signal=None, crop_no=None,
                                      variety_no=None, message_no=None,
                                      mday=None, message=None):
        # Send management message to JSON output
        self.states.MANAGEMENT_MESSAGES.append(mday.strftime('{"day":"%Y-%m-%d",') + '"msg_id":'+'"'+str(message_no)+'",' + '"msg":' + '"'+message+'"}')


from django.shortcuts import render
from app3_1.forms import PersonForm
from app3_1.models import Person

# Create your views here.

def index(request):
    pform1 = PersonForm()
    if request.method=='POST':
        # Accept value from form
        pid = request.POST.get('pid')
        name = request.POST.get('fullname')
        address = request.POST.get('contactaddress')
        # print(pid, name, address)
        person1 = Person(pid=pid, name=name, address=address)
        person1.save()
        return render(request, 'app3_1/index.html', {'form1': pform1})
    else:
        # Display Web form
        return render(request, 'app3_1/index.html', {'form1':pform1})


from DSA.Queue.implement_queue_linked_list import MyQueue
class BinarySearchTree:
    def __init__(self, data):
        self.data = data
        self.leftChild = None
        self.rightChild = None

    def levelOrderTraversal(self):
        if self == None:
            return
        customQueue = MyQueue()
        customQueue.enqueue(self)
        while not customQueue.isEmpty():
            root = customQueue.dequeue()
            print(root.value.data)
            if root.value.leftChild:
                print('leftChild', root.value.leftChild.data)
                customQueue.enqueue(root.value.leftChild)
            if root.value.rightChild:
                print('rightChild', root.value.rightChild.data)
                customQueue.enqueue(root.value.rightChild)

    def preOrderTravesal(self):
        if self == None:
            return
        print(self.data)
        if self.leftChild:
            self.leftChild.preOrderTravesal()
        if self.rightChild:
            self.rightChild.preOrderTravesal()

    def inOrderTraversal(self):
        if self == None:
            return
        if self.leftChild:
            self.leftChild.preOrderTravesal()
        print(self.data)
        if self.rightChild:
            self.rightChild.preOrderTravesal()

    def postOrderTraversal(self):
        if self == None:
            return
        if self.leftChild:
            self.leftChild.preOrderTravesal()
        if self.rightChild:
            self.rightChild.preOrderTravesal()
        print(self.data)

    def insertNode(self, value):
        newNode = BinarySearchTree(value)
        if self == None:
            self = newNode
        else:
            if value < self.data:
                if not self.leftChild:
                    self.leftChild = newNode
                else:
                    self.leftChild.insertNode(value)
            else:
                if not self.rightChild:
                    self.rightChild = newNode
                else:
                    self.rightChild.insertNode(value)
        return newNode

    def searchValue(self, value):
        if self == None:
            return 'BST is empty'
        if self.data == value:
            print('Value found')
            return self.data
        else:
            if value < self.data:
                if self.leftChild:
                    self.leftChild.searchValue(value)
                else:
                    print('Value not found in BST')
                    return 'Value not found in BST'
            else:
                if self.rightChild:
                    self.rightChild.searchValue(value)
                else:
                    print('Value not found in BST')
                    return 'Value not found in BST'

def findMinVal(rootNode):
    if rootNode is None:
        return rootNode
    while rootNode.leftChild:
        rootNode = rootNode.leftChild
    return rootNode

def deleteBSTNode(rootNode, value):
    if rootNode == None:
        return rootNode
    if value < rootNode.data:
        rootNode.leftChild = deleteBSTNode(rootNode.leftChild, value)
    elif value > rootNode.data:
        rootNode.rightChild = deleteBSTNode(rootNode.rightChild, value)
    else:
        if rootNode.leftChild is None:
            temp = rootNode.rightChild
            rootNode = None
            return temp
        if rootNode.rightChild is None:
            temp = rootNode.leftChild
            rootNode = None
            return temp

        minVal = findMinVal(rootNode.rightChild)
        rootNode.data = minVal.data
        rootNode.rightChild = deleteBSTNode(rootNode.rightChild, minVal.data)

    return rootNode

def deleteBST(rootNode):
    rootNode.leftChild = None
    rootNode.rightChild = None
    rootNode = None
    return 'Success'

newBST = BinarySearchTree(70)
bt1 = newBST.insertNode(50)
# print('bt1.data',bt1.data)

bt2 = newBST.insertNode(90)
bt3 = newBST.insertNode(30)
bt4 = newBST.insertNode(60)
bt5 = newBST.insertNode(20)
bt6 = newBST.insertNode(40)
bt7 = newBST.insertNode(80)
bt8 = newBST.insertNode(100)
bt8 = newBST.insertNode(10)
bt8 = newBST.insertNode(110)
bt8 = newBST.insertNode(120)
bt8 = newBST.insertNode(75)
bt8 = newBST.insertNode(72)
bt8 = newBST.insertNode(55)
bt8 = newBST.insertNode(65)

# print(newBST)
deleteBSTNode(newBST, 50)
# print(findMinValue(newBST.rightChild))

# k = newBST.rightChild.findRightMinValue()
# print(minValueNode(newBST.rightChild).data)
newBST.levelOrderTraversal()

# print('preOrderTraversal')
# newBST.preOrderTravesal()

# newBST.searchValue(41)

# newBST.deleteValue(10)
# print(100)
# print()
# print('After delete!')
# newBST.levelOrderTraversal()

# anewBST = BinarySearchTree(10)
# anewBST.levelOrderTraversal()
# anewBST.deleteValue(10)
# anewBST.levelOrderTraversal()


import pygame

pygame.init()

window_width=700
window_height=400

BLACK = (0, 0, 0)
FPS=30

size = (window_width, window_height)
screen = pygame.display.set_mode(size)

pygame.display.set_caption("Hello Scrolling Background")
run = True

clock = pygame.time.Clock()

background_image0 = pygame.image.load("bg0.jpg").convert()
background_image1 = pygame.image.load("bg1.jpg").convert()

dx=5
dy=5
by=0
bx0=0
bx1=window_width

while run:
     # keep loop running at the right speed
    clock.tick(FPS)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
    #keys

    screen.blit(background_image0, [bx0, by])
    screen.blit(background_image1, [bx1, by])
    pygame.display.update()

    bx0 -=dx
    bx1 -=dx

    if bx0 <=-window_width:
        bx0=700

    if bx1 <=-window_width:
        bx1=700

pygame.quit()


class Actor:

  def __init__(self, state_space_dim = STATE_SPACE_DIM,
                actions_actfunc_dict = ACTIONS_ACTFUNC_DICT,
                alr = ALR, actor_1_dim = ACTOR_1_DIM,
                actor_2_dim = ACTOR_2_DIM, name = 'Actor',
                chkpt_dir = CHKPT_DIR):

    self.model_name = name
    self.checkpoint_dir = chkpt_dir
    self.alr = alr
    self.state_space_dim = state_space_dim
    self.actions_actfunc_dict = actions_actfunc_dict
    self.model = self.create_actor(actor_1_dim, actor_2_dim, alr)

  def __call__(self, state):
    return self.model.predict(state)

  def create_actor(self, actor_1_dim, actor_2_dim, alr):

    S = Input(shape=[self.state_space_dim])
    h0 = Dense(actor_1_dim, activation='relu')(S)
    h1 = Dense(actor_2_dim, activation='relu')(h0)

    lista = []
    for k,v in self.actions_actfunc_dict.items():
      lista.append(Dense(1,activation = v[0])(h1))

    V = Concatenate()(lista)

    model = Model(inputs = S, outputs = V)
    model.compile(optimizer = Adam(learning_rate = alr))

    return model

  def save_model(self, count):
    if not os.path.isdir(os.path.join(os.getcwd(), self.checkpoint_dir, str(count))):
      os.mkdir(os.path.join(os.getcwd(), self.checkpoint_dir, str(count)))
    self.model.save_weights(os.path.join(os.getcwd(), self.checkpoint_dir,
                            str(count), self.model_name + '_ddpg.h5'))

  def load_model(self, count):
    self.model.load_weights(os.path.join(os.getcwd(), self.checkpoint_dir,
                            str(count), self.model_name + '_ddpg.h5'))


class AddressList(object):
    """Represents a firewall address list on a RouterOS device

    Attributes:
        cidrs (list[str]): All of the CIDRs within this address list
    """
    def __init__(self, pairs):
        """Initializes the address list

        Args:
            pairs ((str, str)): The (index, cidr) pairs to initialize this address
            list with
        """
        self._indexes = dict()
        self.cidrs = set()

        for index, address in pairs:
            indexSet = self._indexes.get(address)
            if indexSet is None:
                indexSet = set()
                self._indexes[address] = indexSet

            indexSet.add(index)
            self.cidrs.add(address)

    def get_indices(self, cidr):
        """Fetches the index(es) of a given CIDR

        Args:
            cidr (str): The CIDR to look up

        Returns:
            list[str]: Indexes of the given CIDR
        """
        return self._indexes.get(cidr, None)


import argparse
import time
import numpy as np
import math
from tqdm import tqdm
import torch
import torch.nn as nn
import torch.optim as optim
import matplotlib.pyplot as plt
from utils import makedirs
from utils import load_dataset
import torch.nn.functional as F
from torchdiffeq import odeint_adjoint as odeint

makedirs("figures")
makedirs("png")
makedirs("log")

# Choose experiment: Pendulum or Cartpole
name = "Pendulum"

n = 2
if name == "Cartpole":
    n = 4

# Resnet model
class resnet(nn.Module):
    def __init__(self):
        super(resnet, self).__init__()

        self.net = nn.Sequential(
            nn.Linear(n, 512),
            nn.ReLU(),
            nn.Linear(512, n),
        )

    def forward(self, y):
        return self.net(y)

    def unroll(self, x0, N):
        pred = x0.new_zeros((x0.shape[0], N, x0.shape[1]))
        x = x0
        pred[:, 0] = x
        for i in range(N - 1):
            x = x + self.forward(x)
            pred[:, i + 1] = x
        return pred

def train(N_epochs, batch_size=50, plot=False):
    # Initialize model and optimizer
    func = resnet()
    optimizer = optim.Adam(func.parameters(), lr=1e-3)

    # Load data
    train_loader, test_loader, mean, std = load_dataset(name, batch_size)

    loss_list = []
    for Epoch in range(N_epochs):
        # Train loop
        avg_loss = 0
        for batch in train_loader:
            batch_y0 = batch[:, 0]
            batch_y = batch
            N = batch_y.shape[1]
            optimizer.zero_grad()
            pred_y = func.unroll(batch_y0, N)
            loss = F.mse_loss(pred_y, batch_y)
            loss.backward()
            optimizer.step()
            avg_loss += loss.detach().cpu().numpy()
        avg_loss = avg_loss / len(train_loader)

        # Test loop
        with torch.no_grad():
            loss = 0
            for batch in test_loader:
                batch_y0 = batch[:, 0]
                batch_y = batch
                N = batch.shape[1]
                pred_y = func.unroll(batch_y0, N)
                loss += F.mse_loss(pred_y, batch_y).detach().cpu().numpy()
            loss = loss / len(test_loader)
            loss_list.append(loss)
    print("Epoch {:02d} | Test Loss {:.6f}".format(Epoch, loss))

    return np.array(loss_list)

# Train for 100 epochs with 10 different seeds
N = 10
N_epochs = 100
loss = np.zeros((N, N_epochs))
for i in range(N):
    loss[i] = train(N_epochs)
np.save("log/" + name + "resnet_loss", loss)


import numpy as np
from matplotlib import pyplot as plt
from scipy.stats import multivariate_normal
from sklearn.cluster import KMeans
import random
np.random.seed(7)

def initialization_kmeans(X, p, q, variance_level=None):
    """
    X : dataset
    p : number of clusters
    q : dimension of the latent space
    variance_level
    pi : proportions of clusters
    mu : centers of the clusters in the observation space
    W : latent to observation matricies
    sigma2 : noise
    """

    N, d = X.shape

    # initialization
    init_centers = np.random.randint(0, N, p)
    while (len(np.unique(init_centers)) != p):
        init_centers = np.random.randint(0, N, p)

    mu = X[init_centers, :]
    distance_square = np.zeros((N, p))
    clusters = np.zeros(N, dtype=np.int32)

    D_old = -2
    D = -1

    while(D_old != D):
        D_old = D

        # assign clusters
        for c in range(p):
            distance_square[:, c] = np.power(X - mu[c, :], 2).sum(1)
        clusters = np.argmin(distance_square, axis=1)

        # compute distortion
        distmin = distance_square[range(N), clusters]
        D = distmin.sum()

        # compute new centers
        for c in range(p):
            mu[c, :] = X[clusters == c, :].mean(0)

    #for c in range(p):
    #    plt.scatter(X[clusters == c, 0], X[clusters == c, 1], c=np.random.rand(3,1))

    # parameter initialization
    pi = np.zeros(p)
    W = np.zeros((p, d, q))
    sigma2 = np.zeros(p)
    for c in range(p):
        if variance_level:
            W[c, :, :] = variance_level * np.random.randn(d, q)
        else:
            W[c, :, :] = np.random.randn(d, q)

        pi[c] = (clusters == c).sum() / N
        if variance_level:
            sigma2[c] = np.abs((variance_level/10) * np.random.randn())
        else:
            sigma2[c] = (distmin[clusters == c]).mean() / d

    return pi, mu, W, sigma2, clusters

def generateData(family, N=300):
    assert family in ['sine', 'elipse']

    if family == 'sine':
        x = np.linspace(-1, 1, N) + 0.3 * np.random.random(N)
        y = np.sin(5 * x) + 0.3 * np.random.randn(N)
    elif family == 'elipse':
        angle = np.linspace(0, 2 * np.pi, N)
        x = 1.5 * np.cos(angle) + 0.05 * np.random.randn(N)
        y = np.sin(angle) + 0.05 * np.random.randn(N)
    x = x.reshape([-1, 1])
    y = y.reshape([-1, 1])
    data = np.concatenate((x, y), axis=1)
    plotData(data)
    plt.show()
    return data

def plot_fig(X, clusters, W, mu, sigma):
    for c in np.unique(clusters):
        plt.scatter(X[clusters == c, 0], X[clusters == c, 1])
        C = sigma[c]*np.eye(2) + np.dot(W[c, :, :], W[c, :, :].T)
        sample = np.random.multivariate_normal(mu[c, :].reshape((-1)), C, 100)
        plt.scatter(sample[:, 0], sample[:, 1], c='b', s=3)

    plt.scatter(mu[:, 0], mu[:, 1], c='k', s=100)
    plt.show()

def mixture_ppca(X, n_clusters, n_latent=1):
    N, D = X.shape  # N: number of samples, D: number of dims in X

    # initializing
    # kmeans = KMeans(n_clusters=n_clusters, random_state=0).fit(X)
    # mu = kmeans.cluster_centers_
    # pi = np.ones([n_clusters]) * 1/n_clusters
    # W = np.random.rand(n_clusters, D, n_latent)
    # sigma = np.ones(n_clusters)
    pi, mu, W, sigma, clusters = initialization_kmeans(X, n_clusters, n_latent)
    plot_fig(X, clusters, W, mu, sigma)

    # variables
    _, _, d = W.shape  # d: dims of latent variables (d << D), K: number of clusters
    M = np.zeros((n_clusters, d, d))  # M_k shape : d x d
    C = np.zeros((n_clusters, D, D))  # C_k shape : D x D
    Cinvs = np.zeros((n_clusters, D, D))  # C_k shape : D x D
    Minvs = np.zeros((n_clusters, d, d))
    R = np.zeros((N, n_clusters))
    ES = np.zeros((n_clusters, d, 1, N))
    ESS = np.zeros((n_clusters, N, d, d))

    # EM algorithm
    MAX_iter = 500
    for i in range(MAX_iter):
        # print("{}th iteration".format(i))

        # E step ==================
        for k in range(n_clusters):
            C[k, :, :] = sigma[k] * np.identity(D) + np.matmul(W[k, :, :], W[k, :, :].T)

        for k in range(n_clusters):  # update r_ni
            Y = multivariate_normal.pdf(X, mean=mu[k, :], cov=C[k, :, :])
            R[:, k] = pi[k]*Y

        R_sum = np.sum(R, axis=1).reshape((-1, 1))
        R[:, :] = R[:, :]/R_sum

        for k in range(n_clusters):
            # M_k : W_{k}^{T}W_{k} + sigma_{k}^{2}I
            M[k, :, :] = np.dot(W[k, :, :].T, W[k, :, :]) + sigma[k]*np.eye(d)
            Minvs[k, :, :] = np.linalg.inv(M[k, :, :])

            # C inverse
            Cinvs[k, :, :] = (np.eye(D) - np.dot(np.dot(W[k, :, :], Minvs[k, :, :]), W[k, :, :].T)) / sigma[k]

            # E(s)
            MW = np.dot(Minvs[k, :, :], W[k, :, :].T)
            sigM = sigma[k]*Minvs[k, :, :]
            cnt = X-mu[k, :]
            for n in range(N):
                es = np.dot(MW, cnt[n, :].reshape((D, -1)))
                ES[k, :, :, n] = es
                ESS[k, n, :, :] = sigM + np.dot(es, es.T)

        # M step ==================
        for k in range(n_clusters):
            # pi_new
            pi[k] = np.sum(R[:, k], 0)/N

            # mu_new
            WE = np.zeros((D, 1, N))
            for n in range(N):
                WE[:, :, n] = np.dot(W[k, :, :], ES[k, :, :, n])
            mu[k, :] = np.sum(np.multiply(R[:, k].reshape(-1, 1), (X - np.transpose(np.squeeze(WE)))), 0)\
                       /np.sum(R[:, k].reshape(-1, 1), 0)

            # W_new
            cnt = X - mu[k, :]
            W_front = np.zeros((N, D, d))
            W_back = np.zeros((N, d, d))
            for n in range(N):
                W_front[n, :, :] = R[n, k] * np.dot(cnt[n, :].reshape(-1, 1), ES[k, :, :, n].T)
                W_back[n, :, :] = np.multiply(R[n, k], ESS[k, n, :, :])
            W[k, :, :] = np.dot(np.sum(W_front, 0), np.linalg.inv(np.sum(W_back, 0)))

            # Sigma_new
            wtw = np.dot(W[k, :, :].T, W[k, :, :])
            sig_front = np.zeros((N, 1))
            sig_mid = np.zeros((N, 1))
            sig_last = np.zeros((N, 1))
            for n in range(N):
                sig_front[n, :] = R[n, k] * np.dot(cnt[n, :], cnt[n, :])
                sig_mid[n, :] = R[n, k] * 2*np.dot(np.dot(ES[k, :, :, n].T, W[k, :, :].T), cnt[n, :])
                sig_last[n, :] = R[n, k] * np.trace(np.dot(ESS[k, n, :, :], wtw))

            sigma[k] = (np.sum(sig_front, 0) - np.sum(sig_mid, 0) + np.sum(sig_last, 0)) / (D * np.sum(R[:, k], 0))

    return pi, mu, sigma, W, R

def plotContour(A, mu, sigma2):
    K = len(mu)
    delta = 0.1
    x1_min = x2_min = -2
    x1_max = x2_max = 2
    x1 = np.arange(x1_min, x1_max, delta)
    x2 = np.arange(x2_min, x2_max, delta)
    X1, X2 = np.meshgrid(x1, x2)
    for k in range(K):
        C = np.matmul(A[k], A[k].T) + sigma2[k]*np.identity(2)
        Z = np.zeros([len(x1), len(x2)])
        for i in range(len(x1)):
            for j in range(len(x2)):
                x = np.array([x1[i], x2[j]])
                Z[i, j] = multivariate_normal.pdf(x, mu[k, :], C)
        contour = plt.axes().contour(X1, X2, Z.T)

def plotData(data):
    plt.scatter(data[:,0],data[:,1])
    return

def main():
    # sample = 300
    # x = np.arange(sample)
    # noise = 0.08 * np.asarray(random.sample(range(100, 500), sample))
    # y = 100*np.sin(2 * np.pi * x/100) + noise
    # sin_data = np.transpose(np.array([x.T, y.T]))
    # plt.scatter(x, y)
    # plt.show()

    # sin_data = np.transpose([x, 5*x, 10*x, 2*x])
    sin_data = generateData('sine')
    pi, mu, sigma, W, R = mixture_ppca(sin_data, 6, 1)
    print(pi)
    pi, mu, sigma, W, R = mixture_ppca(sin_data, 4, 1)
    print(pi)
    plotData(sin_data)
    plotContour(W, mu, sigma)
    plt.show()
    plot_fig(sin_data, R.argmax(axis=1), W, mu, sigma)

if __name__ == '__main__':
    main()

assn2 - Mixture PPCA/Mixture of PPCA/mppca.py


# SVG Path specification parser

import re
from . import path
import xml.etree.ElementTree as ET
import re
import math

COMMANDS = set('MmZzLlHhVvCcSsQqTtAa')
UPPERCASE = set('MZLHVCSQTA')

COMMAND_RE = re.compile("([MmZzLlHhVvCcSsQqTtAa])")
FLOAT_RE = re.compile("[-+]?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?")

SVG_COLORS = {
"aliceblue": (0.941176,0.972549,1),
"antiquewhite": (0.980392,0.921569,0.843137),
"aqua": (0,1,1),
"aquamarine": (0.498039,1,0.831373),
"azure": (0.941176,1,1),
"beige": (0.960784,0.960784,0.862745),
"bisque": (1,0.894118,0.768627),
"black": (0,0,0),
"blanchedalmond": (1,0.921569,0.803922),
"blue": (0,0,1),
"blueviolet": (0.541176,0.168627,0.886275),
"brown": (0.647059,0.164706,0.164706),
"burlywood": (0.870588,0.721569,0.529412),
"cadetblue": (0.372549,0.619608,0.627451),
"chartreuse": (0.498039,1,0),
"chocolate": (0.823529,0.411765,0.117647),
"coral": (1,0.498039,0.313725),
"cornflowerblue": (0.392157,0.584314,0.929412),
"cornsilk": (1,0.972549,0.862745),
"crimson": (0.862745,0.0784314,0.235294),
"cyan": (0,1,1),
"darkblue": (0,0,0.545098),
"darkcyan": (0,0.545098,0.545098),
"darkgoldenrod": (0.721569,0.52549,0.0431373),
"darkgray": (0.662745,0.662745,0.662745),
"darkgreen": (0,0.392157,0),
"darkgrey": (0.662745,0.662745,0.662745),
"darkkhaki": (0.741176,0.717647,0.419608),
"darkmagenta": (0.545098,0,0.545098),
"darkolivegreen": (0.333333,0.419608,0.184314),
"darkorange": (1,0.54902,0),
"darkorchid": (0.6,0.196078,0.8),
"darkred": (0.545098,0,0),
"darksalmon": (0.913725,0.588235,0.478431),
"darkseagreen": (0.560784,0.737255,0.560784),
"darkslateblue": (0.282353,0.239216,0.545098),
"darkslategray": (0.184314,0.309804,0.309804),
"darkslategrey": (0.184314,0.309804,0.309804),
"darkturquoise": (0,0.807843,0.819608),
"darkviolet": (0.580392,0,0.827451),
"deeppink": (1,0.0784314,0.576471),
"deepskyblue": (0,0.74902,1),
"dimgray": (0.411765,0.411765,0.411765),
"dimgrey": (0.411765,0.411765,0.411765),
"dodgerblue": (0.117647,0.564706,1),
"firebrick": (0.698039,0.133333,0.133333),
"floralwhite": (1,0.980392,0.941176),
"forestgreen": (0.133333,0.545098,0.133333),
"fuchsia": (1,0,1),
"gainsboro": (0.862745,0.862745,0.862745),
"ghostwhite": (0.972549,0.972549,1),
"gold": (1,0.843137,0),
"goldenrod": (0.854902,0.647059,0.12549),
"gray": (0.501961,0.501961,0.501961),
"grey": (0.501961,0.501961,0.501961),
"green": (0,0.501961,0),
"greenyellow": (0.678431,1,0.184314),
"honeydew": (0.941176,1,0.941176),
"hotpink": (1,0.411765,0.705882),
"indianred": (0.803922,0.360784,0.360784),
"indigo": (0.294118,0,0.509804),
"ivory": (1,1,0.941176),
"khaki": (0.941176,0.901961,0.54902),
"lavender": (0.901961,0.901961,0.980392),
"lavenderblush": (1,0.941176,0.960784),
"lawngreen": (0.486275,0.988235,0),
"lemonchiffon": (1,0.980392,0.803922),
"lightblue": (0.678431,0.847059,0.901961),
"lightcoral": (0.941176,0.501961,0.501961),
"lightcyan": (0.878431,1,1),
"lightgoldenrodyellow": (0.980392,0.980392,0.823529),
"lightgray": (0.827451,0.827451,0.827451),
"lightgreen": (0.564706,0.933333,0.564706),
"lightgrey": (0.827451,0.827451,0.827451),
"lightpink": (1,0.713725,0.756863),
"lightsalmon": (1,0.627451,0.478431),
"lightseagreen": (0.12549,0.698039,0.666667),
"lightskyblue": (0.529412,0.807843,0.980392),
"lightslategray": (0.466667,0.533333,0.6),
"lightslategrey": (0.466667,0.533333,0.6),
"lightsteelblue": (0.690196,0.768627,0.870588),
"lightyellow": (1,1,0.878431),
"lime": (0,1,0),
"limegreen": (0.196078,0.803922,0.196078),
"linen": (0.980392,0.941176,0.901961),
"magenta": (1,0,1),
"maroon": (0.501961,0,0),
"mediumaquamarine": (0.4,0.803922,0.666667),
"mediumblue": (0,0,0.803922),
"mediumorchid": (0.729412,0.333333,0.827451),
"mediumpurple": (0.576471,0.439216,0.858824),
"mediumseagreen": (0.235294,0.701961,0.443137),
"mediumslateblue": (0.482353,0.407843,0.933333),
"mediumspringgreen": (0,0.980392,0.603922),
"mediumturquoise": (0.282353,0.819608,0.8),
"mediumvioletred": (0.780392,0.0823529,0.521569),
"midnightblue": (0.0980392,0.0980392,0.439216),
"mintcream": (0.960784,1,0.980392),
"mistyrose": (1,0.894118,0.882353),
"moccasin": (1,0.894118,0.709804),
"navajowhite": (1,0.870588,0.678431),
"navy": (0,0,0.501961),
"oldlace": (0.992157,0.960784,0.901961),
"olive": (0.501961,0.501961,0),
"olivedrab": (0.419608,0.556863,0.137255),
"orange": (1,0.647059,0),
"orangered": (1,0.270588,0),
"orchid": (0.854902,0.439216,0.839216),
"palegoldenrod": (0.933333,0.909804,0.666667),
"palegreen": (0.596078,0.984314,0.596078),
"paleturquoise": (0.686275,0.933333,0.933333),
"palevioletred": (0.858824,0.439216,0.576471),
"papayawhip": (1,0.937255,0.835294),
"peachpuff": (1,0.854902,0.72549),
"peru": (0.803922,0.521569,0.247059),
"pink": (1,0.752941,0.796078),
"plum": (0.866667,0.627451,0.866667),
"powderblue": (0.690196,0.878431,0.901961),
"purple": (0.501961,0,0.501961),
"red": (1,0,0),
"rosybrown": (0.737255,0.560784,0.560784),
"royalblue": (0.254902,0.411765,0.882353),
"saddlebrown": (0.545098,0.270588,0.0745098),
"salmon": (0.980392,0.501961,0.447059),
"sandybrown": (0.956863,0.643137,0.376471),
"seagreen": (0.180392,0.545098,0.341176),
"seashell": (1,0.960784,0.933333),
"sienna": (0.627451,0.321569,0.176471),
"silver": (0.752941,0.752941,0.752941),
"skyblue": (0.529412,0.807843,0.921569),
"slateblue": (0.415686,0.352941,0.803922),
"slategray": (0.439216,0.501961,0.564706),
"slategrey": (0.439216,0.501961,0.564706),
"snow": (1,0.980392,0.980392),
"springgreen": (0,1,0.498039),
"steelblue": (0.27451,0.509804,0.705882),
"tan": (0.823529,0.705882,0.54902),
"teal": (0,0.501961,0.501961),
"thistle": (0.847059,0.74902,0.847059),
"tomato": (1,0.388235,0.278431),
"turquoise": (0.25098,0.878431,0.815686),
"violet": (0.933333,0.509804,0.933333),
"wheat": (0.960784,0.870588,0.701961),
"white": (1,1,1),
"whitesmoke": (0.960784,0.960784,0.960784),
"yellow": (1,1,0),
"yellowgreen": (0.603922,0.803922,0.196078),
}

def _tokenize_path(pathdef):
    for x in COMMAND_RE.split(pathdef):
        if x in COMMANDS:
            yield x
        for token in FLOAT_RE.findall(x):
            yield token

def applyMatrix(matrix, z):
    return complex(z.real * matrix[0] + z.imag * matrix[1] + matrix[2],
             z.real * matrix[3] + z.imag * matrix[4] + matrix[5] )

def matrixMultiply(matrix1, matrix2):
    if matrix1 is None:
        return matrix2
    elif matrix2 is None:
        return matrix1

    m1 = [matrix1[0:3], matrix1[3:6] ] # don't need last row
    m2 = [matrix2[0:3], matrix2[3:6], [0,0,1]]

    out = []

    for i in range(2):
        for j in range(3):
            out.append( sum(m1[i][k]*m2[k][j] for k in range(3)) )

    return out

def parse_path(pathdef, current_pos=0j, matrix = None, svgState=None):
    if matrix is None:
        scaler=lambda z : z
    else:
        scaler=lambda z : applyMatrix(matrix, z)
    if svgState is None:
        svgState = path.SVGState()

    # In the SVG specs, initial movetos are absolute, even if
    # specified as 'm'. This is the default behavior here as well.
    # But if you pass in a current_pos variable, the initial moveto
    # will be relative to that current_pos. This is useful.
    elements = list(_tokenize_path(pathdef))
    # Reverse for easy use of .pop()
    elements.reverse()

    segments = path.Path(svgState = svgState)
    start_pos = None
    command = None

    while elements:

        if elements[-1] in COMMANDS:
            # New command.
            last_command = command  # Used by S and T
            command = elements.pop()
            absolute = command in UPPERCASE
            command = command.upper()
        else:
            # If this element starts with numbers, it is an implicit command
            # and we don't change the command. Check that it's allowed:
            if command is None:
                raise ValueError("Unallowed implicit command in %s, position %s" % (
                    pathdef, len(pathdef.split()) - len(elements)))
            last_command = command  # Used by S and T

        if command == 'M':
            # Moveto command.
            x = elements.pop()
            y = elements.pop()
            pos = float(x) + float(y) * 1j
            if absolute:
                current_pos = pos
            else:
                current_pos += pos

            # when M is called, reset start_pos
            # This behavior of Z is defined in svg spec:
            # http://www.w3.org/TR/SVG/paths.html#PathDataClosePathCommand
            start_pos = current_pos

            # Implicit moveto commands are treated as lineto commands.
            # So we set command to lineto here, in case there are
            # further implicit commands after this moveto.
            command = 'L'

        elif command == 'Z':
            # Close path
            if current_pos != start_pos:
                segments.append(path.Line(scaler(current_pos), scaler(start_pos)))
            if len(segments):
                segments.closed = True
            current_pos = start_pos
            start_pos = None
            command = None  # You can't have implicit commands after closing.

        elif command == 'L':
            x = elements.pop()
            y = elements.pop()
            pos = float(x) + float(y) * 1j
            if not absolute:
                pos += current_pos
            segments.append(path.Line(scaler(current_pos), scaler(pos)))
            current_pos = pos

        elif command == 'H':
            x = elements.pop()
            pos = float(x) + current_pos.imag * 1j
            if not absolute:
                pos += current_pos.real
            segments.append(path.Line(scaler(current_pos), scaler(pos)))
            current_pos = pos

        elif command == 'V':
            y = elements.pop()
            pos = current_pos.real + float(y) * 1j
            if not absolute:
                pos += current_pos.imag * 1j
            segments.append(path.Line(scaler(current_pos), scaler(pos)))
            current_pos = pos

        elif command == 'C':
            control1 = float(elements.pop()) + float(elements.pop()) * 1j
            control2 = float(elements.pop()) + float(elements.pop()) * 1j
            end = float(elements.pop()) + float(elements.pop()) * 1j

            if not absolute:
                control1 += current_pos
                control2 += current_pos
                end += current_pos

            segments.append(path.CubicBezier(scaler(current_pos), scaler(control1), scaler(control2), scaler(end)))
            current_pos = end

        elif command == 'S':
            # Smooth curve. First control point is the "reflection" of
            # the second control point in the previous path.

            if last_command not in 'CS':
                # If there is no previous command or if the previous command
                # was not an C, c, S or s, assume the first control point is
                # coincident with the current point.
                control1 = scaler(current_pos)
            else:
                # The first control point is assumed to be the reflection of
                # the second control point on the previous command relative
                # to the current point.
                control1 = 2 * scaler(current_pos) - segments[-1].control2

            control2 = float(elements.pop()) + float(elements.pop()) * 1j
            end = float(elements.pop()) + float(elements.pop()) * 1j

            if not absolute:
                control2 += current_pos
                end += current_pos

            segments.append(path.CubicBezier(scaler(current_pos), control1, scaler(control2), scaler(end)))
            current_pos = end

        elif command == 'Q':
            control = float(elements.pop()) + float(elements.pop()) * 1j
            end = float(elements.pop()) + float(elements.pop()) * 1j

            if not absolute:
                control += current_pos
                end += current_pos

            segments.append(path.QuadraticBezier(scaler(current_pos), scaler(control), scaler(end)))
            current_pos = end

        elif command == 'T':
            # Smooth curve. Control point is the "reflection" of
            # the second control point in the previous path.

            if last_command not in 'QT':
                # If there is no previous command or if the previous command
                # was not an Q, q, T or t, assume the first control point is
                # coincident with the current point.
                control = scaler(current_pos)
            else:
                # The control point is assumed to be the reflection of
                # the control point on the previous command relative
                # to the current point.
                control = 2 * scaler(current_pos) - segments[-1].control

            end = float(elements.pop()) + float(elements.pop()) * 1j

            if not absolute:
                end += current_pos

            segments.append(path.QuadraticBezier(scaler(current_pos), control, scaler(end)))
            current_pos = end

        elif command == 'A':
            radius = float(elements.pop()) + float(elements.pop()) * 1j
            rotation = float(elements.pop())
            arc = float(elements.pop())
            sweep = float(elements.pop())
            end = float(elements.pop()) + float(elements.pop()) * 1j

            if not absolute:
                end += current_pos

            segments.append(path.Arc(current_pos, radius, rotation, arc, sweep, end, scaler))
            current_pos = end

    return segments

def path_from_ellipse(x, y, rx, ry, matrix, state):
    arc = "M %.9f %.9f " % (x-rx,y)
    arc += "A %.9f %.9f 0 0 1 %.9f %.9f " % (rx, ry, x+rx,y)
    arc += "A %.9f %.9f 0 0 1 %.9f %.9f" % (rx, ry, x-rx,y)
    return parse_path(arc, matrix=matrix, svgState=state)

def path_from_rect(x,y,w,h,rx,ry, matrix,state):
    if not rx and not ry:
        rect = "M %.9f %.9f h %.9f v %.9f h %.9f Z" % (x,y,w,h,-w)
    else:
        if rx is None:
            rx = ry
        elif ry is None:
            ry = rx
        rect = "M %.9f %.9f h %.9f " % (x+rx,y,w-2*rx)
        rect += "a %.9f %.9f 0 0 1 %.9f %.9f " % (rx, ry, rx, ry)
        rect += "v %.9f " % (h-2*ry)
        rect += "a %.9f %.9f 0 0 1 %.9f %.9f " % (rx, ry, -rx, ry)
        rect += "h %.9f " % -(w-2*rx)
        rect += "a %.9f %.9f 0 0 1 %.9f %.9f " % (rx, ry, -rx, -ry)
        rect += "v %.9f " % -(h-2*ry)
        rect += "a %.9f %.9f 0 0 1 %.9f %.9f Z" % (rx, ry, rx, -ry)
    return parse_path(rect, matrix=matrix, svgState=state)

def sizeFromString(text):
    """
    Returns size in mm, if possible.
    """
    text = re.sub(r'\s',r'', text)
    try:
        return float(text)*25.4/96 # px
    except:
        if text[-1] == '%':
            return float(text[:-1]) # NOT mm
        units = text[-2:].lower()
        x = float(text[:-2])
        convert = { 'mm':1, 'cm':10, 'in':25.4, 'px':25.4/96, 'pt':25.4/72, 'pc':12*25.4/72 }
        try:
            return x * convert[units]
        except:
            return x # NOT mm

def rgbFromColor(colorName):
    colorName = colorName.strip().lower()
    if colorName == 'none':
        return None
    cmd = re.split(r'[\s(),]+', colorName)
    if cmd[0] == 'rgb':
        colors = cmd[1:4]
        outColor = []
        for c in colors:
            if c.endswith('%'):
                outColor.append(float(c[:-1]) / 100.)
            else:
                outColor.append(float(c) / 255.)
        return tuple(outColor)
    elif colorName.startswith('#'):
        if len(colorName) == 4:
            return (int(colorName[1],16)/15., int(colorName[2],16)/15., int(colorName[3],16)/15.)
        else:
            return (int(colorName[1:3],16)/255., int(colorName[3:5],16)/255., int(colorName[5:7],16)/255.)
    else:
        return SVG_COLORS[colorName]

def getPathsFromSVG(svg):
    def updateStateCommand(state,cmd,arg):
        if cmd == 'fill':
            state.fill = rgbFromColor(arg)
        elif cmd == 'fill-opacity':
            state.fillOpacity = float(arg)
        elif cmd == 'fill-rule':
            state.fillRule = arg
#            if state.fill is None:
#                state.fill = (0.,0.,0.)
        elif cmd == 'stroke':
            state.stroke = rgbFromColor(arg)
        elif cmd == 'stroke-opacity':
            state.strokeOpacity = rgbFromColor(arg)
        elif cmd == 'stroke-width':
            state.strokeWidth = float(arg)
        elif cmd == 'vector-effect':
            state.strokeWidthScaling = 'non-scaling-stroke' not in cmd
            # todo better scaling for non-uniform cases?

    def updateState(tree,state,matrix):
        state = state.clone()
        try:
            style = re.sub(r'\s',r'', tree.attrib['style']).lower()
            for item in style.split(';'):
                cmd,arg = item.split(':')[:2]
                updateStateCommand(state,cmd,arg)
        except:
            pass

        for item in tree.attrib:
            try:
                updateStateCommand(state,item,tree.attrib[item])
            except:
                pass

        if state.strokeWidth and state.strokeWidthScaling:
            # this won't work great for non-uniform scaling
            h = abs(applyMatrix(matrix, complex(0,state.strokeWidth)) - applyMatrix(matrix, 0j))
            w = abs(applyMatrix(matrix, complex(state.strokeWidth,0)) - applyMatrix(matrix, 0j))
            state.strokeWidth = (h+w)/2
        return state

    def reorder(a,b,c,d,e,f):
        return [a,c,e, b,d,f]

    def updateMatrix(tree, matrix):
        try:
            transformList = re.split(r'\)[\s,]+', tree.attrib['transform'].strip().lower())
        except KeyError:
            return matrix

        for transform in transformList:
            cmd = re.split(r'[,()\s]+', transform)

            updateMatrix = None

            if cmd[0] == 'matrix':
                updateMatrix = reorder(*list(map(float, cmd[1:7])))
            elif cmd[0] == 'translate':
                x = float(cmd[1])
                if len(cmd) >= 3 and cmd[2] != '':
                    y = float(cmd[2])
                else:
                    y = 0
                updateMatrix = reorder(1,0,0,1,x,y)
            elif cmd[0] == 'scale':
                x = float(cmd[1])
                if len(cmd) >= 3 and cmd[2] != '':
                    y = float(cmd[2])
                else:
                    y = x
                updateMatrix = reorder(x,0,0, y,0,0)
            elif cmd[0] == 'rotate':
                theta = float(cmd[1]) * math.pi / 180.
                c = math.cos(theta)
                s = math.sin(theta)
                updateMatrix = [c, -s, 0,  s, c, 0]
                if len(cmd) >= 4 and cmd[2] != '':
                    x = float(cmd[2])
                    y = float(cmd[3])
                    updateMatrix = matrixMultiply(updateMatrix, [1,0,-x, 0,1,-y])
                    updateMatrix = matrixMultiply([1,0,x, 0,1,y], updateMatrix)
            elif cmd[0] == 'skewX':
                theta = float(cmd[1]) * math.pi / 180.
                updateMatrix = [1, math.tan(theta), 0,  0,1,0]
            elif cmd[0] == 'skewY':
                theta = float(cmd[1]) * math.pi / 180.
                updateMatrix = [1,0,0, math.tan(theta),1,0]

            matrix = matrixMultiply(matrix, updateMatrix)

        return matrix

    def updateStateAndMatrix(tree,state,matrix):
        matrix = updateMatrix(tree,matrix)
        return updateState(tree,state,matrix),matrix

    def getPaths(paths, matrix, tree, state, savedElements):
        def getFloat(attribute,default=0.):
            try:
                return float(tree.attrib[attribute].strip())
            except KeyError:
                return default

        tag = re.sub(r'.*}', '', tree.tag).lower()
        try:
            savedElements[tree.attrib['id']] = tree
        except KeyError:
            pass

        state, matrix = updateStateAndMatrix(tree, state, matrix)
        if tag == 'path':
            path = parse_path(tree.attrib['d'], matrix=matrix, svgState=state)
            if len(path):
                paths.append(path)
        elif tag == 'circle':
            path = path_from_ellipse(getFloat('cx'), getFloat('cy'), getFloat('r'), getFloat('r'), matrix, state)
            paths.append(path)
        elif tag == 'ellipse':
            path = path_from_ellipse(getFloat('cx'), getFloat('cy'), getFloat('rx'), getFloat('ry'), matrix, state)
            paths.append(path)
        elif tag == 'line':
            x1 = getFloat('x1')
            y1 = getFloat('y1')
            x2 = getFloat('x2')
            y2 = getFloat('y2')
            p = 'M %.9f %.9f L %.9f %.9f' % (x1,y1,x2,y2)
            path = parse_path(p, matrix=matrix, svgState=state)
            paths.append(path)
        elif tag == 'polygon':
            points = re.split(r'[\s,]+', tree.attrib['points'].strip())
            p = ' '.join(['M', points[0], points[1], 'L'] + points[2:] + ['Z'])
            path = parse_path(p, matrix=matrix, svgState=state)
            paths.append(path)
        elif tag == 'polyline':
            points = re.split(r'[\s,]+', tree.attrib['points'].strip())
            p = ' '.join(['M', points[0], points[1], 'L'] + points[2:])
            path = parse_path(p, matrix=matrix, svgState=state)
            paths.append(path)
        elif tag == 'rect':
            x = getFloat('x')
            y = getFloat('y')
            w = getFloat('width')
            h = getFloat('height')
            rx = getFloat('rx',default=None)
            ry = getFloat('ry',default=None)
            path = path_from_rect(x,y,w,h,rx,ry, matrix,state)
            paths.append(path)
        elif tag == 'g' or tag == 'svg':
            for child in tree:
                getPaths(paths, matrix, child, state, savedElements)
        elif tag == 'use':
            try:
                link = None
                for tag in tree.attrib:
                    if tag.strip().lower().endswith("}href"):
                        link = tree.attrib[tag]
                        break
                if link is None or link[0] != '#':
                    raise KeyError
                source = savedElements[link[1:]]
                x = 0
                y = 0
                try:
                    x = float(tree.attrib['x'])
                except:
                    pass
                try:
                    y = float(tree.attrib['y'])
                except:
                    pass
                # TODO: handle width and height? (Inkscape does not)
                matrix = matrixMultiply(matrix, reorder(1,0,0,1,x,y))
                getPaths(paths, matrix, source, state, dict(savedElements))
            except KeyError:
                pass

    def scale(width, height, viewBox, z):
        x = (z.real - viewBox[0]) / (viewBox[2] - viewBox[0]) * width
        y = (viewBox[3]-z.imag) / (viewBox[3] - viewBox[1]) * height
        return complex(x,y)

    paths = []

    try:
        width = sizeFromString(svg.attrib['width'].strip())
    except KeyError:
        width = None
    try:
        height = sizeFromString(svg.attrib['height'].strip())
    except KeyError:
        height = None

    try:
        viewBox = list(map(float, re.split(r'[\s,]+', svg.attrib['viewBox'].strip())))
    except KeyError:
        if width is None or height is None:
            raise KeyError
        viewBox = [0, 0, width*96/25.4, height*96/25.4]

    if width is None:
        width = viewBox[2] * 25.4/96

    if height is None:
        height = viewBox[3] * 25.4/96

    viewBoxWidth = viewBox[2]
    viewBoxHeight = viewBox[3]

    viewBox[2] += viewBox[0]
    viewBox[3] += viewBox[1]

    try:
        preserve = svg.attrib['preserveAspectRatio'].strip().lower().split()
        if len(preserve[0]) != 8:
            raise KeyError
        if len(preserve)>=2 and preserve[1] == 'slice':
            if viewBoxWidth/viewBoxHeight > width/height:
                # viewbox is wider than viewport, so scale by height to ensure
                # viewbox covers the viewport
                rescale = height / viewBoxHeight
            else:
                rescale = width / viewBoxWidth
        else:
            if viewBoxWidth/viewBoxHeight > width/height:
                # viewbox is wider than viewport, so scale by width to ensure
                # viewport covers the viewbox
                rescale = width / viewBoxWidth
            else:
                rescale = height / viewBoxHeight
        matrix = [rescale, 0, 0,
                  0, rescale, 0];

        if preserve[0][0:4] == 'xmin':
            # viewBox[0] to 0
            matrix[2] = -viewBox[0] * rescale
        elif preserve[0][0:4] == 'xmid':
            # viewBox[0] to width/2
            matrix[2] = -viewBox[0] * rescale + width/2
        else: # preserve[0][0:4] == 'xmax':
            # viewBox[0] to width
            matrix[2] = -viewBox[0] * rescale + width

        if preserve[0][4:8] == 'ymin':
            # viewBox[1] to 0
            matrix[5] = -viewBox[1] * rescale
        elif preserve[0][4:8] == 'ymid':
            # viewBox[0] to width/2
            matrix[5] = -viewBox[1] * rescale + height/2
        else: # preserve[0][4:8] == 'xmax':
            # viewBox[0] to width
            matrix[5] = -viewBox[1] * rescale + height
    except:
        matrix = [ width/viewBoxWidth, 0, -viewBox[0]* width/viewBoxWidth,
                   0, -height/viewBoxHeight, viewBox[3]*height/viewBoxHeight ]

    getPaths(paths, matrix, svg, path.SVGState(), {})

    return ( paths, applyMatrix(matrix, complex(viewBox[0], viewBox[1])),
                applyMatrix(matrix, complex(viewBox[2], viewBox[3])) )

def getPathsFromSVGFile(filename):
    return getPathsFromSVG(ET.parse(filename).getroot())


import pytest

from linotp.lib.crypto.encrypted_data import EncryptedData

TEST_STRING = "test string to be encrypted"

# pylint:disable=redefined-outer-name

@pytest.fixture
def data():
    """
    Fixture to return an instance of encryptedData

    The unencrypted string is TEST_STRING
    """

    instance = EncryptedData(TEST_STRING)

    return instance

def test_str(data):
    """
    str() should return the string itself
    """
    assert str(data) == TEST_STRING

def test_repr(data):
    """
    repr() should return a placeholder
    """
    rep = repr(data)
    assert TEST_STRING not in rep
    assert rep == "XXXXXX"

@pytest.mark.usefixtures("hsm_obj")
def test_round_trip(app):
    orig_string = TEST_STRING

    with app.test_request_context():
        instance = EncryptedData.from_unencrypted(orig_string)
        unencrypted = instance.get_unencrypted()

        assert orig_string == unencrypted


"""Database manager tool. """

import argparse
import textwrap
import os
import re
import bz2
import logging
import sys
from functools import total_ordering

# import pandas as pd

from database.db import ETGDatabase
from database.online import scry
from database.online.gcs import GCSConnection

@total_ordering
class DBFile:
    """Wrapper around database filename for easy manipulation."""
    def __init__(self, filename: str):
        components = re.split("[_.]", filename)

        self.filename = filename
        self.version = int(components[1][1:])

    def __eq__(self, other: object) -> bool:
        return self.version == other.version

    def __lt__(self, other: object) -> bool:
        return self.version < other.version

class DBManager:
    """Updates, compresses, and pushes/pulls databases."""
    def __init__(self, args, logger, comp_type="bz2"):
        self.args = args
        self.logger = logger

        self.comp_type = comp_type

    # Commands ------------------------

    def update(self):
        """Downloads data and creates/updates database."""
        path = "data/db/"

        dbfile = self._get_dbfile("db")

        # Download data
        data = scry.download_default_cards()
        data = scry.to_dataframe(data)
        # temp_path = "database/experiments/data/"
        # data = pd.read_json(temp_path + os.listdir(temp_path)[-2])

        if dbfile:
            fname = dbfile.filename
        else:
            fname = "etg_v1.db"

        db = ETGDatabase(path + fname)
        db.update(data)

    def increment(self):
        """Creates new version of database by copying."""
        path = "data/db/"

        dbfile = self._get_dbfile("db")

        if dbfile:
            # Open database
            db = ETGDatabase(path + dbfile.filename)

            # Open new database
            new_filename = f"etg_v{dbfile.version + 1}.db"
            db_new = ETGDatabase(path + new_filename)

            # Copy to new and set new as working db
            db.conn.backup(db_new.conn)
            db = db_new
        else:
            self._log_warning("db-mgr: No database to increment!")

    def zip(self):
        dbfile = self._get_dbfile("db")

        if dbfile:
            zip_filename = dbfile.filename.split(".")[0] + ".bz2"

            with open(f"data/db/{dbfile.filename}", "rb") as f_in:
                with bz2.BZ2File(f"data/zip/{zip_filename}", "wb") as f_out:
                    f_out.writelines(f_in)
        else:
            self._log_warning("db-mgr: No databases to zip!")

    def unzip(self):
        zipfile = self._get_dbfile("zip")

        if zipfile:
            db_filename = zipfile.filename.split(".")[0] + ".db"

            with bz2.BZ2File(f"data/zip/{zipfile.filename}", "rb") as f_in:
                with open(f"data/db/{db_filename}", "wb") as f_out:
                    f_out.writelines(f_in)
        else:
            self._log_warning("db-mgr: No databases to unzip!")

    def push(self):
        self.zip()

        path = "data/zip/"

        gcs = GCSConnection()

        dbfile = self._get_dbfile("zip")

        if dbfile:
            fname = dbfile.filename
            fsize = self._get_filesize(path, fname)

            print(f"db-mgr: Pushing '{fname}' [{fsize:.4f} Mb]...")

            gcs.upload(path + fname, fname)

            # Delete older versions so only a given number remain
            gcs.clean(3)
        else:
            self._log_warning("db-mgr: No zipped databases to push!")

    def pull(self):
        path = "data/zip/"

        gcs = GCSConnection()

        source_names = gcs.get_filenames()
        dbfile = self._get_dbfile(self.comp_type, source_names)

        if dbfile:
            fname = dbfile.filename

            print(f"db-mgr: Pulling '{fname}'...")

            gcs.download(fname, path + fname)

            self.unzip()
        else:
            self._log_warning("db-mgr: No databases to pull!")

    # Helpers -------------------------

    def _get_dbfile(self, ftype, filenames=None):
        """Gets latest or specific version as DBFile."""
        v = self.args.version
        if v is None:
            return self._get_latest_dbfile(ftype, filenames)
        else:
            return self._get_version_dbfile(ftype, v)

    def _get_latest_dbfile(self, ftype: str, filenames = None):
        """Helper method for getting latest as a DBFile."""
        if filenames is None:
            path = f"data/{ftype}/"
            filenames = os.listdir(path)

        # Change file type to compression type if applicable
        if ftype == "zip":
            ftype = self.comp_type

        # Get newest version
        files = [DBFile(fname) for fname in filenames if f".{ftype}" in fname]

        if files:
            latest_file = max(files)

            return latest_file

        return None

    def _get_version_dbfile(self, ftype: str, version: int):
        """Helper method for getting a specific version as a DBFile."""
        path = f"data/{ftype}/"

        # Create filename for version
        fname = f"etg_v{version}."
        if ftype == "zip":
            ftype = self.comp_type
        fname += ftype

        if fname not in os.listdir(path):
            raise FileNotFoundError(f"There is no db version '{fname}'!")

        return DBFile(fname)

    def _log_warning(self, msg: str):
        print(msg)
        self.logger.warning(msg)

    @staticmethod
    def _get_filesize(path: str, fname: str):
        fsize = os.stat(path + fname).st_size

        # Bytes to Mb
        fsize = fsize / (1024 ** 2)

        return fsize

def main():
    # Parser
    descr = textwrap.dedent("""
        Manages ETG database updating and storage.

        Examples:
            $ py database/mgr.py update    -- updates latest db and creates new version
            $ py database/mgr.py zip -v 2  -- zip v2 in data/db/ to data/zip/
            $ py database/mgr.py push      -- push latest zipped db to online storage
    """)
    # Config argument parser
    parser = argparse.ArgumentParser(
        description=descr,
        formatter_class=argparse.RawTextHelpFormatter
    )
    parser.add_argument(
        "command",
        choices=["update", "increment", "zip", "unzip", "pull", "push"],
        help=(
            "Select a command for latest (default) or specified (-v) db version:\n"
            "  update    - Downloads daily data and creates/updates a db\n"
            "  increment - Copys db to create a new version\n"
            "  zip       - Compresses db and writes to data/zip/\n"
            "  unzip     - Uncompresses db and writes to data/db/\n"
            "  push      - Zips and pushes db to online storage (deletes older versions if too many)"
            "  pull      - Pulls zipped db from online storage and unzips\n"
        )
    )
    parser.add_argument("-v", "--version", type=int, help="Version number to operate on")

    # Config logger
    logging.basicConfig(
        filename="error.log",
        level=logging.WARNING,
        format="%(asctime)s - %(levelname)s - %(filename)s - %(funcName)s() -> %(message)s",
    )

    # Set logger to document uncaught errors
    sys.excepthook = lambda exc_type, exc_value, exc_traceback: logger.error(
        "Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback)
    )

    # Create manager
    args = parser.parse_args()
    logger = logging.getLogger()
    mgr = DBManager(args, logger)

    # Other init
    cmd = args.command
    db_alias = "latest db" if args.version is None else f"db v{args.version}"

    # Call command
    if cmd == "update":
        print(f"db-mgr: Updating {db_alias}...")
        mgr.update()
    if cmd == "increment":
        print(f"db-mgr: Creating new version of {db_alias}...")
        mgr.increment()
    if cmd == "zip":
        print(f"db-mgr: Zipping {db_alias}...")
        mgr.zip()
    if cmd == "unzip":
        print(f"db-mgr: Unzipping {db_alias}...")
        mgr.unzip()
    if cmd == "push":
        print(f"db-mgr: Pushing {db_alias}...")
        mgr.push()
    if cmd == "pull":
        print(f"db-mgr: Pulling {db_alias}...")
        mgr.pull()

if __name__ == "__main__":
    main()


"""Steps implementation for following scenarios: reset user's environment in OpenShift.io."""

from behave import when, then
from features.src.resetEnv import ResetEnvironment
from pyshould import should

@when(u'I reset environment')
def when_reset_environment(context):
    """Reset the environment."""
    resetEnv = ResetEnvironment()
    resetEnv.removeSpaces()
    resetEnv.cleanTenant()
    context.resetEnv = resetEnv

@then(u'I should see clean environment')
def then_clean_environment(context):
    """Check that environment has been reset."""
    len(context.resetEnv.getSpaces()) | should.equal(0).described_as(
        "Number of spaces after environment reset is 0."
    )


"""
MacGregor Winegard
Date: 11/21/2021
This function graphs one trajectory in 3d
"""
import numpy as np
np.set_printoptions(threshold = np.inf)
import matplotlib.pyplot as plt

#https://stackoverflow.com/questions/1054271/how-to-import-a-python-class-that-is-in-a-directory-above
import pathlib
import sys
_parentdir = pathlib.Path(__file__).parent.parent.resolve()
sys.path.insert(0, str(_parentdir))
from functions import kg_functions as fxns
sys.path.remove(str(_parentdir))

l_0 = float(input("Input l_0: "))
h_0 = float(input("Input h_0: "))
n_steps = int(input("Num steps: "))

result = fxns.calc_trajectory(l_0, h_0, n_steps)

print("Here is the trajectory:")
print(result)

print("Plotting")
fig = plt.figure()
ax = plt.axes(projection='3d')
ax.plot3D(
        result[:,0],
        result[:,1],
        np.linspace(0, n_steps, n_steps+1)
        )
plt.show()


#!/usr/bin/python

#hello.py
import sys, getopt, codecs

def copyFromFileToFile(src_file_name, dest_file_name, lines, somestring, start = 0):
    src_file = codecs.open(src_file_name, 'r', 'utf-8')
    dest_file = codecs.open(dest_file_name, 'w', 'utf-8')

    line = src_file.readline()
    i = 0;
    num = 0;
    while line:
        i += 1
        if (i >= start):
            num+= 1
            if num>lines:
                break

            if (line.find(somestring) >= 0):
                dest_file.write(line)

        line = src_file.readline()

    src_file.close();
    dest_file.close();

def usage():
    print('Help!! Please put in "-i inputfile_name -o output_file_name -l 10000 -c somestring -s 50"!')

def parseParams():
    opts, args = getopt.getopt(sys.argv[1:], "hi:o:l:c:s:")

    input_file=""
    output_file="output"
    lines = 1000
    somestring = "";
    start = 0

    for op, value in opts:
        if op == "-i":
            input_file = value
        elif op == "-o":
            output_file = value
        elif op == "-l":
            lines = int(value)
        elif op == "-c":
            somestring = value
        elif op == "-s":
            start = int(value)
        elif op == "-h":
            usage()
            sys.exit()

    if (input_file == ""):
        usage()
        sys.exit()

    print("input", input_file, "output", output_file, "line", lines, "contain", somestring, "start from:", start)

    return input_file, output_file, lines, somestring, start

if __name__=="__main__":

    input_file, output_file, lines, somestring, start = parseParams()

    copyFromFileToFile(input_file, output_file, lines, somestring, start)


"""mysite1 URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.conf.urls import url, include
    2. Add a URL to urlpatterns:  url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from django.contrib import admin
from . import views

#该配置项将子行而下逐一匹配 若某行配置上，则终止向下匹配行为
urlpatterns = [
    #url(正则,视图函数,name = 别名)
    url(r'^admin/', admin.site.urls),
    url(r'^$',views.index_view),
    # http://127.0.0.1:8000/page1
    url(r'^page1$', views.page1_view),
    #http://127.0.0.1:8000/page2
    url(r'^page2$', views.page2_view),
    url(r'^page(\d+)',views.pagen_view),
    url(r'^(\d+)/(\w+)/(\d+)',views.acl_view),
    url(r'^person/(?P<name>\w+)/(?P<age>\d{1,2})',views.person_view),
    url(r'^birthday/(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})',views.birthday_view),
    url(r'^birthday/(?P<day>\d{1,2})/(?P<month>\d{1,2})/(?P<year>\d{4})',views.birthday_view),
    url(r'^test_get$',views.test_get),
    url(r'^test_get_server$',views.test_get_server),
]


#!/usr/bin/env python
import os
from setuptools import find_packages, setuptools

with open("README.md", "r") as fh:
    long_description = fh.read()

setuptools.setup(
    name="mygeoparse",
    version="0.0.9",
    description='Malaysia Address Parser',
    long_description=long_description,
    long_description_content_type='text/markdown',
    url='https://github.com/azzan-amin-97/tlo-my-address-parser.git',
    download_url='https://github.com/azzan-amin-97/tlo-my-address-parser/archive/refs/heads/master.zip',
    author="Azzan Amin",
    author_email='ibnuamin97@thelorry.com',
    packages=["mygeoparse"],
    keywords=['address', 'parser', 'ner'],
    license='MIT',
    install_requires=['spacy>=2.3.2', 'pandas'],
    classifiers=[
        # How mature is this project? Common values are
        #   3 - Alpha
        #   4 - Beta
        #   5 - Production/Stable
        'Development Status :: 3 - Alpha',

        # Indicate who your project is intended for
        'Intended Audience :: Developers',
        'Topic :: Software Development',

        # Pick your license as you wish (should match "license" above)
        'License :: OSI Approved :: MIT License',
        'Operating System :: OS Independent',

        # Specify the Python versions you support here. In particular, ensure
        # that you indicate whether you support Python 2, Python 3 or both.
        'Programming Language :: Python :: 3.6',
    ]
)


from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager

from ProductListing import ProductListing
from ProductDetail import ProductDetail
import json

def crawl_links_from_listing_page(driver, url):
  productListing = ProductListing(driver)
  productListing.open_browser_with_link(url)
  productListing.click_load_more()
  links = productListing.crawl_links_from_product_list()
  return links

def crawl_data_from_detail_page(driver, links, limit_size = 0):
  productDetail = ProductDetail(driver)
  result = []
  count = 0
  for link in links:
    if limit_size > 0 and count == limit_size:
      break
    productDetail.open_browser_with_link(link)
    productDetail.open_browser_with_link(link)
    title = productDetail.crawl_product_title()
    current_price = productDetail.crawl_product_current_price()
    previous_price = productDetail.crawl_product_previous_price()
    color = productDetail.crawl_product_color()
    thumbnails = productDetail.crawl_product_thumbnails()
    rating = productDetail.crawl_product_rating()
    total_reviews = productDetail.crawl_product_total_reviews()
    result.append({
      "url": link,
      "title": title,
      "current_price": current_price,
      "previous_price": previous_price,
      "color": color,
      "rating": rating,
      "total_reviews": total_reviews,
      "thumbnails": thumbnails
    })
    count = count + 1
  return result

def main():
  # Initialize Chrome WebDriver
  driver = webdriver.Chrome(ChromeDriverManager().install())
  init_link = 'https://www.asos.com/women/shoes/boots/cat/?cid=6455&nlid=ww|shoes|shop+by+product|boots'

  links = crawl_links_from_listing_page(driver, init_link)

  # Demo with limit size
  limit_size = 10
  products = crawl_data_from_detail_page(driver, links, limit_size)

  result = {
    "count": len(products),
    "products": products,
  }

  driver.quit()

  with open('data.json', 'w', encoding='utf-8') as f:
    json.dump(result, f, ensure_ascii=False, indent=4)

main()


from time import sleep

import diagnostic_msgs
import diagnostic_updater
import rclpy
import std_msgs

time_to_launch = 0

"""Used as a tutorial for loading and using diagnostic updater.
DummyClass and dummy_diagnostics show how to use a diagnostic_updater
class.
"""

def dummy_diagnostic(stat):
    # stat is supposed to be of type diagnostic_updater.DiagnosticStatusWrapper
    # DiagnosticStatusWrapper is a derived class of
    # diagnostic_msgs.msg.DiagnosticStatus that provides a set of convenience
    # methods.

    # summary sets the level and message.
    # As opposed to the C++ API, there is no summaryf function: use python's
    # string formatting instead
    if time_to_launch < 10:
        # summary for formatted text.
        stat.summary(
            diagnostic_msgs.msg.DiagnosticStatus.ERROR,
            'Buckle your seat belt. Launch in %f seconds!' % time_to_launch)
    else:
        # summary for unformatted text. It's just the same ;)
        stat.summary(
            diagnostic_msgs.msg.DiagnosticStatus.OK,
            'Launch is in a long time. Have a soda.')

    # add is used to append key-value pairs.
    # Again, as oppose to the C++ API, there is no addf function. The second
    # argument is always converted to a str using the str() function.
    stat.add('Diagnostic Name', 'dummy')
    # add transparently handles conversion to string (using str()).
    stat.add('Time to Launch', 'time_to_launch')
    # add allows arbitrary printf style formatting.
    stat.add('Geeky thing to say', 'The square of the time to launch %f is %f'
             % (time_to_launch, time_to_launch * time_to_launch))

    # As opposed to the C++ diagnostic function which modifies its argument,
    # the python version must return the modified message.
    return stat

class DummyClass:

    def produce_diagnostics(self, stat):
        stat.summary(diagnostic_msgs.msg.DiagnosticStatus.WARN,
                     'This is a silly updater.')
        stat.add('Stupidicity of this updater', '1000')
        return stat

class DummyTask(diagnostic_updater.DiagnosticTask):

    def __init__(self):
        diagnostic_updater.DiagnosticTask.__init__(
            self,
            'Updater Derived from DiagnosticTask')

    def run(self, stat):
        stat.summary(diagnostic_msgs.msg.DiagnosticStatus.WARN,
                     'This is another silly updater.')
        stat.add('Stupidicity of this updater', '2000')
        return stat

def check_lower_bound(stat):
    if time_to_launch > 5:
        stat.summary(diagnostic_msgs.msg.DiagnosticStatus.OK, 'Lower-bound OK')
    else:
        stat.summary(diagnostic_msgs.msg.DiagnosticStatus.ERROR, 'Too low')
    stat.add('Low-Side Margin', 'time_to_launch - 5')
    return stat

def check_upper_bound(stat):
    if time_to_launch < 10:
        stat.summary(diagnostic_msgs.msg.DiagnosticStatus.OK, 'Upper-bound OK')
    else:
        stat.summary(diagnostic_msgs.msg.DiagnosticStatus.WARN, 'Too high')
    stat.add('Top-Side Margin', '10 - time_to_launch')
    return stat

def main():
    rclpy.init()
    node = rclpy.create_node('diagnostic_updater_example')
    # The Updater class advertises to /diagnostics, and has a
    # ~diagnostic_period parameter that says how often the diagnostics
    # should be published.
    updater = diagnostic_updater.Updater(node)

    # The diagnostic_updater.Updater class will fill out the hardware_id
    # field of the diagnostic_msgs.msg.DiagnosticStatus message. You need to
    # use the setHardwareID() method to set the hardware ID.
    #
    # The hardware ID should be able to identify the specific device you are
    # working with.  If it is not appropriate to fill out a hardware ID in
    # your case, you should call setHardwareID("none") to avoid warnings.
    # (A warning will be generated as soon as your node updates with no
    # non-OK statuses.)
    updater.setHardwareID('none')
    # Or...
    updater.setHardwareID('Device-%i-%i' % (27, 46))

    # Diagnostic tasks are added to the Updater. They will later be run when
    # the updater decides to update.
    # As opposed to the C++ API, there is only one add function. It can take
    # several types of arguments:
    #  - add(task): where task is a DiagnosticTask
    #  - add(name, fn): add a DiagnosticTask embodied by a name and function
    updater.add('Function updater', dummy_diagnostic)
    dc = DummyClass()
    updater.add('Method updater', dc.produce_diagnostics)

    # Internally, updater.add converts its arguments into a DiagnosticTask.
    # Sometimes it can be useful to work directly with DiagnosticTasks. Look
    # at FrequencyStatus and TimestampStatus in update_functions for a
    # real-life example of how to make a DiagnosticTask by deriving from
    # DiagnosticTask.

    # Alternatively, a FunctionDiagnosticTask is a derived class from
    # DiagnosticTask that can be used to create a DiagnosticTask from
    # a function. This will be useful when combining multiple diagnostic
    # tasks using a CompositeDiagnosticTask.
    lower = diagnostic_updater.FunctionDiagnosticTask('Lower-bound check',
                                                      check_lower_bound)
    upper = diagnostic_updater.FunctionDiagnosticTask('Upper-bound check',
                                                      check_upper_bound)

    # If you want to merge the outputs of two diagnostic tasks together, you
    # can create a CompositeDiagnosticTask, also a derived class from
    # DiagnosticTask. For example, we could combine the upper and lower
    # bounds check into a single DiagnosticTask.
    bounds = diagnostic_updater.CompositeDiagnosticTask('Bound check')
    bounds.addTask(lower)
    bounds.addTask(upper)

    # We can then add the CompositeDiagnosticTask to our Updater. When it is
    # run, the overall name will be the name of the composite task, i.e.,
    # "Bound check". The summary will be a combination of the summary of the
    # lower and upper tasks (see DiagnosticStatusWrapper.mergeSummary for
    # details on how the merging is done). The lists of key-value pairs will be
    # concatenated.
    updater.add(bounds)

    # You can broadcast a message in all the DiagnosticStatus if your node
    # is in a special state.
    updater.broadcast(diagnostic_msgs.msg.DiagnosticStatus.OK,
                      'Doing important initialization stuff.')

    pub1 = node.create_publisher(std_msgs.msg.Bool, 'topic1', 10)
    sleep(2)  # It isn't important if it doesn't take time.

    # Some diagnostic tasks are very common, such as checking the rate
    # at which a topic is publishing, or checking that timestamps are
    # sufficiently recent. FrequencyStatus and TimestampStatus can do these
    # checks for you.
    #
    # Usually you would instantiate them via a HeaderlessTopicDiagnostic
    # (FrequencyStatus only, for topics that do not contain a header) or a
    # TopicDiagnostic (FrequencyStatus and TimestampStatus, for topics that
    # do contain a header).
    #
    # Some values are passed to the constructor as pointers. If these values
    # are changed, the FrequencyStatus/TimestampStatus will start operating
    # with the new values.
    #
    # Refer to diagnostic_updater.FrequencyStatusParam and
    # diagnostic_updater.TimestampStatusParam documentation for details on
    # what the parameters mean:
    freq_bounds = {'min': 0.5, 'max': 2}  # If you update these values, the
    # HeaderlessTopicDiagnostic will use the new values.
    pub1_freq = (
        diagnostic_updater.HeaderlessTopicDiagnostic(
            'topic1', updater,
            diagnostic_updater.FrequencyStatusParam(freq_bounds, 0.1, 10)))

    # Note that TopicDiagnostic, HeaderlessDiagnosedPublisher,
    # HeaderlessDiagnosedPublisher and DiagnosedPublisher all descend from
    # CompositeDiagnosticTask, so you can add your own fields to them using
    # the addTask method.
    #
    # Each time pub1_freq is updated, lower will also get updated and its
    # output will be merged with the output from pub1_freq.
    pub1_freq.addTask(lower)  # (This wouldn't work if lower was stateful).

    # If we know that the state of the node just changed, we can force an
    # immediate update.
    updater.force_update()

    # We can remove a task by refering to its name.
    if not updater.removeByName('Bound check'):
        node.get_logger().error(
            'The Bound check task was not found when trying to remove it.')

    msg = std_msgs.msg.Bool()
    while rclpy.ok():
        sleep(0.1)

        # Calls to pub1 have to be accompanied by calls to pub1_freq to keep
        # the statistics up to date.
        msg.data = False
        pub1.publish(msg)
        pub1_freq.tick()

        rclpy.spin_once(node, timeout_sec=1)

if __name__ == '__main__':
    main()


import numpy as np
from unsupervised_learning.MDS.multiple_dimensional_scaling import MultipleDimensionalScaling

class Isomap:
    """ Isomap，流形学习，非线性降维.
    Attributes:
        d: 降维后的维数/特征数
        k: 计算测地距离矩阵时的邻域样本个数
    """
    def __init__(self, d, k):
        self.d = d
        self.k = k

    def _floyd(self, euclidean_distance):
        """ 计算测地距离矩阵 """
        n_samples = euclidean_distance.shape[0]
        geodesic_distance = np.full_like(euclidean_distance, np.max(euclidean_distance) * 1e8)
        k_index = np.argsort(euclidean_distance, axis=1)
        # 构建迭代用的初始距离矩阵
        for i in range(n_samples):
            geodesic_distance[i, k_index[i, :self.k+1]] = euclidean_distance[i, k_index[i, :self.k+1]]
        # 使用Floyd算法进行迭代计算
        for step in range(n_samples):
            for i in range(n_samples):
                for j in range(n_samples):
                    if geodesic_distance[i, j] > geodesic_distance[i, step] + geodesic_distance[step, j]:
                        geodesic_distance[i, j] = geodesic_distance[i, step] + geodesic_distance[step, j]
        return geodesic_distance

    def dimension_reduction(self, X):
        """ 非线性降维 """
        n_samples = X.shape[0]
        # 以下是MDS算法（只不过用测地距离代替了欧氏距离）
        # -------------------------------------
        # 1) 计算距离的平方矩阵
        euclidean_distance = np.sqrt(MultipleDimensionalScaling.calculate_distance_matrix(X))
        distance_squared_matrix = np.power(self._floyd(euclidean_distance), 2)
        # 2) 计算降维后的内积矩阵
        dist_i_squared = np.expand_dims(distance_squared_matrix.sum(axis=1), axis=1) / n_samples
        dist_j_squared = distance_squared_matrix.sum(axis=0) / n_samples
        dist_squared = distance_squared_matrix.sum() / n_samples ** 2
        inner_product_matrix = -0.5 * (distance_squared_matrix - dist_i_squared -
                                       dist_j_squared + dist_squared)
        # 3) 对内积矩阵进行特征值分解以获得降维后的坐标
        eigenvalues, eigenvectors = np.linalg.eig(inner_product_matrix)
        picked_index = eigenvalues.argsort()[::-1][:self.d]
        picked_eigenvalues = np.sqrt(np.diag(eigenvalues[picked_index])).real
        picked_eigenvectors = eigenvectors.T[picked_index].real
        return np.dot(picked_eigenvectors.T, picked_eigenvalues)

if __name__ == '__main__':
    def main():
        # from sklearn.datasets import load_iris
        # import matplotlib.pyplot as plt
        # iris_data = load_iris()
        # X, Y = iris_data.data, iris_data.target

        from sklearn.datasets import make_s_curve, make_swiss_roll
        import matplotlib.pyplot as plt
        # X, Y = make_s_curve(n_samples=500, noise=0.15, random_state=40)
        X, Y = make_swiss_roll(n_samples=500, noise=0.15, random_state=100)

        isomap = Isomap(d=2, k=20)
        y = isomap.dimension_reduction(X)
        plt.scatter(y[:, 0], y[:, 1], c=Y)
        plt.show()
    main()


from __future__ import annotations

import asyncio
import atexit
import threading
from multiprocessing.util import _exit_function  # type: ignore[attr-defined]
from typing import TYPE_CHECKING, Any

import uvloop

from app.lib import settings

from .base import Queue, Worker

if TYPE_CHECKING:
    from collections.abc import Awaitable, Callable, Collection

    import saq

__all__ = ["create_worker_instance", "run_worker"]

def create_worker_instance(
    queue: Queue,
    tasks: Collection[Callable[..., Any] | tuple[str, Callable]],
    scheduled_tasks: Collection[saq.CronJob] | None = None,
    startup: Callable[[dict[str, Any]], Awaitable[Any]] | None = None,
    shutdown: Callable[[dict[str, Any]], Awaitable[Any]] | None = None,
    before_process: Callable[[dict[str, Any]], Awaitable[Any]] | None = None,
    after_process: Callable[[dict[str, Any]], Awaitable[Any]] | None = None,
    concurrency: int | None = None,
) -> Worker:
    """Create worker instance.

    Args:
        queue: Queue: The queue instance to use for the worker
        tasks: Collection[Callable[..., Any] | tuple[str, Callable]]: Functions to be called via the async workers
        scheduled_tasks (Collection[saq.CronJob] | None, optional): Scheduled functions to be called via the async workers. Defaults to None.
        startup (Callable[[dict[str, Any]], Awaitable[Any]] | None, optional): Async function called on startup. Defaults to None.
        shutdown (Callable[[dict[str, Any]], Awaitable[Any]] | None, optional): Async functions called on startup. Defaults to None.
        before_process (Callable[[dict[str, Any]], Awaitable[Any]] | None, optional): Async function called before a job processes.. Defaults to None.
        after_process (Callable[[dict[str, Any]], Awaitable[Any]] | None, optional): _Async function called after a job processes. Defaults to None.
        concurrency (int | None, optional): _description_. Defaults to None.

    Returns:
        Worker: The worker instance
    """
    if concurrency is None:
        concurrency = settings.worker.CONCURRENCY
    return Worker(
        queue,
        functions=tasks,
        cron_jobs=scheduled_tasks,
        startup=startup,
        shutdown=shutdown,
        before_process=before_process,
        after_process=after_process,
        concurrency=concurrency,
    )

def run_worker() -> None:
    """Run a worker."""
    from app.domain import scheduled_tasks, tasks
    from app.lib import log
    from app.lib.log.worker import after_process as after_logging_process
    from app.lib.log.worker import before_process as before_logging_process
    from app.lib.log.worker import on_shutdown as shutdown_logging_process
    from app.lib.log.worker import on_startup as startup_logging_process
    from app.lib.worker import queues

    if threading.current_thread() is not threading.main_thread():
        atexit.unregister(_exit_function)
    logger = log.get_logger()
    logger.info("Starting working pool")
    loop = _create_event_loop()
    worker_instances: list[Worker] = [
        create_worker_instance(
            queue=queue,
            tasks=tasks.get(queue, []),
            scheduled_tasks=scheduled_tasks.get(queue, []),
            startup=startup_logging_process,
            shutdown=shutdown_logging_process,
            after_process=after_logging_process,
            before_process=before_logging_process,
        )
        for queue in queues.values()
    ]
    try:
        for i, worker_instance in enumerate(worker_instances):
            if i < len(worker_instances) - 1:
                loop.create_task(worker_instance.start())
            else:
                loop.run_until_complete(worker_instance.start())
    except KeyboardInterrupt:
        for worker_instance in worker_instances:
            loop.run_until_complete(worker_instance.stop())

def _create_event_loop() -> asyncio.AbstractEventLoop:
    asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())
    return asyncio.new_event_loop()


# https://atcoder.jp/contests/abc285/tasks/abc285_a

a, b = [int(x) for x in input().split()]

def solve(a: int, b: int):
    result = (b == a * 2) or (b == a * 2 + 1)
    print(["No", "Yes"][result])

solve(a, b)