/* THIS IS A SINGLE-FILE DISTRIBUTION CONCATENATED FROM THE OPEN62541 SOURCES
 * visit http://open62541.org/ for information about this software
 * Git-Revision: v1.4.0-rc2-321-g0bd65af85
 */

/*
 * Copyright (C) 2014-2021 the contributors as stated in the AUTHORS file
 *
 * This file is part of open62541. open62541 is free software: you can
 * redistribute it and/or modify it under the terms of the Mozilla Public
 * License v2.0 as stated in the LICENSE file provided with open62541.
 *
 * open62541 is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE.
 */

#ifndef UA_DYNAMIC_LINKING_EXPORT
# define UA_DYNAMIC_LINKING_EXPORT
# define MDNSD_DYNAMIC_LINKING
#endif

#define UA_INLINABLE_IMPL 1

/* Disable security warnings for BSD sockets on MSVC */
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
# define _CRT_SECURE_NO_WARNINGS
#endif

#include "open62541.h"

/**** amalgamated original file "/deps/open62541_queue.h" ****/

/*	$OpenBSD: queue.h,v 1.38 2013/07/03 15:05:21 fgsch Exp $	*/
/*	$NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $	*/

/*
 * Copyright (c) 1991, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *	@(#)queue.h	8.5 (Berkeley) 8/20/94
 */


/*
 * This file defines five types of data structures: singly-linked lists, 
 * lists, simple queues, tail queues, and circular queues.
 *
 *
 * A singly-linked list is headed by a single forward pointer. The elements
 * are singly linked for minimum space and pointer manipulation overhead at
 * the expense of O(n) removal for arbitrary elements. New elements can be
 * added to the list after an existing element or at the head of the list.
 * Elements being removed from the head of the list should use the explicit
 * macro for this purpose for optimum efficiency. A singly-linked list may
 * only be traversed in the forward direction.  Singly-linked lists are ideal
 * for applications with large datasets and few or no removals or for
 * implementing a LIFO queue.
 *
 * A list is headed by a single forward pointer (or an array of forward
 * pointers for a hash table header). The elements are doubly linked
 * so that an arbitrary element can be removed without a need to
 * traverse the list. New elements can be added to the list before
 * or after an existing element or at the head of the list. A list
 * may only be traversed in the forward direction.
 *
 * A simple queue is headed by a pair of pointers, one the head of the
 * list and the other to the tail of the list. The elements are singly
 * linked to save space, so elements can only be removed from the
 * head of the list. New elements can be added to the list before or after
 * an existing element, at the head of the list, or at the end of the
 * list. A simple queue may only be traversed in the forward direction.
 *
 * A tail queue is headed by a pair of pointers, one to the head of the
 * list and the other to the tail of the list. The elements are doubly
 * linked so that an arbitrary element can be removed without a need to
 * traverse the list. New elements can be added to the list before or
 * after an existing element, at the head of the list, or at the end of
 * the list. A tail queue may be traversed in either direction.
 *
 * A circle queue is headed by a pair of pointers, one to the head of the
 * list and the other to the tail of the list. The elements are doubly
 * linked so that an arbitrary element can be removed without a need to
 * traverse the list. New elements can be added to the list before or after
 * an existing element, at the head of the list, or at the end of the list.
 * A circle queue may be traversed in either direction, but has a more
 * complex end of list detection.
 *
 * For details on the use of these macros, see the queue(3) manual page.
 */

#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC))
#define _Q_INVALIDATE(a) (a) = ((void *)-1)
#else
#define _Q_INVALIDATE(a)
#endif

/*
 * Singly-linked List definitions.
 */
#define SLIST_HEAD(name, type)						\
struct name {								\
    struct type *slh_first;	/* first element */			\
}
 
#define	SLIST_HEAD_INITIALIZER(head)					\
    { NULL }

#define SLIST_ENTRY(type)						\
struct {								\
    struct type *sle_next;	/* next element */			\
}
 
/*
 * Singly-linked List access methods.
 */
#define	SLIST_FIRST(head)	((head)->slh_first)
#define	SLIST_END(head)		NULL
#define	SLIST_EMPTY(head)	(SLIST_FIRST(head) == SLIST_END(head))
#define	SLIST_NEXT(elm, field)	((elm)->field.sle_next)

#define	SLIST_FOREACH(var, head, field)					\
    for((var) = SLIST_FIRST(head);					\
        (var) != SLIST_END(head);					\
        (var) = SLIST_NEXT(var, field))

#define	SLIST_FOREACH_SAFE(var, head, field, tvar)			\
    for ((var) = SLIST_FIRST(head);				\
        (var) && ((tvar) = SLIST_NEXT(var, field), 1);		\
        (var) = (tvar))

/*
 * Singly-linked List functions.
 */
#define	SLIST_INIT(head) do {						\
    SLIST_FIRST(head) = SLIST_END(head);				\
} while(0)

#define	SLIST_INSERT_AFTER(slistelm, elm, field) do {			\
    (elm)->field.sle_next = (slistelm)->field.sle_next;		\
    (slistelm)->field.sle_next = (elm);				\
} while (0)

#define	SLIST_INSERT_HEAD(head, elm, field) do {			\
    (elm)->field.sle_next = (head)->slh_first;			\
    (head)->slh_first = (elm);					\
} while (0)

#define	SLIST_REMOVE_AFTER(elm, field) do {				\
    (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next;	\
} while (0)

#define	SLIST_REMOVE_HEAD(head, field) do {				\
    (head)->slh_first = (head)->slh_first->field.sle_next;		\
} while (0)

#define SLIST_REMOVE(head, elm, type, field) do {			\
    if ((head)->slh_first == (elm)) {				\
        SLIST_REMOVE_HEAD((head), field);			\
    } else {							\
        struct type *curelm = (head)->slh_first;		\
                                    \
        while (curelm->field.sle_next != (elm))			\
            curelm = curelm->field.sle_next;		\
        curelm->field.sle_next =				\
            curelm->field.sle_next->field.sle_next;		\
        _Q_INVALIDATE((elm)->field.sle_next);			\
    }								\
} while (0)

/*
 * List definitions.
 */
#define LIST_HEAD(name, type)						\
struct name {								\
    struct type *lh_first;	/* first element */			\
}

#define LIST_HEAD_INITIALIZER(head)					\
    { NULL }

#define LIST_ENTRY(type)						\
struct {								\
    struct type *le_next;	/* next element */			\
    struct type **le_prev;	/* address of previous next element */	\
}

/*
 * List access methods
 */
#define	LIST_FIRST(head)		((head)->lh_first)
#define	LIST_END(head)			NULL
#define	LIST_EMPTY(head)		(LIST_FIRST(head) == LIST_END(head))
#define	LIST_NEXT(elm, field)		((elm)->field.le_next)

#define LIST_FOREACH(var, head, field)					\
    for((var) = LIST_FIRST(head);					\
        (var)!= LIST_END(head);					\
        (var) = LIST_NEXT(var, field))

#define	LIST_FOREACH_SAFE(var, head, field, tvar)			\
    for ((var) = LIST_FIRST(head);				\
        (var) && ((tvar) = LIST_NEXT(var, field), 1);		\
        (var) = (tvar))

/*
 * List functions.
 */
#define	LIST_INIT(head) do {						\
    LIST_FIRST(head) = LIST_END(head);				\
} while (0)

#define LIST_INSERT_AFTER(listelm, elm, field) do {			\
    if (((elm)->field.le_next = (listelm)->field.le_next) != NULL)	\
        (listelm)->field.le_next->field.le_prev =		\
            &(elm)->field.le_next;				\
    (listelm)->field.le_next = (elm);				\
    (elm)->field.le_prev = &(listelm)->field.le_next;		\
} while (0)

#define	LIST_INSERT_BEFORE(listelm, elm, field) do {			\
    (elm)->field.le_prev = (listelm)->field.le_prev;		\
    (elm)->field.le_next = (listelm);				\
    *(listelm)->field.le_prev = (elm);				\
    (listelm)->field.le_prev = &(elm)->field.le_next;		\
} while (0)

#define LIST_INSERT_HEAD(head, elm, field) do {				\
    if (((elm)->field.le_next = (head)->lh_first) != NULL)		\
        (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
    (head)->lh_first = (elm);					\
    (elm)->field.le_prev = &(head)->lh_first;			\
} while (0)

#define LIST_REMOVE(elm, field) do {					\
    if ((elm)->field.le_next != NULL)				\
        (elm)->field.le_next->field.le_prev =			\
            (elm)->field.le_prev;				\
    *(elm)->field.le_prev = (elm)->field.le_next;			\
    _Q_INVALIDATE((elm)->field.le_prev);				\
    _Q_INVALIDATE((elm)->field.le_next);				\
} while (0)

#define LIST_REPLACE(elm, elm2, field) do {				\
    if (((elm2)->field.le_next = (elm)->field.le_next) != NULL)	\
        (elm2)->field.le_next->field.le_prev =			\
            &(elm2)->field.le_next;				\
    (elm2)->field.le_prev = (elm)->field.le_prev;			\
    *(elm2)->field.le_prev = (elm2);				\
    _Q_INVALIDATE((elm)->field.le_prev);				\
    _Q_INVALIDATE((elm)->field.le_next);				\
} while (0)

/*
 * Simple queue definitions.
 */
#define SIMPLEQ_HEAD(name, type)					\
struct name {								\
    struct type *sqh_first;	/* first element */			\
    struct type **sqh_last;	/* addr of last next element */		\
}

#define SIMPLEQ_HEAD_INITIALIZER(head)					\
    { NULL, &(head).sqh_first }

#define SIMPLEQ_ENTRY(type)						\
struct {								\
    struct type *sqe_next;	/* next element */			\
}

/*
 * Simple queue access methods.
 */
#define	SIMPLEQ_FIRST(head)	    ((head)->sqh_first)
#define	SIMPLEQ_END(head)	    NULL
#define	SIMPLEQ_EMPTY(head)	    (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
#define	SIMPLEQ_NEXT(elm, field)    ((elm)->field.sqe_next)

#define SIMPLEQ_FOREACH(var, head, field)				\
    for((var) = SIMPLEQ_FIRST(head);				\
        (var) != SIMPLEQ_END(head);					\
        (var) = SIMPLEQ_NEXT(var, field))

#define	SIMPLEQ_FOREACH_SAFE(var, head, field, tvar)			\
    for ((var) = SIMPLEQ_FIRST(head);				\
        (var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1);		\
        (var) = (tvar))

/*
 * Simple queue functions.
 */
#define	SIMPLEQ_INIT(head) do {						\
    (head)->sqh_first = NULL;					\
    (head)->sqh_last = &(head)->sqh_first;				\
} while (0)

#define SIMPLEQ_INSERT_HEAD(head, elm, field) do {			\
    if (((elm)->field.sqe_next = (head)->sqh_first) == NULL)	\
        (head)->sqh_last = &(elm)->field.sqe_next;		\
    (head)->sqh_first = (elm);					\
} while (0)

#define SIMPLEQ_INSERT_TAIL(head, elm, field) do {			\
    (elm)->field.sqe_next = NULL;					\
    *(head)->sqh_last = (elm);					\
    (head)->sqh_last = &(elm)->field.sqe_next;			\
} while (0)

#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\
    if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
        (head)->sqh_last = &(elm)->field.sqe_next;		\
    (listelm)->field.sqe_next = (elm);				\
} while (0)

#define SIMPLEQ_REMOVE_HEAD(head, field) do {			\
    if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
        (head)->sqh_last = &(head)->sqh_first;			\
} while (0)

#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do {			\
    if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \
        == NULL)							\
        (head)->sqh_last = &(elm)->field.sqe_next;		\
} while (0)

/*
 * XOR Simple queue definitions.
 */
#define XSIMPLEQ_HEAD(name, type)					\
struct name {								\
    struct type *sqx_first;	/* first element */			\
    struct type **sqx_last;	/* addr of last next element */		\
    unsigned long sqx_cookie;					\
}

#define XSIMPLEQ_ENTRY(type)						\
struct {								\
    struct type *sqx_next;	/* next element */			\
}

/*
 * XOR Simple queue access methods.
 */
#define XSIMPLEQ_XOR(head, ptr)	    ((__typeof(ptr))((head)->sqx_cookie ^ \
                    (unsigned long)(ptr)))
#define	XSIMPLEQ_FIRST(head)	    XSIMPLEQ_XOR(head, ((head)->sqx_first))
#define	XSIMPLEQ_END(head)	    NULL
#define	XSIMPLEQ_EMPTY(head)	    (XSIMPLEQ_FIRST(head) == XSIMPLEQ_END(head))
#define	XSIMPLEQ_NEXT(head, elm, field)    XSIMPLEQ_XOR(head, ((elm)->field.sqx_next))


#define XSIMPLEQ_FOREACH(var, head, field)				\
    for ((var) = XSIMPLEQ_FIRST(head);				\
        (var) != XSIMPLEQ_END(head);				\
        (var) = XSIMPLEQ_NEXT(head, var, field))

#define	XSIMPLEQ_FOREACH_SAFE(var, head, field, tvar)			\
    for ((var) = XSIMPLEQ_FIRST(head);				\
        (var) && ((tvar) = XSIMPLEQ_NEXT(head, var, field), 1);	\
        (var) = (tvar))

/*
 * XOR Simple queue functions.
 */
#define	XSIMPLEQ_INIT(head) do {					\
    arc4random_buf(&(head)->sqx_cookie, sizeof((head)->sqx_cookie)); \
    (head)->sqx_first = XSIMPLEQ_XOR(head, NULL);			\
    (head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first);	\
} while (0)

#define XSIMPLEQ_INSERT_HEAD(head, elm, field) do {			\
    if (((elm)->field.sqx_next = (head)->sqx_first) ==		\
        XSIMPLEQ_XOR(head, NULL))					\
        (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
    (head)->sqx_first = XSIMPLEQ_XOR(head, (elm));			\
} while (0)

#define XSIMPLEQ_INSERT_TAIL(head, elm, field) do {			\
    (elm)->field.sqx_next = XSIMPLEQ_XOR(head, NULL);		\
    *(XSIMPLEQ_XOR(head, (head)->sqx_last)) = XSIMPLEQ_XOR(head, (elm)); \
    (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next);	\
} while (0)

#define XSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\
    if (((elm)->field.sqx_next = (listelm)->field.sqx_next) ==	\
        XSIMPLEQ_XOR(head, NULL))					\
        (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
    (listelm)->field.sqx_next = XSIMPLEQ_XOR(head, (elm));		\
} while (0)

#define XSIMPLEQ_REMOVE_HEAD(head, field) do {				\
    if (((head)->sqx_first = XSIMPLEQ_XOR(head,			\
        (head)->sqx_first)->field.sqx_next) == XSIMPLEQ_XOR(head, NULL)) \
        (head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \
} while (0)

#define XSIMPLEQ_REMOVE_AFTER(head, elm, field) do {			\
    if (((elm)->field.sqx_next = XSIMPLEQ_XOR(head,			\
        (elm)->field.sqx_next)->field.sqx_next)			\
        == XSIMPLEQ_XOR(head, NULL))				\
        (head)->sqx_last = 					\
            XSIMPLEQ_XOR(head, &(elm)->field.sqx_next);		\
} while (0)

            
/*
 * Tail queue definitions.
 */
#define TAILQ_HEAD(name, type)						\
struct name {								\
    struct type *tqh_first;	/* first element */			\
    struct type **tqh_last;	/* addr of last next element */		\
}

#define TAILQ_HEAD_INITIALIZER(head)					\
    { NULL, &(head).tqh_first }

#define TAILQ_ENTRY(type)						\
struct {								\
    struct type *tqe_next;	/* next element */			\
    struct type **tqe_prev;	/* address of previous next element */	\
}

/* 
 * tail queue access methods 
 */
#define	TAILQ_FIRST(head)		((head)->tqh_first)
#define	TAILQ_END(head)			NULL
#define	TAILQ_NEXT(elm, field)		((elm)->field.tqe_next)
#define TAILQ_LAST(head, headname)					\
    (*(((struct headname *)((head)->tqh_last))->tqh_last))
/* XXX */
#define TAILQ_PREV(elm, headname, field)				\
    (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
#define	TAILQ_EMPTY(head)						\
    (TAILQ_FIRST(head) == TAILQ_END(head))

#define TAILQ_FOREACH(var, head, field)					\
    for((var) = TAILQ_FIRST(head);					\
        (var) != TAILQ_END(head);					\
        (var) = TAILQ_NEXT(var, field))

#define	TAILQ_FOREACH_SAFE(var, head, field, tvar)			\
    for ((var) = TAILQ_FIRST(head);					\
        (var) != TAILQ_END(head) &&					\
        ((tvar) = TAILQ_NEXT(var, field), 1);			\
        (var) = (tvar))


#define TAILQ_FOREACH_REVERSE(var, head, headname, field)		\
    for((var) = TAILQ_LAST(head, headname);				\
        (var) != TAILQ_END(head);					\
        (var) = TAILQ_PREV(var, headname, field))

#define	TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar)	\
    for ((var) = TAILQ_LAST(head, headname);			\
        (var) != TAILQ_END(head) &&					\
        ((tvar) = TAILQ_PREV(var, headname, field), 1);		\
        (var) = (tvar))

/*
 * Tail queue functions.
 */
#define	TAILQ_INIT(head) do {						\
    (head)->tqh_first = NULL;					\
    (head)->tqh_last = &(head)->tqh_first;				\
} while (0)

#define TAILQ_INSERT_HEAD(head, elm, field) do {			\
    if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)	\
        (head)->tqh_first->field.tqe_prev =			\
            &(elm)->field.tqe_next;				\
    else								\
        (head)->tqh_last = &(elm)->field.tqe_next;		\
    (head)->tqh_first = (elm);					\
    (elm)->field.tqe_prev = &(head)->tqh_first;			\
} while (0)

#define TAILQ_INSERT_TAIL(head, elm, field) do {			\
    (elm)->field.tqe_next = NULL;					\
    (elm)->field.tqe_prev = (head)->tqh_last;			\
    *(head)->tqh_last = (elm);					\
    (head)->tqh_last = &(elm)->field.tqe_next;			\
} while (0)

#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
    if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
        (elm)->field.tqe_next->field.tqe_prev =			\
            &(elm)->field.tqe_next;				\
    else								\
        (head)->tqh_last = &(elm)->field.tqe_next;		\
    (listelm)->field.tqe_next = (elm);				\
    (elm)->field.tqe_prev = &(listelm)->field.tqe_next;		\
} while (0)

#define	TAILQ_INSERT_BEFORE(listelm, elm, field) do {			\
    (elm)->field.tqe_prev = (listelm)->field.tqe_prev;		\
    (elm)->field.tqe_next = (listelm);				\
    *(listelm)->field.tqe_prev = (elm);				\
    (listelm)->field.tqe_prev = &(elm)->field.tqe_next;		\
} while (0)

#define TAILQ_REMOVE(head, elm, field) do {				\
    if (((elm)->field.tqe_next) != NULL)				\
        (elm)->field.tqe_next->field.tqe_prev =			\
            (elm)->field.tqe_prev;				\
    else								\
        (head)->tqh_last = (elm)->field.tqe_prev;		\
    *(elm)->field.tqe_prev = (elm)->field.tqe_next;			\
    _Q_INVALIDATE((elm)->field.tqe_prev);				\
    _Q_INVALIDATE((elm)->field.tqe_next);				\
} while (0)

#define TAILQ_REPLACE(head, elm, elm2, field) do {			\
    if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL)	\
        (elm2)->field.tqe_next->field.tqe_prev =		\
            &(elm2)->field.tqe_next;				\
    else								\
        (head)->tqh_last = &(elm2)->field.tqe_next;		\
    (elm2)->field.tqe_prev = (elm)->field.tqe_prev;			\
    *(elm2)->field.tqe_prev = (elm2);				\
    _Q_INVALIDATE((elm)->field.tqe_prev);				\
    _Q_INVALIDATE((elm)->field.tqe_next);				\
} while (0)

/*
 * Circular queue definitions.
 */
#define CIRCLEQ_HEAD(name, type)					\
struct name {								\
    struct type *cqh_first;		/* first element */		\
    struct type *cqh_last;		/* last element */		\
}

#define CIRCLEQ_HEAD_INITIALIZER(head)					\
    { CIRCLEQ_END(&head), CIRCLEQ_END(&head) }

#define CIRCLEQ_ENTRY(type)						\
struct {								\
    struct type *cqe_next;		/* next element */		\
    struct type *cqe_prev;		/* previous element */		\
}

/*
 * Circular queue access methods 
 */
#define	CIRCLEQ_FIRST(head)		((head)->cqh_first)
#define	CIRCLEQ_LAST(head)		((head)->cqh_last)
#define	CIRCLEQ_END(head)		((void *)(head))
#define	CIRCLEQ_NEXT(elm, field)	((elm)->field.cqe_next)
#define	CIRCLEQ_PREV(elm, field)	((elm)->field.cqe_prev)
#define	CIRCLEQ_EMPTY(head)						\
    (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))

#define CIRCLEQ_FOREACH(var, head, field)				\
    for((var) = CIRCLEQ_FIRST(head);				\
        (var) != CIRCLEQ_END(head);					\
        (var) = CIRCLEQ_NEXT(var, field))

#define	CIRCLEQ_FOREACH_SAFE(var, head, field, tvar)			\
    for ((var) = CIRCLEQ_FIRST(head);				\
        (var) != CIRCLEQ_END(head) &&				\
        ((tvar) = CIRCLEQ_NEXT(var, field), 1);			\
        (var) = (tvar))

#define CIRCLEQ_FOREACH_REVERSE(var, head, field)			\
    for((var) = CIRCLEQ_LAST(head);					\
        (var) != CIRCLEQ_END(head);					\
        (var) = CIRCLEQ_PREV(var, field))

#define	CIRCLEQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar)	\
    for ((var) = CIRCLEQ_LAST(head, headname);			\
        (var) != CIRCLEQ_END(head) && 				\
        ((tvar) = CIRCLEQ_PREV(var, headname, field), 1);		\
        (var) = (tvar))

/*
 * Circular queue functions.
 */
#define	CIRCLEQ_INIT(head) do {						\
    (head)->cqh_first = CIRCLEQ_END(head);				\
    (head)->cqh_last = CIRCLEQ_END(head);				\
} while (0)

#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\
    (elm)->field.cqe_next = (listelm)->field.cqe_next;		\
    (elm)->field.cqe_prev = (listelm);				\
    if ((listelm)->field.cqe_next == CIRCLEQ_END(head))		\
        (head)->cqh_last = (elm);				\
    else								\
        (listelm)->field.cqe_next->field.cqe_prev = (elm);	\
    (listelm)->field.cqe_next = (elm);				\
} while (0)

#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do {		\
    (elm)->field.cqe_next = (listelm);				\
    (elm)->field.cqe_prev = (listelm)->field.cqe_prev;		\
    if ((listelm)->field.cqe_prev == CIRCLEQ_END(head))		\
        (head)->cqh_first = (elm);				\
    else								\
        (listelm)->field.cqe_prev->field.cqe_next = (elm);	\
    (listelm)->field.cqe_prev = (elm);				\
} while (0)

#define CIRCLEQ_INSERT_HEAD(head, elm, field) do {			\
    (elm)->field.cqe_next = (head)->cqh_first;			\
    (elm)->field.cqe_prev = CIRCLEQ_END(head);			\
    if ((head)->cqh_last == CIRCLEQ_END(head))			\
        (head)->cqh_last = (elm);				\
    else								\
        (head)->cqh_first->field.cqe_prev = (elm);		\
    (head)->cqh_first = (elm);					\
} while (0)

#define CIRCLEQ_INSERT_TAIL(head, elm, field) do {			\
    (elm)->field.cqe_next = CIRCLEQ_END(head);			\
    (elm)->field.cqe_prev = (head)->cqh_last;			\
    if ((head)->cqh_first == CIRCLEQ_END(head))			\
        (head)->cqh_first = (elm);				\
    else								\
        (head)->cqh_last->field.cqe_next = (elm);		\
    (head)->cqh_last = (elm);					\
} while (0)

#define	CIRCLEQ_REMOVE(head, elm, field) do {				\
    if ((elm)->field.cqe_next == CIRCLEQ_END(head))			\
        (head)->cqh_last = (elm)->field.cqe_prev;		\
    else								\
        (elm)->field.cqe_next->field.cqe_prev =			\
            (elm)->field.cqe_prev;				\
    if ((elm)->field.cqe_prev == CIRCLEQ_END(head))			\
        (head)->cqh_first = (elm)->field.cqe_next;		\
    else								\
        (elm)->field.cqe_prev->field.cqe_next =			\
            (elm)->field.cqe_next;				\
    _Q_INVALIDATE((elm)->field.cqe_prev);				\
    _Q_INVALIDATE((elm)->field.cqe_next);				\
} while (0)

#define CIRCLEQ_REPLACE(head, elm, elm2, field) do {			\
    if (((elm2)->field.cqe_next = (elm)->field.cqe_next) ==		\
        CIRCLEQ_END(head))						\
        (head)->cqh_last = (elm2);				\
    else								\
        (elm2)->field.cqe_next->field.cqe_prev = (elm2);	\
    if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) ==		\
        CIRCLEQ_END(head))						\
        (head)->cqh_first = (elm2);				\
    else								\
        (elm2)->field.cqe_prev->field.cqe_next = (elm2);	\
    _Q_INVALIDATE((elm)->field.cqe_prev);				\
    _Q_INVALIDATE((elm)->field.cqe_next);				\
} while (0)


/**** amalgamated original file "/deps/pcg_basic.h" ****/

/*
 * PCG Random Number Generation for C.
 *
 * Copyright 2014 Melissa O'Neill <oneill@pcg-random.org>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * For additional information about the PCG random number generation scheme,
 * including its license and other licensing options, visit
 *
 *     http://www.pcg-random.org
 */


#if defined(UNDER_CE) || !defined(_MSC_VER) || _MSC_VER >= 1800
# include <stdint.h>
#else
#endif

#ifdef __cplusplus
extern "C" {
#endif

typedef struct pcg_state_setseq_64 {
    uint64_t state;  /* RNG state.  All values are possible. */
    uint64_t inc;    /* Controls which RNG sequence (stream) is selected. Must
                      * *always* be odd. */
} pcg32_random_t;

#define PCG32_INITIALIZER { 0x853c49e6748fea9bULL, 0xda3e39cb94b95bdbULL }

void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initial_state, uint64_t initseq);
uint32_t pcg32_random_r(pcg32_random_t* rng);

#ifdef __cplusplus
}
#endif


/**** amalgamated original file "/deps/libc_time.h" ****/


struct mytm {
    int tm_sec;
    int tm_min;
    int tm_hour;
    int tm_mday;
    int tm_mon;
    int tm_year;
};

int __secs_to_tm(long long t, struct mytm *tm);
long long __tm_to_secs(const struct mytm *tm);


/**** amalgamated original file "/deps/base64.h" ****/

#ifndef UA_BASE64_H_
#define UA_BASE64_H_


_UA_BEGIN_DECLS

#include <stddef.h>

/**
 * base64_encode - Base64 encode
 * @src: Data to be encoded
 * @len: Length of the data to be encoded
 * @out_len: Pointer to output length variable
 * Returns: Allocated buffer of out_len bytes of encoded data,
 * or %NULL on failure. The output is NOT Null-terminated. */
unsigned char *
UA_base64(const unsigned char *src, size_t len, size_t *out_len);

/* Requires as input a buffer of length at least 4*((len + 2) / 3).
 * Returns the actual size */
size_t
UA_base64_buf(const unsigned char *src, size_t len, unsigned char *out);

/**
 * base64_decode - Base64 decode
 * @src: Data to be decoded
 * @len: Length of the data to be decoded
 * @out_len: Pointer to output length variable
 * Returns: Allocated buffer of out_len bytes of decoded data,
 * or %NULL on failure. */
unsigned char *
UA_unbase64(const unsigned char *src, size_t len, size_t *out_len);

_UA_END_DECLS

#endif /* UA_BASE64_H_ */

/**** amalgamated original file "/deps/dtoa.h" ****/

// Copyright 2013, Andreas Samoljuk
// Copyright 2023, Julius Pfrommer
//
// Boost Software License - Version 1.0 - August 17th, 2003
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

#ifndef DTOA_H
#define DTOA_H

#ifdef __cplusplus
extern "C" {
#endif

// Prints a double-value as a readable string. The buffer must be at least 24
// chars wide. Returns the number of printed characters. Does not
// null-terminate.
unsigned dtoa(double d, char* buffer);

#ifdef __cplusplus
}
#endif

#endif // DTOA_H

/**** amalgamated original file "/deps/mp_printf.h" ****/

/**
 * @author (c) Eyal Rozenberg <eyalroz1@gmx.com>
 *             2021-2023, Haifa, Palestine/Israel
 * @author (c) Marco Paland (info@paland.com)
 *             2014-2019, PALANDesign Hannover, Germany
 *
 * @note Others have made smaller contributions to this file: see the
 * contributors page at https://github.com/eyalroz/printf/graphs/contributors
 * or ask one of the authors.
 *
 * @brief Small stand-alone implementation of the printf family of functions
 * (`(v)printf`, `(v)s(n)printf` etc., geared towards use on embedded systems with
 * a very limited resources.
 *
 * @note the implementations are thread-safe; re-entrant; use no functions from
 * the standard library; and do not dynamically allocate any memory.
 *
 * @license The MIT License (MIT)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#ifndef MP_PRINTF_H
#define MP_PRINTF_H

#include <stdarg.h>
#include <stddef.h>

#ifdef __cplusplus
extern "C" {
#endif

#ifdef __GNUC__
# if ((__GNUC__ == 4 && __GNUC_MINOR__>= 4) || __GNUC__ > 4)
#  define ATTR_PRINTF(one_based_format_index, first_arg) \
__attribute__((format(gnu_printf, (one_based_format_index), (first_arg))))
# else
# define ATTR_PRINTF(one_based_format_index, first_arg) \
__attribute__((format(printf, (one_based_format_index), (first_arg))))
# endif
# define ATTR_VPRINTF(one_based_format_index) ATTR_PRINTF((one_based_format_index), 0)
#else
# define ATTR_PRINTF(one_based_format_index, first_arg)
# define ATTR_VPRINTF(one_based_format_index)
#endif

/**
 * An implementation of the C standard's snprintf/vsnprintf
 *
 * @param s An array in which to store the formatted string. It must be large
 * enough to fit either the entire formatted output, or at least @p n
 * characters. Alternatively, it can be NULL, in which case nothing will be
 * printed, and only the number of characters which _could_ have been printed is
 * tallied and returned.
 * @param n The maximum number of characters to write to the array, including a
 * terminating null character
 * @param format A string specifying the format of the output, with %-marked
 * specifiers of how to interpret additional arguments.
 * @param arg Additional arguments to the function, one for each specifier in @p
 * format
 * @return The number of characters that COULD have been written into @p s, not
 * counting the terminating null character. A value equal or larger than @p n
 * indicates truncation. Only when the returned value is non-negative and less
 * than @p n, the null-terminated string has been fully and successfully
 * printed.
 */
int  mp_snprintf(char* s, size_t count, const char* format, ...) ATTR_PRINTF(3, 4);
int mp_vsnprintf(char* s, size_t count, const char* format, va_list arg) ATTR_VPRINTF(3);

#ifdef __cplusplus
} // extern "C"
#endif

#endif // MP_PRINTF_H

/**** amalgamated original file "/deps/itoa.h" ****/

/*
 * Copyright 2017 Techie Delight
 * Permission is hereby granted, free of charge, to any person obtaining a copy 
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights 
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
 * copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included 
 * in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 
 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef ITOA_H
#define ITOA_H

#ifdef __cplusplus
extern "C" {
#endif


UA_UInt16 itoaUnsigned(UA_UInt64 value, char* buffer, UA_Byte base);
UA_UInt16 itoaSigned(UA_Int64 value, char* buffer);

#ifdef __cplusplus
}
#endif

#endif /* ITOA_H */


/**** amalgamated original file "/deps/ziptree.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
 *
 *    Copyright 2018, 2021-2022 (c) Julius Pfrommer
 */


#include <stddef.h>

#ifdef _MSC_VER
# define ZIP_INLINE __inline
#else
# define ZIP_INLINE inline
#endif

#if defined(__GNUC__) || defined(__clang__)
# define ZIP_UNUSED __attribute__((unused))
#else
# define ZIP_UNUSED
#endif

#ifdef __cplusplus
extern "C" {
#endif

/* Reusable zip tree implementation. The style is inspired by the BSD
 * sys/queue.h linked list definition.
 *
 * Zip trees were developed in: Tarjan, R. E., Levy, C. C., and Timmel, S. "Zip
 * Trees." arXiv preprint arXiv:1806.06726 (2018). The original definition was
 * modified in two ways:
 *
 * - Multiple elements with the same key can be inserted. These appear adjacent
 *   in the tree. ZIP_FIND will return the topmost of these elements.
 * - The pointer-value of the elements are used as the rank. This simplifies the
 *   code and is (empirically) faster.
 *
 * The ZIP_ENTRY definitions are to be contained in the tree entries themselves.
 * Use ZIP_FUNCTIONS to define the signature of the zip tree functions. */

#define ZIP_HEAD(name, type)                    \
struct name {                                   \
    struct type *root;                          \
}

#define ZIP_ENTRY(type)                         \
struct {                                        \
    struct type *left;                          \
    struct type *right;                         \
}

enum ZIP_CMP {
    ZIP_CMP_LESS = -1,
    ZIP_CMP_EQ = 0,
    ZIP_CMP_MORE = 1
};

/* The comparison method "cmp" for a zip tree has the signature.
 * Provide this to the ZIP_FUNCTIONS macro.
 *
 *   enum ZIP_CMP cmpMethod(const keytype *a, const keytype *b);
 */
typedef enum ZIP_CMP (*zip_cmp_cb)(const void *key1, const void *key2);

#define ZIP_INIT(head) do { (head)->root = NULL; } while (0)
#define ZIP_ROOT(head) (head)->root
#define ZIP_LEFT(elm, field) (elm)->field.left
#define ZIP_RIGHT(elm, field) (elm)->field.right
#define ZIP_INSERT(name, head, elm) name##_ZIP_INSERT(head, elm)
#define ZIP_FIND(name, head, key) name##_ZIP_FIND(head, key)
#define ZIP_MIN(name, head) name##_ZIP_MIN(head)
#define ZIP_MAX(name, head) name##_ZIP_MAX(head)

/* Returns the element if it was found in the tree. Returns NULL otherwise. */
#define ZIP_REMOVE(name, head, elm) name##_ZIP_REMOVE(head, elm)

/* Split (_UNZIP) and merge (_ZIP) trees. _UNZIP splits at the key and moves
 * elements <= into the left output (right otherwise). */
#define ZIP_ZIP(name, left, right) name##_ZIP_ZIP(left, right)
#define ZIP_UNZIP(name, head, key, left, right) \
    name##_ZIP_UNZIP(head, key, left, right)

/* ZIP_ITER uses in-order traversal of the tree (in the order of the keys). The
 * memory if a node is not accessed by ZIP_ITER after the callback has been
 * executed for it. So a tree can be cleaned by calling free on each node from
 * within the iteration callback.
 *
 * ZIP_ITER returns a void pointer. The first callback to return non-NULL aborts
 * the iteration. This pointer is then returned. */
typedef void * (*zip_iter_cb)(void *context, void *elm);
#define ZIP_ITER(name, head, cb, ctx) name##_ZIP_ITER(head, cb, ctx)

/* Same as _ITER, but only visits elements with the given key */
#define ZIP_ITER_KEY(name, head, key, cb, ctx) name##_ZIP_ITER_KEY(head, key, cb, ctx)

/* Macro to generate typed ziptree methods */
#define ZIP_FUNCTIONS(name, type, field, keytype, keyfield, cmp)        \
                                                                        \
ZIP_UNUSED static ZIP_INLINE void                                       \
name##_ZIP_INSERT(struct name *head, struct type *el) {                 \
    __ZIP_INSERT(head, (zip_cmp_cb)cmp, offsetof(struct type, field),   \
                 offsetof(struct type, keyfield), el);                  \
}                                                                       \
                                                                        \
ZIP_UNUSED static ZIP_INLINE struct type *                              \
name##_ZIP_REMOVE(struct name *head, struct type *elm) {                \
    return (struct type*)                                               \
        __ZIP_REMOVE(head, (zip_cmp_cb)cmp,                             \
                     offsetof(struct type, field),                      \
                     offsetof(struct type, keyfield), elm);             \
}                                                                       \
                                                                        \
ZIP_UNUSED static ZIP_INLINE struct type *                              \
name##_ZIP_FIND(struct name *head, const keytype *key) {                \
    struct type *cur = ZIP_ROOT(head);                                  \
    while(cur) {                                                        \
        enum ZIP_CMP eq = cmp(key, &cur->keyfield);                     \
        if(eq == ZIP_CMP_EQ)                                            \
            break;                                                      \
        if(eq == ZIP_CMP_LESS)                                          \
            cur = ZIP_LEFT(cur, field);                                 \
        else                                                            \
            cur = ZIP_RIGHT(cur, field);                                \
    }                                                                   \
    return cur;                                                         \
}                                                                       \
                                                                        \
ZIP_UNUSED static ZIP_INLINE struct type *                              \
name##_ZIP_MIN(struct name *head) {                                     \
    struct type *cur = ZIP_ROOT(head);                                  \
    if(!cur)                                                            \
        return NULL;                                                    \
    while(ZIP_LEFT(cur, field)) {                                       \
        cur = ZIP_LEFT(cur, field);                                     \
    }                                                                   \
    return cur;                                                         \
}                                                                       \
                                                                        \
ZIP_UNUSED static ZIP_INLINE struct type *                              \
name##_ZIP_MAX(struct name *head) {                                     \
    struct type *cur = ZIP_ROOT(head);                                  \
    if(!cur)                                                            \
        return NULL;                                                    \
    while(ZIP_RIGHT(cur, field)) {                                      \
        cur = ZIP_RIGHT(cur, field);                                    \
    }                                                                   \
    return cur;                                                         \
}                                                                       \
                                                                        \
typedef void * (*name##_cb)(void *context, struct type *elm);           \
                                                                        \
ZIP_UNUSED static ZIP_INLINE void *                                     \
name##_ZIP_ITER(struct name *head, name##_cb cb, void *context) {       \
    return __ZIP_ITER(offsetof(struct type, field), (zip_iter_cb)cb,    \
                      context, ZIP_ROOT(head));                         \
}                                                                       \
                                                                        \
ZIP_UNUSED static ZIP_INLINE void *                                     \
name##_ZIP_ITER_KEY(struct name *head, const keytype *key,              \
                    name##_cb cb, void *context) {                      \
    return __ZIP_ITER_KEY((zip_cmp_cb)cmp, offsetof(struct type, field), \
                          offsetof(struct type, keyfield), key,         \
                          (zip_iter_cb)cb, context, ZIP_ROOT(head));    \
}                                                                       \
                                                                        \
ZIP_UNUSED static ZIP_INLINE struct type *                              \
name##_ZIP_ZIP(struct type *left, struct type *right) {                 \
    return (struct type*)                                               \
        __ZIP_ZIP(offsetof(struct type, field), left, right);           \
}                                                                       \
                                                                        \
ZIP_UNUSED static ZIP_INLINE void                                       \
name##_ZIP_UNZIP(struct name *head, const keytype *key,                 \
                 struct name *left, struct name *right) {               \
    __ZIP_UNZIP((zip_cmp_cb)cmp, offsetof(struct type, field),          \
                offsetof(struct type, keyfield), key,                   \
                head, left, right);                                     \
}

/* Internal definitions. Don't use directly. */

void
__ZIP_INSERT(void *h, zip_cmp_cb cmp, unsigned short fieldoffset,
             unsigned short keyoffset, void *elm);

void *
__ZIP_REMOVE(void *h, zip_cmp_cb cmp, unsigned short fieldoffset,
             unsigned short keyoffset, void *elm);

void *
__ZIP_ITER(unsigned short fieldoffset, zip_iter_cb cb,
           void *context, void *elm);

void *
__ZIP_ITER_KEY(zip_cmp_cb cmp, unsigned short fieldoffset,
               unsigned short keyoffset, const void *key,
               zip_iter_cb cb, void *context, void *elm);

void *
__ZIP_ZIP(unsigned short fieldoffset, void *left, void *right);

void
__ZIP_UNZIP(zip_cmp_cb cmp, unsigned short fieldoffset,
            unsigned short keyoffset, const void *key,
            void *h, void *l, void *r);

#ifdef __cplusplus
} /* extern "C" */
#endif


/**** amalgamated original file "/src/ua_types_encoding_binary.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2015 (c) Sten Grüner
 *    Copyright 2014, 2017 (c) Florian Palm
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
 */



_UA_BEGIN_DECLS

typedef UA_StatusCode (*UA_exchangeEncodeBuffer)(void *handle, UA_Byte **bufPos,
                                                 const UA_Byte **bufEnd);

/* Encodes the scalar value described by type in the binary encoding. Encoding
 * is thread-safe if thread-local variables are enabled. Encoding is also
 * reentrant and can be safely called from signal handlers or interrupts.
 *
 * @param src The value. Must not be NULL.
 * @param type The value type. Must not be NULL.
 * @param bufPos Points to a pointer to the current position in the encoding
 *        buffer. Must not be NULL. The pointer is advanced by the number of
 *        encoded bytes, or, if the buffer is exchanged, to the position in the
 *        new buffer.
 * @param bufEnd Points to a pointer to the end of the encoding buffer (encoding
 *        always stops before *buf_end). Must not be NULL. The pointer is
 *        changed when the buffer is exchanged.
 * @param exchangeCallback Called when the end of the buffer is reached. This is
          used to send out a message chunk before continuing with the encoding.
          Is ignored if NULL.
 * @param exchangeHandle Custom data passed into the exchangeCallback.
 * @return Returns a statuscode whether encoding succeeded. */
UA_StatusCode
UA_encodeBinaryInternal(const void *src, const UA_DataType *type,
                        UA_Byte **bufPos, const UA_Byte **bufEnd,
                        UA_exchangeEncodeBuffer exchangeCallback,
                        void *exchangeHandle)
    UA_FUNC_ATTR_WARN_UNUSED_RESULT;

/* Decodes a scalar value described by type from binary encoding. Decoding
 * is thread-safe if thread-local variables are enabled. Decoding is also
 * reentrant and can be safely called from signal handlers or interrupts.
 *
 * @param src The buffer with the binary encoded value. Must not be NULL.
 * @param offset The current position in the buffer. Must not be NULL. The value
 *        is advanced as decoding progresses.
 * @param dst The target value. Must not be NULL. The target is assumed to have
 *        size type->memSize. The value is reset to zero before decoding. If
 *        decoding fails, members are deleted and the value is reset (zeroed)
 *        again.
 * @param type The value type. Must not be NULL.
 * @param customTypesSize The number of non-standard datatypes contained in the
 *        customTypes array.
 * @param customTypes An array of non-standard datatypes (not included in
 *        UA_TYPES). Can be NULL if customTypesSize is zero.
 * @return Returns a statuscode whether decoding succeeded. */
UA_StatusCode
UA_decodeBinaryInternal(const UA_ByteString *src, size_t *offset,
                        void *dst, const UA_DataType *type,
                        const UA_DataTypeArray *customTypes)
    UA_FUNC_ATTR_WARN_UNUSED_RESULT;

const UA_DataType *
UA_findDataTypeByBinary(const UA_NodeId *typeId);

_UA_END_DECLS


/**** amalgamated original file "/src/util/ua_util_internal.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014, 2017 (c) Florian Palm
 *    Copyright 2015 (c) LEvertz
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Jan Hermes)
 */


#define UA_INTERNAL


_UA_BEGIN_DECLS

/* Macro-Expand for MSVC workarounds */
#define UA_MACRO_EXPAND(x) x

/* Print a NodeId in logs */
#define UA_LOG_NODEID_INTERNAL(NODEID, LEVEL, LOG)   \
    if(UA_LOGLEVEL <= UA_LOGLEVEL_##LEVEL) {         \
        UA_String nodeIdStr = UA_STRING_NULL;        \
        UA_NodeId_print(NODEID, &nodeIdStr);         \
        LOG;                                         \
        UA_String_clear(&nodeIdStr);                 \
    }

#define UA_LOG_NODEID_TRACE(NODEID, LOG) UA_LOG_NODEID_INTERNAL(NODEID, TRACE, LOG)
#define UA_LOG_NODEID_DEBUG(NODEID, LOG) UA_LOG_NODEID_INTERNAL(NODEID, DEBUG, LOG)
#define UA_LOG_NODEID_INFO(NODEID, LOG) UA_LOG_NODEID_INTERNAL(NODEID, INFO, LOG)
#define UA_LOG_NODEID_WARNING(NODEID, LOG) UA_LOG_NODEID_INTERNAL(NODEID, WARNING, LOG)
#define UA_LOG_NODEID_ERROR(NODEID, LOG) UA_LOG_NODEID_INTERNAL(NODEID, ERROR, LOG)
#define UA_LOG_NODEID_FATAL(NODEID, LOG) UA_LOG_NODEID_INTERNAL(NODEID, FATAL, LOG)

/* Short names for integer. These are not exposed on the public API, since many
 * user-applications make the same definitions in their headers. */
typedef UA_Byte u8;
typedef UA_SByte i8;
typedef UA_UInt16 u16;
typedef UA_Int16 i16;
typedef UA_UInt32 u32;
typedef UA_Int32 i32;
typedef UA_UInt64 u64;
typedef UA_Int64 i64;
typedef UA_StatusCode status;

/* Well-known ReferenceTypes */
UA_StatusCode
lookupRefType(UA_Server *server, UA_QualifiedName *qn, UA_NodeId *outRefTypeId);

/* Returns the canonical BrowseName of the ReferenceType or the encoded
 * NodeId. The outBN is assumed to be pre-allocated with a buffer. This fails if
 * the NodeId contains an '>' character, which makes the parsing ambigous. */
UA_StatusCode
getRefTypeBrowseName(const UA_NodeId *refTypeId, UA_String *outBN);

/* Unescape &-escaped string. The string is modified */
void
UA_String_unescape(UA_String *s, UA_Boolean extended);

/* Returns the position of the first unescaped reserved character (or the end
 * position) */
char *
find_unescaped(char *pos, char *end, UA_Boolean extended);

/* Escape s2 and append it to s. Memory is allocated internally. */
UA_StatusCode
UA_String_escapeAppend(UA_String *s, const UA_String s2, UA_Boolean extended);

UA_StatusCode
UA_String_append(UA_String *s, const UA_String s2);

/* Case insensitive lookup. Returns UA_ATTRIBUTEID_INVALID if not found. */
UA_AttributeId
UA_AttributeId_fromName(const UA_String name);

/**
 * Error checking macros
 */

static UA_INLINE UA_Boolean
isGood(UA_StatusCode code) {
    return code == UA_STATUSCODE_GOOD;
}

static UA_INLINE UA_Boolean
isNonNull(const void *ptr) {
    return ptr != NULL;
}

static UA_INLINE UA_Boolean
isTrue(uint8_t expr) {
    return expr;
}

#define UA_CHECK(A, EVAL_ON_ERROR)                                                       \
    do {                                                                                 \
        if(UA_UNLIKELY(!isTrue(A))) {                                                    \
            EVAL_ON_ERROR;                                                               \
        }                                                                                \
    } while(0)

#define UA_CHECK_STATUS(STATUSCODE, EVAL_ON_ERROR)                                       \
    UA_CHECK(isGood(STATUSCODE), EVAL_ON_ERROR)

#define UA_CHECK_MEM(STATUSCODE, EVAL_ON_ERROR)                                       \
    UA_CHECK(isNonNull(STATUSCODE), EVAL_ON_ERROR)

#ifdef UA_DEBUG_FILE_LINE_INFO
#define UA_CHECK_LOG_INTERNAL(A, STATUSCODE, EVAL, LOG, LOGGER, CAT, MSG, ...)           \
    UA_MACRO_EXPAND(                                                                     \
        UA_CHECK(A, LOG(LOGGER, CAT, "" MSG "%s (%s:%d: StatusCode: %s)", __VA_ARGS__,   \
                        __FILE__, __LINE__, UA_StatusCode_name(STATUSCODE));             \
                 EVAL))
#else
#define UA_CHECK_LOG_INTERNAL(A, STATUSCODE, EVAL, LOG, LOGGER, CAT, MSG, ...)           \
    UA_MACRO_EXPAND(                                                                     \
        UA_CHECK(A, LOG(LOGGER, CAT, "" MSG "%s (StatusCode: %s)", __VA_ARGS__,   \
                        UA_StatusCode_name(STATUSCODE));             \
                 EVAL))
#endif

#define UA_CHECK_LOG(A, EVAL, LEVEL, LOGGER, CAT, ...)                                   \
    UA_MACRO_EXPAND(UA_CHECK_LOG_INTERNAL(A, UA_STATUSCODE_BAD, EVAL, UA_LOG_##LEVEL,    \
                                          LOGGER, CAT, __VA_ARGS__, ""))

#define UA_CHECK_STATUS_LOG(STATUSCODE, EVAL, LEVEL, LOGGER, CAT, ...)                   \
    UA_MACRO_EXPAND(UA_CHECK_LOG_INTERNAL(isGood(STATUSCODE), STATUSCODE,  \
                                          EVAL, UA_LOG_##LEVEL, LOGGER, CAT,             \
                                          __VA_ARGS__, ""))

#define UA_CHECK_MEM_LOG(PTR, EVAL, LEVEL, LOGGER, CAT, ...)                   \
    UA_MACRO_EXPAND(UA_CHECK_LOG_INTERNAL(isNonNull(PTR), UA_STATUSCODE_BADOUTOFMEMORY,  \
                                          EVAL, UA_LOG_##LEVEL, LOGGER, CAT,             \
                                          __VA_ARGS__, ""))

/**
 * Check Macros
 * Usage examples:
 *
 *    void *data = malloc(...);
 *    UA_CHECK(data, return error);
 *
 *    UA_StatusCode rv = some_func(...);
 *    UA_CHECK_STATUS(rv, return rv);
 *
 *    UA_Logger *logger = &server->config.logger;
 *    rv = bar_func(...);
 *    UA_CHECK_STATUS_WARN(rv, return rv, logger, UA_LOGCATEGORY_SERVER, "msg & args %s", "arg");
 */
#define UA_CHECK_FATAL(A, EVAL, LOGGER, CAT, ...)                                        \
    UA_MACRO_EXPAND(UA_CHECK_LOG(A, EVAL, FATAL, LOGGER, CAT, __VA_ARGS__))
#define UA_CHECK_ERROR(A, EVAL, LOGGER, CAT, ...)                                        \
    UA_MACRO_EXPAND(UA_CHECK_LOG(A, EVAL, ERROR, LOGGER, CAT, __VA_ARGS__))
#define UA_CHECK_WARN(A, EVAL, LOGGER, CAT, ...)                                         \
    UA_MACRO_EXPAND(UA_CHECK_LOG(A, EVAL, WARNING, LOGGER, CAT, __VA_ARGS__))
#define UA_CHECK_INFO(A, EVAL, LOGGER, CAT, ...)                                         \
    UA_MACRO_EXPAND(UA_CHECK_LOG(A, EVAL, INFO, LOGGER, CAT, __VA_ARGS__))

#define UA_CHECK_STATUS_FATAL(STATUSCODE, EVAL, LOGGER, CAT, ...)                        \
    UA_MACRO_EXPAND(                                                                     \
        UA_CHECK_STATUS_LOG(STATUSCODE, EVAL, FATAL, LOGGER, CAT, __VA_ARGS__))
#define UA_CHECK_STATUS_ERROR(STATUSCODE, EVAL, LOGGER, CAT, ...)                        \
    UA_MACRO_EXPAND(                                                                     \
        UA_CHECK_STATUS_LOG(STATUSCODE, EVAL, ERROR, LOGGER, CAT, __VA_ARGS__))
#define UA_CHECK_STATUS_WARN(STATUSCODE, EVAL, LOGGER, CAT, ...)                         \
    UA_MACRO_EXPAND(                                                                     \
        UA_CHECK_STATUS_LOG(STATUSCODE, EVAL, WARNING, LOGGER, CAT, __VA_ARGS__))
#define UA_CHECK_STATUS_INFO(STATUSCODE, EVAL, LOGGER, CAT, ...)                         \
    UA_MACRO_EXPAND(                                                                     \
        UA_CHECK_STATUS_LOG(STATUSCODE, EVAL, INFO, LOGGER, CAT, __VA_ARGS__))
#define UA_CHECK_STATUS_DEBUG(STATUSCODE, EVAL, LOGGER, CAT, ...)                         \
    UA_MACRO_EXPAND(                                                                     \
        UA_CHECK_STATUS_LOG(STATUSCODE, EVAL, DEBUG, LOGGER, CAT, __VA_ARGS__))

#define UA_CHECK_MEM_FATAL(PTR, EVAL, LOGGER, CAT, ...)                        \
    UA_MACRO_EXPAND(                                                                     \
        UA_CHECK_MEM_LOG(PTR, EVAL, FATAL, LOGGER, CAT, __VA_ARGS__))
#define UA_CHECK_MEM_ERROR(PTR, EVAL, LOGGER, CAT, ...)                        \
    UA_MACRO_EXPAND(                                                                     \
        UA_CHECK_MEM_LOG(PTR, EVAL, ERROR, LOGGER, CAT, __VA_ARGS__))
#define UA_CHECK_MEM_WARN(PTR, EVAL, LOGGER, CAT, ...)                         \
    UA_MACRO_EXPAND(                                                                     \
        UA_CHECK_MEM_LOG(PTR, EVAL, WARNING, LOGGER, CAT, __VA_ARGS__))
#define UA_CHECK_MEM_INFO(PTR, EVAL, LOGGER, CAT, ...)                         \
    UA_MACRO_EXPAND(                                                                     \
        UA_CHECK_MEM_LOG(PTR, EVAL, INFO, LOGGER, CAT, __VA_ARGS__))

/**
 * Utility Functions
 * ----------------- */

#ifdef UA_ENABLE_DISCOVERY_SEMAPHORE
# ifdef _WIN32
#  include <io.h>
#  define UA_fileExists(X) ( _access(X, 0) == 0)
# else
#  include <unistd.h>
#  define UA_fileExists(X) ( access(X, 0) == 0)
# endif
#endif

void
UA_cleanupDataTypeWithCustom(const UA_DataTypeArray *customTypes);

/* Get the number of optional fields contained in an structure type */
size_t UA_EXPORT
getCountOfOptionalFields(const UA_DataType *type);

/* Dump packet for debugging / fuzzing */
#ifdef UA_DEBUG_DUMP_PKGS
void UA_EXPORT
UA_dump_hex_pkg(UA_Byte* buffer, size_t bufferLen);
#endif

/* Get pointer to leaf certificate of a specified valid chain of DER encoded
 * certificates */
UA_ByteString getLeafCertificate(UA_ByteString chain);

/* Unions that represent any of the supported request or response message */
typedef union {
    UA_RequestHeader requestHeader;
    UA_FindServersRequest findServersRequest;
    UA_GetEndpointsRequest getEndpointsRequest;
#ifdef UA_ENABLE_DISCOVERY
# ifdef UA_ENABLE_DISCOVERY_MULTICAST
    UA_FindServersOnNetworkRequest findServersOnNetworkRequest;
# endif
    UA_RegisterServerRequest registerServerRequest;
    UA_RegisterServer2Request registerServer2Request;
#endif
    UA_OpenSecureChannelRequest openSecureChannelRequest;
    UA_CreateSessionRequest createSessionRequest;
    UA_ActivateSessionRequest activateSessionRequest;
    UA_CloseSessionRequest closeSessionRequest;
    UA_AddNodesRequest addNodesRequest;
    UA_AddReferencesRequest addReferencesRequest;
    UA_DeleteNodesRequest deleteNodesRequest;
    UA_DeleteReferencesRequest deleteReferencesRequest;
    UA_BrowseRequest browseRequest;
    UA_BrowseNextRequest browseNextRequest;
    UA_TranslateBrowsePathsToNodeIdsRequest translateBrowsePathsToNodeIdsRequest;
    UA_RegisterNodesRequest registerNodesRequest;
    UA_UnregisterNodesRequest unregisterNodesRequest;
    UA_ReadRequest readRequest;
    UA_WriteRequest writeRequest;
#ifdef UA_ENABLE_HISTORIZING
    UA_HistoryReadRequest historyReadRequest;
    UA_HistoryUpdateRequest historyUpdateRequest;
#endif
#ifdef UA_ENABLE_METHODCALLS
    UA_CallRequest callRequest;
#endif
#ifdef UA_ENABLE_SUBSCRIPTIONS
    UA_CreateMonitoredItemsRequest createMonitoredItemsRequest;
    UA_DeleteMonitoredItemsRequest deleteMonitoredItemsRequest;
    UA_ModifyMonitoredItemsRequest modifyMonitoredItemsRequest;
    UA_SetMonitoringModeRequest setMonitoringModeRequest;
    UA_CreateSubscriptionRequest createSubscriptionRequest;
    UA_ModifySubscriptionRequest modifySubscriptionRequest;
    UA_SetPublishingModeRequest setPublishingModeRequest;
    UA_PublishRequest publishRequest;
    UA_RepublishRequest republishRequest;
    UA_DeleteSubscriptionsRequest deleteSubscriptionsRequest;
#endif
} UA_Request;

typedef union {
    UA_ResponseHeader responseHeader;
    UA_FindServersResponse findServersResponse;
    UA_GetEndpointsResponse getEndpointsResponse;
#ifdef UA_ENABLE_DISCOVERY
# ifdef UA_ENABLE_DISCOVERY_MULTICAST
    UA_FindServersOnNetworkResponse findServersOnNetworkResponse;
# endif
    UA_RegisterServerResponse registerServerResponse;
    UA_RegisterServer2Response registerServer2Response;
#endif
    UA_OpenSecureChannelResponse openSecureChannelResponse;
    UA_CreateSessionResponse createSessionResponse;
    UA_ActivateSessionResponse activateSessionResponse;
    UA_CloseSessionResponse closeSessionResponse;
    UA_AddNodesResponse addNodesResponse;
    UA_AddReferencesResponse addReferencesResponse;
    UA_DeleteNodesResponse deleteNodesResponse;
    UA_DeleteReferencesResponse deleteReferencesResponse;
    UA_BrowseResponse browseResponse;
    UA_BrowseNextResponse browseNextResponse;
    UA_TranslateBrowsePathsToNodeIdsResponse translateBrowsePathsToNodeIdsResponse;
    UA_RegisterNodesResponse registerNodesResponse;
    UA_UnregisterNodesResponse unregisterNodesResponse;
    UA_ReadResponse readResponse;
    UA_WriteResponse writeResponse;
#ifdef UA_ENABLE_HISTORIZING
    UA_HistoryReadResponse historyReadResponse;
    UA_HistoryUpdateResponse historyUpdateResponse;
#endif
#ifdef UA_ENABLE_METHODCALLS
    UA_CallResponse callResponse;
#endif
#ifdef UA_ENABLE_SUBSCRIPTIONS
    UA_CreateMonitoredItemsResponse createMonitoredItemsResponse;
    UA_DeleteMonitoredItemsResponse deleteMonitoredItemsResponse;
    UA_ModifyMonitoredItemsResponse modifyMonitoredItemsResponse;
    UA_SetMonitoringModeResponse setMonitoringModeResponse;
    UA_CreateSubscriptionResponse createSubscriptionResponse;
    UA_ModifySubscriptionResponse modifySubscriptionResponse;
    UA_SetPublishingModeResponse setPublishingModeResponse;
    UA_PublishResponse publishResponse;
    UA_RepublishResponse republishResponse;
    UA_DeleteSubscriptionsResponse deleteSubscriptionsResponse;
#endif
} UA_Response;

/* Do not expose UA_String_equal_ignorecase to public API as it currently only handles
 * ASCII strings, and not UTF8! */
UA_Boolean UA_EXPORT
UA_String_equal_ignorecase(const UA_String *s1, const UA_String *s2);

/********************/
/* Encoding Helpers */
/********************/

/* out must be a buffer with at least 36 elements, the length of every guid */
void UA_Guid_to_hex(const UA_Guid *guid, u8* out, UA_Boolean lower);

#define UA_ENCODING_HELPERS(TYPE, UPCASE_TYPE)                          \
    static UA_INLINE size_t                                             \
    UA_##TYPE##_calcSizeBinary(const UA_##TYPE *src) {                    \
        return UA_calcSizeBinary(src, &UA_TYPES[UA_TYPES_##UPCASE_TYPE]); \
    }                                                                   \
    static UA_INLINE UA_StatusCode                                      \
    UA_##TYPE##_encodeBinary(const UA_##TYPE *src, UA_Byte **bufPos, const UA_Byte *bufEnd) { \
        return UA_encodeBinaryInternal(src, &UA_TYPES[UA_TYPES_##UPCASE_TYPE], \
                                       bufPos, &bufEnd, NULL, NULL);    \
    }                                                                   \
    static UA_INLINE UA_StatusCode                                      \
    UA_##TYPE##_decodeBinary(const UA_ByteString *src, size_t *offset, UA_##TYPE *dst) { \
    return UA_decodeBinaryInternal(src, offset, dst, \
                                   &UA_TYPES[UA_TYPES_##UPCASE_TYPE], NULL); \
    }

UA_ENCODING_HELPERS(Boolean, BOOLEAN)
UA_ENCODING_HELPERS(SByte, SBYTE)
UA_ENCODING_HELPERS(Byte, BYTE)
UA_ENCODING_HELPERS(Int16, INT16)
UA_ENCODING_HELPERS(UInt16, UINT16)
UA_ENCODING_HELPERS(Int32, INT32)
UA_ENCODING_HELPERS(UInt32, UINT32)
UA_ENCODING_HELPERS(Int64, INT64)
UA_ENCODING_HELPERS(UInt64, UINT64)
UA_ENCODING_HELPERS(Float, FLOAT)
UA_ENCODING_HELPERS(Double, DOUBLE)
UA_ENCODING_HELPERS(String, STRING)
UA_ENCODING_HELPERS(DateTime, DATETIME)
UA_ENCODING_HELPERS(Guid, GUID)
UA_ENCODING_HELPERS(ByteString, BYTESTRING)
UA_ENCODING_HELPERS(XmlElement, XMLELEMENT)
UA_ENCODING_HELPERS(NodeId, NODEID)
UA_ENCODING_HELPERS(ExpandedNodeId, EXPANDEDNODEID)
UA_ENCODING_HELPERS(StatusCode, STATUSCODE)
UA_ENCODING_HELPERS(QualifiedName, QUALIFIEDNAME)
UA_ENCODING_HELPERS(LocalizedText, LOCALIZEDTEXT)
UA_ENCODING_HELPERS(ExtensionObject, EXTENSIONOBJECT)
UA_ENCODING_HELPERS(DataValue, DATAVALUE)
UA_ENCODING_HELPERS(Variant, VARIANT)
UA_ENCODING_HELPERS(DiagnosticInfo, DIAGNOSTICINFO)

_UA_END_DECLS


/**** amalgamated original file "/build/src_generated/open62541/transport_generated.h" ****/

/**********************************
 * Autogenerated -- do not modify *
 **********************************/

/* Must be before the include guards */
#ifdef UA_ENABLE_AMALGAMATION
#else
#endif



_UA_BEGIN_DECLS

/**
 * Every type is assigned an index in an array containing the type descriptions.
 * These descriptions are used during type handling (copying, deletion,
 * binary encoding, ...). */
#define UA_TRANSPORT_COUNT 9
extern UA_EXPORT UA_DataType UA_TRANSPORT[UA_TRANSPORT_COUNT];

/**
 * MessageType
 * ^^^^^^^^^^^
 * Message Type and whether the message contains an intermediate chunk */
typedef enum {
    UA_MESSAGETYPE_ACK = 0x4B4341,
    UA_MESSAGETYPE_HEL = 0x4C4548,
    UA_MESSAGETYPE_MSG = 0x47534D,
    UA_MESSAGETYPE_OPN = 0x4E504F,
    UA_MESSAGETYPE_CLO = 0x4F4C43,
    UA_MESSAGETYPE_ERR = 0x525245,
    UA_MESSAGETYPE_RHE = 0x454852,
    UA_MESSAGETYPE_INVALID = 0x0,
    __UA_MESSAGETYPE_FORCE32BIT = 0x7fffffff
} UA_MessageType;
UA_STATIC_ASSERT(sizeof(UA_MessageType) == sizeof(UA_Int32), enum_must_be_32bit);

#define UA_TRANSPORT_MESSAGETYPE 0

/**
 * ChunkType
 * ^^^^^^^^^
 * Type of the chunk */
typedef enum {
    UA_CHUNKTYPE_FINAL = 0x46000000,
    UA_CHUNKTYPE_INTERMEDIATE = 0x43000000,
    UA_CHUNKTYPE_ABORT = 0x41000000,
    __UA_CHUNKTYPE_FORCE32BIT = 0x7fffffff
} UA_ChunkType;
UA_STATIC_ASSERT(sizeof(UA_ChunkType) == sizeof(UA_Int32), enum_must_be_32bit);

#define UA_TRANSPORT_CHUNKTYPE 1

/**
 * TcpMessageHeader
 * ^^^^^^^^^^^^^^^^
 * TCP Header */
typedef struct {
    UA_UInt32 messageTypeAndChunkType;
    UA_UInt32 messageSize;
} UA_TcpMessageHeader;

#define UA_TRANSPORT_TCPMESSAGEHEADER 2

/**
 * TcpHelloMessage
 * ^^^^^^^^^^^^^^^
 * Hello Message */
typedef struct {
    UA_UInt32 protocolVersion;
    UA_UInt32 receiveBufferSize;
    UA_UInt32 sendBufferSize;
    UA_UInt32 maxMessageSize;
    UA_UInt32 maxChunkCount;
    UA_String endpointUrl;
} UA_TcpHelloMessage;

#define UA_TRANSPORT_TCPHELLOMESSAGE 3

/**
 * TcpReverseHelloMessage
 * ^^^^^^^^^^^^^^^^^^^^^^
 */
typedef struct {
    UA_String serverUri;
    UA_String endpointUrl;
} UA_TcpReverseHelloMessage;

#define UA_TRANSPORT_TCPREVERSEHELLOMESSAGE 4

/**
 * TcpAcknowledgeMessage
 * ^^^^^^^^^^^^^^^^^^^^^
 * Acknowledge Message */
typedef struct {
    UA_UInt32 protocolVersion;
    UA_UInt32 receiveBufferSize;
    UA_UInt32 sendBufferSize;
    UA_UInt32 maxMessageSize;
    UA_UInt32 maxChunkCount;
} UA_TcpAcknowledgeMessage;

#define UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE 5

/**
 * TcpErrorMessage
 * ^^^^^^^^^^^^^^^
 * Error Message */
typedef struct {
    UA_UInt32 error;
    UA_String reason;
} UA_TcpErrorMessage;

#define UA_TRANSPORT_TCPERRORMESSAGE 6

/**
 * AsymmetricAlgorithmSecurityHeader
 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 * Asymmetric Security Header */
typedef struct {
    UA_ByteString securityPolicyUri;
    UA_ByteString senderCertificate;
    UA_ByteString receiverCertificateThumbprint;
} UA_AsymmetricAlgorithmSecurityHeader;

#define UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER 7

/**
 * SequenceHeader
 * ^^^^^^^^^^^^^^
 * Secure Layer Sequence Header */
typedef struct {
    UA_UInt32 sequenceNumber;
    UA_UInt32 requestId;
} UA_SequenceHeader;

#define UA_TRANSPORT_SEQUENCEHEADER 8


_UA_END_DECLS


/**** amalgamated original file "/build/src_generated/open62541/transport_generated_handling.h" ****/

/**********************************
 * Autogenerated -- do not modify *
 **********************************/



_UA_BEGIN_DECLS

#if defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 6
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
# pragma GCC diagnostic ignored "-Wmissing-braces"
#endif


/* MessageType */
UA_INLINABLE( void
UA_MessageType_init(UA_MessageType *p) ,{
    memset(p, 0, sizeof(UA_MessageType));
})

UA_INLINABLE( UA_MessageType *
UA_MessageType_new(void) ,{
    return (UA_MessageType*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_MESSAGETYPE]);
})

UA_INLINABLE( UA_StatusCode
UA_MessageType_copy(const UA_MessageType *src, UA_MessageType *dst) ,{
    return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_MESSAGETYPE]);
})

UA_DEPRECATED UA_INLINABLE( void
UA_MessageType_deleteMembers(UA_MessageType *p) ,{
    UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_MESSAGETYPE]);
})

UA_INLINABLE( void
UA_MessageType_clear(UA_MessageType *p) ,{
    UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_MESSAGETYPE]);
})

UA_INLINABLE( void
UA_MessageType_delete(UA_MessageType *p) ,{
    UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_MESSAGETYPE]);
})static UA_INLINE UA_Boolean
UA_MessageType_equal(const UA_MessageType *p1, const UA_MessageType *p2) {
    return (UA_order(p1, p2, &UA_TRANSPORT[UA_TRANSPORT_MESSAGETYPE]) == UA_ORDER_EQ);
}



/* ChunkType */
UA_INLINABLE( void
UA_ChunkType_init(UA_ChunkType *p) ,{
    memset(p, 0, sizeof(UA_ChunkType));
})

UA_INLINABLE( UA_ChunkType *
UA_ChunkType_new(void) ,{
    return (UA_ChunkType*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_CHUNKTYPE]);
})

UA_INLINABLE( UA_StatusCode
UA_ChunkType_copy(const UA_ChunkType *src, UA_ChunkType *dst) ,{
    return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_CHUNKTYPE]);
})

UA_DEPRECATED UA_INLINABLE( void
UA_ChunkType_deleteMembers(UA_ChunkType *p) ,{
    UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_CHUNKTYPE]);
})

UA_INLINABLE( void
UA_ChunkType_clear(UA_ChunkType *p) ,{
    UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_CHUNKTYPE]);
})

UA_INLINABLE( void
UA_ChunkType_delete(UA_ChunkType *p) ,{
    UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_CHUNKTYPE]);
})static UA_INLINE UA_Boolean
UA_ChunkType_equal(const UA_ChunkType *p1, const UA_ChunkType *p2) {
    return (UA_order(p1, p2, &UA_TRANSPORT[UA_TRANSPORT_CHUNKTYPE]) == UA_ORDER_EQ);
}



/* TcpMessageHeader */
UA_INLINABLE( void
UA_TcpMessageHeader_init(UA_TcpMessageHeader *p) ,{
    memset(p, 0, sizeof(UA_TcpMessageHeader));
})

UA_INLINABLE( UA_TcpMessageHeader *
UA_TcpMessageHeader_new(void) ,{
    return (UA_TcpMessageHeader*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER]);
})

UA_INLINABLE( UA_StatusCode
UA_TcpMessageHeader_copy(const UA_TcpMessageHeader *src, UA_TcpMessageHeader *dst) ,{
    return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER]);
})

UA_DEPRECATED UA_INLINABLE( void
UA_TcpMessageHeader_deleteMembers(UA_TcpMessageHeader *p) ,{
    UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER]);
})

UA_INLINABLE( void
UA_TcpMessageHeader_clear(UA_TcpMessageHeader *p) ,{
    UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER]);
})

UA_INLINABLE( void
UA_TcpMessageHeader_delete(UA_TcpMessageHeader *p) ,{
    UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER]);
})static UA_INLINE UA_Boolean
UA_TcpMessageHeader_equal(const UA_TcpMessageHeader *p1, const UA_TcpMessageHeader *p2) {
    return (UA_order(p1, p2, &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER]) == UA_ORDER_EQ);
}



/* TcpHelloMessage */
UA_INLINABLE( void
UA_TcpHelloMessage_init(UA_TcpHelloMessage *p) ,{
    memset(p, 0, sizeof(UA_TcpHelloMessage));
})

UA_INLINABLE( UA_TcpHelloMessage *
UA_TcpHelloMessage_new(void) ,{
    return (UA_TcpHelloMessage*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE]);
})

UA_INLINABLE( UA_StatusCode
UA_TcpHelloMessage_copy(const UA_TcpHelloMessage *src, UA_TcpHelloMessage *dst) ,{
    return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE]);
})

UA_DEPRECATED UA_INLINABLE( void
UA_TcpHelloMessage_deleteMembers(UA_TcpHelloMessage *p) ,{
    UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE]);
})

UA_INLINABLE( void
UA_TcpHelloMessage_clear(UA_TcpHelloMessage *p) ,{
    UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE]);
})

UA_INLINABLE( void
UA_TcpHelloMessage_delete(UA_TcpHelloMessage *p) ,{
    UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE]);
})static UA_INLINE UA_Boolean
UA_TcpHelloMessage_equal(const UA_TcpHelloMessage *p1, const UA_TcpHelloMessage *p2) {
    return (UA_order(p1, p2, &UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE]) == UA_ORDER_EQ);
}



/* TcpReverseHelloMessage */
UA_INLINABLE( void
UA_TcpReverseHelloMessage_init(UA_TcpReverseHelloMessage *p) ,{
    memset(p, 0, sizeof(UA_TcpReverseHelloMessage));
})

UA_INLINABLE( UA_TcpReverseHelloMessage *
UA_TcpReverseHelloMessage_new(void) ,{
    return (UA_TcpReverseHelloMessage*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_TCPREVERSEHELLOMESSAGE]);
})

UA_INLINABLE( UA_StatusCode
UA_TcpReverseHelloMessage_copy(const UA_TcpReverseHelloMessage *src, UA_TcpReverseHelloMessage *dst) ,{
    return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_TCPREVERSEHELLOMESSAGE]);
})

UA_DEPRECATED UA_INLINABLE( void
UA_TcpReverseHelloMessage_deleteMembers(UA_TcpReverseHelloMessage *p) ,{
    UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_TCPREVERSEHELLOMESSAGE]);
})

UA_INLINABLE( void
UA_TcpReverseHelloMessage_clear(UA_TcpReverseHelloMessage *p) ,{
    UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_TCPREVERSEHELLOMESSAGE]);
})

UA_INLINABLE( void
UA_TcpReverseHelloMessage_delete(UA_TcpReverseHelloMessage *p) ,{
    UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_TCPREVERSEHELLOMESSAGE]);
})static UA_INLINE UA_Boolean
UA_TcpReverseHelloMessage_equal(const UA_TcpReverseHelloMessage *p1, const UA_TcpReverseHelloMessage *p2) {
    return (UA_order(p1, p2, &UA_TRANSPORT[UA_TRANSPORT_TCPREVERSEHELLOMESSAGE]) == UA_ORDER_EQ);
}



/* TcpAcknowledgeMessage */
UA_INLINABLE( void
UA_TcpAcknowledgeMessage_init(UA_TcpAcknowledgeMessage *p) ,{
    memset(p, 0, sizeof(UA_TcpAcknowledgeMessage));
})

UA_INLINABLE( UA_TcpAcknowledgeMessage *
UA_TcpAcknowledgeMessage_new(void) ,{
    return (UA_TcpAcknowledgeMessage*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE]);
})

UA_INLINABLE( UA_StatusCode
UA_TcpAcknowledgeMessage_copy(const UA_TcpAcknowledgeMessage *src, UA_TcpAcknowledgeMessage *dst) ,{
    return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE]);
})

UA_DEPRECATED UA_INLINABLE( void
UA_TcpAcknowledgeMessage_deleteMembers(UA_TcpAcknowledgeMessage *p) ,{
    UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE]);
})

UA_INLINABLE( void
UA_TcpAcknowledgeMessage_clear(UA_TcpAcknowledgeMessage *p) ,{
    UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE]);
})

UA_INLINABLE( void
UA_TcpAcknowledgeMessage_delete(UA_TcpAcknowledgeMessage *p) ,{
    UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE]);
})static UA_INLINE UA_Boolean
UA_TcpAcknowledgeMessage_equal(const UA_TcpAcknowledgeMessage *p1, const UA_TcpAcknowledgeMessage *p2) {
    return (UA_order(p1, p2, &UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE]) == UA_ORDER_EQ);
}



/* TcpErrorMessage */
UA_INLINABLE( void
UA_TcpErrorMessage_init(UA_TcpErrorMessage *p) ,{
    memset(p, 0, sizeof(UA_TcpErrorMessage));
})

UA_INLINABLE( UA_TcpErrorMessage *
UA_TcpErrorMessage_new(void) ,{
    return (UA_TcpErrorMessage*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE]);
})

UA_INLINABLE( UA_StatusCode
UA_TcpErrorMessage_copy(const UA_TcpErrorMessage *src, UA_TcpErrorMessage *dst) ,{
    return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE]);
})

UA_DEPRECATED UA_INLINABLE( void
UA_TcpErrorMessage_deleteMembers(UA_TcpErrorMessage *p) ,{
    UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE]);
})

UA_INLINABLE( void
UA_TcpErrorMessage_clear(UA_TcpErrorMessage *p) ,{
    UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE]);
})

UA_INLINABLE( void
UA_TcpErrorMessage_delete(UA_TcpErrorMessage *p) ,{
    UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE]);
})static UA_INLINE UA_Boolean
UA_TcpErrorMessage_equal(const UA_TcpErrorMessage *p1, const UA_TcpErrorMessage *p2) {
    return (UA_order(p1, p2, &UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE]) == UA_ORDER_EQ);
}



/* AsymmetricAlgorithmSecurityHeader */
UA_INLINABLE( void
UA_AsymmetricAlgorithmSecurityHeader_init(UA_AsymmetricAlgorithmSecurityHeader *p) ,{
    memset(p, 0, sizeof(UA_AsymmetricAlgorithmSecurityHeader));
})

UA_INLINABLE( UA_AsymmetricAlgorithmSecurityHeader *
UA_AsymmetricAlgorithmSecurityHeader_new(void) ,{
    return (UA_AsymmetricAlgorithmSecurityHeader*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER]);
})

UA_INLINABLE( UA_StatusCode
UA_AsymmetricAlgorithmSecurityHeader_copy(const UA_AsymmetricAlgorithmSecurityHeader *src, UA_AsymmetricAlgorithmSecurityHeader *dst) ,{
    return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER]);
})

UA_DEPRECATED UA_INLINABLE( void
UA_AsymmetricAlgorithmSecurityHeader_deleteMembers(UA_AsymmetricAlgorithmSecurityHeader *p) ,{
    UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER]);
})

UA_INLINABLE( void
UA_AsymmetricAlgorithmSecurityHeader_clear(UA_AsymmetricAlgorithmSecurityHeader *p) ,{
    UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER]);
})

UA_INLINABLE( void
UA_AsymmetricAlgorithmSecurityHeader_delete(UA_AsymmetricAlgorithmSecurityHeader *p) ,{
    UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER]);
})static UA_INLINE UA_Boolean
UA_AsymmetricAlgorithmSecurityHeader_equal(const UA_AsymmetricAlgorithmSecurityHeader *p1, const UA_AsymmetricAlgorithmSecurityHeader *p2) {
    return (UA_order(p1, p2, &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER]) == UA_ORDER_EQ);
}



/* SequenceHeader */
UA_INLINABLE( void
UA_SequenceHeader_init(UA_SequenceHeader *p) ,{
    memset(p, 0, sizeof(UA_SequenceHeader));
})

UA_INLINABLE( UA_SequenceHeader *
UA_SequenceHeader_new(void) ,{
    return (UA_SequenceHeader*)UA_new(&UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER]);
})

UA_INLINABLE( UA_StatusCode
UA_SequenceHeader_copy(const UA_SequenceHeader *src, UA_SequenceHeader *dst) ,{
    return UA_copy(src, dst, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER]);
})

UA_DEPRECATED UA_INLINABLE( void
UA_SequenceHeader_deleteMembers(UA_SequenceHeader *p) ,{
    UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER]);
})

UA_INLINABLE( void
UA_SequenceHeader_clear(UA_SequenceHeader *p) ,{
    UA_clear(p, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER]);
})

UA_INLINABLE( void
UA_SequenceHeader_delete(UA_SequenceHeader *p) ,{
    UA_delete(p, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER]);
})static UA_INLINE UA_Boolean
UA_SequenceHeader_equal(const UA_SequenceHeader *p1, const UA_SequenceHeader *p2) {
    return (UA_order(p1, p2, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER]) == UA_ORDER_EQ);
}



#if defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 6
# pragma GCC diagnostic pop
#endif

_UA_END_DECLS


/**** amalgamated original file "/src/ua_securechannel.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2017 (c) Florian Palm
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
 */




_UA_BEGIN_DECLS

struct UA_SecureChannel;
typedef struct UA_SecureChannel UA_SecureChannel;

/* Forward-Declaration so the SecureChannel can point to a singly-linked list of
 * Sessions. This is only used in the server, not in the client. */
struct UA_Session;
typedef struct UA_Session UA_Session;

/* The message header of the OPC UA binary protocol is structured as follows:
 *
 * - MessageType (3 Byte)
 * - IsFinal (1 Byte)
 * - MessageSize (4 Byte)
 * *** UA_SECURECHANNEL_MESSAGEHEADER_LENGTH ***
 * - SecureChannelId (4 Byte)
 * *** UA_SECURECHANNEL_CHANNELHEADER_LENGTH ***
 * - SecurityHeader (4 Byte TokenId for symmetric, otherwise dynamic length)
 * - SequenceHeader (8 Byte)
 *   - SequenceNumber
 *   - RequestId
 */

#define UA_SECURECHANNEL_MESSAGEHEADER_LENGTH 8
#define UA_SECURECHANNEL_CHANNELHEADER_LENGTH 12
#define UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH 4
#define UA_SECURECHANNEL_SEQUENCEHEADER_LENGTH 8
#define UA_SECURECHANNEL_SYMMETRIC_HEADER_UNENCRYPTEDLENGTH \
    (UA_SECURECHANNEL_CHANNELHEADER_LENGTH +                \
     UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH)
#define UA_SECURECHANNEL_SYMMETRIC_HEADER_TOTALLENGTH   \
    (UA_SECURECHANNEL_CHANNELHEADER_LENGTH +            \
    UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH +  \
     UA_SECURECHANNEL_SEQUENCEHEADER_LENGTH)

/* Minimum length of a valid message (ERR message with an empty reason) */
#define UA_SECURECHANNEL_MESSAGE_MIN_LENGTH 16

/* For chunked requests */
typedef struct UA_Chunk {
    SIMPLEQ_ENTRY(UA_Chunk) pointers;
    UA_ByteString bytes;
    UA_MessageType messageType;
    UA_ChunkType chunkType;
    UA_UInt32 requestId;
    UA_Boolean copied; /* Do the bytes point to a buffer from the network or was
                        * memory allocated for the chunk separately */
} UA_Chunk;

typedef SIMPLEQ_HEAD(UA_ChunkQueue, UA_Chunk) UA_ChunkQueue;

typedef enum {
    UA_SECURECHANNELRENEWSTATE_NORMAL,

    /* Client has sent an OPN, but not received a response so far. */
    UA_SECURECHANNELRENEWSTATE_SENT,

    /* The server waits for the first request with the new token for the rollover.
     * The new token is stored in the altSecurityToken. The configured local and
     * remote symmetric encryption keys are the old ones. */
    UA_SECURECHANNELRENEWSTATE_NEWTOKEN_SERVER,

    /* The client already uses the new token. But he waits for the server to respond
     * with the new token to complete the rollover. The old token is stored in
     * altSecurityToken. The local symmetric encryption key is new. The remote
     * encryption key is the old one. */
    UA_SECURECHANNELRENEWSTATE_NEWTOKEN_CLIENT
} UA_SecureChannelRenewState;

struct UA_SecureChannel {
    UA_SecureChannelState state;
    UA_SecureChannelRenewState renewState;
    UA_MessageSecurityMode securityMode;
    UA_ShutdownReason shutdownReason;
    UA_ConnectionConfig config;

    /* Connection handling in the EventLoop */
    UA_ConnectionManager *connectionManager;
    uintptr_t connectionId;

    /* Rules for revolving the token with a renew OPN request: The client is
     * allowed to accept messages with the old token until the OPN response has
     * arrived. The server accepts the old token until one message secured with
     * the new token has arrived.
     *
     * We recognize whether nextSecurityToken contains a valid next token if the
     * ChannelId is not 0. */
    UA_ChannelSecurityToken securityToken;    /* Also contains the channelId */
    UA_ChannelSecurityToken altSecurityToken; /* Alternative token for the rollover.
                                               * See the renewState. */

    /* The endpoint and context of the channel */
    const UA_SecurityPolicy *securityPolicy;
    void *channelContext; /* For interaction with the security policy */

    /* Asymmetric encryption info */
    UA_ByteString remoteCertificate;
    UA_Byte remoteCertificateThumbprint[20]; /* The thumbprint of the remote certificate */

    /* Symmetric encryption nonces. These are used to generate the key material
     * and must not be reused once the keys are in place.
     *
     * Nonces are also used during the CreateSession / ActivateSession
     * handshake. These are not handled here, as the Session handling can
     * overlap with a RenewSecureChannel. */
    UA_ByteString remoteNonce;
    UA_ByteString localNonce;

    UA_UInt32 receiveSequenceNumber;
    UA_UInt32 sendSequenceNumber;

    /* Sessions that are bound to the SecureChannel (singly-linked list, only
     * used in the server) */
    UA_Session *sessions;

    /* If a buffer is received, first all chunks are put into the completeChunks
     * queue. Then they are processed in order. This ensures that processing
     * buffers is reentrant with the correct processing order. (This has lead to
     * problems in the client in the past.) */
    UA_ChunkQueue completeChunks; /* Received full chunks that have not been
                                   * decrypted so far */
    UA_ChunkQueue decryptedChunks; /* Received chunks that were decrypted but
                                    * not processed */
    size_t decryptedChunksCount;
    size_t decryptedChunksLength;
    UA_ByteString incompleteChunk; /* A half-received chunk (TCP is a
                                    * streaming protocol) is stored here */

    UA_CertificateGroup *certificateVerification;
    UA_StatusCode (*processOPNHeader)(void *application, UA_SecureChannel *channel,
                                      const UA_AsymmetricAlgorithmSecurityHeader *asymHeader);
};

void UA_SecureChannel_init(UA_SecureChannel *channel);

/* Trigger the shutdown */
void UA_SecureChannel_shutdown(UA_SecureChannel *channel,
                               UA_ShutdownReason shutdownReason);

/* Eventual cleanup after the channel has closed. It is possible to call _init
 * on the channel afterwards to reset it to the fresh status. */
void UA_SecureChannel_clear(UA_SecureChannel *channel);

/* Process the remote configuration in the HEL/ACK handshake. The connection
 * config is initialized with the local settings. */
UA_StatusCode
UA_SecureChannel_processHELACK(UA_SecureChannel *channel,
                               const UA_TcpAcknowledgeMessage *remoteConfig);

UA_StatusCode
UA_SecureChannel_setSecurityPolicy(UA_SecureChannel *channel,
                                   const UA_SecurityPolicy *securityPolicy,
                                   const UA_ByteString *remoteCertificate);

UA_Boolean
UA_SecureChannel_isConnected(UA_SecureChannel *channel);

/* Returns true if the channel has timed out. Performs the SecurityToken
 * rollover if required and possible. */
UA_Boolean
UA_SecureChannel_checkTimeout(UA_SecureChannel *channel,
                              UA_DateTime nowMonotonic);

/* When a fatal error occurs the Server shall send an Error Message to the
 * Client and close the socket. When a Client encounters one of these errors, it
 * shall also close the socket but does not send an Error Message. After the
 * socket is closed a Client shall try to reconnect automatically using the
 * mechanisms described in [...]. */
void
UA_SecureChannel_sendError(UA_SecureChannel *channel, UA_TcpErrorMessage *error);

/* Remove (partially) received unprocessed chunks */
void
UA_SecureChannel_deleteBuffered(UA_SecureChannel *channel);

/* Wrapper function for generating a local nonce for the supplied channel. Uses
 * the random generator of the channels security policy to allocate and generate
 * a nonce with the specified length. */
UA_StatusCode
UA_SecureChannel_generateLocalNonce(UA_SecureChannel *channel);

UA_StatusCode
UA_SecureChannel_generateLocalKeys(const UA_SecureChannel *channel);

UA_StatusCode
generateRemoteKeys(const UA_SecureChannel *channel);

/**
 * Sending Messages
 * ---------------- */

UA_StatusCode
UA_SecureChannel_sendAsymmetricOPNMessage(UA_SecureChannel *channel, UA_UInt32 requestId,
                                          const void *content, const UA_DataType *contentType);

UA_StatusCode
UA_SecureChannel_sendSymmetricMessage(UA_SecureChannel *channel, UA_UInt32 requestId,
                                      UA_MessageType messageType, void *payload,
                                      const UA_DataType *payloadType);

/* The MessageContext is forwarded into the encoding layer so that we can send
 * chunks before continuing to encode. This lets us reuse a fixed chunk-sized
 * messages buffer. */
typedef struct {
    UA_SecureChannel *channel;
    UA_UInt32 requestId;
    UA_UInt32 messageType;

    UA_UInt16 chunksSoFar;
    size_t messageSizeSoFar;

    UA_ByteString messageBuffer;
    UA_Byte *buf_pos;
    const UA_Byte *buf_end;

    UA_Boolean final;
} UA_MessageContext;

/* Start the context of a new symmetric message. */
UA_StatusCode
UA_MessageContext_begin(UA_MessageContext *mc, UA_SecureChannel *channel,
                        UA_UInt32 requestId, UA_MessageType messageType);

/* Encode the content and send out full chunks. If the return code is good, then
 * the ChunkInfo contains encoded content that has not been sent. If the return
 * code is bad, then the ChunkInfo has been cleaned up internally. */
UA_StatusCode
UA_MessageContext_encode(UA_MessageContext *mc, const void *content,
                         const UA_DataType *contentType);

/* Sends a symmetric message already encoded in the context. The context is
 * cleaned up, also in case of errors. */
UA_StatusCode
UA_MessageContext_finish(UA_MessageContext *mc);

/* To be used when a failure occures when a MessageContext is open. Note that
 * the _encode and _finish methods will clean up internally. _abort can be run
 * on a MessageContext that has already been cleaned up before. */
void
UA_MessageContext_abort(UA_MessageContext *mc);

/**
 * Receive Message
 * --------------- */

typedef UA_StatusCode
(UA_ProcessMessageCallback)(void *application, UA_SecureChannel *channel,
                            UA_MessageType messageType, UA_UInt32 requestId,
                            UA_ByteString *message);

/* Process a received buffer. The callback function is called with the message
 * body if the message is complete. The message is removed afterwards. Returns
 * if an irrecoverable error occured.
 *
 * Note that only MSG and CLO messages are decrypted. HEL/ACK/OPN/... are
 * forwarded verbatim to the application. */
UA_StatusCode
UA_SecureChannel_processBuffer(UA_SecureChannel *channel, void *application,
                               UA_ProcessMessageCallback callback,
                               const UA_ByteString *buffer,
                               UA_DateTime nowMonotonic);

/* Internal methods in ua_securechannel_crypto.h */

void
hideBytesAsym(const UA_SecureChannel *channel, UA_Byte **buf_start,
              const UA_Byte **buf_end);

/* Decrypt and verify via the signature. The chunk buffer is reused to hold the
 * decrypted data after the MessageHeader and SecurityHeader. The chunk length
 * is reduced by the signature, padding and encryption overhead.
 *
 * The offset argument points to the start of the encrypted content (beginning
 * with the SequenceHeader).*/
UA_StatusCode
decryptAndVerifyChunk(const UA_SecureChannel *channel,
                      const UA_SecurityPolicyCryptoModule *cryptoModule,
                      UA_MessageType messageType, UA_ByteString *chunk,
                      size_t offset);

size_t
calculateAsymAlgSecurityHeaderLength(const UA_SecureChannel *channel);

UA_StatusCode
prependHeadersAsym(UA_SecureChannel *const channel, UA_Byte *header_pos,
                   const UA_Byte *buf_end, size_t totalLength,
                   size_t securityHeaderLength, UA_UInt32 requestId,
                   size_t *const finalLength);

void
setBufPos(UA_MessageContext *mc);

UA_StatusCode
checkSymHeader(UA_SecureChannel *channel, const UA_UInt32 tokenId,
               UA_DateTime nowMonotonic);

UA_StatusCode
checkAsymHeader(UA_SecureChannel *channel,
                const UA_AsymmetricAlgorithmSecurityHeader *asymHeader);

void
padChunk(UA_SecureChannel *channel, const UA_SecurityPolicyCryptoModule *cm,
         const UA_Byte *start, UA_Byte **pos);

UA_StatusCode
signAndEncryptAsym(UA_SecureChannel *channel, size_t preSignLength,
                   UA_ByteString *buf, size_t securityHeaderLength,
                   size_t totalLength);

UA_StatusCode
signAndEncryptSym(UA_MessageContext *messageContext,
                  size_t preSigLength, size_t totalLength);

/**
 * Log Helper
 * ----------
 * C99 requires at least one element for the variadic argument. If the log
 * statement has no variable arguments, supply an additional NULL. It will be
 * ignored by printf.
 *
 * We have to jump through some hoops to enable the use of format strings
 * without arguments since (pedantic) C99 does not allow variadic macros with
 * zero arguments. So we add a dummy argument that is not printed (%.0s is
 * string of length zero). */

#define UA_LOG_CHANNEL_INTERNAL(LOGGER, LEVEL, CHANNEL, MSG, ...)       \
    if(UA_LOGLEVEL <= UA_LOGLEVEL_##LEVEL) {                            \
        UA_LOG_##LEVEL(LOGGER, UA_LOGCATEGORY_SECURECHANNEL,            \
                       "TCP %lu\t| SC %" PRIu32 "\t| " MSG "%.0s", \
                       (long unsigned)(CHANNEL)->connectionId,          \
                       (CHANNEL)->securityToken.channelId, __VA_ARGS__); \
    }

#define UA_LOG_TRACE_CHANNEL(LOGGER, CHANNEL, ...)                      \
    UA_MACRO_EXPAND(UA_LOG_CHANNEL_INTERNAL(LOGGER, TRACE, CHANNEL, __VA_ARGS__, ""))
#define UA_LOG_DEBUG_CHANNEL(LOGGER, CHANNEL, ...)                      \
    UA_MACRO_EXPAND(UA_LOG_CHANNEL_INTERNAL(LOGGER, DEBUG, CHANNEL, __VA_ARGS__, ""))
#define UA_LOG_INFO_CHANNEL(LOGGER, CHANNEL, ...)                       \
    UA_MACRO_EXPAND(UA_LOG_CHANNEL_INTERNAL(LOGGER, INFO, CHANNEL, __VA_ARGS__, ""))
#define UA_LOG_WARNING_CHANNEL(LOGGER, CHANNEL, ...)                    \
    UA_MACRO_EXPAND(UA_LOG_CHANNEL_INTERNAL(LOGGER, WARNING, CHANNEL, __VA_ARGS__, ""))
#define UA_LOG_ERROR_CHANNEL(LOGGER, CHANNEL, ...)                      \
    UA_MACRO_EXPAND(UA_LOG_CHANNEL_INTERNAL(LOGGER, ERROR, CHANNEL, __VA_ARGS__, ""))
#define UA_LOG_FATAL_CHANNEL(LOGGER, CHANNEL, ...)                      \
    UA_MACRO_EXPAND(UA_LOG_CHANNEL_INTERNAL(LOGGER, FATAL, CHANNEL, __VA_ARGS__, ""))

_UA_END_DECLS


/**** amalgamated original file "/src/server/ua_session.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2019 (c) HMS Industrial Networks AB (Author: Jonas Green)
 */




_UA_BEGIN_DECLS

#define UA_MAXCONTINUATIONPOINTS 5

struct ContinuationPoint;
typedef struct ContinuationPoint ContinuationPoint;

/* Returns the next entry in the linked list */
ContinuationPoint *
ContinuationPoint_clear(ContinuationPoint *cp);

struct UA_Subscription;
typedef struct UA_Subscription UA_Subscription;

#ifdef UA_ENABLE_SUBSCRIPTIONS
typedef struct UA_PublishResponseEntry {
    SIMPLEQ_ENTRY(UA_PublishResponseEntry) listEntry;
    UA_UInt32 requestId;
    UA_DateTime maxTime; /* Based on the TimeoutHint of the request */
    UA_PublishResponse response;
} UA_PublishResponseEntry;
#endif

struct UA_Session {
    UA_Session *next; /* singly-linked list */
    UA_SecureChannel *channel; /* The pointer back to the SecureChannel in the session. */

    UA_NodeId sessionId;
    UA_NodeId authenticationToken;
    UA_String sessionName;
    UA_Boolean activated;

    void *context; /* Pointer assigned by the user in the
                    * accessControl->activateSession context */

    UA_ByteString serverNonce;

    UA_ApplicationDescription clientDescription;
    UA_String clientUserIdOfSession;
    UA_Double timeout; /* in ms */
    UA_DateTime validTill;

    UA_KeyValueMap *attributes;

    /* TODO: Currently unused */
    UA_UInt32 maxRequestMessageSize;
    UA_UInt32 maxResponseMessageSize;

    UA_UInt16         availableContinuationPoints;
    ContinuationPoint *continuationPoints;

    /* Localization information */
    size_t localeIdsSize;
    UA_String *localeIds;

#ifdef UA_ENABLE_SUBSCRIPTIONS
    /* The queue is ordered according to the priority byte (higher bytes come
     * first). When a late subscription finally publishes, then it is pushed to
     * the back within the sub-set of subscriptions that has the same priority
     * (round-robin scheduling). */
    size_t subscriptionsSize;
    TAILQ_HEAD(, UA_Subscription) subscriptions;

    size_t responseQueueSize;
    SIMPLEQ_HEAD(, UA_PublishResponseEntry) responseQueue;

    size_t totalRetransmissionQueueSize; /* Retransmissions of all subscriptions */
#endif

#ifdef UA_ENABLE_DIAGNOSTICS
    UA_SessionSecurityDiagnosticsDataType securityDiagnostics;
    UA_SessionDiagnosticsDataType diagnostics;
#endif
};

/**
 * Session Lifecycle
 * ----------------- */

void UA_Session_init(UA_Session *session);
void UA_Session_clear(UA_Session *session, UA_Server *server);
void UA_Session_attachToSecureChannel(UA_Session *session, UA_SecureChannel *channel);
void UA_Session_detachFromSecureChannel(UA_Session *session);
UA_StatusCode UA_Session_generateNonce(UA_Session *session);

/* If any activity on a session happens, the timeout is extended */
void UA_Session_updateLifetime(UA_Session *session, UA_DateTime now,
                               UA_DateTime nowMonotonic);

/**
 * Subscription handling
 * --------------------- */

#ifdef UA_ENABLE_SUBSCRIPTIONS

void
UA_Session_attachSubscription(UA_Session *session, UA_Subscription *sub);

/* If releasePublishResponses is true and the last subscription is removed, all
 * outstanding PublishResponse are sent with a StatusCode. But we don't do that
 * if a Subscription is only detached for modification. */
void
UA_Session_detachSubscription(UA_Server *server, UA_Session *session,
                              UA_Subscription *sub, UA_Boolean releasePublishResponses);

UA_Subscription *
UA_Session_getSubscriptionById(UA_Session *session,
                               UA_UInt32 subscriptionId);


void
UA_Session_queuePublishReq(UA_Session *session,
                           UA_PublishResponseEntry* entry,
                           UA_Boolean head);

UA_PublishResponseEntry *
UA_Session_dequeuePublishReq(UA_Session *session);

#endif

/**
 * Log Helper
 * ----------
 * We have to jump through some hoops to enable the use of format strings
 * without arguments since (pedantic) C99 does not allow variadic macros with
 * zero arguments. So we add a dummy argument that is not printed (%.0s is
 * string of length zero). */

#define UA_LOG_SESSION_INTERNAL(LOGGER, LEVEL, SESSION, MSG, ...)       \
    if(UA_LOGLEVEL <= UA_LOGLEVEL_##LEVEL) {                           \
        int nameLen = (SESSION) ? (int)(SESSION)->sessionName.length : 0; \
        const char *nameStr = (SESSION) ?                               \
            (const char*)(SESSION)->sessionName.data : "";              \
        unsigned long sockId = ((SESSION) && (SESSION)->channel) ? \
            (unsigned long)(SESSION)->channel->connectionId : 0; \
        UA_UInt32 chanId = ((SESSION) && (SESSION)->channel) ?   \
            (SESSION)->channel->securityToken.channelId : 0;     \
        UA_LOG_##LEVEL(LOGGER, UA_LOGCATEGORY_SESSION,                  \
                       "TCP %lu\t| SC %" PRIu32 "\t| Session \"%.*s\"\t| " MSG "%.0s", \
                       sockId, chanId, nameLen, nameStr, __VA_ARGS__);   \
    }

#define UA_LOG_TRACE_SESSION(LOGGER, SESSION, ...)                      \
    UA_MACRO_EXPAND(UA_LOG_SESSION_INTERNAL(LOGGER, TRACE, SESSION, __VA_ARGS__, ""))
#define UA_LOG_DEBUG_SESSION(LOGGER, SESSION, ...)                      \
    UA_MACRO_EXPAND(UA_LOG_SESSION_INTERNAL(LOGGER, DEBUG, SESSION, __VA_ARGS__, ""))
#define UA_LOG_INFO_SESSION(LOGGER, SESSION, ...)                       \
    UA_MACRO_EXPAND(UA_LOG_SESSION_INTERNAL(LOGGER, INFO, SESSION, __VA_ARGS__, ""))
#define UA_LOG_WARNING_SESSION(LOGGER, SESSION, ...)                    \
    UA_MACRO_EXPAND(UA_LOG_SESSION_INTERNAL(LOGGER, WARNING, SESSION, __VA_ARGS__, ""))
#define UA_LOG_ERROR_SESSION(LOGGER, SESSION, ...)                      \
    UA_MACRO_EXPAND(UA_LOG_SESSION_INTERNAL(LOGGER, ERROR, SESSION, __VA_ARGS__, ""))
#define UA_LOG_FATAL_SESSION(LOGGER, SESSION, ...)                      \
    UA_MACRO_EXPAND(UA_LOG_SESSION_INTERNAL(LOGGER, FATAL, SESSION, __VA_ARGS__, ""))

_UA_END_DECLS


/**** amalgamated original file "/src/server/ua_subscription.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2015-2018, 2021-2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015 (c) Oleksiy Vasylyev
 *    Copyright 2017 (c) Florian Palm
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Mattias Bornhager
 *    Copyright 2019 (c) HMS Industrial Networks AB (Author: Jonas Green)
 *    Copyright 2020 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati)
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Andreas Ebner)
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Jan Hermes)
 */




_UA_BEGIN_DECLS

#ifdef UA_ENABLE_SUBSCRIPTIONS

/* MonitoredItems create Notifications. Subscriptions collect Notifications from
 * (several) MonitoredItems and publish them to the client.
 *
 * Notifications are put into two queues at the same time. One for the
 * MonitoredItem that generated the notification. Here we can remove it if the
 * space reserved for the MonitoredItem runs full. The second queue is the
 * "global" queue for all Notifications generated in a Subscription. For
 * publication, the notifications are taken out of the "global" queue in the
 * order of their creation. */

/*****************/
/* Notifications */
/*****************/

/* Set to the TAILQ_NEXT pointer of a notification, the sentinel that the
 * notification was not added to the global queue */
#define UA_SUBSCRIPTION_QUEUE_SENTINEL ((UA_Notification*)0x01)

typedef struct UA_Notification {
    TAILQ_ENTRY(UA_Notification) localEntry;  /* Notification list for the MonitoredItem */
    TAILQ_ENTRY(UA_Notification) globalEntry; /* Notification list for the Subscription */
    UA_MonitoredItem *mon; /* Always set */

    /* The event field is used if mon->attributeId is the EventNotifier */
    union {
        UA_MonitoredItemNotification dataChange;
#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
        UA_EventFieldList event;
#endif
    } data;

#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
    UA_Boolean isOverflowEvent; /* Counted manually */
#endif
} UA_Notification;

/* Initializes and sets the sentinel pointers */
UA_Notification * UA_Notification_new(void);

/* Notifications are always added to the queue of the MonitoredItem. That queue
 * can overflow. If Notifications are reported, they are also added to the
 * global queue of the Subscription. There they are picked up by the publishing
 * callback.
 *
 * There are two ways Notifications can be put into the global queue of the
 * Subscription: They are added because the MonitoringMode of the MonitoredItem
 * is "reporting". Or the MonitoringMode is "sampling" and a link is trigered
 * that puts the last Notification into the global queue. */
void UA_Notification_enqueueAndTrigger(UA_Server *server,
                                       UA_Notification *n);

/* Dequeue and delete the notification */
void UA_Notification_delete(UA_Notification *n);

/* A NotificationMessage contains an array of notifications.
 * Sent NotificationMessages are stored for the republish service. */
typedef struct UA_NotificationMessageEntry {
    TAILQ_ENTRY(UA_NotificationMessageEntry) listEntry;
    UA_NotificationMessage message;
} UA_NotificationMessageEntry;

/* Queue Definitions */
typedef TAILQ_HEAD(NotificationQueue, UA_Notification) NotificationQueue;
typedef TAILQ_HEAD(NotificationMessageQueue, UA_NotificationMessageEntry)
    NotificationMessageQueue;

/*****************/
/* MonitoredItem */
/*****************/

/* The type of sampling for MonitoredItems depends on the sampling interval.
 *
 * >0: Cyclic callback
 * =0: Attached to the node. Sampling is triggered after every "write".
 * <0: Attached to the subscription. Triggered just before every "publish". */
typedef enum {
    UA_MONITOREDITEMSAMPLINGTYPE_NONE = 0,
    UA_MONITOREDITEMSAMPLINGTYPE_CYCLIC, /* Cyclic callback */
    UA_MONITOREDITEMSAMPLINGTYPE_EVENT,  /* Attached to the node. Can be a "write
                                          * event" for DataChange MonitoredItems
                                          * with a zero sampling interval .*/
    UA_MONITOREDITEMSAMPLINGTYPE_PUBLISH /* Attached to the subscription */
} UA_MonitoredItemSamplingType;

struct UA_MonitoredItem {
    UA_DelayedCallback delayedFreePointers;
    LIST_ENTRY(UA_MonitoredItem) listEntry; /* Linked list in the Subscription */
    UA_Subscription *subscription;          /* Always non-NULL */
    UA_UInt32 monitoredItemId;

    /* Status and Settings */
    UA_ReadValueId itemToMonitor;
    UA_MonitoringMode monitoringMode;
    UA_TimestampsToReturn timestampsToReturn;
    UA_Boolean registered;       /* Registered in the server / Subscription */
    UA_DateTime triggeredUntil;  /* If the MonitoringMode is SAMPLING,
                                  * triggering the MonitoredItem puts the latest
                                  * Notification into the publishing queue (of
                                  * the Subscription). In addition, the first
                                  * new sample is also published (and not just
                                  * sampled) if it occurs within the duration of
                                  * one publishing cycle after the triggering. */

    /* If the filter is a UA_DataChangeFilter: The DataChangeFilter always
     * contains an absolute deadband definition. Part 8, §6.2 gives the
     * following formula to test for percentage deadbands:
     *
     * DataChange if (absolute value of (last cached value - current value)
     *                > (deadbandValue/100.0) * ((high–low) of EURange)))
     *
     * So we can convert from a percentage to an absolute deadband and keep
     * the hot code path simple.
     *
     * TODO: Store the percentage deadband to recompute when the UARange is
     * changed at runtime of the MonitoredItem */
    UA_MonitoringParameters parameters;

    /* Sampling */
    UA_MonitoredItemSamplingType samplingType;
    union {
        UA_UInt64 callbackId;
        UA_MonitoredItem *nodeListNext; /* Event-Based: Attached to Node */
        LIST_ENTRY(UA_MonitoredItem) subscriptionSampling; /* Linked to publish
                                                            * interval */
    } sampling;
    UA_DataValue lastValue;

    /* Triggering Links */
    size_t triggeringLinksSize;
    UA_UInt32 *triggeringLinks;

    /* Notification Queue */
    NotificationQueue queue;
    size_t queueSize; /* This is the current size. See also the configured
                       * (maximum) queueSize in the parameters. */
    size_t eventOverflows; /* Separate counter for the queue. Can at most double
                            * the queue size */
};

void UA_MonitoredItem_init(UA_MonitoredItem *mon);
void UA_MonitoredItem_delete(UA_Server *server, UA_MonitoredItem *mon);
void UA_MonitoredItem_removeOverflowInfoBits(UA_MonitoredItem *mon);
void UA_MonitoredItem_sampleCallback(UA_Server *server, UA_MonitoredItem *mon);
void UA_Server_registerMonitoredItem(UA_Server *server, UA_MonitoredItem *mon);

/* Register sampling. Either by adding a repeated callback or by adding the
 * MonitoredItem to a linked list in the node. */
UA_StatusCode
UA_MonitoredItem_registerSampling(UA_Server *server, UA_MonitoredItem *mon);

void
UA_MonitoredItem_unregisterSampling(UA_Server *server, UA_MonitoredItem *mon);

UA_StatusCode
UA_MonitoredItem_setMonitoringMode(UA_Server *server, UA_MonitoredItem *mon,
                                   UA_MonitoringMode monitoringMode);


/* Do not use the value after calling this. It will be moved to mon or freed. */
void
UA_MonitoredItem_processSampledValue(UA_Server *server, UA_MonitoredItem *mon,
                                     UA_DataValue *value);

UA_StatusCode
UA_MonitoredItem_removeLink(UA_Subscription *sub, UA_MonitoredItem *mon,
                            UA_UInt32 linkId);

UA_StatusCode
UA_MonitoredItem_addLink(UA_Subscription *sub, UA_MonitoredItem *mon,
                         UA_UInt32 linkId);

UA_StatusCode
UA_MonitoredItem_createDataChangeNotification(UA_Server *server, UA_MonitoredItem *mon,
                                              const UA_DataValue *value);

/* Remove entries until mon->maxQueueSize is reached. Sets infobits for lost
 * data if required. */
void UA_MonitoredItem_ensureQueueSpace(UA_Server *server, UA_MonitoredItem *mon);

/****************/
/* Subscription */
/****************/

/* We use only a subset of the states defined in the standard */
typedef enum {
    UA_SUBSCRIPTIONSTATE_STOPPED = 0,
    UA_SUBSCRIPTIONSTATE_REMOVING,
    UA_SUBSCRIPTIONSTATE_ENABLED_NOPUBLISH, /* only keepalive */
    UA_SUBSCRIPTIONSTATE_ENABLED
} UA_SubscriptionState;

/* Subscriptions are managed in a server-wide linked list. If they are attached
 * to a Session, then they are additionaly in the per-Session linked-list. A
 * subscription is always generated for a Session. But the CloseSession Service
 * may keep Subscriptions intact beyond the Session lifetime. They can then be
 * re-bound to a new Session with the TransferSubscription Service. */
struct UA_Subscription {
    UA_DelayedCallback delayedFreePointers;
    LIST_ENTRY(UA_Subscription) serverListEntry;
    /* Ordered according to the priority byte and round-robin scheduling for
     * late subscriptions. See ua_session.h. Only set if session != NULL. */
    TAILQ_ENTRY(UA_Subscription) sessionListEntry;
    UA_Session *session; /* May be NULL if no session is attached. */
    UA_UInt32 subscriptionId;

    /* Settings */
    UA_UInt32 lifeTimeCount;
    UA_UInt32 maxKeepAliveCount;
    UA_Double publishingInterval; /* in ms */
    UA_UInt32 notificationsPerPublish;
    UA_Byte priority;

    /* Runtime information */
    UA_SubscriptionState state;
    UA_Boolean late;
    UA_StatusCode statusChange; /* If set, a notification is generated and the
                                 * Subscription is deleted within
                                 * UA_Subscription_publish. */
    UA_UInt32 nextSequenceNumber;
    UA_UInt32 currentKeepAliveCount;
    UA_UInt32 currentLifetimeCount;

    /* Publish Callback. Registered if id > 0. */
    UA_UInt64 publishCallbackId;

    /* Delayed callback to schedule publication of more notifications */
    UA_Boolean delayedCallbackRegistered;
    UA_DelayedCallback delayedMoreNotifications;

    /* MonitoredItems */
    UA_UInt32 lastMonitoredItemId; /* increase the identifiers */
    LIST_HEAD(, UA_MonitoredItem) monitoredItems;
    UA_UInt32 monitoredItemsSize;

    /* MonitoredItems that are sampled in every publish callback (with the
     * publish interval of the subscription) */
    LIST_HEAD(, UA_MonitoredItem) samplingMonitoredItems;

    /* Global list of notifications from the MonitoredItems */
    TAILQ_HEAD(, UA_Notification) notificationQueue;
    UA_UInt32 notificationQueueSize; /* Total queue size */
    UA_UInt32 dataChangeNotifications;
    UA_UInt32 eventNotifications;

    /* Retransmission Queue */
    NotificationMessageQueue retransmissionQueue;
    size_t retransmissionQueueSize;

    /* Statistics for the server diagnostics. The fields are defined according
     * to the SubscriptionDiagnosticsDataType (Part 5, §12.15). */
#ifdef UA_ENABLE_DIAGNOSTICS
    UA_NodeId ns0Id; /* Representation in the Session object */

    UA_UInt32 modifyCount;
    UA_UInt32 enableCount;
    UA_UInt32 disableCount;
    UA_UInt32 republishRequestCount;
    UA_UInt32 republishMessageCount;
    UA_UInt32 transferRequestCount;
    UA_UInt32 transferredToAltClientCount;
    UA_UInt32 transferredToSameClientCount;
    UA_UInt32 publishRequestCount;
    UA_UInt32 dataChangeNotificationsCount;
    UA_UInt32 eventNotificationsCount;
    UA_UInt32 notificationsCount;
    UA_UInt32 latePublishRequestCount;
    UA_UInt32 discardedMessageCount;
    UA_UInt32 monitoringQueueOverflowCount;
    UA_UInt32 eventQueueOverFlowCount;
#endif
};

UA_Subscription * UA_Subscription_new(void);

void
UA_Subscription_delete(UA_Server *server, UA_Subscription *sub);

UA_StatusCode
Subscription_setState(UA_Server *server, UA_Subscription *sub,
                      UA_SubscriptionState state);

void
Subscription_resetLifetime(UA_Subscription *sub);

UA_MonitoredItem *
UA_Subscription_getMonitoredItem(UA_Subscription *sub,
                                 UA_UInt32 monitoredItemId);

void
UA_Subscription_publish(UA_Server *server, UA_Subscription *sub);

void
UA_Subscription_localPublish(UA_Server *server, UA_Subscription *sub);

void
UA_Subscription_resendData(UA_Server *server, UA_Subscription *sub);

UA_StatusCode
UA_Subscription_removeRetransmissionMessage(UA_Subscription *sub,
                                            UA_UInt32 sequenceNumber);

void
UA_Session_ensurePublishQueueSpace(UA_Server *server, UA_Session *session);

/* Forward declaration for A&C used in ua_server_internal.h" */
struct UA_ConditionSource;
typedef struct UA_ConditionSource UA_ConditionSource;

/* Event Handling */
#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS

#define UA_EVENTFILTER_MAXELEMENTS 64 /* Max operator elements */
#define UA_EVENTFILTER_MAXOPERANDS 64 /* Max operands per operator */
#define UA_EVENTFILTER_MAXSELECT   64 /* Max select clauses */

UA_StatusCode
UA_MonitoredItem_addEvent(UA_Server *server, UA_MonitoredItem *mon,
                          const UA_NodeId *event);

UA_StatusCode
generateEventId(UA_ByteString *generatedId);

/* Static validation when the filter is registered */
UA_StatusCode
UA_SimpleAttributeOperandValidation(UA_Server *server,
                                    const UA_SimpleAttributeOperand *sao);

/* Static validation when the filter is registered */
UA_ContentFilterElementResult
UA_ContentFilterElementValidation(UA_Server *server, size_t operatorIndex,
                                  size_t operatorsCount,
                                  const UA_ContentFilterElement *ef);

/* Evaluate content filter, exported only for unit testing */
UA_StatusCode
evaluateWhereClause(UA_Server *server, UA_Session *session, const UA_NodeId *eventNode,
                    const UA_ContentFilter *contentFilter,
                    UA_ContentFilterResult *contentFilterResult);

#endif

/***********/
/* Helpers */
/***********/

/* Setting an integer value within bounds */
#define UA_BOUNDEDVALUE_SETWBOUNDS(BOUNDS, SRC, DST) { \
        if(SRC > BOUNDS.max) DST = BOUNDS.max;         \
        else if(SRC < BOUNDS.min) DST = BOUNDS.min;    \
        else DST = SRC;                                \
    }

/* Logging
 * See a description of the tricks used in ua_session.h */
#define UA_LOG_SUBSCRIPTION_INTERNAL(LOGGER, LEVEL, SUB, MSG, ...)      \
    do {                                                                \
        if((SUB) && (SUB)->session) {                                   \
            UA_LOG_##LEVEL##_SESSION(LOGGER, (SUB)->session,            \
                                     "Subscription %" PRIu32 " | " MSG "%.0s", \
                                     (SUB)->subscriptionId, __VA_ARGS__); \
        } else {                                                        \
            UA_LOG_##LEVEL(LOGGER, UA_LOGCATEGORY_SERVER,               \
                           "Subscription %" PRIu32 " | " MSG "%.0s",    \
                           (SUB) ? (SUB)->subscriptionId : 0, __VA_ARGS__); \
        }                                                               \
    } while(0)

#if UA_LOGLEVEL <= 100
# define UA_LOG_TRACE_SUBSCRIPTION(LOGGER, SUB, ...)                     \
    UA_MACRO_EXPAND(UA_LOG_SUBSCRIPTION_INTERNAL(LOGGER, TRACE, SUB, __VA_ARGS__, ""))
#else
# define UA_LOG_TRACE_SUBSCRIPTION(LOGGER, SUB, ...) do {} while(0)
#endif

#if UA_LOGLEVEL <= 200
# define UA_LOG_DEBUG_SUBSCRIPTION(LOGGER, SUB, ...)                     \
    UA_MACRO_EXPAND(UA_LOG_SUBSCRIPTION_INTERNAL(LOGGER, DEBUG, SUB, __VA_ARGS__, ""))
#else
# define UA_LOG_DEBUG_SUBSCRIPTION(LOGGER, SUB, ...) do {} while(0)
#endif

#if UA_LOGLEVEL <= 300
# define UA_LOG_INFO_SUBSCRIPTION(LOGGER, SUB, ...)                     \
    UA_MACRO_EXPAND(UA_LOG_SUBSCRIPTION_INTERNAL(LOGGER, INFO, SUB, __VA_ARGS__, ""))
#else
# define UA_LOG_INFO_SUBSCRIPTION(LOGGER, SUB, ...) do {} while(0)
#endif

#if UA_LOGLEVEL <= 400
# define UA_LOG_WARNING_SUBSCRIPTION(LOGGER, SUB, ...)                     \
    UA_MACRO_EXPAND(UA_LOG_SUBSCRIPTION_INTERNAL(LOGGER, WARNING, SUB, __VA_ARGS__, ""))
#else
# define UA_LOG_WARNING_SUBSCRIPTION(LOGGER, SUB, ...) do {} while(0)
#endif

#if UA_LOGLEVEL <= 500
# define UA_LOG_ERROR_SUBSCRIPTION(LOGGER, SUB, ...)                     \
    UA_MACRO_EXPAND(UA_LOG_SUBSCRIPTION_INTERNAL(LOGGER, ERROR, SUB, __VA_ARGS__, ""))
#else
# define UA_LOG_ERROR_SUBSCRIPTION(LOGGER, SUB, ...) do {} while(0)
#endif

#if UA_LOGLEVEL <= 600
# define UA_LOG_FATAL_SUBSCRIPTION(LOGGER, SUB, ...)                     \
    UA_MACRO_EXPAND(UA_LOG_SUBSCRIPTION_INTERNAL(LOGGER, FATAL, SUB, __VA_ARGS__, ""))
#else
# define UA_LOG_FATAL_SUBSCRIPTION(LOGGER, SUB, ...) do {} while(0)
#endif

#endif /* UA_ENABLE_SUBSCRIPTIONS */

_UA_END_DECLS


/**** amalgamated original file "/src/pubsub/ua_pubsub_networkmessage.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2017 - 2018 Fraunhofer IOSB (Author: Tino Bischoff)
 * Copyright (c) 2017-2019 Fraunhofer IOSB (Author: Andreas Ebner)
 */



#ifdef UA_ENABLE_PUBSUB

_UA_BEGIN_DECLS

#define UA_NETWORKMESSAGE_MAX_NONCE_LENGTH 16

/* DataSet Payload Header */
typedef struct {
    UA_Byte count;
    UA_UInt16* dataSetWriterIds;
} UA_DataSetPayloadHeader;

/* FieldEncoding Enum  */
typedef enum {
    UA_FIELDENCODING_VARIANT = 0,
    UA_FIELDENCODING_RAWDATA = 1,
    UA_FIELDENCODING_DATAVALUE = 2,
    UA_FIELDENCODING_UNKNOWN = 3
} UA_FieldEncoding;

/* DataSetMessage Type */
typedef enum {
    UA_DATASETMESSAGE_DATAKEYFRAME = 0,
    UA_DATASETMESSAGE_DATADELTAFRAME = 1,
    UA_DATASETMESSAGE_EVENT = 2,
    UA_DATASETMESSAGE_KEEPALIVE = 3
} UA_DataSetMessageType;

/* DataSetMessage Header */
typedef struct {
    UA_Boolean dataSetMessageValid;
    UA_FieldEncoding fieldEncoding;
    UA_Boolean dataSetMessageSequenceNrEnabled;
    UA_Boolean timestampEnabled;
    UA_Boolean statusEnabled;
    UA_Boolean configVersionMajorVersionEnabled;
    UA_Boolean configVersionMinorVersionEnabled;
    UA_DataSetMessageType dataSetMessageType;
    UA_Boolean picoSecondsIncluded;
    UA_UInt16 dataSetMessageSequenceNr;
    UA_UtcTime timestamp;
    UA_UInt16 picoSeconds;
    UA_UInt16 status;
    UA_UInt32 configVersionMajorVersion;
    UA_UInt32 configVersionMinorVersion;
} UA_DataSetMessageHeader;

/**
 * DataSetMessage
 * ^^^^^^^^^^^^^^ */

typedef struct {
    UA_UInt16 fieldCount;
    UA_DataValue* dataSetFields;
    UA_ByteString rawFields;
    /* Json keys for the dataSetFields: TODO: own dataSetMessageType for json? */
    UA_String* fieldNames;
    /* This information is for proper en- and decoding needed */
    UA_DataSetMetaDataType *dataSetMetaDataType;
} UA_DataSetMessage_DataKeyFrameData;

typedef struct {
    UA_UInt16 fieldIndex;
    UA_DataValue fieldValue;
} UA_DataSetMessage_DeltaFrameField;

typedef struct {
    UA_UInt16 fieldCount;
    UA_DataSetMessage_DeltaFrameField* deltaFrameFields;
} UA_DataSetMessage_DataDeltaFrameData;

typedef struct {
    UA_DataSetMessageHeader header;
    union {
        UA_DataSetMessage_DataKeyFrameData keyFrameData;
        UA_DataSetMessage_DataDeltaFrameData deltaFrameData;
    } data;
    size_t configuredSize;
} UA_DataSetMessage;

typedef struct {
    UA_UInt16* sizes;
    UA_DataSetMessage* dataSetMessages;
} UA_DataSetPayload;

typedef enum {
    UA_NETWORKMESSAGE_DATASET = 0,
    UA_NETWORKMESSAGE_DISCOVERY_REQUEST = 1,
    UA_NETWORKMESSAGE_DISCOVERY_RESPONSE = 2
} UA_NetworkMessageType;

/**
 * UA_NetworkMessageGroupHeader
 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
typedef struct {
    UA_Boolean writerGroupIdEnabled;
    UA_Boolean groupVersionEnabled;
    UA_Boolean networkMessageNumberEnabled;
    UA_Boolean sequenceNumberEnabled;
    UA_UInt16 writerGroupId;
    UA_UInt32 groupVersion; // spec: type "VersionTime"
    UA_UInt16 networkMessageNumber;
    UA_UInt16 sequenceNumber;
} UA_NetworkMessageGroupHeader;

/**
 * UA_NetworkMessageSecurityHeader
 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */
typedef struct {
    UA_Boolean networkMessageSigned;
    UA_Boolean networkMessageEncrypted;
    UA_Boolean securityFooterEnabled;
    UA_Boolean forceKeyReset;
    UA_UInt32 securityTokenId;      // spec: IntegerId
    UA_Byte messageNonce[UA_NETWORKMESSAGE_MAX_NONCE_LENGTH];
    UA_UInt16 messageNonceSize;
    UA_UInt16 securityFooterSize;
} UA_NetworkMessageSecurityHeader;

/**
 * UA_NetworkMessage
 * ^^^^^^^^^^^^^^^^^ */
typedef struct {
    UA_Byte version;
    UA_Boolean messageIdEnabled;
    UA_String messageId; /* For Json NetworkMessage */
    UA_Boolean publisherIdEnabled;
    UA_Boolean groupHeaderEnabled;
    UA_Boolean payloadHeaderEnabled;
    UA_Boolean dataSetClassIdEnabled;
    UA_Boolean securityEnabled;
    UA_Boolean timestampEnabled;
    UA_Boolean picosecondsEnabled;
    UA_Boolean chunkMessage;
    UA_Boolean promotedFieldsEnabled;
    UA_NetworkMessageType networkMessageType;
    UA_PublisherIdType publisherIdType;
    UA_PublisherId publisherId;
    UA_Guid dataSetClassId;

    UA_NetworkMessageGroupHeader groupHeader;

    union {
        UA_DataSetPayloadHeader dataSetPayloadHeader;
    } payloadHeader;

    UA_DateTime timestamp;
    UA_UInt16 picoseconds;
    UA_UInt16 promotedFieldsSize;
    UA_Variant* promotedFields; /* BaseDataType */

    UA_NetworkMessageSecurityHeader securityHeader;

    union {
        UA_DataSetPayload dataSetPayload;
    } payload;

    UA_ByteString securityFooter;
} UA_NetworkMessage;

/**********************************************/
/*          Network Message Offsets           */
/**********************************************/

/* Offsets for buffered messages in the PubSub fast path. */
typedef enum {
    UA_PUBSUB_OFFSETTYPE_DATASETMESSAGE_SEQUENCENUMBER,
    UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_SEQUENCENUMBER,
    UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_FIELDENCDODING,
    UA_PUBSUB_OFFSETTYPE_TIMESTAMP_PICOSECONDS,
    UA_PUBSUB_OFFSETTYPE_TIMESTAMP,     /* source pointer */
    UA_PUBSUB_OFFSETTYPE_TIMESTAMP_NOW, /* no source */
    UA_PUBSUB_OFFSETTYPE_PAYLOAD_DATAVALUE,
    UA_PUBSUB_OFFSETTYPE_PAYLOAD_VARIANT,
    UA_PUBSUB_OFFSETTYPE_PAYLOAD_RAW,
    /* For subscriber RT */
    UA_PUBSUB_OFFSETTYPE_PUBLISHERID,
    UA_PUBSUB_OFFSETTYPE_WRITERGROUPID,
    UA_PUBSUB_OFFSETTYPE_DATASETWRITERID
    /* Add more offset types as needed */
} UA_NetworkMessageOffsetType;

typedef struct {
    UA_NetworkMessageOffsetType contentType;
    union {
        UA_UInt16 sequenceNumber;
        UA_DataValue value;
    } content;
    size_t offset;
} UA_NetworkMessageOffset;

typedef struct {
    UA_ByteString buffer; /* The precomputed message buffer */
    UA_NetworkMessageOffset *offsets; /* Offsets for changes in the message buffer */
    size_t offsetsSize;
    UA_NetworkMessage *nm; /* The precomputed NetworkMessage for subscriber */
    size_t rawMessageLength;
#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
    UA_ByteString encryptBuffer; /* The precomputed message buffer is copied
                                  * into the encrypt buffer for encryption and
                                  * signing*/
    UA_Byte *payloadPosition; /* Payload Position of the message to encrypt*/
#endif
} UA_NetworkMessageOffsetBuffer;

void
UA_NetworkMessageOffsetBuffer_clear(UA_NetworkMessageOffsetBuffer *nmob);

UA_StatusCode
UA_NetworkMessage_updateBufferedMessage(UA_NetworkMessageOffsetBuffer *buffer);

UA_StatusCode
UA_NetworkMessage_updateBufferedNwMessage(UA_NetworkMessageOffsetBuffer *buffer,
                                          const UA_ByteString *src, size_t *bufferPosition);

/**
 * DataSetMessage
 * ^^^^^^^^^^^^^^ */

UA_StatusCode
UA_DataSetMessageHeader_encodeBinary(const UA_DataSetMessageHeader* src,
                                     UA_Byte **bufPos, const UA_Byte *bufEnd);

UA_StatusCode
UA_DataSetMessageHeader_decodeBinary(const UA_ByteString *src, size_t *offset,
                                     UA_DataSetMessageHeader* dst);

UA_StatusCode
UA_DataSetMessage_encodeBinary(const UA_DataSetMessage* src, UA_Byte **bufPos,
                               const UA_Byte *bufEnd);

UA_StatusCode
UA_DataSetMessage_decodeBinary(const UA_ByteString *src, size_t *offset,
                               UA_DataSetMessage* dst, UA_UInt16 dsmSize,
                               const UA_DataTypeArray *customTypes,
                               UA_DataSetMetaDataType *dsm);

size_t
UA_DataSetMessage_calcSizeBinary(UA_DataSetMessage *p,
                                 UA_NetworkMessageOffsetBuffer *offsetBuffer,
                                 size_t currentOffset);

void UA_DataSetMessage_clear(UA_DataSetMessage* p);

/**
 * NetworkMessage Encoding
 * ^^^^^^^^^^^^^^^^^^^^^^^ */

/* If dataToEncryptStart not-NULL, then it will be set to the start-position of
 * the payload in the buffer. */
UA_StatusCode
UA_NetworkMessage_encodeBinary(const UA_NetworkMessage* src,
                               UA_Byte **bufPos, const UA_Byte *bufEnd,
                               UA_Byte **dataToEncryptStart);

UA_StatusCode
UA_NetworkMessage_encodeHeaders(const UA_NetworkMessage* src,
                               UA_Byte **bufPos, const UA_Byte *bufEnd);

UA_StatusCode
UA_NetworkMessage_encodePayload(const UA_NetworkMessage* src,
                               UA_Byte **bufPos, const UA_Byte *bufEnd);

UA_StatusCode
UA_NetworkMessage_encodeFooters(const UA_NetworkMessage* src,
                               UA_Byte **bufPos, const UA_Byte *bufEnd);

/**
 * NetworkMessage Decoding
 * ^^^^^^^^^^^^^^^^^^^^^^^ */

UA_StatusCode
UA_NetworkMessage_decodeHeaders(const UA_ByteString *src, size_t *offset,
                                UA_NetworkMessage *dst);

UA_StatusCode
UA_NetworkMessage_decodePayload(const UA_ByteString *src, size_t *offset,
                                UA_NetworkMessage *dst, const UA_DataTypeArray *customTypes,
                                UA_DataSetMetaDataType *dsm);

UA_StatusCode
UA_NetworkMessage_decodeFooters(const UA_ByteString *src, size_t *offset,
                                UA_NetworkMessage *dst);

UA_StatusCode
UA_NetworkMessage_decodeBinary(const UA_ByteString *src, size_t *offset,
                               UA_NetworkMessage* dst, const UA_DataTypeArray *customTypes);
                               
UA_StatusCode
UA_NetworkMessageHeader_decodeBinary(const UA_ByteString *src, size_t *offset,
                                     UA_NetworkMessage *dst);

/* Also stores the offset if offsetBuffer != NULL */
size_t
UA_NetworkMessage_calcSizeBinary(UA_NetworkMessage *p,
                                 UA_NetworkMessageOffsetBuffer *offsetBuffer);

#ifdef UA_ENABLE_PUBSUB_ENCRYPTION

UA_StatusCode
UA_NetworkMessage_signEncrypt(UA_NetworkMessage *nm, UA_MessageSecurityMode securityMode,
                              UA_PubSubSecurityPolicy *policy, void *policyContext,
                              UA_Byte *messageStart, UA_Byte *encryptStart,
                              UA_Byte *sigStart);
#endif

void
UA_NetworkMessage_clear(UA_NetworkMessage* p);

#ifdef UA_ENABLE_JSON_ENCODING
UA_StatusCode
UA_NetworkMessage_encodeJson(const UA_NetworkMessage *src,
                             UA_Byte **bufPos, const UA_Byte **bufEnd, UA_String *namespaces,
                             size_t namespaceSize, UA_String *serverUris,
                             size_t serverUriSize, UA_Boolean useReversible);

size_t
UA_NetworkMessage_calcSizeJson(const UA_NetworkMessage *src,
                               UA_String *namespaces, size_t namespaceSize,
                               UA_String *serverUris, size_t serverUriSize,
                               UA_Boolean useReversible);

UA_StatusCode UA_NetworkMessage_decodeJson(UA_NetworkMessage *dst, const UA_ByteString *src);
#endif

_UA_END_DECLS

#endif /* UA_ENABLE_PUBSUB */


/**** amalgamated original file "/src/pubsub/ua_pubsub.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2017-2019 Fraunhofer IOSB (Author: Andreas Ebner)
 * Copyright (c) 2019 Kalycito Infotech Private Limited
 * Copyright (c) 2020 Yannick Wallerer, Siemens AG
 * Copyright (c) 2020, 2022 Thomas Fischer, Siemens AG
 * Copyright (c) 2021 Fraunhofer IOSB (Author: Jan Hermes)
 * Copyright (c) 2022 Siemens AG (Author: Thomas Fischer)
 * Copyright (c) 2022 Fraunhofer IOSB (Author: Noel Graf)
 * Copyright (c) 2022 Linutronix GmbH (Author: Muddasir Shakil)
 */


#define UA_INTERNAL


#ifdef UA_ENABLE_PUBSUB_SKS
#include <ua_pubsub_keystorage.h>
#endif

/**
 * PubSub State Machine
 * --------------------
 * 
 * The following table described the behaviour of components expected during
 * state changes and also the integration which is expected between the
 * components.
 *
 * We distinguish between `enabled` and `disabled` states. The disabled states
 * or `Disabled` and `Error`. The difference is that disabled states need to
 * manually enabled (via the _enable method call). The other states are either
 * Operational or return automatically to the Operational state once the
 * prerequisites are met.
 * 
 * +----------------+-------+--------------------+----------------+--------------------+----------------+----------------+
 * |**Component**   |       |**Disabled**        |**Paused**      |**Pre-Operational** |**Operational** |**Error**       |
 * +----------------+-------+--------------------+----------------+--------------------+----------------+----------------+
 * |PubSubConnection|Trigger|Manual disable      |Not available   |Manual enable ||    |Pre-Operational |Unrecoverable   |
 * |                |       |                    |                |Recoverable abort of|&& Connected    |abort of the    |
 * |                |       |                    |                |EventLoop connection|EventLoop       |EventLoop       |
 * |                |       |                    |                |                    |connection      |connection ||   |
 * |                |       |                    |                |                    |                |Internal Error  |
 * |                +-------+--------------------+----------------+--------------------+----------------+----------------+
 * |                |Action |The underlying      |                |Start the async     |                |Same as the     |
 * |                |       |connection is closed|                |opening of the      |                |Disabled case   |
 * |                |       |(async). Immediately|                |underlying EventLoop|                |                |
 * |                |       |set the EventLoop   |                |connection.         |                |                |
 * |                |       |connection context  |                |Automatically switch|                |                |
 * |                |       |pointer to NULL. So |                |to operational when |                |                |
 * |                |       |that the            |                |the EventLoop       |                |                |
 * |                |       |PubSubConnection can|                |connection is fully |                |                |
 * |                |       |be freed without    |                |open. This can only |                |                |
 * |                |       |waiting for the     |                |be signaled by the  |                |                |
 * |                |       |EventLoop connection|                |underlying EventLoop|                |                |
 * |                |       |to finish closing.  |                |connection in the   |                |                |
 * +----------------+-------+--------------------+----------------+--------------------+----------------+----------------+
 * |WriterGroup     |Trigger|Manual disable      |WG is enabled &&|WG is enabled &&    |WG is enabled &&|Internal error  |
 * |                |       |                    |PubSubConnection|PubSubConnection    |PubSubConnection|                |
 * |                |       |                    |not enabled     |Pre-Operational     |Operational     |                |
 * |                +-------+--------------------+----------------+--------------------+----------------+----------------+
 * |                |Action |Publish callback    |Publish callback|Publish callback    |Publish callback|Publish callback|
 * |                |       |deregistered        |deregistered    |deregistered        |registered      |deregistered    |
 * +----------------+-------+--------------------+----------------+--------------------+----------------+----------------+
 * |DataSetWriter   |Trigger|Manual disable      |DSW enabled &&  |DSW enabled && WG   |DSW enabled &&  |Internal error  |
 * |                |       |                    |WG is not       |Pre-Operational     |WG is           |                |
 * |                |       |                    |enabled         |                    |Operational     |                |
 * +----------------+-------+--------------------+----------------+--------------------+----------------+----------------+
 * |ReaderGroup     |Trigger|Manual disable      |RG enabled &&   |RG enabled &&       |RG enabled &&   |Internal error  |
 * |                |       |                    |PubSubConnection|(PubSubConnection   |PubSubConnection|                |
 * |                |       |                    |not enabled     |Pre-Operational ||  |Operational &&  |                |
 * |                |       |                    |                |RG-connection not   |RG-connection   |                |
 * |                |       |                    |                |fully established)  |established     |                |
 * |                +-------+--------------------+----------------+--------------------+----------------+----------------+
 * |                |Action |RG connection       |RG connection   |RG connection       |RG connection   |RG connection   |
 * |                |       |disconnected        |disconnected    |connected           |connected       |disconnected    |
 * +----------------+-------+--------------------+----------------+--------------------+----------------+----------------+
 * |DataSetReader   |Trigger|Manual disable      |DSR enabled &&  |DSR enabled && RG   |DSR enabled &&  |Internal error  |
 * |                |       |                    |RG not enabled  |Pre-Operational     |RG Operational  |                |
 * +----------------+-------+--------------------+----------------+--------------------+----------------+----------------+
 */

_UA_BEGIN_DECLS

#ifdef UA_ENABLE_PUBSUB

/* Max number of underlying for sending and receiving */
#define UA_PUBSUB_MAXCHANNELS 8

struct UA_WriterGroup;
typedef struct UA_WriterGroup UA_WriterGroup;

struct UA_ReaderGroup;
typedef struct UA_ReaderGroup UA_ReaderGroup;

struct UA_SecurityGroup;
typedef struct UA_SecurityGroup UA_SecurityGroup;

const char *
UA_PubSubState_name(UA_PubSubState state);

/**********************************************/
/*            PublishedDataSet                */
/**********************************************/

typedef struct UA_PublishedDataSet {
    TAILQ_ENTRY(UA_PublishedDataSet) listEntry;
    TAILQ_HEAD(, UA_DataSetField) fields;
    UA_NodeId identifier;
    UA_String logIdString;
    UA_PublishedDataSetConfig config;
    UA_DataSetMetaDataType dataSetMetaData;
    UA_UInt16 fieldSize;
    UA_UInt16 promotedFieldsCount;
    UA_UInt16 configurationFreezeCounter;
} UA_PublishedDataSet;

UA_StatusCode
UA_PublishedDataSetConfig_copy(const UA_PublishedDataSetConfig *src,
                               UA_PublishedDataSetConfig *dst);

UA_PublishedDataSet *
UA_PublishedDataSet_findPDSbyId(UA_Server *server, UA_NodeId identifier);

UA_PublishedDataSet *
UA_PublishedDataSet_findPDSbyName(UA_Server *server, UA_String name);

UA_AddPublishedDataSetResult
UA_PublishedDataSet_create(UA_Server *server,
                           const UA_PublishedDataSetConfig *publishedDataSetConfig,
                           UA_NodeId *pdsIdentifier);

void
UA_PublishedDataSet_clear(UA_Server *server,
                          UA_PublishedDataSet *publishedDataSet);

UA_StatusCode
UA_PublishedDataSet_remove(UA_Server *server, UA_PublishedDataSet *publishedDataSet);

UA_StatusCode
getPublishedDataSetConfig(UA_Server *server, const UA_NodeId pds,
                          UA_PublishedDataSetConfig *config);

typedef struct UA_StandaloneSubscribedDataSet{
    UA_StandaloneSubscribedDataSetConfig config;
    UA_NodeId identifier;
    TAILQ_ENTRY(UA_StandaloneSubscribedDataSet) listEntry;
    UA_NodeId connectedReader;
} UA_StandaloneSubscribedDataSet;

UA_StatusCode
UA_StandaloneSubscribedDataSetConfig_copy(const UA_StandaloneSubscribedDataSetConfig *src,
                                          UA_StandaloneSubscribedDataSetConfig *dst);
UA_StandaloneSubscribedDataSet *
UA_StandaloneSubscribedDataSet_findSDSbyId(UA_Server *server, UA_NodeId identifier);
UA_StandaloneSubscribedDataSet *
UA_StandaloneSubscribedDataSet_findSDSbyName(UA_Server *server, UA_String identifier);
void
UA_StandaloneSubscribedDataSet_clear(UA_Server *server,
                                     UA_StandaloneSubscribedDataSet *subscribedDataSet);

#define UA_LOG_DATASET_INTERNAL(LOGGER, LEVEL, PDS, MSG, ...)           \
    if(UA_LOGLEVEL <= UA_LOGLEVEL_##LEVEL) {                            \
        UA_LOG_##LEVEL(LOGGER, UA_LOGCATEGORY_PUBSUB, "%.*s" MSG "%.0s", \
                       (int)(PDS)->logIdString.length,                  \
                       (char*)(PDS)->logIdString.data, __VA_ARGS__);    \
    }

#define UA_LOG_TRACE_DATASET(LOGGER, PDS, ...)                          \
    UA_MACRO_EXPAND(UA_LOG_DATASET_INTERNAL(LOGGER, TRACE, PDS, __VA_ARGS__, ""))
#define UA_LOG_DEBUG_DATASET(LOGGER, PDS, ...)                          \
    UA_MACRO_EXPAND(UA_LOG_DATASET_INTERNAL(LOGGER, DEBUG, PDS, __VA_ARGS__, ""))
#define UA_LOG_INFO_DATASET(LOGGER, PDS, ...)                           \
    UA_MACRO_EXPAND(UA_LOG_DATASET_INTERNAL(LOGGER, INFO, PDS, __VA_ARGS__, ""))
#define UA_LOG_WARNING_DATASET(LOGGER, PDS, ...)                        \
    UA_MACRO_EXPAND(UA_LOG_DATASET_INTERNAL(LOGGER, WARNING, PDS, __VA_ARGS__, ""))
#define UA_LOG_ERROR_DATASET(LOGGER, PDS, ...)                          \
    UA_MACRO_EXPAND(UA_LOG_DATASET_INTERNAL(LOGGER, ERROR, PDS, __VA_ARGS__, ""))
#define UA_LOG_FATAL_DATASET(LOGGER, PDS, ...)                          \
    UA_MACRO_EXPAND(UA_LOG_DATASET_INTERNAL(LOGGER, FATAL, PDS, __VA_ARGS__, ""))

/**********************************************/
/*               Connection                   */
/**********************************************/

typedef struct UA_PubSubConnection {
    UA_PubSubComponentEnumType componentType;

    TAILQ_ENTRY(UA_PubSubConnection) listEntry;
    UA_NodeId identifier;
    UA_String logIdString;

    /* The send/recv connections are only opened if the state is operational */
    UA_PubSubState state;
    UA_PubSubConnectionConfig config;
    UA_Boolean json; /* Extracted from the TransportProfileUrl */

    /* Channels belonging to the PubSubConnection. Send channels belong to
     * WriterGroups, recv channels belong to ReaderGroups. We only open channels 
     * if there is at least one WriterGroup/ReaderGroup respectively.
     *
     * Some channels belong exclusively to just one WriterGroup/ReaderGroup that
     * defines additional connection properties. For example an MQTT topic name
     * or QoS parameters. In that case a dedicated NetworkCallback is used that
     * takes this ReaderGroup/WriterGroup directly as context. */
    UA_ConnectionManager *cm;
    uintptr_t recvChannels[UA_PUBSUB_MAXCHANNELS];
    size_t recvChannelsSize;
    uintptr_t sendChannel;

    size_t writerGroupsSize;
    LIST_HEAD(, UA_WriterGroup) writerGroups;

    size_t readerGroupsSize;
    LIST_HEAD(, UA_ReaderGroup) readerGroups;

    UA_UInt16 configurationFreezeCounter;

    UA_Boolean deleteFlag; /* To be deleted - in addition to the PubSubState */
    UA_DelayedCallback dc; /* For delayed freeing */
} UA_PubSubConnection;

UA_StatusCode
UA_PubSubConnectionConfig_copy(const UA_PubSubConnectionConfig *src,
                               UA_PubSubConnectionConfig *dst);

UA_PubSubConnection *
UA_PubSubConnection_findConnectionbyId(UA_Server *server,
                                       UA_NodeId connectionIdentifier);

UA_StatusCode
UA_PubSubConnection_create(UA_Server *server,
                           const UA_PubSubConnectionConfig *connectionConfig,
                           UA_NodeId *connectionIdentifier);

void
UA_PubSubConnectionConfig_clear(UA_PubSubConnectionConfig *connectionConfig);

void
UA_PubSubConnection_delete(UA_Server *server, UA_PubSubConnection *c);

UA_StatusCode
UA_PubSubConnection_connect(UA_Server *server, UA_PubSubConnection *c,
                            UA_Boolean validate);

void
UA_PubSubConnection_process(UA_Server *server, UA_PubSubConnection *c,
                            UA_ByteString msg);


void
UA_PubSubConnection_disconnect(UA_PubSubConnection *c);

/* Returns either the eventloop configured in the connection or, in its absence,
 * for the server */
UA_EventLoop *
UA_PubSubConnection_getEL(UA_Server *server, UA_PubSubConnection *c);

UA_StatusCode
UA_PubSubConnection_setPubSubState(UA_Server *server,
                                   UA_PubSubConnection *connection,
                                   UA_PubSubState targetState);

#define UA_LOG_CONNECTION_INTERNAL(LOGGER, LEVEL, CONNECTION, MSG, ...) \
    if(UA_LOGLEVEL <= UA_LOGLEVEL_##LEVEL) {                            \
        UA_LOG_##LEVEL(LOGGER, UA_LOGCATEGORY_PUBSUB, "%.*s" MSG "%.0s", \
                       (int)(CONNECTION)->logIdString.length,           \
                       (char*)(CONNECTION)->logIdString.data, __VA_ARGS__); \
    }

#define UA_LOG_TRACE_CONNECTION(LOGGER, CONNECTION, ...)                \
    UA_MACRO_EXPAND(UA_LOG_CONNECTION_INTERNAL(LOGGER, TRACE, CONNECTION, __VA_ARGS__, ""))
#define UA_LOG_DEBUG_CONNECTION(LOGGER, CONNECTION, ...)                \
    UA_MACRO_EXPAND(UA_LOG_CONNECTION_INTERNAL(LOGGER, DEBUG, CONNECTION, __VA_ARGS__, ""))
#define UA_LOG_INFO_CONNECTION(LOGGER, CONNECTION, ...)                 \
    UA_MACRO_EXPAND(UA_LOG_CONNECTION_INTERNAL(LOGGER, INFO, CONNECTION, __VA_ARGS__, ""))
#define UA_LOG_WARNING_CONNECTION(LOGGER, CONNECTION, ...)              \
    UA_MACRO_EXPAND(UA_LOG_CONNECTION_INTERNAL(LOGGER, WARNING, CONNECTION, __VA_ARGS__, ""))
#define UA_LOG_ERROR_CONNECTION(LOGGER, CONNECTION, ...)                \
    UA_MACRO_EXPAND(UA_LOG_CONNECTION_INTERNAL(LOGGER, ERROR, CONNECTION, __VA_ARGS__, ""))
#define UA_LOG_FATAL_CONNECTION(LOGGER, CONNECTION, ...)                \
    UA_MACRO_EXPAND(UA_LOG_CONNECTION_INTERNAL(LOGGER, FATAL, CONNECTION, __VA_ARGS__, ""))

/**********************************************/
/*              DataSetWriter                 */
/**********************************************/

typedef struct UA_DataSetWriterSample {
    UA_Boolean valueChanged;
    UA_DataValue value;
} UA_DataSetWriterSample;

typedef struct UA_DataSetWriter {
    UA_PubSubComponentEnumType componentType;
    UA_DataSetWriterConfig config;
    LIST_ENTRY(UA_DataSetWriter) listEntry;
    UA_NodeId identifier;
    UA_String logIdString;
    UA_WriterGroup *linkedWriterGroup;
    UA_NodeId connectedDataSet;
    UA_ConfigurationVersionDataType connectedDataSetVersion;
    UA_PubSubState state;

    /* Deltaframes */
    UA_UInt16 deltaFrameCounter; /* count of sent deltaFrames */
    size_t lastSamplesCount;
    UA_DataSetWriterSample *lastSamples;

    UA_UInt16 actualDataSetMessageSequenceCount;
    UA_Boolean configurationFrozen;
    UA_UInt64  pubSubStateTimerId;
} UA_DataSetWriter;

UA_StatusCode
UA_DataSetWriterConfig_copy(const UA_DataSetWriterConfig *src,
                            UA_DataSetWriterConfig *dst);

UA_DataSetWriter *
UA_DataSetWriter_findDSWbyId(UA_Server *server, UA_NodeId identifier);

UA_StatusCode
UA_DataSetWriter_setPubSubState(UA_Server *server,
                                UA_DataSetWriter *dataSetWriter,
                                UA_PubSubState targetState);

UA_StatusCode
UA_DataSetWriter_generateDataSetMessage(UA_Server *server,
                                        UA_DataSetMessage *dataSetMessage,
                                        UA_DataSetWriter *dataSetWriter);

UA_StatusCode
UA_DataSetWriter_prepareDataSet(UA_Server *server, UA_DataSetWriter *dsw,
                                UA_DataSetMessage *dsm);

void
UA_DataSetWriter_freezeConfiguration(UA_Server *server, UA_DataSetWriter *dsw);

void
UA_DataSetWriter_unfreezeConfiguration(UA_Server *server, UA_DataSetWriter *dsw);

UA_StatusCode
UA_DataSetWriter_create(UA_Server *server,
                        const UA_NodeId writerGroup, const UA_NodeId dataSet,
                        const UA_DataSetWriterConfig *dataSetWriterConfig,
                        UA_NodeId *writerIdentifier);


UA_StatusCode
UA_DataSetWriter_remove(UA_Server *server, UA_DataSetWriter *dataSetWriter);

#define UA_LOG_WRITER_INTERNAL(LOGGER, LEVEL, WRITER, MSG, ...)         \
    if(UA_LOGLEVEL <= UA_LOGLEVEL_##LEVEL) {                            \
        UA_LOG_##LEVEL(LOGGER, UA_LOGCATEGORY_PUBSUB, "%.*s" MSG "%.0s", \
                       (int)(WRITER)->logIdString.length,               \
                       (char*)(WRITER)->logIdString.data,               \
                       __VA_ARGS__);                                    \
    }

#define UA_LOG_TRACE_WRITER(LOGGER, WRITER, ...)                        \
    UA_MACRO_EXPAND(UA_LOG_WRITER_INTERNAL(LOGGER, TRACE, WRITER, __VA_ARGS__, ""))
#define UA_LOG_DEBUG_WRITER(LOGGER, WRITER, ...)                        \
    UA_MACRO_EXPAND(UA_LOG_WRITER_INTERNAL(LOGGER, DEBUG, WRITER, __VA_ARGS__, ""))
#define UA_LOG_INFO_WRITER(LOGGER, WRITER, ...)                         \
    UA_MACRO_EXPAND(UA_LOG_WRITER_INTERNAL(LOGGER, INFO, WRITER, __VA_ARGS__, ""))
#define UA_LOG_WARNING_WRITER(LOGGER, WRITER, ...)                      \
    UA_MACRO_EXPAND(UA_LOG_WRITER_INTERNAL(LOGGER, WARNING, WRITER, __VA_ARGS__, ""))
#define UA_LOG_ERROR_WRITER(LOGGER, WRITER, ...)                        \
    UA_MACRO_EXPAND(UA_LOG_WRITER_INTERNAL(LOGGER, ERROR, WRITER, __VA_ARGS__, ""))
#define UA_LOG_FATAL_WRITER(LOGGER, WRITER, ...)                        \
    UA_MACRO_EXPAND(UA_LOG_WRITER_INTERNAL(LOGGER, FATAL, WRITER, __VA_ARGS__, ""))

/**********************************************/
/*               WriterGroup                  */
/**********************************************/

struct UA_WriterGroup {
    UA_PubSubComponentEnumType componentType;
    UA_WriterGroupConfig config;
    LIST_ENTRY(UA_WriterGroup) listEntry;
    UA_NodeId identifier;
    UA_String logIdString;

    LIST_HEAD(, UA_DataSetWriter) writers;
    UA_UInt32 writersCount;

    UA_UInt64 publishCallbackId; /* registered if != 0 */
    UA_PubSubState state;
    UA_NetworkMessageOffsetBuffer bufferedMessage;
    UA_UInt16 sequenceNumber; /* Increased after every succressuly sent message */
    UA_Boolean configurationFrozen;
    UA_DateTime lastPublishTimeStamp;

    /* The ConnectionManager pointer is stored in the Connection. The channels
     * are either stored here or in the Connection, but never both. */
    UA_PubSubConnection *linkedConnection;
    uintptr_t sendChannel;
    UA_Boolean deleteFlag;

#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
    UA_UInt32 securityTokenId;
    UA_UInt32 nonceSequenceNumber; /* To be part of the MessageNonce */
    void *securityPolicyContext;
#ifdef UA_ENABLE_PUBSUB_SKS
    UA_PubSubKeyStorage *keyStorage; /* non-owning pointer to keyStorage*/
#endif
#endif
};

UA_StatusCode
UA_WriterGroup_create(UA_Server *server, const UA_NodeId connection,
                      const UA_WriterGroupConfig *writerGroupConfig,
                      UA_NodeId *writerGroupIdentifier);

UA_StatusCode
UA_WriterGroup_remove(UA_Server *server, UA_WriterGroup *wg);

void
UA_WriterGroup_disconnect(UA_WriterGroup *wg);

UA_StatusCode
UA_WriterGroup_connect(UA_Server *server, UA_WriterGroup *wg,
                       UA_Boolean validate);

UA_Boolean
UA_WriterGroup_canConnect(UA_WriterGroup *wg);

UA_StatusCode
setWriterGroupEncryptionKeys(UA_Server *server, const UA_NodeId writerGroup,
                             UA_UInt32 securityTokenId,
                             const UA_ByteString signingKey,
                             const UA_ByteString encryptingKey,
                             const UA_ByteString keyNonce);

UA_StatusCode
UA_WriterGroupConfig_copy(const UA_WriterGroupConfig *src,
                          UA_WriterGroupConfig *dst);

UA_WriterGroup *
UA_WriterGroup_findWGbyId(UA_Server *server, UA_NodeId identifier);

UA_StatusCode
UA_WriterGroup_freezeConfiguration(UA_Server *server, UA_WriterGroup *wg);

UA_StatusCode
UA_WriterGroup_unfreezeConfiguration(UA_Server *server, UA_WriterGroup *wg);

UA_StatusCode
UA_WriterGroup_setPubSubState(UA_Server *server,
                              UA_WriterGroup *writerGroup,
                              UA_PubSubState targetState);
UA_StatusCode
UA_WriterGroup_addPublishCallback(UA_Server *server, UA_WriterGroup *writerGroup);

void
UA_WriterGroup_publishCallback(UA_Server *server,
                               UA_WriterGroup *writerGroup);

UA_StatusCode
UA_WriterGroup_updateConfig(UA_Server *server, UA_WriterGroup *wg,
                            const UA_WriterGroupConfig *config);

UA_StatusCode
UA_WriterGroup_enableWriterGroup(UA_Server *server,
                                 const UA_NodeId writerGroup);

#define UA_LOG_WRITERGROUP_INTERNAL(LOGGER, LEVEL, WG, MSG, ...) \
    if(UA_LOGLEVEL <= UA_LOGLEVEL_##LEVEL) {                            \
        UA_LOG_##LEVEL(LOGGER, UA_LOGCATEGORY_PUBSUB, "%.*s" MSG "%.0s", \
                       (int)(WG)->logIdString.length,                   \
                       (char*)(WG)->logIdString.data, __VA_ARGS__);     \
    }

#define UA_LOG_TRACE_WRITERGROUP(LOGGER, WRITERGROUP, ...)              \
    UA_MACRO_EXPAND(UA_LOG_WRITERGROUP_INTERNAL(LOGGER, TRACE, WRITERGROUP, __VA_ARGS__, ""))
#define UA_LOG_DEBUG_WRITERGROUP(LOGGER, WRITERGROUP, ...)              \
    UA_MACRO_EXPAND(UA_LOG_WRITERGROUP_INTERNAL(LOGGER, DEBUG, WRITERGROUP, __VA_ARGS__, ""))
#define UA_LOG_INFO_WRITERGROUP(LOGGER, WRITERGROUP, ...)               \
    UA_MACRO_EXPAND(UA_LOG_WRITERGROUP_INTERNAL(LOGGER, INFO, WRITERGROUP, __VA_ARGS__, ""))
#define UA_LOG_WARNING_WRITERGROUP(LOGGER, WRITERGROUP, ...)            \
    UA_MACRO_EXPAND(UA_LOG_WRITERGROUP_INTERNAL(LOGGER, WARNING, WRITERGROUP, __VA_ARGS__, ""))
#define UA_LOG_ERROR_WRITERGROUP(LOGGER, WRITERGROUP, ...)              \
    UA_MACRO_EXPAND(UA_LOG_WRITERGROUP_INTERNAL(LOGGER, ERROR, WRITERGROUP, __VA_ARGS__, ""))
#define UA_LOG_FATAL_WRITERGROUP(LOGGER, WRITERGROUP, ...)              \
    UA_MACRO_EXPAND(UA_LOG_WRITERGROUP_INTERNAL(LOGGER, FATAL, WRITERGROUP, __VA_ARGS__, ""))

/**********************************************/
/*               DataSetField                 */
/**********************************************/

typedef struct UA_DataSetField {
    UA_DataSetFieldConfig config;
    TAILQ_ENTRY(UA_DataSetField) listEntry;
    UA_NodeId identifier;
    UA_NodeId publishedDataSet;     /* parent pds */
    UA_FieldMetaData fieldMetaData; /* contains the dataSetFieldId */
    UA_UInt64 sampleCallbackId;
    UA_Boolean sampleCallbackIsRegistered;
    UA_Boolean configurationFrozen;
} UA_DataSetField;

UA_StatusCode
UA_DataSetFieldConfig_copy(const UA_DataSetFieldConfig *src,
                           UA_DataSetFieldConfig *dst);

UA_DataSetField *
UA_DataSetField_findDSFbyId(UA_Server *server, UA_NodeId identifier);

UA_DataSetFieldResult
UA_DataSetField_remove(UA_Server *server, UA_DataSetField *currentField);

UA_DataSetFieldResult
UA_DataSetField_create(UA_Server *server, const UA_NodeId publishedDataSet,
                       const UA_DataSetFieldConfig *fieldConfig,
                       UA_NodeId *fieldIdentifier);

void
UA_PubSubDataSetField_sampleValue(UA_Server *server, UA_DataSetField *field,
                                  UA_DataValue *value);

/**********************************************/
/*               DataSetReader                */
/**********************************************/

/* DataSetReader Type definition */
typedef struct UA_DataSetReader {
    UA_PubSubComponentEnumType componentType;
    UA_DataSetReaderConfig config;
    UA_NodeId identifier;
    UA_String logIdString;
    UA_ReaderGroup *linkedReaderGroup;
    LIST_ENTRY(UA_DataSetReader) listEntry;

    UA_PubSubState state;
    UA_Boolean configurationFrozen;
    UA_NetworkMessageOffsetBuffer bufferedMessage;

#ifdef UA_ENABLE_PUBSUB_MONITORING
    /* MessageReceiveTimeout handling */
    UA_ServerCallback msgRcvTimeoutTimerCallback;
    UA_UInt64 msgRcvTimeoutTimerId;
    UA_Boolean msgRcvTimeoutTimerRunning;
#endif
    UA_DateTime lastHeartbeatReceived;
} UA_DataSetReader;

/* Process Network Message using DataSetReader */
void
UA_DataSetReader_process(UA_Server *server,
                         UA_DataSetReader *dataSetReader,
                         UA_DataSetMessage *dataSetMsg);

UA_StatusCode
UA_DataSetReader_checkIdentifier(UA_Server *server, UA_NetworkMessage *msg,
                                 UA_DataSetReader *reader,
                                 UA_ReaderGroupConfig readerGroupConfig);

UA_StatusCode
UA_DataSetReader_create(UA_Server *server, UA_NodeId readerGroupIdentifier,
                        const UA_DataSetReaderConfig *dataSetReaderConfig,
                        UA_NodeId *readerIdentifier);

UA_StatusCode
UA_DataSetReader_prepareOffsetBuffer(UA_Server *server, UA_DataSetReader *reader,
                                     UA_ByteString *buf, size_t *pos);

void
UA_DataSetReader_decodeAndProcessRT(UA_Server *server, UA_DataSetReader *dsr,
                                    UA_ByteString *buf);

UA_StatusCode
UA_DataSetReader_remove(UA_Server *server, UA_DataSetReader *dsr);

/* Copy the configuration of Target Variables */
UA_StatusCode UA_TargetVariables_copy(const UA_TargetVariables *src,
                                      UA_TargetVariables *dst);

/* Clear the Target Variables configuration */
void UA_TargetVariables_clear(UA_TargetVariables *subscribedDataSetTarget);

/* Copy the configuration of Field Target Variables */
UA_StatusCode UA_FieldTargetVariable_copy(const UA_FieldTargetVariable *src,
                                          UA_FieldTargetVariable *dst);

UA_StatusCode
DataSetReader_createTargetVariables(UA_Server *server, UA_DataSetReader *dsr,
                                    size_t targetVariablesSize,
                                    const UA_FieldTargetVariable *targetVariables);

/* Returns an error reason if the target state is `Error` */
UA_StatusCode
UA_DataSetReader_setPubSubState(UA_Server *server, UA_DataSetReader *dsr,
                                UA_PubSubState targetState);

#define UA_LOG_READER_INTERNAL(LOGGER, LEVEL, READER, MSG, ...)         \
    if(UA_LOGLEVEL <= UA_LOGLEVEL_##LEVEL) {                            \
        UA_LOG_##LEVEL(LOGGER, UA_LOGCATEGORY_PUBSUB, "%.*s" MSG "%.0s", \
                       (int)(READER)->logIdString.length,               \
                       (char*)(READER)->logIdString.data,               \
                       __VA_ARGS__);                                    \
    }

#define UA_LOG_TRACE_READER(LOGGER, READER, ...)                        \
    UA_MACRO_EXPAND(UA_LOG_READER_INTERNAL(LOGGER, TRACE, READER, __VA_ARGS__, ""))
#define UA_LOG_DEBUG_READER(LOGGER, READER, ...)                        \
    UA_MACRO_EXPAND(UA_LOG_READER_INTERNAL(LOGGER, DEBUG, READER, __VA_ARGS__, ""))
#define UA_LOG_INFO_READER(LOGGER, READER, ...)                         \
    UA_MACRO_EXPAND(UA_LOG_READER_INTERNAL(LOGGER, INFO, READER, __VA_ARGS__, ""))
#define UA_LOG_WARNING_READER(LOGGER, READER, ...)                      \
    UA_MACRO_EXPAND(UA_LOG_READER_INTERNAL(LOGGER, WARNING, READER, __VA_ARGS__, ""))
#define UA_LOG_ERROR_READER(LOGGER, READER, ...)                        \
    UA_MACRO_EXPAND(UA_LOG_READER_INTERNAL(LOGGER, ERROR, READER, __VA_ARGS__, ""))
#define UA_LOG_FATAL_READER(LOGGER, READER, ...)                        \
    UA_MACRO_EXPAND(UA_LOG_READER_INTERNAL(LOGGER, FATAL, READER, __VA_ARGS__, ""))

/**********************************************/
/*                ReaderGroup                 */
/**********************************************/

struct UA_ReaderGroup {
    UA_PubSubComponentEnumType componentType;
    UA_ReaderGroupConfig config;
    UA_NodeId identifier;
    UA_String logIdString;
    LIST_ENTRY(UA_ReaderGroup) listEntry;

    LIST_HEAD(, UA_DataSetReader) readers;
    UA_UInt32 readersCount;

    UA_PubSubState state;
    UA_Boolean configurationFrozen;
    UA_Boolean hasReceived; /* Received a message since the last _connect */

    /* The ConnectionManager pointer is stored in the Connection. The channels 
     * are either stored here or in the Connection, but never both. */
    UA_PubSubConnection *linkedConnection;
    uintptr_t recvChannels[UA_PUBSUB_MAXCHANNELS];
    size_t recvChannelsSize;
    UA_Boolean deleteFlag;

#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
    UA_UInt32 securityTokenId;
    UA_UInt32 nonceSequenceNumber; /* To be part of the MessageNonce */
    void *securityPolicyContext;
#ifdef UA_ENABLE_PUBSUB_SKS
    UA_PubSubKeyStorage *keyStorage;
#endif
#endif
};

UA_StatusCode
UA_ReaderGroup_create(UA_Server *server, UA_NodeId connectionId,
                      const UA_ReaderGroupConfig *rgc,
                      UA_NodeId *readerGroupId);

UA_StatusCode
UA_ReaderGroup_remove(UA_Server *server, UA_ReaderGroup *rg);

UA_StatusCode
UA_ReaderGroup_connect(UA_Server *server, UA_ReaderGroup *rg, UA_Boolean validate);

void
UA_ReaderGroup_disconnect(UA_ReaderGroup *rg);

UA_StatusCode
setReaderGroupEncryptionKeys(UA_Server *server, const UA_NodeId readerGroup,
                             UA_UInt32 securityTokenId,
                             const UA_ByteString signingKey,
                             const UA_ByteString encryptingKey,
                             const UA_ByteString keyNonce);

UA_StatusCode
UA_ReaderGroupConfig_copy(const UA_ReaderGroupConfig *src,
                          UA_ReaderGroupConfig *dst);

/* Prototypes for internal util functions - some functions maybe removed later
 * (currently moved from public to internal) */
UA_ReaderGroup *
UA_ReaderGroup_findRGbyId(UA_Server *server, UA_NodeId identifier);

UA_DataSetReader *
UA_ReaderGroup_findDSRbyId(UA_Server *server, UA_NodeId identifier);

UA_StatusCode
UA_ReaderGroup_freezeConfiguration(UA_Server *server, UA_ReaderGroup *rg);

UA_StatusCode
UA_ReaderGroup_unfreezeConfiguration(UA_Server *server, UA_ReaderGroup *rg);

UA_StatusCode
UA_ReaderGroup_setPubSubState(UA_Server *server, UA_ReaderGroup *rg,
                              UA_PubSubState targetState);

UA_Boolean
UA_ReaderGroup_decodeAndProcessRT(UA_Server *server, UA_ReaderGroup *readerGroup,
                                    UA_ByteString *buf);

UA_Boolean
UA_ReaderGroup_process(UA_Server *server, UA_ReaderGroup *readerGroup,
                       UA_NetworkMessage *nm);

#define UA_LOG_READERGROUP_INTERNAL(LOGGER, LEVEL, RG, MSG, ...)        \
    if(UA_LOGLEVEL <= UA_LOGLEVEL_##LEVEL) {                            \
        UA_LOG_##LEVEL(LOGGER, UA_LOGCATEGORY_PUBSUB, "%.*s" MSG "%.0s", \
                       (int)(RG)->logIdString.length,                   \
                       (char*)(RG)->logIdString.data,                   \
                       __VA_ARGS__);                                    \
    }

#define UA_LOG_TRACE_READERGROUP(LOGGER, READERGROUP, ...)              \
    UA_MACRO_EXPAND(UA_LOG_READERGROUP_INTERNAL(LOGGER, TRACE, READERGROUP, __VA_ARGS__, ""))
#define UA_LOG_DEBUG_READERGROUP(LOGGER, READERGROUP, ...)              \
    UA_MACRO_EXPAND(UA_LOG_READERGROUP_INTERNAL(LOGGER, DEBUG, READERGROUP, __VA_ARGS__, ""))
#define UA_LOG_INFO_READERGROUP(LOGGER, READERGROUP, ...)               \
    UA_MACRO_EXPAND(UA_LOG_READERGROUP_INTERNAL(LOGGER, INFO, READERGROUP, __VA_ARGS__, ""))
#define UA_LOG_WARNING_READERGROUP(LOGGER, READERGROUP, ...)            \
    UA_MACRO_EXPAND(UA_LOG_READERGROUP_INTERNAL(LOGGER, WARNING, READERGROUP, __VA_ARGS__, ""))
#define UA_LOG_ERROR_READERGROUP(LOGGER, READERGROUP, ...)              \
    UA_MACRO_EXPAND(UA_LOG_READERGROUP_INTERNAL(LOGGER, ERROR, READERGROUP, __VA_ARGS__, ""))
#define UA_LOG_FATAL_READERGROUP(LOGGER, READERGROUP, ...)              \
    UA_MACRO_EXPAND(UA_LOG_READERGROUP_INTERNAL(LOGGER, FATAL, READERGROUP, __VA_ARGS__, ""))

/*********************************************************/
/*               Reading Message handling                */
/*********************************************************/

#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
UA_StatusCode
verifyAndDecrypt(const UA_Logger *logger, UA_ByteString *buffer,
                 const size_t *currentPosition, const UA_NetworkMessage *nm,
                 UA_Boolean doValidate, UA_Boolean doDecrypt,
                 void *channelContext, UA_PubSubSecurityPolicy *securityPolicy);

UA_StatusCode
verifyAndDecryptNetworkMessage(const UA_Logger *logger, UA_ByteString *buffer,
                               size_t *currentPosition, UA_NetworkMessage *nm,
                               UA_ReaderGroup *readerGroup);
#endif

/* Takes a value (and not a pointer) to the buffer. The original buffer is
   const. Internally we may adjust the length during decryption. */
UA_StatusCode
decodeNetworkMessage(UA_Server *server, UA_ByteString *buffer, size_t *pos,
                     UA_NetworkMessage *nm, UA_PubSubConnection *connection);

#ifdef UA_ENABLE_PUBSUB_SKS
/*********************************************************/
/*                    SecurityGroup                      */
/*********************************************************/
struct UA_SecurityGroup {
    UA_String securityGroupId;
    UA_SecurityGroupConfig config;
    UA_PubSubKeyStorage *keyStorage;
    UA_NodeId securityGroupNodeId;
    UA_UInt64 callbackId;
    UA_DateTime baseTime;
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    UA_NodeId securityGroupFolderId;
#endif
    TAILQ_ENTRY(UA_SecurityGroup) listEntry;
};

UA_StatusCode
UA_SecurityGroupConfig_copy(const UA_SecurityGroupConfig *src,
                            UA_SecurityGroupConfig *dst);

/* finds the SecurityGroup within the server by SecurityGroup Name/Id*/
UA_SecurityGroup *
UA_SecurityGroup_findSGbyName(UA_Server *server, UA_String securityGroupName);

/* finds the SecurityGroup within the server by NodeId*/
UA_SecurityGroup *
UA_SecurityGroup_findSGbyId(UA_Server *server, UA_NodeId identifier);

void
UA_SecurityGroup_delete(UA_SecurityGroup *securityGroup);

void
removeSecurityGroup(UA_Server *server, UA_SecurityGroup *securityGroup);

#endif /* UA_ENABLE_PUBSUB_SKS */

/******************/
/* PubSub Manager */
/******************/

typedef struct UA_TopicAssign {
    UA_ReaderGroup *rgIdentifier;
    UA_String topic;
    TAILQ_ENTRY(UA_TopicAssign) listEntry;
} UA_TopicAssign;

typedef enum {
    UA_WRITER_GROUP = 0,
    UA_DATA_SET_WRITER = 1,
} UA_ReserveIdType;

typedef struct UA_ReserveId {
    UA_UInt16 id;
    UA_ReserveIdType reserveIdType;
    UA_String transportProfileUri;
    UA_NodeId sessionId;
    ZIP_ENTRY(UA_ReserveId) treeEntry;
} UA_ReserveId;

typedef ZIP_HEAD(UA_ReserveIdTree, UA_ReserveId) UA_ReserveIdTree;

typedef struct UA_PubSubManager {
    UA_UInt64 defaultPublisherId;
    /* Connections and PublishedDataSets can exist alone (own lifecycle) -> top
     * level components */
    size_t connectionsSize;
    TAILQ_HEAD(, UA_PubSubConnection) connections;

    size_t publishedDataSetsSize;
    TAILQ_HEAD(, UA_PublishedDataSet) publishedDataSets;

    size_t subscribedDataSetsSize;
    TAILQ_HEAD(, UA_StandaloneSubscribedDataSet) subscribedDataSets;

    size_t topicAssignSize;
    TAILQ_HEAD(, UA_TopicAssign) topicAssign;

    size_t reserveIdsSize;
    UA_ReserveIdTree reserveIds;

#ifdef UA_ENABLE_PUBSUB_SKS
    LIST_HEAD(, UA_PubSubKeyStorage) pubSubKeyList;

    size_t securityGroupsSize;
    TAILQ_HEAD(, UA_SecurityGroup) securityGroups;
#endif

#ifndef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    UA_UInt32 uniqueIdCount;
#endif
} UA_PubSubManager;

UA_StatusCode
UA_PubSubManager_addPubSubTopicAssign(UA_Server *server, UA_ReaderGroup *readerGroup,
                                      UA_String topic);

UA_StatusCode
UA_PubSubManager_reserveIds(UA_Server *server, UA_NodeId sessionId, UA_UInt16 numRegWriterGroupIds,
                            UA_UInt16 numRegDataSetWriterIds, UA_String transportProfileUri,
                            UA_UInt16 **writerGroupIds, UA_UInt16 **dataSetWriterIds);

void
UA_PubSubManager_freeIds(UA_Server *server);

void
UA_PubSubManager_init(UA_Server *server, UA_PubSubManager *pubSubManager);

void
UA_PubSubManager_shutdown(UA_Server *server, UA_PubSubManager *pubSubManager);

void
UA_PubSubManager_delete(UA_Server *server, UA_PubSubManager *pubSubManager);

#ifndef UA_ENABLE_PUBSUB_INFORMATIONMODEL
void
UA_PubSubManager_generateUniqueNodeId(UA_PubSubManager *psm, UA_NodeId *nodeId);
#endif

#ifdef UA_ENABLE_PUBSUB_FILE_CONFIG
/* Decodes the information from the ByteString. If the decoded content is a
 * PubSubConfiguration in a UABinaryFileDataType-object. It will overwrite the
 * current PubSub configuration from the server. */
UA_StatusCode
UA_PubSubManager_loadPubSubConfigFromByteString(UA_Server *server,
                                                const UA_ByteString buffer);

/* Saves the current PubSub configuration of a server in a byteString. */
UA_StatusCode
UA_PubSubManager_getEncodedPubSubConfiguration(UA_Server *server,
                                               UA_ByteString *buffer);
#endif

UA_Guid
UA_PubSubManager_generateUniqueGuid(UA_Server *server);

UA_UInt32
UA_PubSubConfigurationVersionTimeDifference(UA_DateTime now);

/*************************************************/
/*      PubSub component monitoring              */
/*************************************************/

#ifdef UA_ENABLE_PUBSUB_MONITORING

UA_StatusCode
UA_PubSubManager_setDefaultMonitoringCallbacks(UA_PubSubMonitoringInterface *monitoringInterface);

#endif /* UA_ENABLE_PUBSUB_MONITORING */

#endif /* UA_ENABLE_PUBSUB */

_UA_END_DECLS


/**** amalgamated original file "/src/pubsub/ua_pubsub_ns0.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2017-2018 Fraunhofer IOSB (Author: Andreas Ebner)
 * Copyright (c) 2019 Kalycito Infotech Private Limited
 * Copyright (c) 2022 Siemens AG (Author: Thomas Fischer)
 * Copyright (c) 2022 Linutronix GmbH (Author: Muddasir Shakil)
 */

#ifndef UA_PUBSUB_NS0_H_
#define UA_PUBSUB_NS0_H_


_UA_BEGIN_DECLS

#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL /* conditional compilation */

UA_StatusCode
initPubSubNS0(UA_Server *server);

UA_StatusCode
addPubSubConnectionRepresentation(UA_Server *server, UA_PubSubConnection *connection);

UA_StatusCode
addWriterGroupRepresentation(UA_Server *server, UA_WriterGroup *writerGroup);

UA_StatusCode
addReaderGroupRepresentation(UA_Server *server, UA_ReaderGroup *readerGroup);

UA_StatusCode
addDataSetWriterRepresentation(UA_Server *server, UA_DataSetWriter *dataSetWriter);

UA_StatusCode
addPublishedDataItemsRepresentation(UA_Server *server, UA_PublishedDataSet *publishedDataSet);

UA_StatusCode
addStandaloneSubscribedDataSetRepresentation(UA_Server *server, UA_StandaloneSubscribedDataSet *subscribedDataSet);

UA_StatusCode
addDataSetReaderRepresentation(UA_Server *server, UA_DataSetReader *dataSetReader);

UA_StatusCode
connectDataSetReaderToDataSet(UA_Server *server, UA_NodeId dsrId, UA_NodeId standaloneSdsId);

#ifdef UA_ENABLE_PUBSUB_SKS
UA_StatusCode
addSecurityGroupRepresentation(UA_Server *server, UA_SecurityGroup *securityGroup);
#endif /* UA_ENABLE_PUBSUB_SKS */

#endif /* UA_ENABLE_PUBSUB_INFORMATIONMODEL */

_UA_END_DECLS

#endif /* UA_PUBSUB_NS0_H_ */

/**** amalgamated original file "/src/pubsub/ua_pubsub_keystorage.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2019 ifak e.V. Magdeburg (Holger Zipper)
 * Copyright (c) 2022 Linutronix GmbH (Author: Muddasir Shakil)
 */

#ifndef UA_PUBSUB_KEYSTORAGE
#define UA_PUBSUB_KEYSTORAGE



_UA_BEGIN_DECLS

#ifdef UA_ENABLE_PUBSUB_SKS

/**
 * PubSubKeyStorage
 * ================
 * A PubSubKeyStorage provides a linked list to store all the keys used to
 * secure the messages. It keeps the records of old keys (past keys), current
 * key, new keys (futurekeys), time to move to next key and callback id.
 *
 * PubSubKeyListItem is the basic item stored in the KeyList of KeyStorage. It
 * provides keyId, Key, and pointer to the next key in KeyList. The KeyId is used
 * to identify and update currentKey in the keystorage. The KeyId is the SecurityTokenId
 * that appears in the header of messages secured with the CurrentKey.
 *
 * Working
 * =======
 *                     +------------------------------+
 *                     |AddReaderGroup/AddWriterGroup |
 *                     +------------------------------+
 *                                    |
 *                                    V
 *                     +--------------------+
 *                     |CheckSecurityGroupId|
 *                     +--------------------+
 *                                    |Yes
 *                                    V
 *                     +--------------------+
 *                     |InitializeKeyStorage|
 *                     +--------------------+
 *                                    |
 *                                    V
 *                     +----------------------------+
 *                     |store/updateKeysInKeyStorage|
 *                     +----------------------------+
 *                                    |
 *                                    V
 *                     +------------------------------------------+
 *                     |activateKeysToAllPubSubGroupChannelContext|
 *                     +------------------------------------------+
 *                                    |                        Ʌ
 *                                    V                        |
 *                     +-----------------------+               |
 *                     |addKeyRolloverCallbacks|               |
 *                     +-----------------------+               |
 *                                    |                        |
 *                                    V                        |
 *                     +-------------------+                   |
 *                     |keyRolloverCallback|                   |
 *                     +-------------------+                   |
 *                                    |CurrentKey!=LastItem    |
 *                                    -------------------------+
 *
 * A KeyStorage is created and initialized when a ReaderGroup or WriterGroup is
 * created with securityGroupId and SecurityMode SignAndEncrypt. The new
 * KeyStorage is added to the server KeyStorageList. At this time KeyList is empty.
 *
 * UA_PubSubKeyStorage_storeSecurityKeys is used to push the keys into existing
 * keystorage. In order to update the KeyList of an existing keyStorage,
 * UA_PubSubKeyStorage_update is called.
 *
 * After adding/updating the keys to keystorage, the current key should be
 * activated to the associated PubSub Group's ChannelContext in the server. The
 * security Policy associated with PubSub Group will take the keys from
 * channel context and use them to secure the messages.
 * The UA_PubSubKeyStorage_storeSecurityKeys and UA_PubSubKeyStorage_update
 * method will be used by setSecurityKeysAction and getSecurityKeysAction to
 * retrieve the keys from SKS server and store keys in local storage.
 *
 * Each key has a life time, after which the current key is expired and move to
 * next key in the existing list. For this a callback function is added to the
 * server. The callback function keyRolloverCallback is added to the server as a
 * timed callback. The addKeyRolloverCallbacks function calculates the time
 * stamp to trigger the callback when the current Key expires and roll
 * over to the next key in existing list.
 *
 */

/**
 * @brief This structure holds the information about the keys
 */
typedef struct UA_PubSubKeyListItem {
    /* The SecurityTokenId associated with Key*/
    UA_UInt32 keyID;

    /* This key is not used directly since the protocol associated with the PubSubGroup(s)
     * specifies an algorithm to generate distinct keys for different types of
     * cryptography operations*/
    UA_ByteString key;

    /* Pointers to the key list entries*/
    TAILQ_ENTRY(UA_PubSubKeyListItem) keyListEntry;
} UA_PubSubKeyListItem;

/* Queue Definition*/
typedef TAILQ_HEAD(keyListItems, UA_PubSubKeyListItem) keyListItems;

/**
 * @brief It is used to hold configuration information required to connect an SKS server
 * and fetch the security keys
 */
typedef struct UA_PubSubSKSConfig {
    UA_ClientConfig clientConfig;
    const char *endpointUrl;
    UA_Server_sksPullRequestCallback userNotifyCallback;
    void *context;
    UA_UInt32 reqId;
} UA_PubSubSKSConfig;

/**
 * @brief This structure holds all info and keys related to one SecurityGroup.
 * it is used as a list.
 */
typedef struct UA_PubSubKeyStorage {

    /**
     * security group id of the security group related to this storage
     */
    UA_String securityGroupID;

    /**
     * none-owning pointer to the security policy related to this storage
     */
    UA_PubSubSecurityPolicy *policy;

    /**
     * in case of the SKS server, the key storage structure is deleted when removing the
     * security group.
     * in case of publisher / subscriber, one key storage structure is
     * referenced by multiple reader / writer groups have a reference count to manage free
     */
    UA_UInt32 referenceCount;

    /**
     * array of keys. the elements inside this array have a next pointer.
     * keyList can therefore be used as linked list.
     */
    keyListItems keyList;

    /**
     * size of the keyList
     */
    size_t keyListSize;

    /**
     * The maximum number of Past keys a keystorage is allowed to store
     */
    UA_UInt32 maxPastKeyCount;

    /**
     * The maximum number of Future keys a keyStorage is allowed to store
     */
    UA_UInt32 maxFutureKeyCount;

    /*
     * The maximum keylist size, calculated from maxPastKeyCount and maxFutureKeyCount
     */
    UA_UInt32 maxKeyListSize;

    /**
     * The SecurityTokenId that appears in the header of messages secured with the
     * CurrentKey. It starts at 1 and is incremented by 1 each time the KeyLifetime
     * elapses even if no keys are requested. If the CurrentTokenId increments past the
     * maximum value of UInt32 it restarts a 1.
     */
    UA_UInt32 currentTokenId;

    /**
     *  the current key used to secure the messages
     */
    UA_PubSubKeyListItem *currentItem;

    /**
     * keyLifeTime used to update the CurrentKey from the Local KeyStorage
     */
    UA_Duration keyLifeTime;

    /**
     * id used to register the callback to retrieve the keys related to this security
     * group
     */
    UA_UInt64 callBackId;

    /**
     * used to store the sks related information to connect with SKS server and fetch security keys.
     */
    UA_PubSubSKSConfig sksConfig;

    /**
     * Pointer to the key storage list
     */
    LIST_ENTRY(UA_PubSubKeyStorage) keyStorageList;

} UA_PubSubKeyStorage;

/**
 * @brief Find the Keystorage from the Server KeyStorageList and returns the pointer to
 * the keystorage
 *
 * @param server holds the keystoragelist
 * @param securityGroupId of the keystorage to be found
 * @return Pointer to the keystorage on success, null pointer on failure
 */
UA_PubSubKeyStorage *
UA_PubSubKeyStorage_findKeyStorage(UA_Server *server, UA_String securityGroupId);

/**
 * @brief retreives the security policy pointer from the PubSub configuration by
 * SecurityPolicyUri
 *
 * @param server the server object
 * @param securityPolicyUri the URI of the security policy
 * @param policy the pointer to the security policy
 * @return UA_StatusCode return status code
 */
UA_PubSubSecurityPolicy *
findPubSubSecurityPolicy(UA_Server *server, const UA_String *securityPolicyUri);

/**
 * @brief Deletes the keystorage from the server and its members
 *
 * @param server where the keystorage is created
 * @param keyStorage pointer to the keystorage
 */
void
UA_PubSubKeyStorage_delete(UA_Server *server, UA_PubSubKeyStorage *keyStorage);

/**
 * @brief Initializes an empty Keystorage for the SecurityGroupId and add it to the Server
 * KeyStorageList
 *
 * @param server The server object
 * @param keyStorage Pointer to the keystorage to be initialized
 * @param securityGroupId The identifier of the SecurityGroup
 * @param policy The security policy assocaited with the security algorithm
 * @param maxPastKeyCount maximum number of past keys a keystorage is allowed to store
 * @param maxFutureKeyCount maximum number of future keys a keystorage is allowed to store
 * @return UA_StatusCode return status code
 */
UA_StatusCode
UA_PubSubKeyStorage_init(UA_Server *server, UA_PubSubKeyStorage *keyStorage,
                         const UA_String *securityGroupId,
                         UA_PubSubSecurityPolicy *policy,
                         UA_UInt32 maxPastKeyCount, UA_UInt32 maxFutureKeyCount);

/**
 * @brief After Keystorage is initialized and added to the server, this method is called
 * to store the current Keys and futurekeys.
 *
 * @param server the server object
 * @param keyStorage pointer to the keyStorage
 * @param currentTokenId The token Id of the current key it starts with 1 and increaments
 * each time keylifetime expires
 * @param currentKey the key used for encrypt the current messages
 * @param futureKeys pointer to the future keys
 * @param futureKeyCount the number future keys provided
 * @param keyLifeTime the time period when the key expires and move to next future key in
 * milli seconds
 * @return UA_StatusCode the return status
 */
UA_StatusCode
UA_PubSubKeyStorage_storeSecurityKeys(UA_Server *server, UA_PubSubKeyStorage *keyStorage,
                                      UA_UInt32 currentTokenId, const UA_ByteString *currentKey,
                                      UA_ByteString *futureKeys, size_t futureKeyCount,
                                      UA_Duration msKeyLifeTime);

/**
 * @brief Finds the KeyItem from the KeyList by KeyId
 *
 * @param keyId the identifier of the Key
 * @param keyStorage pointer to the keystorage
 * @param keyItem returned pointer to the keyItem in the KeyList
 * @return UA_StatusCode return status code
 */
UA_StatusCode
UA_PubSubKeyStorage_getKeyByKeyID(const UA_UInt32 keyId, UA_PubSubKeyStorage *keyStorage,
                                  UA_PubSubKeyListItem **keyItem);

/**
 * @brief Adds a new KeyItem at the end of the KeyList
 * to the new KeyListItem.
 *
 * @param keyStorage pointer to the keystorage
 * @param key the key to be added
 * @param keyID the keyID associated with the key to be added
 */
UA_PubSubKeyListItem *
UA_PubSubKeyStorage_push(UA_PubSubKeyStorage *keyStorage, const UA_ByteString *key,
                         UA_UInt32 keyID);

/**
 * @brief It calculates the time to trigger the callback to update current key, adds the
 * callback to the server and returns the callbackId.
 *
 * @param server the server object
 * @param keyStorage the pointer to the existing keystorage in the server
 * @param callback the callback function to be added to the server
 * @param timeToNextMs time in milli seconds to trigger the callback function
 * @param callbackID the returned callbackId of the added callback function
 * @return UA_StatusCode the return status
 */
UA_StatusCode
UA_PubSubKeyStorage_addKeyRolloverCallback(UA_Server *server,
                                          UA_PubSubKeyStorage *keyStorage,
                                          UA_ServerCallback callback,
                                          UA_Duration timeToNextMs,
                                          UA_UInt64 *callbackID);

/**
 * @brief It takes the current Key data, divide it into signing key, encrypting key and
 * keyNonce according to security policy associated with PubSub Group and set it in
 * channel context of the assocaited PubSub Group. In case of pubSubGroupId is
 * UA_NODEID_NULL, all the Reader/WriterGroup's channelcontext are updated with matching
 * SecurityGroupId.
 *
 * @param server The server object
 * @param pubSubGroupId the nodeId of the Reader/WirterGroup whose channel context to be
 * updated
 * @param securityGroupId The identifier for the SecurityGroup
 * @return UA_StatusCode return status code
 */
UA_StatusCode
UA_PubSubKeyStorage_activateKeyToChannelContext(UA_Server *server, const UA_NodeId pubSubGroupId,
                                                const UA_String securityGroupId);

/**
 * @brief The callback function to update the current key from keystorage in the server
 * and activate the current key into channel context of the associated PubSub Group
 *
 * @param server the server object
 * @param keyStorage the pointer to the keystorage
 */
void
UA_PubSubKeyStorage_keyRolloverCallback(UA_Server *server, UA_PubSubKeyStorage *keyStorage);

/**
 * @brief It updates/adds the current and future keys into the existing KeyStorage.
 * If the currentKeyID is known to existing keyStorage, then it is set as the currentKey
 * and any future keys are appended to the existing list. If the currentKeyId is not know
 * then, existing keyList is discarded and replaced with the new list.
 *
 * @param server the server object
 * @param keyStorage pointer to the keystorage
 * @param currentKey the currentKey data
 * @param currentKeyID the identifier of the current Key
 * @param futureKeySize the size of the future key list
 * @param futureKeys the pointer to the future keys list
 * @param msKeyLifeTime the updated time to move to next key
 * @return UA_StatusCode the return status
 */
UA_StatusCode
UA_PubSubKeyStorage_update(UA_Server *server, UA_PubSubKeyStorage *keyStorage,
                           const UA_ByteString *currentKey, UA_UInt32 currentKeyID,
                           const size_t futureKeySize, UA_ByteString *futureKeys,
                           UA_Duration msKeyLifeTime);

/* KeyStorage must be referenced by atleast one PubSubGroup. This method reduces
 * the reference count by one. If no PubSubGroup uses the key storage, then it
 * is deleted. */
void
UA_PubSubKeyStorage_detachKeyStorage(UA_Server *server, UA_PubSubKeyStorage *keyStorage);

/*Calls get SecurityKeys Method and Store the returned keys into KeyStorage*/
UA_StatusCode
getSecurityKeysAndStoreFetchedKeys(UA_Server *server, UA_PubSubKeyStorage *keyStorage);

#endif

_UA_END_DECLS

#endif /* UA_ENABLE_PUBSUB */

/**** amalgamated original file "/src/server/ua_services.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014-2017 (c) Florian Palm
 *    Copyright 2015 (c) Sten Grüner
 *    Copyright 2014 (c) LEvertz
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015 (c) Christian Fimmers
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 */




_UA_BEGIN_DECLS

/**
 * .. _services:
 *
 * Services
 * ========
 *
 * In OPC UA, all communication is based on service calls, each consisting of a
 * request and a response message. These messages are defined as data structures
 * with a binary encoding and listed in :ref:`generated-types`. Since all
 * Services are pre-defined in the standard, they cannot be modified by the
 * user. But you can use the :ref:`Call <method-services>` service to invoke
 * user-defined methods on the server.
 *
 * The following service signatures are internal and *not visible to users*.
 * Still, we present them here for an overview of the capabilities of OPC UA.
 * Please refer to the :ref:`client` and :ref:`server` API where the services
 * are exposed to end users. Please see part 4 of the OPC UA standard for the
 * authoritative definition of the service and their behaviour.
 *
 * Most services take as input the server, the current session and pointers to
 * the request and response structures. Possible error codes are returned as
 * part of the response. */

typedef void (*UA_Service)(UA_Server*, UA_Session*,
                           const void *request, void *response);

typedef void (*UA_ChannelService)(UA_Server*, UA_SecureChannel*,
                                  const void *request, void *response);

typedef struct {
    UA_UInt32 requestTypeId;
#ifdef UA_ENABLE_DIAGNOSTICS
    UA_UInt16 counterOffset;
#endif
    UA_Boolean sessionRequired;
    UA_Service serviceCallback;
    const UA_DataType *requestType;
    const UA_DataType *responseType;
} UA_ServiceDescription;

/* Returns NULL if none found */
UA_ServiceDescription * getServiceDescription(UA_UInt32 requestTypeId);

/**
 * Discovery Service Set
 * ---------------------
 * This Service Set defines Services used to discover the Endpoints implemented
 * by a Server and to read the security configuration for those Endpoints.
 *
 * FindServers Service
 * ^^^^^^^^^^^^^^^^^^^
 * Returns the Servers known to a Server or Discovery Server. The Client may
 * reduce the number of results returned by specifying filter criteria */
void Service_FindServers(UA_Server *server, UA_Session *session,
                         const UA_FindServersRequest *request,
                         UA_FindServersResponse *response);

/**
 * GetEndpoints Service
 * ^^^^^^^^^^^^^^^^^^^^
 * Returns the Endpoints supported by a Server and all of the configuration
 * information required to establish a SecureChannel and a Session. */
void Service_GetEndpoints(UA_Server *server, UA_Session *session,
                          const UA_GetEndpointsRequest *request,
                          UA_GetEndpointsResponse *response);

#ifdef UA_ENABLE_DISCOVERY

# ifdef UA_ENABLE_DISCOVERY_MULTICAST

/**
 * FindServersOnNetwork Service
 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 * Returns the Servers known to a Discovery Server. Unlike FindServer,
 * this Service is only implemented by Discovery Servers. It additionally
 * returns servers which may have been detected through Multicast. */
void Service_FindServersOnNetwork(UA_Server *server, UA_Session *session,
                                  const UA_FindServersOnNetworkRequest *request,
                                  UA_FindServersOnNetworkResponse *response);

# endif /* UA_ENABLE_DISCOVERY_MULTICAST */

/**
 * RegisterServer
 * ^^^^^^^^^^^^^^
 * Registers a remote server in the local discovery service. */
void Service_RegisterServer(UA_Server *server, UA_Session *session,
                            const UA_RegisterServerRequest *request,
                            UA_RegisterServerResponse *response);

/**
 * RegisterServer2
 * ^^^^^^^^^^^^^^^
 * This Service allows a Server to register its DiscoveryUrls and capabilities
 * with a Discovery Server. It extends the registration information from
 * RegisterServer with information necessary for FindServersOnNetwork. */
void Service_RegisterServer2(UA_Server *server, UA_Session *session,
                            const UA_RegisterServer2Request *request,
                            UA_RegisterServer2Response *response);

#endif /* UA_ENABLE_DISCOVERY */

/**
 * SecureChannel Service Set
 * -------------------------
 * This Service Set defines Services used to open a communication channel that
 * ensures the confidentiality and Integrity of all Messages exchanged with the
 * Server.
 *
 * OpenSecureChannel Service
 * ^^^^^^^^^^^^^^^^^^^^^^^^^
 * Open or renew a SecureChannel that can be used to ensure Confidentiality and
 * Integrity for Message exchange during a Session. */
void Service_OpenSecureChannel(UA_Server *server, UA_SecureChannel* channel,
                               UA_OpenSecureChannelRequest *request,
                               UA_OpenSecureChannelResponse *response);

/**
 * CloseSecureChannel Service
 * ^^^^^^^^^^^^^^^^^^^^^^^^^^
 * Used to terminate a SecureChannel. */
void Service_CloseSecureChannel(UA_Server *server, UA_SecureChannel *channel);

/**
 * Session Service Set
 * -------------------
 * This Service Set defines Services for an application layer connection
 * establishment in the context of a Session.
 *
 * CreateSession Service
 * ^^^^^^^^^^^^^^^^^^^^^
 * Used by an OPC UA Client to create a Session and the Server returns two
 * values which uniquely identify the Session. The first value is the sessionId
 * which is used to identify the Session in the audit logs and in the Server's
 * address space. The second is the authenticationToken which is used to
 * associate an incoming request with a Session. */
void Service_CreateSession(UA_Server *server, UA_SecureChannel *channel,
                           const UA_CreateSessionRequest *request,
                           UA_CreateSessionResponse *response);

/**
 * ActivateSession
 * ^^^^^^^^^^^^^^^
 * Used by the Client to submit its SoftwareCertificates to the Server for
 * validation and to specify the identity of the user associated with the
 * Session. This Service request shall be issued by the Client before it issues
 * any other Service request after CreateSession. Failure to do so shall cause
 * the Server to close the Session. */
void Service_ActivateSession(UA_Server *server, UA_SecureChannel *channel,
                             const UA_ActivateSessionRequest *request,
                             UA_ActivateSessionResponse *response);

/**
 * CloseSession
 * ^^^^^^^^^^^^
 * Used to terminate a Session. */
void Service_CloseSession(UA_Server *server, UA_SecureChannel *channel,
                          const UA_CloseSessionRequest *request,
                          UA_CloseSessionResponse *response);

/**
 * Cancel Service
 * ^^^^^^^^^^^^^^
 * Used to cancel outstanding Service requests. Successfully cancelled service
 * requests shall respond with Bad_RequestCancelledByClient. */
void Service_Cancel(UA_Server *server, UA_Session *session,
                    const UA_CancelRequest *request,
                    UA_CancelResponse *response);

/**
 * NodeManagement Service Set
 * --------------------------
 * This Service Set defines Services to add and delete AddressSpace Nodes and
 * References between them. All added Nodes continue to exist in the
 * AddressSpace even if the Client that created them disconnects from the
 * Server.
 *
 * AddNodes Service
 * ^^^^^^^^^^^^^^^^
 * Used to add one or more Nodes into the AddressSpace hierarchy.
 * If the type or one of the supertypes has any HasInterface references
 * (see OPC 10001-7 - Amendment 7, 4.9.2), the child nodes of the interfaces
 * are added to the new object.
*/
void Service_AddNodes(UA_Server *server, UA_Session *session,
                      const UA_AddNodesRequest *request,
                      UA_AddNodesResponse *response);

/**
 * AddReferences Service
 * ^^^^^^^^^^^^^^^^^^^^^
 * Used to add one or more References to one or more Nodes.*/
void Service_AddReferences(UA_Server *server, UA_Session *session,
                           const UA_AddReferencesRequest *request,
                           UA_AddReferencesResponse *response);

/**
 * DeleteNodes Service
 * ^^^^^^^^^^^^^^^^^^^
 * Used to delete one or more Nodes from the AddressSpace. */
void Service_DeleteNodes(UA_Server *server, UA_Session *session,
                         const UA_DeleteNodesRequest *request,
                         UA_DeleteNodesResponse *response);

/**
 * DeleteReferences
 * ^^^^^^^^^^^^^^^^
 * Used to delete one or more References of a Node. */
void Service_DeleteReferences(UA_Server *server, UA_Session *session,
                              const UA_DeleteReferencesRequest *request,
                              UA_DeleteReferencesResponse *response);

/**
 * .. _view-services:
 *
 * View Service Set
 * ----------------
 * Clients use the browse Services of the View Service Set to navigate through
 * the AddressSpace or through a View which is a subset of the AddressSpace.
 *
 * Browse Service
 * ^^^^^^^^^^^^^^
 * Used to discover the References of a specified Node. The browse can be
 * further limited by the use of a View. This Browse Service also supports a
 * primitive filtering capability. */
void Service_Browse(UA_Server *server, UA_Session *session,
                    const UA_BrowseRequest *request,
                    UA_BrowseResponse *response);

/**
 * BrowseNext Service
 * ^^^^^^^^^^^^^^^^^^
 * Used to request the next set of Browse or BrowseNext response information
 * that is too large to be sent in a single response. "Too large" in this
 * context means that the Server is not able to return a larger response or that
 * the number of results to return exceeds the maximum number of results to
 * return that was specified by the Client in the original Browse request. */
void Service_BrowseNext(UA_Server *server, UA_Session *session,
                        const UA_BrowseNextRequest *request,
                        UA_BrowseNextResponse *response);

/**
 * TranslateBrowsePathsToNodeIds Service
 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 * Used to translate textual node paths to their respective ids. */
void Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *session,
             const UA_TranslateBrowsePathsToNodeIdsRequest *request,
             UA_TranslateBrowsePathsToNodeIdsResponse *response);

/**
 * RegisterNodes Service
 * ^^^^^^^^^^^^^^^^^^^^^
 * Used by Clients to register the Nodes that they know they will access
 * repeatedly (e.g. Write, Call). It allows Servers to set up anything needed so
 * that the access operations will be more efficient. */
void Service_RegisterNodes(UA_Server *server, UA_Session *session,
                           const UA_RegisterNodesRequest *request,
                           UA_RegisterNodesResponse *response);

/**
 * UnregisterNodes Service
 * ^^^^^^^^^^^^^^^^^^^^^^^
 * This Service is used to unregister NodeIds that have been obtained via the
 * RegisterNodes service. */
void Service_UnregisterNodes(UA_Server *server, UA_Session *session,
                             const UA_UnregisterNodesRequest *request,
                             UA_UnregisterNodesResponse *response);

/**
 * Query Service Set
 * -----------------
 * This Service Set is used to issue a Query to a Server. OPC UA Query is
 * generic in that it provides an underlying storage mechanism independent Query
 * capability that can be used to access a wide variety of OPC UA data stores
 * and information management systems. OPC UA Query permits a Client to access
 * data maintained by a Server without any knowledge of the logical schema used
 * for internal storage of the data. Knowledge of the AddressSpace is
 * sufficient.
 *
 * QueryFirst Service
 * ^^^^^^^^^^^^^^^^^^
 * This Service is used to issue a Query request to the Server. */
/* Not Implemented */

/**
 * QueryNext Service
 * ^^^^^^^^^^^^^^^^^
 * This Service is used to request the next set of QueryFirst or QueryNext
 * response information that is too large to be sent in a single response. */
/* Not Impelemented */

/**
 * Attribute Service Set
 * ---------------------
 * This Service Set provides Services to access Attributes that are part of
 * Nodes.
 *
 * Read Service
 * ^^^^^^^^^^^^
 * Used to read attributes of nodes. For constructed attribute values whose
 * elements are indexed, such as an array, this Service allows Clients to read
 * the entire set of indexed values as a composite, to read individual elements
 * or to read ranges of elements of the composite. */
void Service_Read(UA_Server *server, UA_Session *session,
                  const UA_ReadRequest *request,
                  UA_ReadResponse *response);

/**
 * Write Service
 * ^^^^^^^^^^^^^
 * Used to write attributes of nodes. For constructed attribute values whose
 * elements are indexed, such as an array, this Service allows Clients to write
 * the entire set of indexed values as a composite, to write individual elements
 * or to write ranges of elements of the composite. */
void Service_Write(UA_Server *server, UA_Session *session,
                   const UA_WriteRequest *request,
                   UA_WriteResponse *response);

/**
 * HistoryRead Service
 * ^^^^^^^^^^^^^^^^^^^
 * Used to read historical values or Events of one or more Nodes. Servers may
 * make historical values available to Clients using this Service, although the
 * historical values themselves are not visible in the AddressSpace. */
#ifdef UA_ENABLE_HISTORIZING
void Service_HistoryRead(UA_Server *server, UA_Session *session,
                         const UA_HistoryReadRequest *request,
                         UA_HistoryReadResponse *response);

/**
 * HistoryUpdate Service
 * ^^^^^^^^^^^^^^^^^^^^^
 * Used to update historical values or Events of one or more Nodes. Several
 * request parameters indicate how the Server is to update the historical value
 * or Event. Valid actions are Insert, Replace or Delete. */
void
Service_HistoryUpdate(UA_Server *server, UA_Session *session,
                      const UA_HistoryUpdateRequest *request,
                      UA_HistoryUpdateResponse *response);
#endif

/**
 * .. _method-services:
 *
 * Method Service Set
 * ------------------
 * The Method Service Set defines the means to invoke methods. A method shall be
 * a component of an Object. See the section on :ref:`MethodNodes <methodnode>`
 * for more information.
 *
 * Call Service
 * ^^^^^^^^^^^^
 * Used to call (invoke) a methods. Each method call is invoked within the
 * context of an existing Session. If the Session is terminated, the results of
 * the method's execution cannot be returned to the Client and are discarded. */
#ifdef UA_ENABLE_METHODCALLS
void Service_Call(UA_Server *server, UA_Session *session,
                  const UA_CallRequest *request,
                  UA_CallResponse *response);

# if UA_MULTITHREADING >= 100
void Service_CallAsync(UA_Server *server, UA_Session *session, UA_UInt32 requestId,
                       const UA_CallRequest *request, UA_CallResponse *response,
                       UA_Boolean *finished);
#endif
#endif

#ifdef UA_ENABLE_SUBSCRIPTIONS

/**
 * MonitoredItem Service Set
 * -------------------------
 * Clients define MonitoredItems to subscribe to data and Events. Each
 * MonitoredItem identifies the item to be monitored and the Subscription to use
 * to send Notifications. The item to be monitored may be any Node Attribute.
 *
 * CreateMonitoredItems Service
 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 * Used to create and add one or more MonitoredItems to a Subscription. A
 * MonitoredItem is deleted automatically by the Server when the Subscription is
 * deleted. Deleting a MonitoredItem causes its entire set of triggered item
 * links to be deleted, but has no effect on the MonitoredItems referenced by
 * the triggered items. */
void Service_CreateMonitoredItems(UA_Server *server, UA_Session *session,
                                  const UA_CreateMonitoredItemsRequest *request,
                                  UA_CreateMonitoredItemsResponse *response);

/**
 * DeleteMonitoredItems Service
 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 * Used to remove one or more MonitoredItems of a Subscription. When a
 * MonitoredItem is deleted, its triggered item links are also deleted. */
void Service_DeleteMonitoredItems(UA_Server *server, UA_Session *session,
                                  const UA_DeleteMonitoredItemsRequest *request,
                                  UA_DeleteMonitoredItemsResponse *response);

/**
 * ModifyMonitoredItems Service
 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 * Used to modify MonitoredItems of a Subscription. Changes to the MonitoredItem
 * settings shall be applied immediately by the Server. They take effect as soon
 * as practical but not later than twice the new revisedSamplingInterval.
 *
 * Illegal request values for parameters that can be revised do not generate
 * errors. Instead the server will choose default values and indicate them in
 * the corresponding revised parameter. */
void Service_ModifyMonitoredItems(UA_Server *server, UA_Session *session,
                                  const UA_ModifyMonitoredItemsRequest *request,
                                  UA_ModifyMonitoredItemsResponse *response);

/**
 * SetMonitoringMode Service
 * ^^^^^^^^^^^^^^^^^^^^^^^^^
 * Used to set the monitoring mode for one or more MonitoredItems of a
 * Subscription. */
void Service_SetMonitoringMode(UA_Server *server, UA_Session *session,
                               const UA_SetMonitoringModeRequest *request,
                               UA_SetMonitoringModeResponse *response);

/**
 * SetTriggering Service
 * ^^^^^^^^^^^^^^^^^^^^^
 * Used to create and delete triggering links for a triggering item. */
void Service_SetTriggering(UA_Server *server, UA_Session *session,
                           const UA_SetTriggeringRequest *request,
                           UA_SetTriggeringResponse *response);

/**
 * Subscription Service Set
 * ------------------------
 * Subscriptions are used to report Notifications to the Client.
 *
 * CreateSubscription Service
 * ^^^^^^^^^^^^^^^^^^^^^^^^^^
 * Used to create a Subscription. Subscriptions monitor a set of MonitoredItems
 * for Notifications and return them to the Client in response to Publish
 * requests. */
void Service_CreateSubscription(UA_Server *server, UA_Session *session,
                                const UA_CreateSubscriptionRequest *request,
                                UA_CreateSubscriptionResponse *response);

/**
 * ModifySubscription Service
 * ^^^^^^^^^^^^^^^^^^^^^^^^^^
 * Used to modify a Subscription. */
void Service_ModifySubscription(UA_Server *server, UA_Session *session,
                                const UA_ModifySubscriptionRequest *request,
                                UA_ModifySubscriptionResponse *response);

/**
 * SetPublishingMode Service
 * ^^^^^^^^^^^^^^^^^^^^^^^^^
 * Used to enable sending of Notifications on one or more Subscriptions. */
void Service_SetPublishingMode(UA_Server *server, UA_Session *session,
                               const UA_SetPublishingModeRequest *request,
                               UA_SetPublishingModeResponse *response);

/**
 * Publish Service
 * ^^^^^^^^^^^^^^^
 * Used for two purposes. First, it is used to acknowledge the receipt of
 * NotificationMessages for one or more Subscriptions. Second, it is used to
 * request the Server to return a NotificationMessage or a keep-alive
 * Message.
 *
 * Note that the service signature is an exception and does not contain a
 * pointer to a PublishResponse. That is because the service queues up publish
 * requests internally and sends responses asynchronously based on timeouts.
 *
 * Also, this is the only service method that returns a StatusCode. This
 * simplifies keeping track of the diagnostics statistics. */
UA_StatusCode
Service_Publish(UA_Server *server, UA_Session *session,
                const UA_PublishRequest *request, UA_UInt32 requestId);

/**
 * Republish Service
 * ^^^^^^^^^^^^^^^^^
 * Requests the Subscription to republish a NotificationMessage from its
 * retransmission queue. */
void Service_Republish(UA_Server *server, UA_Session *session,
                       const UA_RepublishRequest *request,
                       UA_RepublishResponse *response);

/**
 * DeleteSubscriptions Service
 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
 * Invoked to delete one or more Subscriptions that belong to the Client's
 * Session. */
void Service_DeleteSubscriptions(UA_Server *server, UA_Session *session,
                                 const UA_DeleteSubscriptionsRequest *request,
                                 UA_DeleteSubscriptionsResponse *response);

/**
 * TransferSubscription Service
 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 * Used to transfer a Subscription and its MonitoredItems from one Session to
 * another. For example, a Client may need to reopen a Session and then transfer
 * its Subscriptions to that Session. It may also be used by one Client to take
 * over a Subscription from another Client by transferring the Subscription to
 * its Session. */
void Service_TransferSubscriptions(UA_Server *server, UA_Session *session,
                                   const UA_TransferSubscriptionsRequest *request,
                                   UA_TransferSubscriptionsResponse *response);

#endif /* UA_ENABLE_SUBSCRIPTIONS */

_UA_END_DECLS


/**** amalgamated original file "/src/server/ua_server_async.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
  *    Copyright 2019 (c) Fraunhofer IOSB (Author: Klaus Schick)
 * based on
 *    Copyright 2014-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014, 2017 (c) Florian Palm
 *    Copyright 2015 (c) Sten Grüner
 *    Copyright 2015 (c) Oleksiy Vasylyev
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 */




_UA_BEGIN_DECLS

#if UA_MULTITHREADING >= 100

struct UA_AsyncResponse;
typedef struct UA_AsyncResponse UA_AsyncResponse;

/* A single operation (of a larger request) */
typedef struct UA_AsyncOperation {
    TAILQ_ENTRY(UA_AsyncOperation) pointers;
    UA_CallMethodRequest request;
    UA_CallMethodResult	response;
    size_t index;             /* Index of the operation in the array of ops in
                               * request/response */
    UA_AsyncResponse *parent; /* Always non-NULL. The parent is only removed
                               * when its operations are removed */
} UA_AsyncOperation;

struct UA_AsyncResponse {
    TAILQ_ENTRY(UA_AsyncResponse) pointers; /* Insert new at the end */
    UA_UInt32 requestId;
    UA_NodeId sessionId;
    UA_UInt32 requestHandle;
    UA_DateTime	timeout;
    UA_AsyncOperationType operationType;
    union {
        UA_CallResponse callResponse;
        UA_ReadResponse readResponse;
        UA_WriteResponse writeResponse;
    } response;
    UA_UInt32 opCountdown; /* Counter for outstanding operations. The AR can
                            * only be deleted when all have returned. */
};

typedef TAILQ_HEAD(UA_AsyncOperationQueue, UA_AsyncOperation) UA_AsyncOperationQueue;

typedef struct {
    /* Requests / Responses */
    TAILQ_HEAD(, UA_AsyncResponse) asyncResponses;
    size_t asyncResponsesCount;

    /* Operations for the workers. The queues are all FIFO: Put in at the tail,
     * take out at the head.*/
    UA_Lock queueLock; /* Either take this lock free-standing (with no other
                        * locks). Or take server->serviceMutex first and then
                        * the queueLock. Never take the server->serviceMutex
                        * when the queueLock is already acquired (deadlock)! */
    UA_AsyncOperationQueue newQueue;        /* New operations for the workers */
    UA_AsyncOperationQueue dispatchedQueue; /* Operations taken by a worker. When a result is
                                             * returned, we search for the op here to see if it
                                             * is still "alive" (not timed out). */
    UA_AsyncOperationQueue resultQueue;     /* Results to be integrated */
    size_t opsCount; /* How many operations are transient (in one of the three queues)? */

    UA_UInt64 checkTimeoutCallbackId; /* Registered repeated callbacks */
} UA_AsyncManager;

void UA_AsyncManager_init(UA_AsyncManager *am, UA_Server *server);
void UA_AsyncManager_start(UA_AsyncManager *am, UA_Server *server);
void UA_AsyncManager_stop(UA_AsyncManager *am, UA_Server *server);
void UA_AsyncManager_clear(UA_AsyncManager *am, UA_Server *server);

UA_StatusCode
UA_AsyncManager_createAsyncResponse(UA_AsyncManager *am, UA_Server *server,
                                    const UA_NodeId *sessionId,
                                    const UA_UInt32 requestId,
                                    const UA_UInt32 requestHandle,
                                    const UA_AsyncOperationType operationType,
                                    UA_AsyncResponse **outAr);

/* Only remove the AsyncResponse when the operation count is zero */
void
UA_AsyncManager_removeAsyncResponse(UA_AsyncManager *am, UA_AsyncResponse *ar);

UA_StatusCode
UA_AsyncManager_createAsyncOp(UA_AsyncManager *am, UA_Server *server,
                              UA_AsyncResponse *ar, size_t opIndex,
                              const UA_CallMethodRequest *opRequest);

/* Send out the response with status set. Also removes all outstanding
 * operations from the dispatch queue. The queuelock needs to be taken before
 * calling _cancel. */
UA_UInt32
UA_AsyncManager_cancel(UA_Server *server, UA_Session *session, UA_UInt32 requestHandle);

typedef void (*UA_AsyncServiceOperation)(UA_Server *server, UA_Session *session,
                                         UA_UInt32 requestId, UA_UInt32 requestHandle,
                                         size_t opIndex, const void *requestOperation,
                                         void *responseOperation, UA_AsyncResponse **ar);

/* Creates an AsyncResponse in-situ when an async operation is encountered. If
 * that is the case, the sync responses are moved to the AsyncResponse. */
UA_StatusCode
UA_Server_processServiceOperationsAsync(UA_Server *server, UA_Session *session,
                                        UA_UInt32 requestId, UA_UInt32 requestHandle,
                                        UA_AsyncServiceOperation operationCallback,
                                        const size_t *requestOperations,
                                        const UA_DataType *requestOperationsType,
                                        size_t *responseOperations,
                                        const UA_DataType *responseOperationsType,
                                        UA_AsyncResponse **ar)
UA_FUNC_ATTR_WARN_UNUSED_RESULT;

#endif /* UA_MULTITHREADING >= 100 */

_UA_END_DECLS


/**** amalgamated original file "/src/server/ua_server_internal.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2019 (c) Fraunhofer IOSB (Author: Klaus Schick)
 *    Copyright 2014-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014, 2017 (c) Florian Palm
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Julian Grothoff
 *    Copyright 2019 (c) Kalycito Infotech Private Limited
 *    Copyright 2019 (c) HMS Industrial Networks AB (Author: Jonas Green)
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Andreas Ebner)
 *    Copyright 2022 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati)
 */


#define UA_INTERNAL


_UA_BEGIN_DECLS

#ifdef UA_ENABLE_PUBSUB
#endif

#ifdef UA_ENABLE_DISCOVERY
struct UA_DiscoveryManager;
typedef struct UA_DiscoveryManager UA_DiscoveryManager;
#endif

#ifdef UA_ENABLE_SUBSCRIPTIONS

typedef struct {
    UA_MonitoredItem monitoredItem;
    void *context;
    union {
        UA_Server_DataChangeNotificationCallback dataChangeCallback;
        UA_Server_EventNotificationCallback eventCallback;
    } callback;

    /* For Event-MonitoredItems only. The value fields are overwritten before
     * each callback. They can contain stray pointers between callbacks. So
     * don't clean up the value fields. */
    UA_KeyValueMap eventFields;
} UA_LocalMonitoredItem;

#endif /* !UA_ENABLE_SUBSCRIPTIONS */

/********************/
/* Server Component */
/********************/

/* ServerComponents have an explicit lifecycle. But they can only be started
 * when the underlying server is started. The starting/stopping of
 * ServerComponents is asynchronous. That is, they might require several
 * iterations of the EventLoop to finish starting/stopping.
 *
 * ServerComponents can only be deleted when they are STOPPED. The server will
 * not fully shut down as long as there is a component remaining. */

typedef struct UA_ServerComponent {
    UA_UInt64 identifier;
    UA_String name;
    ZIP_ENTRY(UA_ServerComponent) treeEntry;
    UA_LifecycleState state;

    /* Starting fails if the server is not also already started */
    UA_StatusCode (*start)(UA_Server *server,
                           struct UA_ServerComponent *sc);

    /* Stopping is asynchronous and might need a few iterations of the main-loop
     * to succeed. */
    void (*stop)(UA_Server *server,
                 struct UA_ServerComponent *sc);

    /* Clean up the ServerComponent. Can fail if it is not stopped. */
    UA_StatusCode (*free)(UA_Server *server,
                          struct UA_ServerComponent *sc);

    /* To be set by the server. So the component can notify the server about
     * asynchronous state changes. */
    void (*notifyState)(UA_Server *server, struct UA_ServerComponent *sc,
                        UA_LifecycleState state);
} UA_ServerComponent;

enum ZIP_CMP
cmpServerComponent(const UA_UInt64 *a, const UA_UInt64 *b);

typedef ZIP_HEAD(UA_ServerComponentTree, UA_ServerComponent) UA_ServerComponentTree;

ZIP_FUNCTIONS(UA_ServerComponentTree, UA_ServerComponent, treeEntry,
              UA_UInt64, identifier, cmpServerComponent)

/* Assigns the identifier if the pointer is non-NULL.
 * Starts the component if the server is started. */
void
addServerComponent(UA_Server *server, UA_ServerComponent *sc,
                   UA_UInt64 *identifier);

UA_ServerComponent *
getServerComponentByName(UA_Server *server, UA_String name);

/********************/
/* Server Structure */
/********************/

typedef struct session_list_entry {
    UA_DelayedCallback cleanupCallback;
    LIST_ENTRY(session_list_entry) pointers;
    UA_Session session;
} session_list_entry;

struct UA_Server {
    /* Config */
    UA_ServerConfig config;

    /* Runtime state */
    UA_DateTime startTime;
    UA_DateTime endTime; /* Zeroed out. If a time is set, then the server shuts
                          * down once the time has been reached */

    UA_LifecycleState state;
    UA_UInt64 houseKeepingCallbackId;

    UA_UInt64 serverComponentIds; /* Counter to assign ids from */
    UA_ServerComponentTree serverComponents;

#if UA_MULTITHREADING >= 100
    UA_AsyncManager asyncManager;
#endif

    /* Session Management */
    LIST_HEAD(session_list, session_list_entry) sessions;
    UA_UInt32 sessionCount;
    UA_UInt32 activeSessionCount;

    /* Session for local access to the services for upkeep and the C API. Comes
     * equipped with all possible access rights (Session Id: 1). */
    UA_Session adminSession;

    /* Namespaces */
    size_t namespacesSize;
    UA_String *namespaces;

    /* For bootstrapping, omit some consistency checks, creating a reference to
     * the parent and member instantiation */
    UA_Boolean bootstrapNS0;

    /* Subscriptions */
#ifdef UA_ENABLE_SUBSCRIPTIONS
    /* The admin session is initialized with a special subscription. This
     * subscription generates delayed callbacks with notifications for local
     * processing. */
    UA_Subscription *adminSubscription;

    size_t subscriptionsSize;  /* Number of active subscriptions */
    size_t monitoredItemsSize; /* Number of active monitored items */
    LIST_HEAD(, UA_Subscription) subscriptions; /* All subscriptions in the
                                                 * server. They may be detached
                                                 * from a session. */
    UA_UInt32 lastSubscriptionId; /* To generate unique SubscriptionIds */

# ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS
    LIST_HEAD(, UA_ConditionSource) conditionSources;
    UA_NodeId refreshEvents[2];
# endif
#endif

    /* Publish/Subscribe */
#ifdef UA_ENABLE_PUBSUB
    UA_PubSubManager pubSubManager;
#endif

#if UA_MULTITHREADING >= 100
    UA_Lock serviceMutex;
#endif

    /* Statistics */
    UA_SecureChannelStatistics secureChannelStatistics;
    UA_ServerDiagnosticsSummaryDataType serverDiagnosticsSummary;
};

/***********************/
/* References Handling */
/***********************/

enum ZIP_CMP
cmpRefTargetId(const void *a, const void *b);

enum ZIP_CMP
cmpRefTargetName(const void *a, const void *b);

/* Static inline methods for tree handling */
typedef ZIP_HEAD(UA_ReferenceIdTree, UA_ReferenceTargetTreeElem) UA_ReferenceIdTree;
ZIP_FUNCTIONS(UA_ReferenceIdTree, UA_ReferenceTargetTreeElem, idTreeEntry,
              UA_ReferenceTargetTreeElem, target, cmpRefTargetId)

typedef ZIP_HEAD(UA_ReferenceNameTree, UA_ReferenceTargetTreeElem) UA_ReferenceNameTree;
ZIP_FUNCTIONS(UA_ReferenceNameTree, UA_ReferenceTargetTreeElem, nameTreeEntry,
              UA_ReferenceTarget, target, cmpRefTargetName)

/**************************/
/* SecureChannel Handling */
/**************************/

void
serverNetworkCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
                      void *application, void **connectionContext,
                      UA_ConnectionState state,
                      const UA_KeyValueMap *params,
                      UA_ByteString msg);

UA_StatusCode
sendServiceFault(UA_Server *server, UA_SecureChannel *channel, UA_UInt32 requestId,
                 UA_UInt32 requestHandle, UA_StatusCode statusCode);

/* Gets the a pointer to the context of a security policy supported by the
 * server matched by the security policy uri. */
UA_SecurityPolicy *
getSecurityPolicyByUri(const UA_Server *server,
                       const UA_ByteString *securityPolicyUri);

UA_UInt32
generateSecureChannelTokenId(UA_Server *server);

/********************/
/* Session Handling */
/********************/

UA_StatusCode
getNamespaceByName(UA_Server *server, const UA_String namespaceUri,
                   size_t *foundIndex);

UA_StatusCode
getNamespaceByIndex(UA_Server *server, const size_t namespaceIndex,
                    UA_String *foundUri);

UA_StatusCode
getBoundSession(UA_Server *server, const UA_SecureChannel *channel,
                const UA_NodeId *token, UA_Session **session);

UA_StatusCode
UA_Server_createSession(UA_Server *server, UA_SecureChannel *channel,
                        const UA_CreateSessionRequest *request, UA_Session **session);

void
UA_Server_removeSession(UA_Server *server, session_list_entry *sentry,
                        UA_ShutdownReason shutdownReason);

UA_StatusCode
UA_Server_removeSessionByToken(UA_Server *server, const UA_NodeId *token,
                               UA_ShutdownReason shutdownReason);

void
UA_Server_cleanupSessions(UA_Server *server, UA_DateTime nowMonotonic);

UA_Session *
getSessionByToken(UA_Server *server, const UA_NodeId *token);

UA_Session *
getSessionById(UA_Server *server, const UA_NodeId *sessionId);

/*****************/
/* Node Handling */
/*****************/

/* Calls the callback with the node retrieved from the nodestore on top of the
 * stack. Either a copy or the original node for in-situ editing. Depends on
 * multithreading and the nodestore.*/
typedef UA_StatusCode (*UA_EditNodeCallback)(UA_Server*, UA_Session*,
                                             UA_Node *node, void*);
UA_StatusCode UA_Server_editNode(UA_Server *server, UA_Session *session,
                                 const UA_NodeId *nodeId,
                                 UA_EditNodeCallback callback,
                                 void *data);

/*********************/
/* Utility Functions */
/*********************/

void setServerLifecycleState(UA_Server *server, UA_LifecycleState state);

void setupNs1Uri(UA_Server *server);
UA_UInt16 addNamespace(UA_Server *server, const UA_String name);

UA_Boolean
UA_Node_hasSubTypeOrInstances(const UA_NodeHead *head);

/* Recursively searches "upwards" in the tree following specific reference types */
UA_Boolean
isNodeInTree(UA_Server *server, const UA_NodeId *leafNode,
             const UA_NodeId *nodeToFind, const UA_ReferenceTypeSet *relevantRefs);

/* Convenience function with just a single ReferenceTypeIndex */
UA_Boolean
isNodeInTree_singleRef(UA_Server *server, const UA_NodeId *leafNode,
                       const UA_NodeId *nodeToFind, const UA_Byte relevantRefTypeIndex);

/* Returns an array with the hierarchy of nodes. The start nodes can be returned
 * as well. The returned array starts at the leaf and continues "upwards" or
 * "downwards". Duplicate entries are removed. */
UA_StatusCode
browseRecursive(UA_Server *server, size_t startNodesSize, const UA_NodeId *startNodes,
                UA_BrowseDirection browseDirection, const UA_ReferenceTypeSet *refTypes,
                UA_UInt32 nodeClassMask, UA_Boolean includeStartNodes,
                size_t *resultsSize, UA_ExpandedNodeId **results);

/* Get the bitfield indices of a ReferenceType and possibly its subtypes.
 * refType must point to a ReferenceTypeNode. */
UA_StatusCode
referenceTypeIndices(UA_Server *server, const UA_NodeId *refType,
                     UA_ReferenceTypeSet *indices, UA_Boolean includeSubtypes);

/* Returns the recursive type and interface hierarchy of the node */
UA_StatusCode
getParentTypeAndInterfaceHierarchy(UA_Server *server, const UA_NodeId *typeNode,
                                   UA_NodeId **typeHierarchy, size_t *typeHierarchySize);

/* Returns the recursive interface hierarchy of the node */
UA_StatusCode
getAllInterfaceChildNodeIds(UA_Server *server, const UA_NodeId *objectNode, const UA_NodeId *objectTypeNode,
                                   UA_NodeId **interfaceChildNodes, size_t *interfaceChildNodesSize);

#ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS

UA_StatusCode
UA_getConditionId(UA_Server *server, const UA_NodeId *conditionNodeId,
                  UA_NodeId *outConditionId);

void
UA_ConditionList_delete(UA_Server *server);

UA_Boolean
isConditionOrBranch(UA_Server *server,
                    const UA_NodeId *condition,
                    const UA_NodeId *conditionSource,
                    UA_Boolean *isCallerAC);

#endif /* UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS */

/* Returns the type node from the node on the stack top. The type node is pushed
 * on the stack and returned. */
const UA_Node *
getNodeType(UA_Server *server, const UA_NodeHead *nodeHead);

/* Returns whether we send a response right away (async call or not) */
UA_Boolean
UA_Server_processRequest(UA_Server *server, UA_SecureChannel *channel,
                         UA_UInt32 requestId, UA_ServiceDescription *sd,
                         const UA_Request *request, UA_Response *response);

UA_StatusCode
sendResponse(UA_Server *server, UA_SecureChannel *channel, UA_UInt32 requestId,
             UA_Response *response, const UA_DataType *responseType);

/* Many services come as an array of operations. This function generalizes the
 * processing of the operations. */
typedef void (*UA_ServiceOperation)(UA_Server *server, UA_Session *session,
                                    const void *context,
                                    const void *requestOperation,
                                    void *responseOperation);

UA_StatusCode
UA_Server_processServiceOperations(UA_Server *server, UA_Session *session,
                                   UA_ServiceOperation operationCallback,
                                   const void *context,
                                   const size_t *requestOperations,
                                   const UA_DataType *requestOperationsType,
                                   size_t *responseOperations,
                                   const UA_DataType *responseOperationsType)
    UA_FUNC_ATTR_WARN_UNUSED_RESULT;

/******************************************/
/* Internal function calls, without locks */
/******************************************/
UA_StatusCode
deleteNode(UA_Server *server, const UA_NodeId nodeId,
           UA_Boolean deleteReferences);

UA_StatusCode
addRef(UA_Server *server, const UA_NodeId sourceId,
       const UA_NodeId referenceTypeId, const UA_NodeId targetId,
       UA_Boolean forward);

UA_StatusCode
deleteReference(UA_Server *server, const UA_NodeId sourceNodeId,
                const UA_NodeId referenceTypeId, UA_Boolean isForward,
                const UA_ExpandedNodeId targetNodeId,
                UA_Boolean deleteBidirectional);

UA_StatusCode
addRefWithSession(UA_Server *server, UA_Session *session, const UA_NodeId *sourceId,
                  const UA_NodeId *referenceTypeId, const UA_NodeId *targetId,
                  UA_Boolean forward);

UA_StatusCode
setVariableNode_dataSource(UA_Server *server, const UA_NodeId nodeId,
                           const UA_DataSource dataSource);

UA_StatusCode
setVariableNode_valueCallback(UA_Server *server, const UA_NodeId nodeId,
                              const UA_ValueCallback callback);

UA_StatusCode
setMethodNode_callback(UA_Server *server, const UA_NodeId methodNodeId,
                       UA_MethodCallback methodCallback);

UA_StatusCode
setNodeTypeLifecycle(UA_Server *server, UA_NodeId nodeId,
                     UA_NodeTypeLifecycle lifecycle);

void
Operation_Write(UA_Server *server, UA_Session *session, void *context,
                const UA_WriteValue *wv, UA_StatusCode *result);

UA_StatusCode
writeAttribute(UA_Server *server, UA_Session *session,
               const UA_NodeId *nodeId, const UA_AttributeId attributeId,
               const void *attr, const UA_DataType *attr_type);

#define UA_WRITEATTRIBUTEFUNCS(ATTR, ATTRID, TYPE, TYPENAME)            \
    static UA_INLINE UA_StatusCode                                      \
    write##ATTR##Attribute(UA_Server *server, const UA_NodeId nodeId,   \
                           const TYPE value) {                          \
        return writeAttribute(server, &server->adminSession, &nodeId,   \
                              ATTRID, &value, &UA_TYPES[UA_TYPES_##TYPENAME]); \
    }                                                                   \
    static UA_INLINE UA_StatusCode                                      \
    write##ATTR##AttributeWithSession(UA_Server *server, UA_Session *session, \
                                      const UA_NodeId nodeId, const TYPE value) { \
        return writeAttribute(server, session, &nodeId, ATTRID, &value, \
                              &UA_TYPES[UA_TYPES_##TYPENAME]);          \
    }

static UA_INLINE UA_StatusCode
writeValueAttribute(UA_Server *server, const UA_NodeId nodeId,
                    const UA_Variant *value) {
    return writeAttribute(server, &server->adminSession, &nodeId,
                          UA_ATTRIBUTEID_VALUE, value, &UA_TYPES[UA_TYPES_VARIANT]);
}

UA_WRITEATTRIBUTEFUNCS(IsAbstract, UA_ATTRIBUTEID_ISABSTRACT, UA_Boolean, BOOLEAN)
UA_WRITEATTRIBUTEFUNCS(ValueRank, UA_ATTRIBUTEID_VALUERANK, UA_Int32, INT32)
UA_WRITEATTRIBUTEFUNCS(AccessLevel, UA_ATTRIBUTEID_ACCESSLEVEL, UA_Byte, BYTE)
UA_WRITEATTRIBUTEFUNCS(MinimumSamplingInterval, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL,
                       UA_Double, DOUBLE)

void
Operation_Read(UA_Server *server, UA_Session *session, UA_TimestampsToReturn *ttr,
               const UA_ReadValueId *rvi, UA_DataValue *dv);

UA_DataValue
readWithSession(UA_Server *server, UA_Session *session,
                const UA_ReadValueId *item,
                UA_TimestampsToReturn timestampsToReturn);

UA_StatusCode
readWithReadValue(UA_Server *server, const UA_NodeId *nodeId,
                  const UA_AttributeId attributeId, void *v);

UA_StatusCode
readObjectProperty(UA_Server *server, const UA_NodeId objectId,
                   const UA_QualifiedName propertyName,
                   UA_Variant *value);

UA_BrowsePathResult
translateBrowsePathToNodeIds(UA_Server *server, const UA_BrowsePath *browsePath);

#ifdef UA_ENABLE_SUBSCRIPTIONS

void monitoredItem_sampleCallback(UA_Server *server, UA_MonitoredItem *mon);

UA_Subscription *
getSubscriptionById(UA_Server *server, UA_UInt32 subscriptionId);

#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS

UA_StatusCode
createEvent(UA_Server *server, const UA_NodeId eventType,
            UA_NodeId *outNodeId);

UA_StatusCode
triggerEvent(UA_Server *server, const UA_NodeId eventNodeId,
             const UA_NodeId origin, UA_ByteString *outEventId,
             const UA_Boolean deleteEventNode);

/* Filters the given event with the given filter and writes the results into a
 * notification */
UA_StatusCode
filterEvent(UA_Server *server, UA_Session *session,
            const UA_NodeId *eventNode, UA_EventFilter *filter,
            UA_EventFieldList *efl, UA_EventFilterResult *result);

#endif /* UA_ENABLE_SUBSCRIPTIONS_EVENTS */

#endif /* UA_ENABLE_SUBSCRIPTIONS */

/* Returns a configured SecurityPolicy with encryption. Use Basic256Sha256 if
 * available. Otherwise use any encrypted SecurityPolicy. */
UA_SecurityPolicy *
getDefaultEncryptedSecurityPolicy(UA_Server *server);

UA_StatusCode
setCurrentEndPointsArray(UA_Server *server, const UA_String endpointURL,
                         UA_String *profileUris, size_t profileUrisSize,
                         UA_EndpointDescription **arr, size_t *arrSize);

UA_BrowsePathResult
browseSimplifiedBrowsePath(UA_Server *server, const UA_NodeId origin,
                           size_t browsePathSize, const UA_QualifiedName *browsePath);

UA_StatusCode
writeObjectProperty(UA_Server *server, const UA_NodeId objectId,
                    const UA_QualifiedName propertyName, const UA_Variant value);

UA_StatusCode
writeObjectProperty_scalar(UA_Server *server, const UA_NodeId objectId,
                                     const UA_QualifiedName propertyName,
                                     const void *value, const UA_DataType *type);

UA_StatusCode
getNodeContext(UA_Server *server, UA_NodeId nodeId, void **nodeContext);

UA_StatusCode
setNodeContext(UA_Server *server, UA_NodeId nodeId, void *nodeContext);

void
removeCallback(UA_Server *server, UA_UInt64 callbackId);

UA_StatusCode
changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId,
                               UA_Double interval_ms);

UA_StatusCode
addRepeatedCallback(UA_Server *server, UA_ServerCallback callback,
                    void *data, UA_Double interval_ms, UA_UInt64 *callbackId);

#ifdef UA_ENABLE_DISCOVERY
UA_ServerComponent *
UA_DiscoveryManager_new(UA_Server *server);
#endif

UA_ServerComponent *
UA_BinaryProtocolManager_new(UA_Server *server);

/***********/
/* RefTree */
/***********/

/* A RefTree is a sorted set of NodeIds that ensures we consider each node just
 * once. It holds a single array for both the ExpandedNodeIds and the entries of
 * a tree-structure for fast lookup. A single realloc operation (with some
 * pointer repairing) can be used to increase the capacity of the RefTree.
 *
 * When the RefTree is complete, the tree-part at the end of the targets array
 * can be ignored / cut away to use it as a simple ExpandedNodeId array.
 *
 * The layout of the targets array is as follows:
 *
 * | Targets [ExpandedNodeId, n times] | Tree [RefEntry, n times] | */

#define UA_REFTREE_INITIAL_SIZE 16

typedef struct RefEntry {
    ZIP_ENTRY(RefEntry) zipfields;
    const UA_ExpandedNodeId *target;
    UA_UInt32 targetHash; /* Hash of the target nodeid */
} RefEntry;

ZIP_HEAD(RefHead, RefEntry);
typedef struct RefHead RefHead;

typedef struct {
    UA_ExpandedNodeId *targets;
    RefHead head;
    size_t capacity; /* available space */
    size_t size;     /* used space */
} RefTree;

UA_StatusCode UA_FUNC_ATTR_WARN_UNUSED_RESULT
RefTree_init(RefTree *rt);

void RefTree_clear(RefTree *rt);

UA_StatusCode UA_FUNC_ATTR_WARN_UNUSED_RESULT
RefTree_addNodeId(RefTree *rt, const UA_NodeId *target, UA_Boolean *duplicate);

UA_Boolean
RefTree_contains(RefTree *rt, const UA_ExpandedNodeId *target);

UA_Boolean
RefTree_containsNodeId(RefTree *rt, const UA_NodeId *target);

/***************************************/
/* Check Information Model Consistency */
/***************************************/

/* Read a node attribute in the context of a "checked-out" node. So the
 * attribute will not be copied when possible. The variant then points into the
 * node and has UA_VARIANT_DATA_NODELETE set. */
void
ReadWithNode(const UA_Node *node, UA_Server *server, UA_Session *session,
             UA_TimestampsToReturn timestampsToReturn,
             const UA_ReadValueId *id, UA_DataValue *v);

UA_StatusCode
readValueAttribute(UA_Server *server, UA_Session *session,
                   const UA_VariableNode *vn, UA_DataValue *v);

/* Test whether the value matches a variable definition given by
 * - datatype
 * - valuerank
 * - array dimensions.
 * Sometimes it can be necessary to transform the content of the value, e.g.
 * byte array to bytestring or uint32 to some enum. If editableValue is non-NULL,
 * we try to create a matching variant that points to the original data.
 *
 * The reason is set whenever the return value is false */
UA_Boolean
compatibleValue(UA_Server *server, UA_Session *session, const UA_NodeId *targetDataTypeId,
                UA_Int32 targetValueRank, size_t targetArrayDimensionsSize,
                const UA_UInt32 *targetArrayDimensions, const UA_Variant *value,
                const UA_NumericRange *range, const char **reason);

/* Is the DataType compatible */
UA_Boolean
compatibleDataTypes(UA_Server *server, const UA_NodeId *dataType,
                    const UA_NodeId *constraintDataType);

/* Set to the target type if compatible */
void
adjustValueType(UA_Server *server, UA_Variant *value,
                const UA_NodeId *targetDataTypeId);

/* Is the Value compatible with the DataType? Can perform additional checks
 * compared to compatibleDataTypes. */
UA_Boolean
compatibleValueDataType(UA_Server *server, const UA_DataType *dataType,
                        const UA_NodeId *constraintDataType);


UA_Boolean
compatibleArrayDimensions(size_t constraintArrayDimensionsSize,
                          const UA_UInt32 *constraintArrayDimensions,
                          size_t testArrayDimensionsSize,
                          const UA_UInt32 *testArrayDimensions);

UA_Boolean
compatibleValueArrayDimensions(const UA_Variant *value, size_t targetArrayDimensionsSize,
                               const UA_UInt32 *targetArrayDimensions);

UA_Boolean
compatibleValueRankArrayDimensions(UA_Server *server, UA_Session *session,
                                   UA_Int32 valueRank, size_t arrayDimensionsSize);

UA_Boolean
compatibleValueRanks(UA_Int32 valueRank, UA_Int32 constraintValueRank);

struct BrowseOpts {
    UA_UInt32 maxReferences;
    UA_Boolean recursive;
};

void
Operation_Browse(UA_Server *server, UA_Session *session, const UA_UInt32 *maxrefs,
                 const UA_BrowseDescription *descr, UA_BrowseResult *result);

/************/
/* AddNodes */
/************/

UA_StatusCode
addNode(UA_Server *server, const UA_NodeClass nodeClass,
        const UA_NodeId requestedNewNodeId,
        const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
        const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
        const void *attr, const UA_DataType *attributeType,
        void *nodeContext, UA_NodeId *outNewNodeId);

UA_StatusCode
addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
              const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
              const UA_QualifiedName browseName,
              const UA_MethodAttributes *attr, UA_MethodCallback method,
              size_t inputArgumentsSize, const UA_Argument *inputArguments,
              const UA_NodeId inputArgumentsRequestedNewNodeId,
              UA_NodeId *inputArgumentsOutNewNodeId,
              size_t outputArgumentsSize, const UA_Argument *outputArguments,
              const UA_NodeId outputArgumentsRequestedNewNodeId,
              UA_NodeId *outputArgumentsOutNewNodeId,
              void *nodeContext, UA_NodeId *outNewNodeId);

UA_StatusCode
addNode_begin(UA_Server *server, const UA_NodeClass nodeClass,
              const UA_NodeId requestedNewNodeId, const UA_NodeId parentNodeId,
              const UA_NodeId referenceTypeId, const UA_QualifiedName browseName,
              const UA_NodeId typeDefinition, const void *attr,
              const UA_DataType *attributeType, void *nodeContext,
              UA_NodeId *outNewNodeId);

/* Creates a new node in the nodestore. */
UA_StatusCode
addNode_raw(UA_Server *server, UA_Session *session, void *nodeContext,
            const UA_AddNodesItem *item, UA_NodeId *outNewNodeId);

/* Check the reference to the parent node; Add references. */
UA_StatusCode
addNode_addRefs(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
                const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId,
                const UA_NodeId *typeDefinitionId);

/* Type-check type-definition; Run the constructors */
UA_StatusCode
addNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId);

/**********************/
/* Create Namespace 0 */
/**********************/

UA_StatusCode initNS0(UA_Server *server);

#ifdef UA_ENABLE_DIAGNOSTICS
void createSessionObject(UA_Server *server, UA_Session *session);

void createSubscriptionObject(UA_Server *server, UA_Session *session,
                              UA_Subscription *sub);

UA_StatusCode
readDiagnostics(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
                const UA_NodeId *nodeId, void *nodeContext, UA_Boolean sourceTimestamp,
                const UA_NumericRange *range, UA_DataValue *value);

UA_StatusCode
readSubscriptionDiagnosticsArray(UA_Server *server,
                                 const UA_NodeId *sessionId, void *sessionContext,
                                 const UA_NodeId *nodeId, void *nodeContext,
                                 UA_Boolean sourceTimestamp,
                                 const UA_NumericRange *range, UA_DataValue *value);

UA_StatusCode
readSessionDiagnosticsArray(UA_Server *server,
                            const UA_NodeId *sessionId, void *sessionContext,
                            const UA_NodeId *nodeId, void *nodeContext,
                            UA_Boolean sourceTimestamp,
                            const UA_NumericRange *range, UA_DataValue *value);

UA_StatusCode
readSessionSecurityDiagnostics(UA_Server *server,
                               const UA_NodeId *sessionId, void *sessionContext,
                               const UA_NodeId *nodeId, void *nodeContext,
                               UA_Boolean sourceTimestamp,
                               const UA_NumericRange *range, UA_DataValue *value);
#endif

/***************************/
/* Nodestore Access Macros */
/***************************/

#define UA_NODESTORE_NEW(server, nodeClass)                             \
    server->config.nodestore.newNode(server->config.nodestore.context, nodeClass)

#define UA_NODESTORE_DELETE(server, node)                               \
    server->config.nodestore.deleteNode(server->config.nodestore.context, node)

/* Get the node with all attributes and references */
static UA_INLINE const UA_Node *
UA_NODESTORE_GET(UA_Server *server, const UA_NodeId *nodeId) {
    return server->config.nodestore.
        getNode(server->config.nodestore.context, nodeId, UA_NODEATTRIBUTESMASK_ALL,
                UA_REFERENCETYPESET_ALL, UA_BROWSEDIRECTION_BOTH);
}

/* Get the node with all attributes and references */
static UA_INLINE const UA_Node *
UA_NODESTORE_GETFROMREF(UA_Server *server, UA_NodePointer target) {
    return server->config.nodestore.
        getNodeFromPtr(server->config.nodestore.context, target, UA_NODEATTRIBUTESMASK_ALL,
                       UA_REFERENCETYPESET_ALL, UA_BROWSEDIRECTION_BOTH);
}

#define UA_NODESTORE_GET_SELECTIVE(server, nodeid, attrMask, refs, refDirs) \
    server->config.nodestore.getNode(server->config.nodestore.context,      \
                                     nodeid, attrMask, refs, refDirs)

#define UA_NODESTORE_GETFROMREF_SELECTIVE(server, target, attrMask, refs, refDirs) \
    server->config.nodestore.getNodeFromPtr(server->config.nodestore.context,      \
                                            target, attrMask, refs, refDirs)

#define UA_NODESTORE_RELEASE(server, node)                              \
    server->config.nodestore.releaseNode(server->config.nodestore.context, node)

#define UA_NODESTORE_GETCOPY(server, nodeid, outnode)                      \
    server->config.nodestore.getNodeCopy(server->config.nodestore.context, \
                                         nodeid, outnode)

#define UA_NODESTORE_INSERT(server, node, addedNodeId)                    \
    server->config.nodestore.insertNode(server->config.nodestore.context, \
                                        node, addedNodeId)

#define UA_NODESTORE_REPLACE(server, node)                              \
    server->config.nodestore.replaceNode(server->config.nodestore.context, node)

#define UA_NODESTORE_REMOVE(server, nodeId)                             \
    server->config.nodestore.removeNode(server->config.nodestore.context, nodeId)

#define UA_NODESTORE_GETREFERENCETYPEID(server, index)                  \
    server->config.nodestore.getReferenceTypeId(server->config.nodestore.context, \
                                                index)

/* Handling of Locales */

/* Returns a shallow copy */
UA_LocalizedText
UA_Session_getNodeDisplayName(const UA_Session *session,
                              const UA_NodeHead *head);

UA_LocalizedText
UA_Session_getNodeDescription(const UA_Session *session,
                              const UA_NodeHead *head);

UA_StatusCode
UA_Node_insertOrUpdateDisplayName(UA_NodeHead *head,
                                  const UA_LocalizedText *value);

UA_StatusCode
UA_Node_insertOrUpdateDescription(UA_NodeHead *head,
                                  const UA_LocalizedText *value);

_UA_END_DECLS


/**** amalgamated original file "/src/client/ua_client_internal.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2015 (c) Oleksiy Vasylyev
 *    Copyright 2016-2017 (c) Florian Palm
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
 */


#define UA_INTERNAL


_UA_BEGIN_DECLS

/**************************/
/* Subscriptions Handling */
/**************************/

typedef struct UA_Client_NotificationsAckNumber {
    LIST_ENTRY(UA_Client_NotificationsAckNumber) listEntry;
    UA_SubscriptionAcknowledgement subAck;
} UA_Client_NotificationsAckNumber;

typedef struct UA_Client_MonitoredItem {
    ZIP_ENTRY(UA_Client_MonitoredItem) zipfields;
    UA_UInt32 monitoredItemId;
    UA_UInt32 clientHandle;
    void *context;
    UA_Client_DeleteMonitoredItemCallback deleteCallback;
    union {
        UA_Client_DataChangeNotificationCallback dataChangeCallback;
        UA_Client_EventNotificationCallback eventCallback;
    } handler;
    UA_Boolean isEventMonitoredItem; /* Otherwise a DataChange MoniitoredItem */
} UA_Client_MonitoredItem;

ZIP_HEAD(MonitorItemsTree, UA_Client_MonitoredItem);
typedef struct MonitorItemsTree MonitorItemsTree;

typedef struct UA_Client_Subscription {
    LIST_ENTRY(UA_Client_Subscription) listEntry;
    UA_UInt32 subscriptionId;
    void *context;
    UA_Double publishingInterval;
    UA_UInt32 maxKeepAliveCount;
    UA_Client_StatusChangeNotificationCallback statusChangeCallback;
    UA_Client_DeleteSubscriptionCallback deleteCallback;
    UA_UInt32 sequenceNumber;
    UA_DateTime lastActivity;
    MonitorItemsTree monitoredItems;
} UA_Client_Subscription;

void
__Client_Subscriptions_clean(UA_Client *client);

/* Exposed for fuzzing */
UA_StatusCode
__Client_preparePublishRequest(UA_Client *client, UA_PublishRequest *request);

void
__Client_Subscriptions_backgroundPublish(UA_Client *client);

void
__Client_Subscriptions_backgroundPublishInactivityCheck(UA_Client *client);

/**********/
/* Client */
/**********/

typedef struct AsyncServiceCall {
    LIST_ENTRY(AsyncServiceCall) pointers;
    UA_UInt32 requestId;     /* Unique id */
    UA_UInt32 requestHandle; /* Potentially non-unique if manually defined in
                              * the request header*/
    UA_ClientAsyncServiceCallback callback;
    const UA_DataType *responseType;
    void *userdata;
    UA_DateTime start;
    UA_UInt32 timeout;
    UA_Response *syncResponse; /* If non-null, then this is the synchronous
                                * response to be filled. Set back to null to
                                * indicate that the response was filled. */
} AsyncServiceCall;

typedef LIST_HEAD(UA_AsyncServiceList, AsyncServiceCall) UA_AsyncServiceList;

void
__Client_AsyncService_removeAll(UA_Client *client, UA_StatusCode statusCode);

typedef struct CustomCallback {
    UA_UInt32 callbackId;

    UA_ClientAsyncServiceCallback userCallback;
    void *userData;

    void *clientData;
} CustomCallback;

struct UA_Client {
    UA_ClientConfig config;

    /* Callback ID to remove it from the EventLoop */
    UA_UInt64 houseKeepingCallbackId;

    /* Overall connection status */
    UA_StatusCode connectStatus;

    /* Old status to notify only changes */
    UA_SecureChannelState oldChannelState;
    UA_SessionState oldSessionState;
    UA_StatusCode oldConnectStatus;

    UA_Boolean findServersHandshake;   /* Ongoing FindServers */
    UA_Boolean endpointsHandshake;     /* Ongoing GetEndpoints */

    /* The discoveryUrl can be different from the EndpointUrl in the client
     * configuration. The EndpointUrl is used to connect initially, then the
     * DiscoveryUrl is selected via FindServers. This triggers a reconnect if
     * EndpointUrl != DiscoveryUrl. */
    UA_String discoveryUrl;

    UA_ApplicationDescription serverDescription;

    UA_RuleHandling allowAllCertificateUris;

    /* SecureChannel */
    UA_SecureChannel channel;
    UA_UInt32 requestId; /* Unique, internally defined for each request */
    UA_DateTime nextChannelRenewal;

    /* Session */
    UA_SessionState sessionState;
    UA_NodeId authenticationToken;
    UA_UInt32 requestHandle; /* Unique handles >100,000 are generated if the
                              * request header contains a zero-handle. */
    UA_ByteString serverSessionNonce;
    UA_ByteString clientSessionNonce;

    /* Connectivity check */
    UA_DateTime lastConnectivityCheck;
    UA_Boolean pendingConnectivityCheck;

    /* Async Service */
    UA_AsyncServiceList asyncServiceCalls;

    /* Subscriptions */
    LIST_HEAD(, UA_Client_NotificationsAckNumber) pendingNotificationsAcks;
    LIST_HEAD(, UA_Client_Subscription) subscriptions;
    UA_UInt32 monitoredItemHandles;
    UA_UInt16 currentlyOutStandingPublishRequests;

    /* Internal locking for thread-safety. Methods starting with UA_Client_ that
     * are marked with UA_THREADSAFE take the lock. The lock is released before
     * dropping into the EventLoop and before calling user-defined callbacks.
     * That way user-defined callbacks can themselves call thread-safe client
     * methods. */
#if UA_MULTITHREADING >= 100
    UA_Lock clientMutex;
#endif
};

UA_StatusCode
__Client_AsyncService(UA_Client *client, const void *request,
                      const UA_DataType *requestType,
                      UA_ClientAsyncServiceCallback callback,
                      const UA_DataType *responseType,
                      void *userdata, UA_UInt32 *requestId);

void
__Client_Service(UA_Client *client, const void *request,
                 const UA_DataType *requestType, void *response,
                 const UA_DataType *responseType);

UA_StatusCode
__UA_Client_startup(UA_Client *client);

UA_StatusCode
__Client_renewSecureChannel(UA_Client *client);

UA_StatusCode
processServiceResponse(void *application, UA_SecureChannel *channel,
                       UA_MessageType messageType, UA_UInt32 requestId,
                       UA_ByteString *message);

UA_StatusCode connectInternal(UA_Client *client, UA_Boolean async);
UA_StatusCode connectSecureChannel(UA_Client *client, const char *endpointUrl);
UA_Boolean isFullyConnected(UA_Client *client);
void connectSync(UA_Client *client);
void notifyClientState(UA_Client *client);
void processRHEMessage(UA_Client *client, const UA_ByteString *chunk);
void processERRResponse(UA_Client *client, const UA_ByteString *chunk);
void processACKResponse(UA_Client *client, const UA_ByteString *chunk);
void processOPNResponse(UA_Client *client, const UA_ByteString *message);
void closeSecureChannel(UA_Client *client);
void cleanupSession(UA_Client *client);

void
Client_warnEndpointsResult(UA_Client *client,
                           const UA_GetEndpointsResponse *response,
                           const UA_String *endpointUrl);

_UA_END_DECLS


/**** amalgamated original file "/build/src_generated/open62541/namespace0_generated.h" ****/

/* WARNING: This is a generated file.
 * Any manual changes will be overwritten. */

#ifndef NAMESPACE0_GENERATED_H_
#define NAMESPACE0_GENERATED_H_


#ifdef UA_ENABLE_AMALGAMATION

/* The following declarations are in the open62541.c file so here's needed when compiling nodesets externally */

# ifndef UA_INTERNAL //this definition is needed to hide this code in the amalgamated .c file

typedef UA_StatusCode (*UA_exchangeEncodeBuffer)(void *handle, UA_Byte **bufPos,
                                                 const UA_Byte **bufEnd);

UA_StatusCode
UA_encodeBinary(const void *src, const UA_DataType *type,
                UA_Byte **bufPos, const UA_Byte **bufEnd,
                UA_exchangeEncodeBuffer exchangeCallback,
                void *exchangeHandle) UA_FUNC_ATTR_WARN_UNUSED_RESULT;

UA_StatusCode
UA_decodeBinary(const UA_ByteString *src, size_t *offset, void *dst,
                const UA_DataType *type, size_t customTypesSize,
                const UA_DataType *customTypes) UA_FUNC_ATTR_WARN_UNUSED_RESULT;

size_t
UA_calcSizeBinary(void *p, const UA_DataType *type);

const UA_DataType *
UA_findDataTypeByBinary(const UA_NodeId *typeId);

# endif // UA_INTERNAL

#else // UA_ENABLE_AMALGAMATION
#endif




_UA_BEGIN_DECLS

extern UA_StatusCode namespace0_generated(UA_Server *server);

_UA_END_DECLS

#endif /* NAMESPACE0_GENERATED_H_ */

/**** amalgamated original file "/src/util/ua_eventfilter_parser.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2023-2024 (c) Fraunhofer IOSB (Author: Florian Düwel)
 */



_UA_BEGIN_DECLS

typedef struct UA_Parsed_EventFilter {
    UA_EventFilter filter;
    UA_StatusCode status;
} UA_Parsed_EventFilter;

typedef enum OperandIdentifier {
    ELEMENTOPERAND,
    EXTENSIONOBJECT
} OperandIdentifier;

typedef struct UA_Parsed_Operand {
    OperandIdentifier identifier;
    union {
        char *element_ref;
        UA_ExtensionObject extension;
    } value;
} UA_Parsed_Operand;

typedef struct UA_Parsed_Operator {
    UA_FilterOperator filter;
    size_t nbr_children;
    UA_Parsed_Operand *children;
    size_t ContentFilterArrayPosition;
} UA_Parsed_Operator;

typedef enum ElementIdentifier {
    PARSEDOPERAND,
    parsed_operator
} ElementIdentifier;

typedef union UA_Parsed_Element {
    UA_Parsed_Operator oper;
    UA_Parsed_Operand operand;
} UA_Parsed_Element;

typedef struct Parsed_Element {
    char *ref;
    ElementIdentifier identifier;
    UA_Parsed_Element element;
    TAILQ_ENTRY(Parsed_Element) element_entries;
}UA_Parsed_Element_List;

typedef TAILQ_HEAD(parsed_filter_elements, Parsed_Element) parsed_filter_elements;

typedef struct UA_Element_List {
    parsed_filter_elements head;
}UA_Element_List;

typedef union UA_Local_Operand {
    UA_SimpleAttributeOperand sao;
    UA_NodeId id;
    char *str;
    UA_LiteralOperand literal;
} UA_Local_Operand;

typedef struct counters {
    size_t branch_element_number;
    size_t for_operator_reference;
    size_t operand_ctr;
}UA_Counters;

void save_string(char *str, char **local_str);
void create_next_operand_element(UA_Element_List *elements, UA_Parsed_Operand *operand, char *ref);
UA_StatusCode create_content_filter(UA_Element_List *elements, UA_ContentFilter *filter, char *first_element, UA_StatusCode status);
void add_new_operator(UA_Element_List *global, char *operator_ref, UA_Parsed_Operator *element);
UA_StatusCode append_select_clauses(UA_SimpleAttributeOperand **select_clauses, size_t *sao_size, UA_ExtensionObject *extension, UA_StatusCode status);
UA_StatusCode set_up_browsepath(UA_QualifiedName **q_name_list, size_t *size, char *str, UA_StatusCode status);
UA_StatusCode create_literal_operand(char *string, UA_LiteralOperand *lit, UA_StatusCode status);
UA_StatusCode create_nodeId_from_string(char *identifier, UA_NodeId *id, UA_StatusCode status);
void handle_elementoperand(UA_Parsed_Operand *operand, char *ref);
void handle_sao(UA_SimpleAttributeOperand *simple, UA_Parsed_Operand *operand);
void add_operand_from_branch(char **ref, size_t *operand_ctr, UA_Parsed_Operand *operand, UA_Element_List *global);
void set_up_variant_from_nodeId(UA_NodeId *id, UA_Variant *litvalue);
void handle_oftype_nodeId(UA_Parsed_Operator *element, UA_NodeId *id);
void handle_literal_operand(UA_Parsed_Operand *operand, UA_LiteralOperand *literalValue);
void set_up_typeid(UA_Local_Operand *operand);
void handle_between_operator(UA_Parsed_Operator *element, UA_Parsed_Operand *operand_1, UA_Parsed_Operand *operand_2, UA_Parsed_Operand *operand_3);
void handle_two_operands_operator(UA_Parsed_Operator *element, UA_Parsed_Operand *operand_1, UA_Parsed_Operand *operand_2, UA_FilterOperator *filter);
void init_item_list(UA_Element_List *global, UA_Counters *ctr);
void create_branch_element(UA_Element_List *global, size_t *branch_element_number, UA_FilterOperator filteroperator, char *ref_1, char *ref_2, char **ref);
void handle_for_operator(UA_Element_List *global, size_t *for_operator_reference, char **ref, UA_Parsed_Operator *element);
void change_element_reference(UA_Element_List *global, char *element_name, char *new_element_reference);
void add_in_list_children(UA_Element_List *global, UA_Parsed_Operand *oper);
void create_in_list_operator(UA_Element_List *global, UA_Parsed_Operand *oper, char *element_ref);
void append_string(char **string, char *yytext);
void set_up_variant_from_bool(char *yytext, UA_Variant *litvalue);
void set_up_variant_from_string(char *yytext, UA_Variant *litvalue);
void set_up_variant_from_bstring(char *yytext, UA_Variant *litvalue);
void set_up_variant_from_float(char *yytext, UA_Variant *litvalue);
void set_up_variant_from_double(char *yytext, UA_Variant *litvalue);
void set_up_variant_from_sbyte(char *yytext, UA_Variant *litvalue);
void set_up_variant_from_statuscode(char *yytext, UA_Variant *litvalue);
UA_StatusCode set_up_variant_from_expnodeid(char *yytext, UA_Variant *litvalue, UA_StatusCode status);
void set_up_variant_from_time(const char *yytext, UA_Variant *litvalue);
void set_up_variant_from_byte(char *yytext, UA_Variant *litvalue);
UA_StatusCode set_up_variant_from_qname(char *str, UA_Variant *litvalue, UA_StatusCode status);
void set_up_variant_from_guid(char *yytext, UA_Variant *litvalue);
void set_up_variant_from_int64(char *yytext, UA_Variant *litvalue);
void set_up_variant_from_localized(char *yytext, UA_Variant *litvalue);
void set_up_variant_from_uint16(char *yytext, UA_Variant *litvalue);
void set_up_variant_from_uint32(char *yytext, UA_Variant *litvalue);
void set_up_variant_from_uint64(char *yytext, UA_Variant *litvalue);
void set_up_variant_from_int16(char *yytext, UA_Variant *litvalue);
void set_up_variant_from_int32(char *yytext, UA_Variant *litvalue);
void create_nodeid_element(UA_Element_List *elements, UA_NodeId *id, char *ref);
void add_child_operands(UA_Parsed_Operand *operand_list, size_t operand_list_size, UA_Parsed_Operator *element, UA_FilterOperator oper);

_UA_END_DECLS


/**** amalgamated original file "/deps/cj5.h" ****/

// MIT License
//
// Copyright (c) 2020 Sepehr Taghdisian
// Copyright (c) 2022 Julius Pfrommer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// Very minimal single header JSON5 parser in C99, dervied from jsmn This is the
// modified version of jsmn library Thus main parts of the code is taken from
// jsmn project (https://github.com/zserge/jsmn).
//
// Compliance with JSON5:
//  [x] Object keys may be an ECMAScript 5.1 IdentifierName.
//  [x] Objects may have a single trailing comma.
//  [x] Strings may be single quoted.
//  [x] Strings may span multiple lines by escaping new line characters.
//  [x] Strings may include character escapes.
//  [x] Numbers may be hexadecimal.
//  [x] Numbers may have a leading or trailing decimal point.
//  [x] Numbers may be IEEE 754 positive infinity, negative infinity, and NaN.
//  [x] Numbers may begin with an explicit plus sign.
//  [x] Single and multi-line comments are allowed.
//  [x] Additional white space characters are allowed.
//
// Extensions to JSON5 (more permissive):
//  [x] Root objects can be an array or a primitive value
//  [x] The root object may omit the surrounding brackets
//  [x] Hash ('#') comments out until the end of the line.
//  [x] Strings may include unescaped utf8 bytes
//  [x] Optionally: Stop early when the first encountered JSON element (object,
//      array, value) has been successfully parsed. Do not return an error when
//      the input string was not processed to its full length. This allows the
//      detection of JSON sub-strings as part of an input "lexer".
//
// Usage:
//  The main function to parse json is `cj5_parse`. Like in jsmn, you provide
//  all tokens to be filled as an array and provide the maximum count The result
//  will be return in `cj5_result` struct, and `num_tokens` will represent the
//  actual token count that is parsed. In case of errors, cj_result.error will
//  be set to an error code Here's a quick example of the usage.
//  
//  #include "cj5.h"
//
//  cj5_token tokens[32];
//  cj5_result r = cj5_parse(g_json, (int)strlen(g_json), tokens, 32, NULL);
//  if(r.error != CJ5_ERROR_NONE) {
//      if(r.error == CJ5_ERROR_OVERFLOW) {
//          // you can use r.num_tokens to determine the actual token count and reparse
//          printf("Error: line: %d, col: %d\n", r.error_line, r.error_code);    
//      }
//  }

#ifndef __CJ5_H_
#define __CJ5_H_

#ifdef __cplusplus
# define CJ5_API extern "C"
#else
# define CJ5_API
#endif

#if !defined(_MSC_VER) || _MSC_VER >= 1800
# include <stdint.h>
# include <stdbool.h>
#else
# if !defined(__bool_true_false_are_defined)
#  define bool unsigned char
#  define true 1
#  define false 0
#  define __bool_true_false_are_defined
# endif
#endif

typedef enum cj5_token_type {
    CJ5_TOKEN_OBJECT = 0,
    CJ5_TOKEN_ARRAY,
    CJ5_TOKEN_NUMBER,
    CJ5_TOKEN_STRING,
    CJ5_TOKEN_BOOL,
    CJ5_TOKEN_NULL
} cj5_token_type;

typedef enum cj5_error_code {
    CJ5_ERROR_NONE = 0,
    CJ5_ERROR_INVALID,       // Invalid character/syntax
    CJ5_ERROR_INCOMPLETE,    // Incomplete JSON string
    CJ5_ERROR_OVERFLOW,      // Token buffer overflow (see cj5_result.num_tokens)
    CJ5_ERROR_NOTFOUND
} cj5_error_code;

typedef struct cj5_token {
    cj5_token_type type;
    unsigned int start;     // Start position in the json5 string
    unsigned int end;       // Position of the last character (included)
    unsigned int size;      // For objects and arrays the number of direct
                            // children. Note that this is *not* the number of
                            // overall (recursively nested) child tokens. For
                            // other tokens the length of token in the json
                            // encoding.
    unsigned int parent_id; // The root object is at position zero. It is an
                            // object that has itself as parent.
} cj5_token;

typedef struct cj5_result {
    cj5_error_code error;
    unsigned int error_line;
    unsigned int error_col;
    unsigned int num_tokens;
    const cj5_token* tokens;
    const char* json5;
} cj5_result;

typedef struct cj5_options {
    bool stop_early; /* Return when the first element was parsed. Otherwise an
                      * error is returned if the input was not fully
                      * processed. (default: false) */
} cj5_options;

/* Options can be NULL */
CJ5_API cj5_result
cj5_parse(const char *json5, unsigned int len,
          cj5_token *tokens, unsigned int max_tokens,
          cj5_options *options);

CJ5_API cj5_error_code
cj5_get_bool(const cj5_result *r, unsigned int tok_index, bool *out);

CJ5_API cj5_error_code
cj5_get_float(const cj5_result *r, unsigned int tok_index, double *out);

CJ5_API cj5_error_code
cj5_get_int(const cj5_result *r, unsigned int tok_index, int64_t *out);

CJ5_API cj5_error_code
cj5_get_uint(const cj5_result *r, unsigned int tok_index, uint64_t *out);

// Replaces escape characters, utf8 codepoints, etc.
// The buffer shall have a length of at least token->size + 1.
// Upon success, the length is written to buflen.
// The output string is terminated with \0.
CJ5_API cj5_error_code
cj5_get_str(const cj5_result *r, unsigned int tok_index,
            char *buf, unsigned int *buflen);

// Skips the (nested) structure that starts at the current index. The index is
// updated accordingly. Afterwards it points to the beginning of the following
// structure.
//
// Attention! The index can point to the first element after the token array if
// the root object is skipped.
//
// Cannot fail as long as the token array is the result of cj5_parse.
CJ5_API void
cj5_skip(const cj5_result *r, unsigned int *tok_index);

// Lookup of a key within an object (linear search).
// The current token (index) must point to an object.
// The error code CJ5_ERROR_NOTFOUND is returned if the key is not present.
// Otherwise the index is updated to point to the value associated with the key.
CJ5_API cj5_error_code
cj5_find(const cj5_result *r, unsigned int *tok_index, const char *key);

#endif /* __CJ5_H_ */

/**** amalgamated original file "/deps/parse_num.h" ****/

#ifndef ATOI_H
#define ATOI_H

#ifdef __cplusplus
extern "C" {
#endif

#if !defined(_MSC_VER) || _MSC_VER >= 1800
# include <stddef.h>
# include <stdint.h>
# include <stdbool.h> /* C99 Boolean */
#else
# if !defined(__bool_true_false_are_defined)
#  define bool unsigned char
#  define true 1
#  define false 0
#  define __bool_true_false_are_defined
# endif
#endif

/* Parse integer numbers. Returns the number of parsed digits until the first
 * non-valid character. Returns 0 upon failure.
 *
 * Hex numbers start with 0x.
 * Signed numbers may have a +/- prefix. */

size_t parseUInt64(const char *str, size_t size, uint64_t *result);
size_t parseInt64(const char *str, size_t size, int64_t *result);
size_t parseDouble(const char *str, size_t size, double *result);
    
#ifdef __cplusplus
}
#endif

#endif /* ATOI_H */


/**** amalgamated original file "/src/ua_types_encoding_json.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2018 (c) Fraunhofer IOSB (Author: Lukas Meling)
 */





_UA_BEGIN_DECLS

#define UA_JSON_MAXTOKENCOUNT 256
#define UA_JSON_ENCODING_MAX_RECURSION 100

typedef struct {
    uint8_t *pos;
    const uint8_t *end;

    uint16_t depth; /* How often did we en-/decoding recurse? */
    UA_Boolean commaNeeded[UA_JSON_ENCODING_MAX_RECURSION];
    UA_Boolean useReversible;
    UA_Boolean calcOnly; /* Only compute the length of the decoding */

    size_t namespacesSize;
    const UA_String *namespaces;

    size_t serverUrisSize;
    const UA_String *serverUris;

    UA_Boolean prettyPrint;
    UA_Boolean unquotedKeys;
    UA_Boolean stringNodeIds;
} CtxJson;

UA_StatusCode writeJsonObjStart(CtxJson *ctx);
UA_StatusCode writeJsonObjElm(CtxJson *ctx, const char *key,
                              const void *value, const UA_DataType *type);
UA_StatusCode writeJsonObjEnd(CtxJson *ctx);

UA_StatusCode writeJsonArrStart(CtxJson *ctx);
UA_StatusCode writeJsonArrElm(CtxJson *ctx, const void *value,
                              const UA_DataType *type);
UA_StatusCode writeJsonArrEnd(CtxJson *ctx);

UA_StatusCode writeJsonKey(CtxJson *ctx, const char* key);

/* Adds a comma if needed. Distinct elements go on a new line if pretty-printing
 * is enabled. */
UA_StatusCode writeJsonBeforeElement(CtxJson *ctx, UA_Boolean distinct);

typedef struct {
    const char *json5;
    cj5_token *tokens;
    size_t tokensSize;
    size_t index;
    UA_Byte depth;

    size_t namespacesSize;
    const UA_String *namespaces;

    size_t serverUrisSize;
    const UA_String *serverUris;

    const UA_DataTypeArray *customTypes;

    /* Additonal data for special cases such as networkmessage/datasetmessage
     * Currently only used for dataSetWriterIds */
    size_t numCustom;
    void * custom;
    size_t currentCustomIndex;
} ParseCtx;

typedef UA_StatusCode
(*encodeJsonSignature)(CtxJson *ctx, const void *src, const UA_DataType *type);

typedef UA_StatusCode
(*decodeJsonSignature)(ParseCtx *ctx, void *dst, const UA_DataType *type);

/* Map for decoding a Json Object. An array of this is passed to the
 * decodeFields function. If the key "fieldName" is found in the json object
 * (mark as found and) decode the value with the "function" and write result
 * into "fieldPointer" (destination). */
typedef struct {
    const char *fieldName;
    void *fieldPointer;
    decodeJsonSignature function;
    UA_Boolean found;
    const UA_DataType *type; /* Must be set for values that can be "null". If
                              * the function is not set, decode via the
                              * type->typeKind. */
} DecodeEntry;

UA_StatusCode decodeFields(ParseCtx *ctx, DecodeEntry *entries, size_t entryCount);

/* Expose the jump tables and some methods for PubSub JSON decoding */
extern const encodeJsonSignature encodeJsonJumpTable[UA_DATATYPEKINDS];
extern const decodeJsonSignature decodeJsonJumpTable[UA_DATATYPEKINDS];

UA_StatusCode lookAheadForKey(ParseCtx *ctx, const char *search, size_t *resultIndex);
UA_StatusCode tokenize(ParseCtx *ctx, const UA_ByteString *src, size_t tokensSize);

static UA_INLINE
cj5_token_type currentTokenType(const ParseCtx *ctx) {
    return ctx->tokens[ctx->index].type;
}

static UA_INLINE
size_t getTokenLength(const cj5_token *t) {
    return (size_t)(1u + t->end - t->start);
}

_UA_END_DECLS


/**** amalgamated original file "/src/server/ua_discovery.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014, 2017 (c) Florian Palm
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Julian Grothoff
 */



_UA_BEGIN_DECLS

#ifdef UA_ENABLE_DISCOVERY

typedef struct registeredServer {
    LIST_ENTRY(registeredServer) pointers;
    UA_RegisteredServer registeredServer;
    UA_DateTime lastSeen;
} registeredServer;

/* Store async register service calls. So we can cancel outstanding requests
 * during shutdown. */
typedef struct {
    UA_DelayedCallback cleanupCallback; /* delayed cleanup */
    UA_Server *server;
    UA_DiscoveryManager *dm;
    UA_Client *client;
    UA_String semaphoreFilePath;
    UA_Boolean unregister;

    UA_Boolean register2;
    UA_Boolean shutdown;
    UA_Boolean connectSuccess;
} asyncRegisterRequest;
#define UA_MAXREGISTERREQUESTS 4

#ifdef UA_ENABLE_DISCOVERY_MULTICAST

#define UA_MAXMDNSRECVSOCKETS 8

/**
 * TXT record:
 * [servername]-[hostname]._opcua-tcp._tcp.local. TXT path=/ caps=NA,DA,...
 *
 * A/AAAA record for all ip addresses:
 * [servername]-[hostname]._opcua-tcp._tcp.local. A [ip].
 * [hostname]. A [ip].
 */

typedef struct serverOnNetwork {
    LIST_ENTRY(serverOnNetwork) pointers;
    UA_ServerOnNetwork serverOnNetwork;
    UA_DateTime created;
    UA_DateTime lastSeen;
    UA_Boolean txtSet;
    UA_Boolean srvSet;
    char* pathTmp;
} serverOnNetwork;

#define SERVER_ON_NETWORK_HASH_SIZE 1000
typedef struct serverOnNetwork_hash_entry {
    serverOnNetwork *entry;
    struct serverOnNetwork_hash_entry* next;
} serverOnNetwork_hash_entry;

#endif

struct UA_DiscoveryManager {
    UA_ServerComponent sc;

    UA_UInt64 discoveryCallbackId;

    UA_Server *server; /* backpointer */

    /* Outstanding requests. So they can be cancelled during shutdown. */
    asyncRegisterRequest registerRequests[UA_MAXREGISTERREQUESTS];

    LIST_HEAD(, registeredServer) registeredServers;
    size_t registeredServersSize;
    UA_Server_registerServerCallback registerServerCallback;
    void* registerServerCallbackData;

# ifdef UA_ENABLE_DISCOVERY_MULTICAST
    mdns_daemon_t *mdnsDaemon;
    UA_ConnectionManager *cm;
    uintptr_t mdnsSendConnection;
    uintptr_t mdnsRecvConnections[UA_MAXMDNSRECVSOCKETS];
    size_t mdnsRecvConnectionsSize;
    UA_Boolean mdnsMainSrvAdded;

    /* Full Domain Name of server itself. Used to detect if received mDNS
     * message was from itself */
    UA_String selfFqdnMdnsRecord;

    LIST_HEAD(, serverOnNetwork) serverOnNetwork;

    UA_UInt32 serverOnNetworkRecordIdCounter;
    UA_DateTime serverOnNetworkRecordIdLastReset;

    /* hash mapping domain name to serverOnNetwork list entry */
    struct serverOnNetwork_hash_entry* serverOnNetworkHash[SERVER_ON_NETWORK_HASH_SIZE];

    UA_Server_serverOnNetworkCallback serverOnNetworkCallback;
    void *serverOnNetworkCallbackData;

    UA_UInt64 mdnsCallbackId;
# endif /* UA_ENABLE_DISCOVERY_MULTICAST */
};

void
UA_DiscoveryManager_setState(UA_Server *server,
                             UA_DiscoveryManager *dm,
                             UA_LifecycleState state);

#ifdef UA_ENABLE_DISCOVERY_MULTICAST

/* Sends out a new mDNS package for the given server data. This Method is
 * normally called when another server calls the RegisterServer Service on this
 * server. Then this server is responsible to send out a new mDNS package to
 * announce it.
 *
 * Additionally this method also adds the given server to the internal
 * serversOnNetwork list so that a client finds it when calling
 * FindServersOnNetwork. */
void
UA_Discovery_updateMdnsForDiscoveryUrl(UA_DiscoveryManager *dm, const UA_String *serverName,
                                       const UA_MdnsDiscoveryConfiguration *mdnsConfig,
                                       const UA_String *discoveryUrl, UA_Boolean isOnline,
                                       UA_Boolean updateTxt);

void UA_DiscoveryManager_startMulticast(UA_DiscoveryManager *dm);
void UA_DiscoveryManager_stopMulticast(UA_DiscoveryManager *dm);
void UA_DiscoveryManager_sendMulticastMessages(UA_DiscoveryManager *dm);

UA_StatusCode
UA_DiscoveryManager_addEntryToServersOnNetwork(UA_DiscoveryManager *dm,
                                               const char *fqdnMdnsRecord,
                                               const char *serverName,
                                               size_t serverNameLen,
                                               struct serverOnNetwork **addedEntry);

UA_StatusCode
UA_DiscoveryManager_removeEntryFromServersOnNetwork(UA_DiscoveryManager *dm,
                                                    const char *fqdnMdnsRecord,
                                                    const char *serverName,
                                                    size_t serverNameLen);


void mdns_record_received(const struct resource *r, void *data);

void mdns_create_txt(UA_DiscoveryManager *dm, const char *fullServiceDomain,
                     const char *path, const UA_String *capabilites,
                     const size_t capabilitiesSize,
                     void (*conflict)(char *host, int type, void *arg));

void mdns_set_address_record(UA_DiscoveryManager *dm, const char *fullServiceDomain,
                             const char *localDomain);

mdns_record_t *
mdns_find_record(mdns_daemon_t *mdnsDaemon, unsigned short type,
                 const char *host, const char *rdname);

#endif /* UA_ENABLE_DISCOVERY_MULTICAST */

#endif /* UA_ENABLE_DISCOVERY */

_UA_END_DECLS


/**** amalgamated original file "/src/ua_types.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2020 (c) Fraunhofer IOSB (Author: Andreas Ebner)
 *    Copyright 2014-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014, 2016-2017 (c) Florian Palm
 *    Copyright 2014-2016 (c) Sten Grüner
 *    Copyright 2014 (c) Leon Urbas
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015 (c) Markus Graube
 *    Copyright 2015 (c) Reza Ebrahimi
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2016 (c) Lorenz Haas
 */



#define UA_MAX_ARRAY_DIMS 100 /* Max dimensions of an array */

/* Datatype Handling
 * -----------------
 * This file contains handling functions for the builtin types and functions
 * handling of structured types and arrays. These need type descriptions in a
 * UA_DataType structure. The UA_DataType structures as well as all non-builtin
 * datatypes are autogenerated. */

/* Global definition of NULL type instances. These are always zeroed out, as
 * mandated by the C/C++ standard for global values with no initializer. */
const UA_String UA_STRING_NULL = {0, NULL};
const UA_ByteString UA_BYTESTRING_NULL = {0, NULL};
const UA_Guid UA_GUID_NULL = {0, 0, 0, {0,0,0,0,0,0,0,0}};
const UA_NodeId UA_NODEID_NULL = {0, UA_NODEIDTYPE_NUMERIC, {0}};
const UA_ExpandedNodeId UA_EXPANDEDNODEID_NULL = {{0, UA_NODEIDTYPE_NUMERIC, {0}}, {0, NULL}, 0};

typedef UA_StatusCode
(*UA_copySignature)(const void *src, void *dst, const UA_DataType *type);
extern const UA_copySignature copyJumpTable[UA_DATATYPEKINDS];

typedef void (*UA_clearSignature)(void *p, const UA_DataType *type);
extern const UA_clearSignature clearJumpTable[UA_DATATYPEKINDS];

typedef UA_Order
(*UA_orderSignature)(const void *p1, const void *p2, const UA_DataType *type);
extern const UA_orderSignature orderJumpTable[UA_DATATYPEKINDS];

static UA_Order
nodeIdOrder(const UA_NodeId *p1, const UA_NodeId *p2, const UA_DataType *_);
static UA_Order
expandedNodeIdOrder(const UA_ExpandedNodeId *p1, const UA_ExpandedNodeId *p2,
                    const UA_DataType *_);
static UA_Order
guidOrder(const UA_Guid *p1, const UA_Guid *p2, const UA_DataType *_);

const UA_DataType *
UA_findDataTypeWithCustom(const UA_NodeId *typeId,
                          const UA_DataTypeArray *customTypes) {
    /* Always look in built-in types first (may contain data types from all
     * namespaces).
     *
     * TODO: The standard-defined types are ordered. See if binary search is
     * more efficient. */
    for(size_t i = 0; i < UA_TYPES_COUNT; ++i) {
        if(nodeIdOrder(&UA_TYPES[i].typeId, typeId, NULL) == UA_ORDER_EQ)
            return &UA_TYPES[i];
    }

    /* Search in the customTypes */
    while(customTypes) {
        for(size_t i = 0; i < customTypes->typesSize; ++i) {
            if(nodeIdOrder(&customTypes->types[i].typeId, typeId, NULL) == UA_ORDER_EQ)
                return &customTypes->types[i];
        }
        customTypes = customTypes->next;
    }

    return NULL;
}

const UA_DataType *
UA_findDataType(const UA_NodeId *typeId) {
    return UA_findDataTypeWithCustom(typeId, NULL);
}

void
UA_cleanupDataTypeWithCustom(const UA_DataTypeArray *customTypes) {
    while (customTypes) {
        const UA_DataTypeArray *next = customTypes->next;
        if (customTypes->cleanup) {
            for(size_t i = 0; i < customTypes->typesSize; ++i) {
                const UA_DataType *type = &customTypes->types[i];
#ifdef UA_ENABLE_TYPEDESCRIPTION
                UA_free((void*)(uintptr_t)type->typeName);
                for(size_t j = 0; j < type->membersSize; ++j) {
                    const UA_DataTypeMember *m = &type->members[j];
                    UA_free((void*)(uintptr_t)m->memberName);
                }
#endif
                UA_free((void*)type->members);
            }
            UA_free((void*)(uintptr_t)customTypes->types);
            UA_free((void*)(uintptr_t)customTypes);
        }
        customTypes = next;
    }
}

/*****************/
/* Builtin Types */
/*****************/

UA_String
UA_String_fromChars(const char *src) {
    UA_String s; s.length = 0; s.data = NULL;
    if(!src)
        return s;
    s.length = strlen(src);
    if(s.length > 0) {
        s.data = (u8*)UA_malloc(s.length);
        if(UA_UNLIKELY(!s.data)) {
            s.length = 0;
            return s;
        }
        memcpy(s.data, src, s.length);
    } else {
        s.data = (u8*)UA_EMPTY_ARRAY_SENTINEL;
    }
    return s;
}

UA_Boolean
UA_String_isEmpty(const UA_String *s) {
    return (s->length == 0 || s->data == NULL);
}

static UA_Byte
lowercase(UA_Byte c) {
	if(((int)c) - 'A' < 26) return c | 32;
	return c;
}

static int
casecmp(const UA_Byte *l, const UA_Byte *r, size_t n) {
	if(!n--) return 0;
	for(; *l && *r && n && (*l == *r || lowercase(*l) == lowercase(*r)); l++, r++, n--);
	return lowercase(*l) - lowercase(*r);
}

/* Do not expose UA_String_equal_ignorecase to public API as it currently only handles
 * ASCII strings, and not UTF8! */
UA_Boolean
UA_String_equal_ignorecase(const UA_String *s1, const UA_String *s2) {
    if(s1->length != s2->length)
        return false;
    if(s1->length == 0)
        return true;
    if(s2->data == NULL)
        return false;

    return casecmp(s1->data, s2->data, s1->length) == 0;
}

static UA_StatusCode
String_copy(UA_String const *src, UA_String *dst, const UA_DataType *_) {
    UA_StatusCode res =
        UA_Array_copy(src->data, src->length, (void**)&dst->data,
                      &UA_TYPES[UA_TYPES_BYTE]);
    if(res == UA_STATUSCODE_GOOD)
        dst->length = src->length;
    return res;
}

static void
String_clear(UA_String *s, const UA_DataType *_) {
    UA_Array_delete(s->data, s->length, &UA_TYPES[UA_TYPES_BYTE]);
}

/* QualifiedName */
static UA_StatusCode
QualifiedName_copy(const UA_QualifiedName *src, UA_QualifiedName *dst,
                   const UA_DataType *_) {
    dst->namespaceIndex = src->namespaceIndex;
    return String_copy(&src->name, &dst->name, NULL);
}

static void
QualifiedName_clear(UA_QualifiedName *p, const UA_DataType *_) {
    String_clear(&p->name, NULL);
}

u32
UA_QualifiedName_hash(const UA_QualifiedName *q) {
    return UA_ByteString_hash(q->namespaceIndex,
                              q->name.data, q->name.length);
}

/* DateTime */
UA_DateTimeStruct
UA_DateTime_toStruct(UA_DateTime t) {
    /* Divide, then subtract -> avoid underflow. Also, negative numbers are
     * rounded up, not down. */
    long long secSinceUnixEpoch = (long long)(t / UA_DATETIME_SEC)
        - (long long)(UA_DATETIME_UNIX_EPOCH / UA_DATETIME_SEC);

    /* Negative fractions of a second? Remove one full second from the epoch
     * distance and allow only a positive fraction. */
    UA_DateTime frac = t % UA_DATETIME_SEC;
    if(frac < 0) {
        secSinceUnixEpoch--;
        frac += UA_DATETIME_SEC;
    }

    struct mytm ts;
    memset(&ts, 0, sizeof(struct mytm));
    __secs_to_tm(secSinceUnixEpoch, &ts);

    UA_DateTimeStruct dateTimeStruct;
    dateTimeStruct.year   = (i16)(ts.tm_year + 1900);
    dateTimeStruct.month  = (u16)(ts.tm_mon + 1);
    dateTimeStruct.day    = (u16)ts.tm_mday;
    dateTimeStruct.hour   = (u16)ts.tm_hour;
    dateTimeStruct.min    = (u16)ts.tm_min;
    dateTimeStruct.sec    = (u16)ts.tm_sec;
    dateTimeStruct.milliSec = (u16)((frac % 10000000) / 10000);
    dateTimeStruct.microSec = (u16)((frac % 10000) / 10);
    dateTimeStruct.nanoSec  = (u16)((frac % 10) * 100);
    return dateTimeStruct;
}

UA_DateTime
UA_DateTime_fromStruct(UA_DateTimeStruct ts) {
    /* Seconds since the Unix epoch */
    struct mytm tm;
    memset(&tm, 0, sizeof(struct mytm));
    tm.tm_year = ts.year - 1900;
    tm.tm_mon = ts.month - 1;
    tm.tm_mday = ts.day;
    tm.tm_hour = ts.hour;
    tm.tm_min = ts.min;
    tm.tm_sec = ts.sec;
    long long sec_epoch = __tm_to_secs(&tm);

    UA_DateTime t = UA_DATETIME_UNIX_EPOCH;
    t += sec_epoch * UA_DATETIME_SEC;
    t += ts.milliSec * UA_DATETIME_MSEC;
    t += ts.microSec * UA_DATETIME_USEC;
    t += ts.nanoSec / 100;
    return t;
}

/* Guid */
static const u8 hexmapLower[16] =
    {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
static const u8 hexmapUpper[16] =
    {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

void
UA_Guid_to_hex(const UA_Guid *guid, u8* out, UA_Boolean lower) {
    const u8 *hexmap = (lower) ? hexmapLower : hexmapUpper;
    size_t i = 0, j = 28;
    for(; i<8;i++,j-=4)         /* pos 0-7, 4byte, (a) */
        out[i] = hexmap[(guid->data1 >> j) & 0x0Fu];
    out[i++] = '-';             /* pos 8 */
    for(j=12; i<13;i++,j-=4)    /* pos 9-12, 2byte, (b) */
        out[i] = hexmap[(uint16_t)(guid->data2 >> j) & 0x0Fu];
    out[i++] = '-';             /* pos 13 */
    for(j=12; i<18;i++,j-=4)    /* pos 14-17, 2byte (c) */
        out[i] = hexmap[(uint16_t)(guid->data3 >> j) & 0x0Fu];
    out[i++] = '-';              /* pos 18 */
    for(j=0;i<23;i+=2,j++) {     /* pos 19-22, 2byte (d) */
        out[i] = hexmap[(guid->data4[j] & 0xF0u) >> 4u];
        out[i+1] = hexmap[guid->data4[j] & 0x0Fu];
    }
    out[i++] = '-';              /* pos 23 */
    for(j=2; i<36;i+=2,j++) {    /* pos 24-35, 6byte (e) */
        out[i] = hexmap[(guid->data4[j] & 0xF0u) >> 4u];
        out[i+1] = hexmap[guid->data4[j] & 0x0Fu];
    }
}

UA_StatusCode
UA_Guid_print(const UA_Guid *guid, UA_String *output) {
    if(output->length == 0) {
        UA_StatusCode res =
            UA_ByteString_allocBuffer((UA_ByteString*)output, 36);
        if(res != UA_STATUSCODE_GOOD)
            return res;
    } else {
        if(output->length < 36)
            return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
        output->length = 36;
    }
    UA_Guid_to_hex(guid, output->data, true);
    return UA_STATUSCODE_GOOD;
}

/* ByteString */
UA_StatusCode
UA_ByteString_allocBuffer(UA_ByteString *bs, size_t length) {
    UA_ByteString_init(bs);
    if(length == 0)
        return UA_STATUSCODE_GOOD;
    bs->data = (u8*)UA_malloc(length);
    if(UA_UNLIKELY(!bs->data))
        return UA_STATUSCODE_BADOUTOFMEMORY;
    bs->length = length;
    return UA_STATUSCODE_GOOD;
}

/* NodeId */
static void
NodeId_clear(UA_NodeId *p, const UA_DataType *_) {
    switch(p->identifierType) {
    case UA_NODEIDTYPE_STRING:
    case UA_NODEIDTYPE_BYTESTRING:
        String_clear(&p->identifier.string, NULL);
        break;
    default: break;
    }
}

static UA_StatusCode
NodeId_copy(UA_NodeId const *src, UA_NodeId *dst, const UA_DataType *_) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    switch(src->identifierType) {
    case UA_NODEIDTYPE_NUMERIC:
        *dst = *src;
        return UA_STATUSCODE_GOOD;
    case UA_NODEIDTYPE_STRING:
    case UA_NODEIDTYPE_BYTESTRING:
        retval |= String_copy(&src->identifier.string,
                              &dst->identifier.string, NULL);
        break;
    case UA_NODEIDTYPE_GUID:
        dst->identifier.guid = src->identifier.guid;
        break;
    default:
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    dst->namespaceIndex = src->namespaceIndex;
    dst->identifierType = src->identifierType;
    return retval;
}

UA_Boolean
UA_NodeId_isNull(const UA_NodeId *p) {
    if(p->namespaceIndex != 0)
        return false;
    switch (p->identifierType) {
    case UA_NODEIDTYPE_NUMERIC:
        return (p->identifier.numeric == 0);
    case UA_NODEIDTYPE_STRING:
    case UA_NODEIDTYPE_BYTESTRING:
        return (p->identifier.string.length == 0); /* Null and empty string */
    case UA_NODEIDTYPE_GUID:
        return (guidOrder(&p->identifier.guid, &UA_GUID_NULL, NULL) == UA_ORDER_EQ);
    }
    return false;
}

UA_Order
UA_NodeId_order(const UA_NodeId *n1, const UA_NodeId *n2) {
    return nodeIdOrder(n1, n2, NULL);
}

/* sdbm-hash (http://www.cse.yorku.ca/~oz/hash.html) */
u32
UA_ByteString_hash(u32 initialHashValue,
                   const u8 *data, size_t size) {
    u32 h = initialHashValue;
    for(size_t i = 0; i < size; i++)
        h = data[i] + (h << 6) + (h << 16) - h;
    return h;
}

u32
UA_NodeId_hash(const UA_NodeId *n) {
    switch(n->identifierType) {
    case UA_NODEIDTYPE_NUMERIC:
    default:
        return UA_ByteString_hash(n->namespaceIndex, (const u8*)&n->identifier.numeric,
                                  sizeof(UA_UInt32));
    case UA_NODEIDTYPE_STRING:
    case UA_NODEIDTYPE_BYTESTRING:
        return UA_ByteString_hash(n->namespaceIndex, n->identifier.string.data,
                                  n->identifier.string.length);
    case UA_NODEIDTYPE_GUID:
        return UA_ByteString_hash(n->namespaceIndex, (const u8*)&n->identifier.guid,
                                  sizeof(UA_Guid));
    }
}

/* Computes length for the encoding size and pre-encodes the numeric values */
static size_t
nodeIdSize(const UA_NodeId *id,
           char *nsStr, size_t *nsStrSize,
           char *numIdStr, size_t *numIdStrSize) {
    /* Namespace length */
    size_t len = 0;
    if(id->namespaceIndex != 0) {
        len += 4; /* ns=; */
        *nsStrSize = itoaUnsigned(id->namespaceIndex, nsStr, 10);
        len += *nsStrSize;
    }

    switch (id->identifierType) {
    case UA_NODEIDTYPE_NUMERIC:
        *numIdStrSize = itoaUnsigned(id->identifier.numeric, numIdStr, 10);
        len += 2 + *numIdStrSize;
        break;
    case UA_NODEIDTYPE_STRING:
        len += 2 + id->identifier.string.length;
        break;
    case UA_NODEIDTYPE_GUID:
        len += 2 + 36;
        break;
    case UA_NODEIDTYPE_BYTESTRING:
        len += 2 + (4*((id->identifier.byteString.length + 2) / 3));
        break;
    default:
        len = 0;
    }
    return len;
}

#define PRINT_NODEID                                           \
    /* Encode the namespace */                                 \
    if(id->namespaceIndex != 0) {                              \
        memcpy(pos, "ns=", 3);                                 \
        pos += 3;                                              \
        memcpy(pos, nsStr, nsStrSize);                         \
        pos += nsStrSize;                                      \
        *pos++ = ';';                                          \
    }                                                          \
                                                               \
    /* Encode the identifier */                                \
    switch(id->identifierType) {                               \
    case UA_NODEIDTYPE_NUMERIC:                                \
        memcpy(pos, "i=", 2);                                  \
        pos += 2;                                              \
        memcpy(pos, numIdStr, numIdStrSize);                   \
        pos += numIdStrSize;                                   \
        break;                                                 \
    case UA_NODEIDTYPE_STRING:                                 \
        memcpy(pos, "s=", 2);                                  \
        pos += 2;                                              \
        memcpy(pos, id->identifier.string.data,                \
               id->identifier.string.length);                  \
        pos += id->identifier.string.length;                   \
        break;                                                 \
    case UA_NODEIDTYPE_GUID:                                   \
        memcpy(pos, "g=", 2);                                  \
        pos += 2;                                              \
        UA_Guid_to_hex(&id->identifier.guid,                   \
                       (unsigned char*)pos, true);             \
        pos += 36;                                             \
        break;                                                 \
    case UA_NODEIDTYPE_BYTESTRING:                             \
        memcpy(pos, "b=", 2);                                  \
        pos += 2;                                              \
        pos += UA_base64_buf(id->identifier.byteString.data,   \
                             id->identifier.byteString.length, \
                             (unsigned char*)pos);             \
        break;                                                 \
    }                                                          \
    do { } while(false)

UA_StatusCode
UA_NodeId_print(const UA_NodeId *id, UA_String *output) {
    /* Compute the string length */
    char nsStr[6];
    size_t nsStrSize = 0;
    char numIdStr[11];
    size_t numIdStrSize = 0;
    size_t idLen = nodeIdSize(id, nsStr, &nsStrSize, numIdStr, &numIdStrSize);
    if(idLen == 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Allocate memory if required */
    if(output->length == 0) {
        UA_StatusCode res = UA_ByteString_allocBuffer((UA_ByteString*)output, idLen);
        if(res != UA_STATUSCODE_GOOD)
            return res;
    } else {
        if(output->length < idLen)
            return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
        output->length = idLen;
    }

    /* Print the NodeId */
    char *pos = (char*)output->data;
    PRINT_NODEID;

    UA_assert(output->length == (size_t)((UA_Byte*)pos - output->data));
    return UA_STATUSCODE_GOOD;
}

/* ExpandedNodeId */
static void
ExpandedNodeId_clear(UA_ExpandedNodeId *p, const UA_DataType *_) {
    NodeId_clear(&p->nodeId, _);
    String_clear(&p->namespaceUri, NULL);
}

static UA_StatusCode
ExpandedNodeId_copy(UA_ExpandedNodeId const *src, UA_ExpandedNodeId *dst,
                    const UA_DataType *_) {
    UA_StatusCode retval = NodeId_copy(&src->nodeId, &dst->nodeId, NULL);
    retval |= String_copy(&src->namespaceUri, &dst->namespaceUri, NULL);
    dst->serverIndex = src->serverIndex;
    return retval;
}

UA_Boolean
UA_ExpandedNodeId_isLocal(const UA_ExpandedNodeId *n) {
    return (n->namespaceUri.length == 0 && n->serverIndex == 0);
}

UA_Order
UA_ExpandedNodeId_order(const UA_ExpandedNodeId *n1,
                        const UA_ExpandedNodeId *n2) {
    return expandedNodeIdOrder(n1, n2, NULL);
}

u32
UA_ExpandedNodeId_hash(const UA_ExpandedNodeId *n) {
    u32 h = UA_NodeId_hash(&n->nodeId);
    if(n->serverIndex != 0)
        h = UA_ByteString_hash(h, (const UA_Byte*)&n->serverIndex, 4);
    if(n->namespaceUri.length != 0)
        h = UA_ByteString_hash(h, n->namespaceUri.data, n->namespaceUri.length);
    return h;
}

UA_StatusCode
UA_ExpandedNodeId_print(const UA_ExpandedNodeId *eid, UA_String *output) {
    /* Don't print the namespace-index if a NamespaceUri is set */
    UA_NodeId stackid = eid->nodeId;
    UA_NodeId *id = &stackid; /* for the print-macro below */
    if(eid->namespaceUri.data != NULL)
        id->namespaceIndex = 0;

    /* Compute the string length */
    char nsStr[6];
    size_t nsStrSize = 0;
    char numIdStr[11];
    size_t numIdStrSize = 0;
    size_t idLen = nodeIdSize(id, nsStr, &nsStrSize, numIdStr, &numIdStrSize);
    if(idLen == 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    char srvIdxStr[11];
    size_t srvIdxSize = 0;
    if(eid->serverIndex != 0) {
        idLen += 5; /* svr=; */
        srvIdxSize = itoaUnsigned(eid->serverIndex, srvIdxStr, 10);
        idLen += srvIdxSize;
    }

    if(eid->namespaceUri.data != NULL) {
        idLen += 5; /* nsu=; */
        idLen += eid->namespaceUri.length;
    }

    /* Allocate memory if required */
    if(output->length == 0) {
        UA_StatusCode res = UA_ByteString_allocBuffer((UA_ByteString*)output, idLen);
        if(res != UA_STATUSCODE_GOOD)
            return res;
    } else {
        if(output->length < idLen)
            return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
        output->length = idLen;
    }

    /* Encode the ServerIndex */
    char *pos = (char*)output->data;
    if(eid->serverIndex != 0) {
        memcpy(pos, "svr=", 4);
        pos += 4;
        memcpy(pos, srvIdxStr, srvIdxSize);
        pos += srvIdxSize;
        *pos++ = ';';
    }

    /* Encode the NamespaceUri */
    if(eid->namespaceUri.data != NULL) {
        memcpy(pos, "nsu=", 4);
        pos += 4;
        memcpy(pos, eid->namespaceUri.data, eid->namespaceUri.length);
        pos += eid->namespaceUri.length;
        *pos++ = ';';
    }

    /* Print the NodeId */
    PRINT_NODEID;

    UA_assert(output->length == (size_t)((UA_Byte*)pos - output->data));
    return UA_STATUSCODE_GOOD;
}

/* ExtensionObject */
static void
ExtensionObject_clear(UA_ExtensionObject *p, const UA_DataType *_) {
    switch(p->encoding) {
    case UA_EXTENSIONOBJECT_ENCODED_NOBODY:
    case UA_EXTENSIONOBJECT_ENCODED_BYTESTRING:
    case UA_EXTENSIONOBJECT_ENCODED_XML:
        NodeId_clear(&p->content.encoded.typeId, NULL);
        String_clear(&p->content.encoded.body, NULL);
        break;
    case UA_EXTENSIONOBJECT_DECODED:
        if(p->content.decoded.data)
            UA_delete(p->content.decoded.data, p->content.decoded.type);
        break;
    default:
        break;
    }
}

static UA_StatusCode
ExtensionObject_copy(UA_ExtensionObject const *src, UA_ExtensionObject *dst,
                     const UA_DataType *_) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    switch(src->encoding) {
    case UA_EXTENSIONOBJECT_ENCODED_NOBODY:
    case UA_EXTENSIONOBJECT_ENCODED_BYTESTRING:
    case UA_EXTENSIONOBJECT_ENCODED_XML:
        dst->encoding = src->encoding;
        retval = NodeId_copy(&src->content.encoded.typeId,
                             &dst->content.encoded.typeId, NULL);
        /* ByteString -> copy as string */
        retval |= String_copy(&src->content.encoded.body,
                              &dst->content.encoded.body, NULL);
        break;
    case UA_EXTENSIONOBJECT_DECODED:
    case UA_EXTENSIONOBJECT_DECODED_NODELETE:
        if(!src->content.decoded.type || !src->content.decoded.data)
            return UA_STATUSCODE_BADINTERNALERROR;
        dst->encoding = UA_EXTENSIONOBJECT_DECODED;
        dst->content.decoded.type = src->content.decoded.type;
        retval = UA_Array_copy(src->content.decoded.data, 1,
            &dst->content.decoded.data, src->content.decoded.type);
        break;
    default:
        break;
    }
    return retval;
}

void
UA_ExtensionObject_setValue(UA_ExtensionObject *eo,
                            void * UA_RESTRICT p,
                            const UA_DataType *type) {
    UA_ExtensionObject_init(eo);
    eo->content.decoded.data = p;
    eo->content.decoded.type = type;
    eo->encoding = UA_EXTENSIONOBJECT_DECODED;
}

void
UA_ExtensionObject_setValueNoDelete(UA_ExtensionObject *eo,
                                    void * UA_RESTRICT p,
                                    const UA_DataType *type) {
    UA_ExtensionObject_init(eo);
    eo->content.decoded.data = p;
    eo->content.decoded.type = type;
    eo->encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
}

UA_StatusCode
UA_ExtensionObject_setValueCopy(UA_ExtensionObject *eo,
                                void * UA_RESTRICT p,
                                const UA_DataType *type) {
    UA_ExtensionObject_init(eo);

    /* Make a copy of the value */
    void *val = UA_malloc(type->memSize);
    if(UA_UNLIKELY(!val))
        return UA_STATUSCODE_BADOUTOFMEMORY;
    UA_StatusCode res = UA_copy(p, val, type);
    if(UA_UNLIKELY(res != UA_STATUSCODE_GOOD)) {
        UA_free(val);
        return res;
    }

    /* Set the ExtensionObject */
    eo->content.decoded.data = val;
    eo->content.decoded.type = type;
    eo->encoding = UA_EXTENSIONOBJECT_DECODED;
    return UA_STATUSCODE_GOOD;
}

/* Variant */
static void
Variant_clear(UA_Variant *p, const UA_DataType *_) {
    /* The content is "borrowed" */
    if(p->storageType == UA_VARIANT_DATA_NODELETE)
        return;

    /* Delete the value */
    if(p->type && p->data > UA_EMPTY_ARRAY_SENTINEL) {
        if(p->arrayLength == 0)
            p->arrayLength = 1;
        UA_Array_delete(p->data, p->arrayLength, p->type);
        p->data = NULL;
    }

    /* Delete the array dimensions */
    if((void*)p->arrayDimensions > UA_EMPTY_ARRAY_SENTINEL)
        UA_free(p->arrayDimensions);
}

static UA_StatusCode
Variant_copy(UA_Variant const *src, UA_Variant *dst, const UA_DataType *_) {
    size_t length = src->arrayLength;
    if(UA_Variant_isScalar(src))
        length = 1;
    UA_StatusCode retval = UA_Array_copy(src->data, length,
                                         &dst->data, src->type);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    dst->arrayLength = src->arrayLength;
    dst->type = src->type;
    if(src->arrayDimensions) {
        retval = UA_Array_copy(src->arrayDimensions, src->arrayDimensionsSize,
            (void**)&dst->arrayDimensions, &UA_TYPES[UA_TYPES_INT32]);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
        dst->arrayDimensionsSize = src->arrayDimensionsSize;
    }
    return UA_STATUSCODE_GOOD;
}

void
UA_Variant_setScalar(UA_Variant *v, void * UA_RESTRICT p,
                     const UA_DataType *type) {
    UA_Variant_init(v);
    v->type = type;
    v->arrayLength = 0;
    v->data = p;
}

UA_StatusCode
UA_Variant_setScalarCopy(UA_Variant *v, const void * UA_RESTRICT p,
                         const UA_DataType *type) {
    void *n = UA_malloc(type->memSize);
    if(UA_UNLIKELY(!n))
        return UA_STATUSCODE_BADOUTOFMEMORY;
    UA_StatusCode retval = UA_copy(p, n, type);
    if(UA_UNLIKELY(retval != UA_STATUSCODE_GOOD)) {
        UA_free(n);
        //cppcheck-suppress memleak
        return retval;
    }
    UA_Variant_setScalar(v, n, type);
    //cppcheck-suppress memleak
    return UA_STATUSCODE_GOOD;
}

void UA_Variant_setArray(UA_Variant *v, void * UA_RESTRICT array,
                         size_t arraySize, const UA_DataType *type) {
    UA_Variant_init(v);
    v->data = array;
    v->arrayLength = arraySize;
    v->type = type;
}

UA_StatusCode
UA_Variant_setArrayCopy(UA_Variant *v, const void * UA_RESTRICT array,
                        size_t arraySize, const UA_DataType *type) {
    UA_Variant_init(v);
    UA_StatusCode retval = UA_Array_copy(array, arraySize, &v->data, type);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    v->arrayLength = arraySize;
    v->type = type;
    return UA_STATUSCODE_GOOD;
}

/* Test if a range is compatible with a variant. This may adjust the upper bound
 * (max) in order to fit the variant. */
static UA_StatusCode
checkAdjustRange(const UA_Variant *v, UA_NumericRange *range) {
    /* Test for max array size (64bit only) */
#if (SIZE_MAX > 0xffffffff)
    if(v->arrayLength > UA_UINT32_MAX)
        return UA_STATUSCODE_BADINTERNALERROR;
#endif
    u32 arrayLength = (u32)v->arrayLength;

    /* Assume one array dimension if none defined */
    const u32 *dims = v->arrayDimensions;
    size_t dims_count = v->arrayDimensionsSize;
    if(v->arrayDimensionsSize == 0) {
        dims_count = 1;
        dims = &arrayLength;
    }

    /* Does the range match the dimension of the variant? */
    if(range->dimensionsSize != dims_count)
        return UA_STATUSCODE_BADINDEXRANGENODATA;

    /* Check that the number of elements in the variant matches the array
     * dimensions */
    size_t elements = 1;
    for(size_t i = 0; i < dims_count; ++i)
        elements *= dims[i];
    if(elements != v->arrayLength)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Test the integrity of the range and compute the max index used for every
     * dimension. The standard says in Part 4, Section 7.22:
     *
     * When reading a value, the indexes may not specify a range that is within
     * the bounds of the array. The Server shall return a partial result if some
     * elements exist within the range. */
    for(size_t i = 0; i < dims_count; ++i) {
        if(range->dimensions[i].min > range->dimensions[i].max)
            return UA_STATUSCODE_BADINDEXRANGEINVALID;
        if(range->dimensions[i].min >= dims[i])
            return UA_STATUSCODE_BADINDEXRANGENODATA;

        /* Reduce the max to fit the variant */
        if(range->dimensions[i].max >= dims[i])
            range->dimensions[i].max = dims[i] - 1;
    }

    return UA_STATUSCODE_GOOD;
}

/* Computes the stride for copying the range elements.
 * - total: how many elements are in the range
 * - block: how big is each contiguous block of elements in the variant that
 *   maps into the range
 * - stride: how many elements are between the blocks (beginning to beginning)
 * - first: where does the first block begin */
static void
computeStrides(const UA_Variant *v, const UA_NumericRange range,
               size_t *total, size_t *block, size_t *stride, size_t *first) {
    /* Number of total elements to be copied */
    size_t count = 1;
    for(size_t i = 0; i < range.dimensionsSize; ++i)
        count *= (range.dimensions[i].max - range.dimensions[i].min) + 1;
    *total = count;

    /* Assume one array dimension if none defined */
    u32 arrayLength = (u32)v->arrayLength;
    const u32 *dims = v->arrayDimensions;
    size_t dims_count = v->arrayDimensionsSize;
    if(v->arrayDimensionsSize == 0) {
        dims_count = 1;
        dims = &arrayLength;
    }

    /* Compute the stride length and the position of the first element */
    *block = count;           /* Assume the range describes the entire array. */
    *stride = v->arrayLength; /* So it can be copied as a contiguous block.   */
    *first = 0;
    size_t running_dimssize = 1;
    UA_Boolean found_contiguous = false;
    for(size_t k = dims_count; k > 0;) {
        --k;
        size_t dimrange = 1 + range.dimensions[k].max - range.dimensions[k].min;
        if(!found_contiguous && dimrange != dims[k]) {
            /* Found the maximum block that can be copied contiguously */
            found_contiguous = true;
            *block = running_dimssize * dimrange;
            *stride = running_dimssize * dims[k];
        }
        *first += running_dimssize * range.dimensions[k].min;
        running_dimssize *= dims[k];
    }
}

/* Is the type string-like? */
static UA_Boolean
isStringLike(const UA_DataType *type) {
    if(type == &UA_TYPES[UA_TYPES_STRING] ||
       type == &UA_TYPES[UA_TYPES_BYTESTRING] ||
       type == &UA_TYPES[UA_TYPES_XMLELEMENT])
        return true;
    return false;
}

/* Returns the part of the string that lies within the rangedimension */
static UA_StatusCode
copySubString(const UA_String *src, UA_String *dst,
              const UA_NumericRangeDimension *dim) {
    if(dim->min > dim->max)
        return UA_STATUSCODE_BADINDEXRANGEINVALID;
    if(dim->min >= src->length)
        return UA_STATUSCODE_BADINDEXRANGENODATA;

    size_t length;
    if(dim->max < src->length)
       length = dim->max - dim->min + 1;
    else
        length = src->length - dim->min;

    UA_StatusCode retval = UA_ByteString_allocBuffer(dst, length);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    memcpy(dst->data, &src->data[dim->min], length);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Variant_copyRange(const UA_Variant *src, UA_Variant * UA_RESTRICT dst,
                     const UA_NumericRange range) {
    if(!src->type)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_Boolean isScalar = UA_Variant_isScalar(src);
    UA_Boolean stringLike = isStringLike(src->type);

    /* Upper bound of the dimensions for stack-allocation */
    if(range.dimensionsSize > UA_MAX_ARRAY_DIMS)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Copy the const range to a mutable stack location */
    UA_NumericRangeDimension thisrangedims[UA_MAX_ARRAY_DIMS];
    memcpy(thisrangedims, range.dimensions, sizeof(UA_NumericRangeDimension) * range.dimensionsSize);
    UA_NumericRange thisrange = {range.dimensionsSize, thisrangedims};

    UA_NumericRangeDimension scalarThisDimension = {0,0}; /* a single entry */
    UA_NumericRange nextrange = {0, NULL};

    /* Extract the range for copying at this level. The remaining range is dealt
     * with in the "scalar" type that may define an array by itself (string,
     * variant, ...). */
    UA_Variant arraySrc;
    if(isScalar) {
        /* Replace scalar src with array of length 1 */
        arraySrc = *src;
        arraySrc.arrayLength = 1;
        src = &arraySrc;
        /* Deal with all range dimensions within the scalar */
        thisrange.dimensions = &scalarThisDimension;
        thisrange.dimensionsSize = 1;
        nextrange = range;
    } else {
        /* Deal with as many range dimensions as possible right now */
        size_t dims = src->arrayDimensionsSize;
        if(dims == 0)
            dims = 1;
        if(dims > range.dimensionsSize)
            return UA_STATUSCODE_BADINDEXRANGEINVALID;
       thisrange.dimensionsSize = dims;
       nextrange.dimensions = &range.dimensions[dims];
       nextrange.dimensionsSize = range.dimensionsSize - dims;
    }

    UA_StatusCode retval = checkAdjustRange(src, &thisrange);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Compute the strides */
    size_t count, block, stride, first;
    computeStrides(src, thisrange, &count, &block, &stride, &first);
    UA_assert(block > 0);

    /* Allocate the array */
    UA_Variant_init(dst);
    dst->data = UA_Array_new(count, src->type);
    if(!dst->data)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Copy the range */
    size_t block_count = count / block;
    size_t elem_size = src->type->memSize;
    uintptr_t nextdst = (uintptr_t)dst->data;
    uintptr_t nextsrc = (uintptr_t)src->data + (elem_size * first);
    if(nextrange.dimensionsSize == 0) {
        /* no nextrange */
        if(src->type->pointerFree) {
            for(size_t i = 0; i < block_count; ++i) {
                memcpy((void*)nextdst, (void*)nextsrc, elem_size * block);
                nextdst += block * elem_size;
                nextsrc += stride * elem_size;
            }
        } else {
            for(size_t i = 0; i < block_count; ++i) {
                for(size_t j = 0; j < block; ++j) {
                    retval = UA_copy((const void*)nextsrc,
                                     (void*)nextdst, src->type);
                    nextdst += elem_size;
                    nextsrc += elem_size;
                }
                nextsrc += (stride - block) * elem_size;
            }
        }
    } else {
        /* nextrange can only be used for variants and stringlike with remaining
         * range of dimension 1 */
        if(src->type != &UA_TYPES[UA_TYPES_VARIANT]) {
            if(!stringLike)
                retval = UA_STATUSCODE_BADINDEXRANGENODATA;
            if(nextrange.dimensionsSize != 1)
                retval = UA_STATUSCODE_BADINDEXRANGENODATA;
        }

        /* Copy the content */
        for(size_t i = 0; i < block_count; ++i) {
            for(size_t j = 0; j < block && retval == UA_STATUSCODE_GOOD; ++j) {
                if(stringLike)
                    retval = copySubString((const UA_String*)nextsrc,
                                           (UA_String*)nextdst,
                                           nextrange.dimensions);
                else
                    retval = UA_Variant_copyRange((const UA_Variant*)nextsrc,
                                                  (UA_Variant*)nextdst,
                                                  nextrange);
                nextdst += elem_size;
                nextsrc += elem_size;
            }
            nextsrc += (stride - block) * elem_size;
        }
    }

    /* Clean up if copying failed */
    if(retval != UA_STATUSCODE_GOOD) {
        UA_Array_delete(dst->data, count, src->type);
        dst->data = NULL;
        return retval;
    }

    /* Done if scalar */
    dst->type = src->type;
    if(isScalar)
        return retval;

    /* Copy array dimensions */
    dst->arrayLength = count;
    if(src->arrayDimensionsSize > 0) {
        dst->arrayDimensions =
            (u32*)UA_Array_new(thisrange.dimensionsSize, &UA_TYPES[UA_TYPES_UINT32]);
        if(!dst->arrayDimensions) {
            Variant_clear(dst, NULL);
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }
        dst->arrayDimensionsSize = thisrange.dimensionsSize;
        for(size_t k = 0; k < thisrange.dimensionsSize; ++k)
            dst->arrayDimensions[k] =
                thisrange.dimensions[k].max - thisrange.dimensions[k].min + 1;
    }
    return UA_STATUSCODE_GOOD;
}

/* TODO: Allow ranges to reach inside a scalars that are array-like, e.g.
 * variant and strings. This is already possible for reading... */
static UA_StatusCode
Variant_setRange(UA_Variant *v, void *array, size_t arraySize,
                 const UA_NumericRange range, UA_Boolean copy) {
    if(!v->type)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    /* Upper bound of the dimensions for stack-allocation */
    if(range.dimensionsSize > UA_MAX_ARRAY_DIMS)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Copy the const range to a mutable stack location */
    UA_NumericRangeDimension thisrangedims[UA_MAX_ARRAY_DIMS];
    memcpy(thisrangedims, range.dimensions, sizeof(UA_NumericRangeDimension) * range.dimensionsSize);
    UA_NumericRange thisrange = {range.dimensionsSize, thisrangedims};

    UA_StatusCode retval = checkAdjustRange(v, &thisrange);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Compute the strides */
    size_t count, block, stride, first;
    computeStrides(v, range, &count, &block, &stride, &first);
    if(count != arraySize)
        return UA_STATUSCODE_BADINDEXRANGEINVALID;

    /* Move/copy the elements */
    size_t block_count = count / block;
    size_t elem_size = v->type->memSize;
    uintptr_t nextdst = (uintptr_t)v->data + (first * elem_size);
    uintptr_t nextsrc = (uintptr_t)array;
    if(v->type->pointerFree || !copy) {
        for(size_t i = 0; i < block_count; ++i) {
            memcpy((void*)nextdst, (void*)nextsrc, elem_size * block);
            nextsrc += block * elem_size;
            nextdst += stride * elem_size;
        }
    } else {
        for(size_t i = 0; i < block_count; ++i) {
            for(size_t j = 0; j < block; ++j) {
                clearJumpTable[v->type->typeKind]((void*)nextdst, v->type);
                retval |= UA_copy((void*)nextsrc, (void*)nextdst, v->type);
                nextdst += elem_size;
                nextsrc += elem_size;
            }
            nextdst += (stride - block) * elem_size;
        }
    }

    /* If members were moved, initialize original array to prevent reuse */
    if(!copy && !v->type->pointerFree)
        memset(array, 0, sizeof(elem_size)*arraySize);

    return retval;
}

UA_StatusCode
UA_Variant_setRange(UA_Variant *v, void * UA_RESTRICT array,
                    size_t arraySize, const UA_NumericRange range) {
    return Variant_setRange(v, array, arraySize, range, false);
}

UA_StatusCode
UA_Variant_setRangeCopy(UA_Variant *v, const void * UA_RESTRICT array,
                        size_t arraySize, const UA_NumericRange range) {
    return Variant_setRange(v, (void*)(uintptr_t)array,
                            arraySize, range, true);
}

/* LocalizedText */
static void
LocalizedText_clear(UA_LocalizedText *p, const UA_DataType *_) {
    String_clear(&p->locale, NULL);
    String_clear(&p->text, NULL);
}

static UA_StatusCode
LocalizedText_copy(UA_LocalizedText const *src, UA_LocalizedText *dst,
                   const UA_DataType *_) {
    UA_StatusCode retval = String_copy(&src->locale, &dst->locale, NULL);
    retval |= String_copy(&src->text, &dst->text, NULL);
    return retval;
}

/* DataValue */
static void
DataValue_clear(UA_DataValue *p, const UA_DataType *_) {
    Variant_clear(&p->value, NULL);
}

static UA_StatusCode
DataValue_copy(UA_DataValue const *src, UA_DataValue *dst,
               const UA_DataType *_) {
    memcpy(dst, src, sizeof(UA_DataValue));
    UA_Variant_init(&dst->value);
    UA_StatusCode retval = Variant_copy(&src->value, &dst->value, NULL);
    if(retval != UA_STATUSCODE_GOOD)
        DataValue_clear(dst, NULL);
    return retval;
}

UA_StatusCode
UA_DataValue_copyVariantRange(const UA_DataValue *src, UA_DataValue * UA_RESTRICT dst,
                              const UA_NumericRange range) {
    memcpy(dst, src, sizeof(UA_DataValue));
    UA_Variant_init(&dst->value);
    UA_StatusCode retval = UA_Variant_copyRange(&src->value, &dst->value, range);
    if(retval != UA_STATUSCODE_GOOD)
        DataValue_clear(dst, NULL);
    return retval;
}

/* DiagnosticInfo */
static void
DiagnosticInfo_clear(UA_DiagnosticInfo *p, const UA_DataType *_) {
    String_clear(&p->additionalInfo, NULL);
    if(p->hasInnerDiagnosticInfo && p->innerDiagnosticInfo) {
        DiagnosticInfo_clear(p->innerDiagnosticInfo, NULL);
        UA_free(p->innerDiagnosticInfo);
    }
}

static UA_StatusCode
DiagnosticInfo_copy(UA_DiagnosticInfo const *src, UA_DiagnosticInfo *dst,
                    const UA_DataType *_) {
    memcpy(dst, src, sizeof(UA_DiagnosticInfo));
    UA_String_init(&dst->additionalInfo);
    dst->innerDiagnosticInfo = NULL;
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(src->hasAdditionalInfo)
        retval = String_copy(&src->additionalInfo, &dst->additionalInfo, NULL);
    if(src->hasInnerDiagnosticInfo && src->innerDiagnosticInfo) {
        dst->innerDiagnosticInfo = (UA_DiagnosticInfo*)
            UA_malloc(sizeof(UA_DiagnosticInfo));
        if(UA_LIKELY(dst->innerDiagnosticInfo != NULL)) {
            retval |= DiagnosticInfo_copy(src->innerDiagnosticInfo,
                                          dst->innerDiagnosticInfo, NULL);
            dst->hasInnerDiagnosticInfo = true;
        } else {
            dst->hasInnerDiagnosticInfo = false;
            retval |= UA_STATUSCODE_BADOUTOFMEMORY;
        }
    }
    return retval;
}

/********************/
/* Structured Types */
/********************/

void *
UA_new(const UA_DataType *type) {
    void *p = UA_calloc(1, type->memSize);
    return p;
}

static UA_StatusCode
copyByte(const u8 *src, u8 *dst, const UA_DataType *_) {
    *dst = *src;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
copy2Byte(const u16 *src, u16 *dst, const UA_DataType *_) {
    *dst = *src;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
copy4Byte(const u32 *src, u32 *dst, const UA_DataType *_) {
    *dst = *src;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
copy8Byte(const u64 *src, u64 *dst, const UA_DataType *_) {
    *dst = *src;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
copyGuid(const UA_Guid *src, UA_Guid *dst, const UA_DataType *_) {
    *dst = *src;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
copyStructure(const void *src, void *dst, const UA_DataType *type) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    uintptr_t ptrs = (uintptr_t)src;
    uintptr_t ptrd = (uintptr_t)dst;
    for(size_t i = 0; i < type->membersSize; ++i) {
        const UA_DataTypeMember *m = &type->members[i];
        const UA_DataType *mt = m->memberType;
        ptrs += m->padding;
        ptrd += m->padding;
        if(!m->isOptional) {
            if(!m->isArray) {
                retval |= copyJumpTable[mt->typeKind]((const void *)ptrs, (void *)ptrd, mt);
                ptrs += mt->memSize;
                ptrd += mt->memSize;
            } else {
                size_t *dst_size = (size_t*)ptrd;
                const size_t size = *((const size_t*)ptrs);
                ptrs += sizeof(size_t);
                ptrd += sizeof(size_t);
                retval |= UA_Array_copy(*(void* const*)ptrs, size, (void**)ptrd, mt);
                if(retval == UA_STATUSCODE_GOOD)
                    *dst_size = size;
                else
                    *dst_size = 0;
                ptrs += sizeof(void*);
                ptrd += sizeof(void*);
            }
        } else {
            if(!m->isArray) {
                if(*(void* const*)ptrs != NULL)
                    retval |= UA_Array_copy(*(void* const*)ptrs, 1, (void**)ptrd, mt);
            } else {
                if(*(void* const*)(ptrs+sizeof(size_t)) != NULL) {
                    size_t *dst_size = (size_t*)ptrd;
                    const size_t size = *((const size_t*)ptrs);
                    ptrs += sizeof(size_t);
                    ptrd += sizeof(size_t);
                    retval |= UA_Array_copy(*(void* const*)ptrs, size, (void**)ptrd, mt);
                    if(retval == UA_STATUSCODE_GOOD)
                        *dst_size = size;
                    else
                        *dst_size = 0;
                } else {
                    ptrs += sizeof(size_t);
                    ptrd += sizeof(size_t);
                }
            }
            ptrs += sizeof(void*);
            ptrd += sizeof(void*);
        }
    }
    return retval;
}

static UA_StatusCode
copyUnion(const void *src, void *dst, const UA_DataType *type) {
    uintptr_t ptrs = (uintptr_t) src;
    uintptr_t ptrd = (uintptr_t) dst;
    UA_UInt32 selection = *(UA_UInt32 *)ptrs;
    UA_copy((const UA_UInt32 *) ptrs, (UA_UInt32 *) ptrd, &UA_TYPES[UA_TYPES_UINT32]);
    if(selection == 0)
        return UA_STATUSCODE_GOOD;
    const UA_DataTypeMember *m = &type->members[selection-1];
    const UA_DataType *mt = m->memberType;
    ptrs += m->padding;
    ptrd += m->padding;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;

    if (m->isArray) {
        size_t *dst_size = (size_t*)ptrd;
        const size_t size = *((const size_t*)ptrs);
        ptrs += sizeof(size_t);
        ptrd += sizeof(size_t);
        retval = UA_Array_copy(*(void* const*)ptrs, size, (void**)ptrd, mt);
        if(retval == UA_STATUSCODE_GOOD)
            *dst_size = size;
        else
            *dst_size = 0;
    } else {
        retval = copyJumpTable[mt->typeKind]((const void *)ptrs, (void *)ptrd, mt);
    }

    return retval;
}

static UA_StatusCode
copyNotImplemented(const void *src, void *dst, const UA_DataType *type) {
    return UA_STATUSCODE_BADNOTIMPLEMENTED;
}

const UA_copySignature copyJumpTable[UA_DATATYPEKINDS] = {
    (UA_copySignature)copyByte, /* Boolean */
    (UA_copySignature)copyByte, /* SByte */
    (UA_copySignature)copyByte, /* Byte */
    (UA_copySignature)copy2Byte, /* Int16 */
    (UA_copySignature)copy2Byte, /* UInt16 */
    (UA_copySignature)copy4Byte, /* Int32 */
    (UA_copySignature)copy4Byte, /* UInt32 */
    (UA_copySignature)copy8Byte, /* Int64 */
    (UA_copySignature)copy8Byte, /* UInt64 */
    (UA_copySignature)copy4Byte, /* Float */
    (UA_copySignature)copy8Byte, /* Double */
    (UA_copySignature)String_copy,
    (UA_copySignature)copy8Byte, /* DateTime */
    (UA_copySignature)copyGuid, /* Guid */
    (UA_copySignature)String_copy, /* ByteString */
    (UA_copySignature)String_copy, /* XmlElement */
    (UA_copySignature)NodeId_copy,
    (UA_copySignature)ExpandedNodeId_copy,
    (UA_copySignature)copy4Byte, /* StatusCode */
    (UA_copySignature)QualifiedName_copy,
    (UA_copySignature)LocalizedText_copy,
    (UA_copySignature)ExtensionObject_copy,
    (UA_copySignature)DataValue_copy,
    (UA_copySignature)Variant_copy,
    (UA_copySignature)DiagnosticInfo_copy,
    (UA_copySignature)copyNotImplemented, /* Decimal */
    (UA_copySignature)copy4Byte, /* Enumeration */
    (UA_copySignature)copyStructure,
    (UA_copySignature)copyStructure, /* Structure with Optional Fields */
    (UA_copySignature)copyUnion, /* Union */
    (UA_copySignature)copyNotImplemented /* BitfieldCluster*/
};

UA_StatusCode
UA_copy(const void *src, void *dst, const UA_DataType *type) {
    memset(dst, 0, type->memSize); /* init */
    UA_StatusCode retval = copyJumpTable[type->typeKind](src, dst, type);
    if(retval != UA_STATUSCODE_GOOD)
        UA_clear(dst, type);
    return retval;
}

static void
clearStructure(void *p, const UA_DataType *type) {
    uintptr_t ptr = (uintptr_t)p;
    for(size_t i = 0; i < type->membersSize; ++i) {
        const UA_DataTypeMember *m = &type->members[i];
        const UA_DataType *mt = m->memberType;
        ptr += m->padding;
        if(!m->isOptional) {
            if(!m->isArray) {
                clearJumpTable[mt->typeKind]((void*)ptr, mt);
                ptr += mt->memSize;
            } else {
                size_t length = *(size_t*)ptr;
                ptr += sizeof(size_t);
                UA_Array_delete(*(void**)ptr, length, mt);
                ptr += sizeof(void*);
            }
        } else { /* field is optional */
            if(!m->isArray) {
                /* optional scalar field is contained */
                if((*(void *const *)ptr != NULL))
                    UA_Array_delete(*(void **)ptr, 1, mt);
                ptr += sizeof(void *);
            } else {
                /* optional array field is contained */
                if((*(void *const *)(ptr + sizeof(size_t)) != NULL)) {
                    size_t length = *(size_t *)ptr;
                    ptr += sizeof(size_t);
                    UA_Array_delete(*(void **)ptr, length, mt);
                    ptr += sizeof(void *);
                } else { /* optional array field not contained */
                    ptr += sizeof(size_t);
                    ptr += sizeof(void *);
                }
            }
        }
    }
}

static void
clearUnion(void *p, const UA_DataType *type) {
    uintptr_t ptr = (uintptr_t) p;
    UA_UInt32 selection = *(UA_UInt32 *)ptr;
    if(selection == 0)
        return;
    const UA_DataTypeMember *m = &type->members[selection-1];
    const UA_DataType *mt = m->memberType;
    ptr += m->padding;
    if (m->isArray) {
        size_t length = *(size_t *)ptr;
        ptr += sizeof(size_t);
        UA_Array_delete(*(void **)ptr, length, mt);
    } else {
        UA_clear((void *) ptr, mt);
    }
}

static void nopClear(void *p, const UA_DataType *type) { }

const
UA_clearSignature clearJumpTable[UA_DATATYPEKINDS] = {
    (UA_clearSignature)nopClear, /* Boolean */
    (UA_clearSignature)nopClear, /* SByte */
    (UA_clearSignature)nopClear, /* Byte */
    (UA_clearSignature)nopClear, /* Int16 */
    (UA_clearSignature)nopClear, /* UInt16 */
    (UA_clearSignature)nopClear, /* Int32 */
    (UA_clearSignature)nopClear, /* UInt32 */
    (UA_clearSignature)nopClear, /* Int64 */
    (UA_clearSignature)nopClear, /* UInt64 */
    (UA_clearSignature)nopClear, /* Float */
    (UA_clearSignature)nopClear, /* Double */
    (UA_clearSignature)String_clear, /* String */
    (UA_clearSignature)nopClear, /* DateTime */
    (UA_clearSignature)nopClear, /* Guid */
    (UA_clearSignature)String_clear, /* ByteString */
    (UA_clearSignature)String_clear, /* XmlElement */
    (UA_clearSignature)NodeId_clear,
    (UA_clearSignature)ExpandedNodeId_clear,
    (UA_clearSignature)nopClear, /* StatusCode */
    (UA_clearSignature)QualifiedName_clear,
    (UA_clearSignature)LocalizedText_clear,
    (UA_clearSignature)ExtensionObject_clear,
    (UA_clearSignature)DataValue_clear,
    (UA_clearSignature)Variant_clear,
    (UA_clearSignature)DiagnosticInfo_clear,
    (UA_clearSignature)nopClear, /* Decimal, not implemented */
    (UA_clearSignature)nopClear, /* Enumeration */
    (UA_clearSignature)clearStructure,
    (UA_clearSignature)clearStructure, /* Struct with Optional Fields*/
    (UA_clearSignature)clearUnion, /* Union*/
    (UA_clearSignature)nopClear /* BitfieldCluster, not implemented*/
};

void
UA_clear(void *p, const UA_DataType *type) {
    clearJumpTable[type->typeKind](p, type);
    memset(p, 0, type->memSize); /* init */
}

void
UA_delete(void *p, const UA_DataType *type) {
    clearJumpTable[type->typeKind](p, type);
    UA_free(p);
}

/******************/
/* Value Ordering */
/******************/

#define UA_NUMERICORDER(NAME, TYPE)                                 \
    static UA_Order                                                 \
    NAME(const TYPE *p1, const TYPE *p2, const UA_DataType *type) { \
        if(*p1 != *p2)                                              \
            return (*p1 < *p2) ? UA_ORDER_LESS : UA_ORDER_MORE;     \
        return UA_ORDER_EQ;                                         \
    }

UA_NUMERICORDER(booleanOrder, UA_Boolean)
UA_NUMERICORDER(sByteOrder, UA_SByte)
UA_NUMERICORDER(byteOrder, UA_Byte)
UA_NUMERICORDER(int16Order, UA_Int16)
UA_NUMERICORDER(uInt16Order, UA_UInt16)
UA_NUMERICORDER(int32Order, UA_Int32)
UA_NUMERICORDER(uInt32Order, UA_UInt32)
UA_NUMERICORDER(int64Order, UA_Int64)
UA_NUMERICORDER(uInt64Order, UA_UInt64)

#define UA_FLOATORDER(NAME, TYPE)                                   \
    static UA_Order                                                 \
    NAME(const TYPE *p1, const TYPE *p2, const UA_DataType *type) { \
        if(*p1 != *p2) {                                            \
            /* p1 is NaN */                                         \
            if(*p1 != *p1) {                                        \
                if(*p2 != *p2)                                      \
                    return UA_ORDER_EQ;                             \
                return UA_ORDER_LESS;                               \
            }                                                       \
            /* p2 is NaN */                                         \
            if(*p2 != *p2)                                          \
                return UA_ORDER_MORE;                               \
            return (*p1 < *p2) ? UA_ORDER_LESS : UA_ORDER_MORE;     \
        }                                                           \
        return UA_ORDER_EQ;                                         \
    }

UA_FLOATORDER(floatOrder, UA_Float)
UA_FLOATORDER(doubleOrder, UA_Double)

static UA_Order
guidOrder(const UA_Guid *p1, const UA_Guid *p2, const UA_DataType *type) {
    if(p1->data1 != p2->data1)
        return (p1->data1 < p2->data1) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->data2 != p2->data2)
        return (p1->data2 < p2->data2) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->data3 != p2->data3)
        return (p1->data3 < p2->data3) ? UA_ORDER_LESS : UA_ORDER_MORE;
    int cmp = memcmp(p1->data4, p2->data4, 8);
    if(cmp != 0)
        return (cmp < 0) ? UA_ORDER_LESS : UA_ORDER_MORE;
    return UA_ORDER_EQ;
}

static UA_Order
stringOrder(const UA_String *p1, const UA_String *p2, const UA_DataType *type) {
    if(p1->length != p2->length)
        return (p1->length < p2->length) ? UA_ORDER_LESS : UA_ORDER_MORE;
    /* For zero-length arrays, every pointer not NULL is considered a
     * UA_EMPTY_ARRAY_SENTINEL. */
    if(p1->data == p2->data) return UA_ORDER_EQ;
    if(p1->data == NULL) return UA_ORDER_LESS;
    if(p2->data == NULL) return UA_ORDER_MORE;
    int cmp = memcmp((const char*)p1->data, (const char*)p2->data, p1->length);
    if(cmp != 0)
        return (cmp < 0) ? UA_ORDER_LESS : UA_ORDER_MORE;
    return UA_ORDER_EQ;
}

static UA_Order
nodeIdOrder(const UA_NodeId *p1, const UA_NodeId *p2, const UA_DataType *_) {
    /* Compare namespaceIndex */
    if(p1->namespaceIndex != p2->namespaceIndex)
        return (p1->namespaceIndex < p2->namespaceIndex) ? UA_ORDER_LESS : UA_ORDER_MORE;

    /* Compare identifierType */
    if(p1->identifierType != p2->identifierType)
        return (p1->identifierType < p2->identifierType) ? UA_ORDER_LESS : UA_ORDER_MORE;

    /* Compare the identifier */
    switch(p1->identifierType) {
    case UA_NODEIDTYPE_NUMERIC:
    default:
        if(p1->identifier.numeric != p2->identifier.numeric)
            return (p1->identifier.numeric < p2->identifier.numeric) ?
                UA_ORDER_LESS : UA_ORDER_MORE;
        return UA_ORDER_EQ;
    case UA_NODEIDTYPE_GUID:
        return guidOrder(&p1->identifier.guid, &p2->identifier.guid, NULL);
    case UA_NODEIDTYPE_STRING:
    case UA_NODEIDTYPE_BYTESTRING:
        return stringOrder(&p1->identifier.string, &p2->identifier.string, NULL);
    }
}

static UA_Order
expandedNodeIdOrder(const UA_ExpandedNodeId *p1, const UA_ExpandedNodeId *p2,
                    const UA_DataType *_) {
    if(p1->serverIndex != p2->serverIndex)
        return (p1->serverIndex < p2->serverIndex) ? UA_ORDER_LESS : UA_ORDER_MORE;
    UA_Order o = stringOrder(&p1->namespaceUri, &p2->namespaceUri, NULL);
    if(o != UA_ORDER_EQ)
        return o;
    return nodeIdOrder(&p1->nodeId, &p2->nodeId, NULL);
}

static UA_Order
qualifiedNameOrder(const UA_QualifiedName *p1, const UA_QualifiedName *p2,
                   const UA_DataType *_) {
    if(p1->namespaceIndex != p2->namespaceIndex)
        return (p1->namespaceIndex < p2->namespaceIndex) ? UA_ORDER_LESS : UA_ORDER_MORE;
    return stringOrder(&p1->name, &p2->name, NULL);
}

static UA_Order
localizedTextOrder(const UA_LocalizedText *p1, const UA_LocalizedText *p2,
                   const UA_DataType *_) {
    UA_Order o = stringOrder(&p1->locale, &p2->locale, NULL);
    if(o != UA_ORDER_EQ)
        return o;
    return stringOrder(&p1->text, &p2->text, NULL);
}

static UA_Order
extensionObjectOrder(const UA_ExtensionObject *p1, const UA_ExtensionObject *p2,
                     const UA_DataType *_) {
    UA_ExtensionObjectEncoding enc1 = p1->encoding;
    UA_ExtensionObjectEncoding enc2 = p2->encoding;
    if(enc1 > UA_EXTENSIONOBJECT_DECODED)
        enc1 = UA_EXTENSIONOBJECT_DECODED;
    if(enc2 > UA_EXTENSIONOBJECT_DECODED)
        enc2 = UA_EXTENSIONOBJECT_DECODED;
    if(enc1 != enc2)
        return (enc1 < enc2) ? UA_ORDER_LESS : UA_ORDER_MORE;

    switch(enc1) {
    case UA_EXTENSIONOBJECT_ENCODED_NOBODY:
        return UA_ORDER_EQ;

    case UA_EXTENSIONOBJECT_ENCODED_BYTESTRING:
    case UA_EXTENSIONOBJECT_ENCODED_XML: {
            UA_Order o = nodeIdOrder(&p1->content.encoded.typeId,
                                     &p2->content.encoded.typeId, NULL);
            if(o != UA_ORDER_EQ)
                return o;
            return stringOrder((const UA_String*)&p1->content.encoded.body,
                               (const UA_String*)&p2->content.encoded.body, NULL);
        }

    case UA_EXTENSIONOBJECT_DECODED:
    default: {
            const UA_DataType *type1 = p1->content.decoded.type;
            const UA_DataType *type2 = p1->content.decoded.type;
            if(type1 != type2)
                return ((uintptr_t)type1 < (uintptr_t)type2) ? UA_ORDER_LESS : UA_ORDER_MORE;
            if(!type1)
                return UA_ORDER_EQ;
            return orderJumpTable[type1->typeKind]
                (p1->content.decoded.data, p2->content.decoded.data, type1);
        }
    }
}

/* Part 4: When testing for equality, a Server shall treat null and empty arrays
 * as equal.
 *
 * Don't compare overlayable types as "binary blobs". We have specific order
 * rules also for some overlayable types. For example how NaN floats are
 * compared. */
static UA_Order
arrayOrder(const void *p1, size_t p1Length,
           const void *p2, size_t p2Length,
           const UA_DataType *type) {
    if(p1Length != p2Length)
        return (p1Length < p2Length) ? UA_ORDER_LESS : UA_ORDER_MORE;
    uintptr_t u1 = (uintptr_t)p1;
    uintptr_t u2 = (uintptr_t)p2;
    for(size_t i = 0; i < p1Length; i++) {
        UA_Order o = orderJumpTable[type->typeKind]((const void*)u1, (const void*)u2, type);
        if(o != UA_ORDER_EQ)
            return o;
        u1 += type->memSize;
        u2 += type->memSize;
    }
    return UA_ORDER_EQ;
}

static UA_Order
variantOrder(const UA_Variant *p1, const UA_Variant *p2, const UA_DataType *_) {
    if(p1->type != p2->type)
        return ((uintptr_t)p1->type < (uintptr_t)p2->type) ? UA_ORDER_LESS : UA_ORDER_MORE;

    UA_Order o;
    if(p1->type != NULL) {
        /* Check if both variants are scalars or arrays */
        UA_Boolean s1 = UA_Variant_isScalar(p1);
        UA_Boolean s2 = UA_Variant_isScalar(p2);
        if(s1 != s2)
            return s1 ? UA_ORDER_LESS : UA_ORDER_MORE;
        if(s1) {
            o = orderJumpTable[p1->type->typeKind](p1->data, p2->data, p1->type);
        } else {
            /* Mismatching array length? */
            if(p1->arrayLength != p2->arrayLength)
                return (p1->arrayLength < p2->arrayLength) ? UA_ORDER_LESS : UA_ORDER_MORE;
            o = arrayOrder(p1->data, p1->arrayLength, p2->data, p2->arrayLength, p1->type);
        }
        if(o != UA_ORDER_EQ)
            return o;
    }

    if(p1->arrayDimensionsSize != p2->arrayDimensionsSize)
        return (p1->arrayDimensionsSize < p2->arrayDimensionsSize) ?
            UA_ORDER_LESS : UA_ORDER_MORE;
    o = UA_ORDER_EQ;
    if(p1->arrayDimensionsSize > 0)
        o = arrayOrder(p1->arrayDimensions, p1->arrayDimensionsSize,
                       p2->arrayDimensions, p2->arrayDimensionsSize,
                       &UA_TYPES[UA_TYPES_UINT32]);
    return o;
}

static UA_Order
dataValueOrder(const UA_DataValue *p1, const UA_DataValue *p2, const UA_DataType *_) {
    /* Value */
    if(p1->hasValue != p2->hasValue)
        return (!p1->hasValue) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->hasValue) {
        UA_Order o = variantOrder(&p1->value, &p2->value, NULL);
        if(o != UA_ORDER_EQ)
            return o;
    }

    /* Status */
    if(p1->hasStatus != p2->hasStatus)
        return (!p1->hasStatus) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->hasStatus && p1->status != p2->status)
        return (p1->status < p2->status) ? UA_ORDER_LESS : UA_ORDER_MORE;

    /* SourceTimestamp */
    if(p1->hasSourceTimestamp != p2->hasSourceTimestamp)
        return (!p1->hasSourceTimestamp) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->hasSourceTimestamp && p1->sourceTimestamp != p2->sourceTimestamp)
        return (p1->sourceTimestamp < p2->sourceTimestamp) ? UA_ORDER_LESS : UA_ORDER_MORE;

    /* ServerTimestamp */
    if(p1->hasServerTimestamp != p2->hasServerTimestamp)
        return (!p1->hasServerTimestamp) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->hasServerTimestamp && p1->serverTimestamp != p2->serverTimestamp)
        return (p1->serverTimestamp < p2->serverTimestamp) ? UA_ORDER_LESS : UA_ORDER_MORE;

    /* SourcePicoseconds */
    if(p1->hasSourcePicoseconds != p2->hasSourcePicoseconds)
        return (!p1->hasSourcePicoseconds) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->hasSourcePicoseconds && p1->sourcePicoseconds != p2->sourcePicoseconds)
        return (p1->sourcePicoseconds < p2->sourcePicoseconds) ?
            UA_ORDER_LESS : UA_ORDER_MORE;

    /* ServerPicoseconds */
    if(p1->hasServerPicoseconds != p2->hasServerPicoseconds)
        return (!p1->hasServerPicoseconds) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->hasServerPicoseconds && p1->serverPicoseconds != p2->serverPicoseconds)
        return (p1->serverPicoseconds < p2->serverPicoseconds) ?
            UA_ORDER_LESS : UA_ORDER_MORE;

    return UA_ORDER_EQ;
}

static UA_Order
diagnosticInfoOrder(const UA_DiagnosticInfo *p1, const UA_DiagnosticInfo *p2,
                    const UA_DataType *_) {
    /* SymbolicId */
    if(p1->hasSymbolicId != p2->hasSymbolicId)
        return (!p1->hasSymbolicId) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->hasSymbolicId && p1->symbolicId != p2->symbolicId)
        return (p1->symbolicId < p2->symbolicId) ? UA_ORDER_LESS : UA_ORDER_MORE;

    /* NamespaceUri */
    if(p1->hasNamespaceUri != p2->hasNamespaceUri)
        return (!p1->hasNamespaceUri) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->hasNamespaceUri && p1->namespaceUri != p2->namespaceUri)
        return (p1->namespaceUri < p2->namespaceUri) ? UA_ORDER_LESS : UA_ORDER_MORE;

    /* LocalizedText */
    if(p1->hasLocalizedText != p2->hasLocalizedText)
        return (!p1->hasLocalizedText) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->hasLocalizedText && p1->localizedText != p2->localizedText)
        return (p1->localizedText < p2->localizedText) ? UA_ORDER_LESS : UA_ORDER_MORE;

    /* Locale */
    if(p1->hasLocale != p2->hasLocale)
        return (!p1->hasLocale) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->hasLocale && p1->locale != p2->locale)
        return (p1->locale < p2->locale) ? UA_ORDER_LESS : UA_ORDER_MORE;

    /* AdditionalInfo */
    if(p1->hasAdditionalInfo != p2->hasAdditionalInfo)
        return (!p1->hasAdditionalInfo) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->hasAdditionalInfo) {
        UA_Order o = stringOrder(&p1->additionalInfo, &p2->additionalInfo, NULL);
        if(o != UA_ORDER_EQ)
            return o;
    }

    /* InnerStatusCode */
    if(p1->hasInnerStatusCode != p2->hasInnerStatusCode)
        return (!p1->hasInnerStatusCode) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->hasInnerStatusCode && p1->innerStatusCode != p2->innerStatusCode)
        return (p1->innerStatusCode < p2->innerStatusCode) ? UA_ORDER_LESS : UA_ORDER_MORE;

    /* InnerDiagnosticInfo */
    if(p1->hasInnerDiagnosticInfo != p2->hasInnerDiagnosticInfo)
        return (!p1->hasInnerDiagnosticInfo) ? UA_ORDER_LESS : UA_ORDER_MORE;
    if(p1->innerDiagnosticInfo == p2->innerDiagnosticInfo)
        return UA_ORDER_EQ;
    if(!p1->innerDiagnosticInfo || !p2->innerDiagnosticInfo)
        return (!p1->innerDiagnosticInfo) ? UA_ORDER_LESS : UA_ORDER_MORE;
    return diagnosticInfoOrder(p1->innerDiagnosticInfo, p2->innerDiagnosticInfo, NULL);
}

static UA_Order
structureOrder(const void *p1, const void *p2, const UA_DataType *type) {
    uintptr_t u1 = (uintptr_t)p1;
    uintptr_t u2 = (uintptr_t)p2;
    UA_Order o = UA_ORDER_EQ;
    for(size_t i = 0; i < type->membersSize; ++i) {
        const UA_DataTypeMember *m = &type->members[i];
        const UA_DataType *mt = m->memberType;
        u1 += m->padding;
        u2 += m->padding;
        if(!m->isOptional) {
            if(!m->isArray) {
                o = orderJumpTable[mt->typeKind]((const void *)u1, (const void *)u2, mt);
                u1 += mt->memSize;
                u2 += mt->memSize;
            } else {
                size_t size1 = *(size_t*)u1;
                size_t size2 = *(size_t*)u2;
                u1 += sizeof(size_t);
                u2 += sizeof(size_t);
                o = arrayOrder(*(void* const*)u1, size1, *(void* const*)u2, size2, mt);
                u1 += sizeof(void*);
                u2 += sizeof(void*);
            }
        } else {
            if(!m->isArray) {
                const void *pp1 = *(void* const*)u1;
                const void *pp2 = *(void* const*)u2;
                if(pp1 == pp2) {
                    o = UA_ORDER_EQ;
                } else if(pp1 == NULL) {
                    o = UA_ORDER_LESS;
                } else if(pp2 == NULL) {
                    o = UA_ORDER_MORE;
                } else {
                    o = orderJumpTable[mt->typeKind](pp1, pp2, mt);
                }
            } else {
                size_t sa1 = *(size_t*)u1;
                size_t sa2 = *(size_t*)u2;
                u1 += sizeof(size_t);
                u2 += sizeof(size_t);
                o = arrayOrder(*(void* const*)u1, sa1, *(void* const*)u2, sa2, mt);
            }
            u1 += sizeof(void*);
            u2 += sizeof(void*);
        }

        if(o != UA_ORDER_EQ)
            break;
    }
    return o;
}

static UA_Order
unionOrder(const void *p1, const void *p2, const UA_DataType *type) {
    UA_UInt32 sel1 = *(const UA_UInt32 *)p1;
    UA_UInt32 sel2 = *(const UA_UInt32 *)p2;
    if(sel1 != sel2)
        return (sel1 < sel2) ? UA_ORDER_LESS : UA_ORDER_MORE;

    if(sel1 == 0) {
        return UA_ORDER_EQ;
    }

    const UA_DataTypeMember *m = &type->members[sel1-1];
    const UA_DataType *mt = m->memberType;

    uintptr_t u1 = ((uintptr_t)p1) + m->padding; /* includes switchfield length */
    uintptr_t u2 = ((uintptr_t)p2) + m->padding;
    if(m->isArray) {
        size_t sa1 = *(size_t*)u1;
        size_t sa2 = *(size_t*)u2;
        u1 += sizeof(size_t);
        u2 += sizeof(size_t);
        return arrayOrder(*(void* const*)u1, sa1, *(void* const*)u2, sa2, mt);
    }
    return orderJumpTable[mt->typeKind]((const void*)u1, (const void*)u2, mt);
}

static UA_Order
notImplementedOrder(const void *p1, const void *p2, const UA_DataType *type) {
    return UA_ORDER_EQ;
}

const
UA_orderSignature orderJumpTable[UA_DATATYPEKINDS] = {
    (UA_orderSignature)booleanOrder,
    (UA_orderSignature)sByteOrder,
    (UA_orderSignature)byteOrder,
    (UA_orderSignature)int16Order,
    (UA_orderSignature)uInt16Order,
    (UA_orderSignature)int32Order,
    (UA_orderSignature)uInt32Order,
    (UA_orderSignature)int64Order,
    (UA_orderSignature)uInt64Order,
    (UA_orderSignature)floatOrder,
    (UA_orderSignature)doubleOrder,
    (UA_orderSignature)stringOrder,
    (UA_orderSignature)int64Order,  /* DateTime */
    (UA_orderSignature)guidOrder,
    (UA_orderSignature)stringOrder, /* ByteString */
    (UA_orderSignature)stringOrder, /* XmlElement */
    (UA_orderSignature)nodeIdOrder,
    (UA_orderSignature)expandedNodeIdOrder,
    (UA_orderSignature)uInt32Order, /* StatusCode */
    (UA_orderSignature)qualifiedNameOrder,
    (UA_orderSignature)localizedTextOrder,
    (UA_orderSignature)extensionObjectOrder,
    (UA_orderSignature)dataValueOrder,
    (UA_orderSignature)variantOrder,
    (UA_orderSignature)diagnosticInfoOrder,
    notImplementedOrder, /* Decimal, not implemented */
    (UA_orderSignature)uInt32Order, /* Enumeration */
    (UA_orderSignature)structureOrder,
    (UA_orderSignature)structureOrder, /* Struct with Optional Fields*/
    (UA_orderSignature)unionOrder, /* Union*/
    notImplementedOrder /* BitfieldCluster, not implemented */
};

UA_Order UA_order(const void *p1, const void *p2, const UA_DataType *type) {
    return orderJumpTable[type->typeKind](p1, p2, type);
}

/******************/
/* Array Handling */
/******************/

void *
UA_Array_new(size_t size, const UA_DataType *type) {
    if(size > UA_INT32_MAX)
        return NULL;
    if(size == 0)
        return UA_EMPTY_ARRAY_SENTINEL;
    return UA_calloc(size, type->memSize);
}

UA_StatusCode
UA_Array_copy(const void *src, size_t size,
              void **dst, const UA_DataType *type) {
    if(size == 0) {
        if(src == NULL)
            *dst = NULL;
        else
            *dst= UA_EMPTY_ARRAY_SENTINEL;
        return UA_STATUSCODE_GOOD;
    }

    /* Check the array consistency -- defensive programming in case the user
     * manually created an inconsistent array */
    if(UA_UNLIKELY(!type || !src))
        return UA_STATUSCODE_BADINTERNALERROR;

    /* calloc, so we don't have to check retval in every iteration of copying */
    *dst = UA_calloc(size, type->memSize);
    if(!*dst)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    if(type->pointerFree) {
        memcpy(*dst, src, type->memSize * size);
        return UA_STATUSCODE_GOOD;
    }

    uintptr_t ptrs = (uintptr_t)src;
    uintptr_t ptrd = (uintptr_t)*dst;
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    for(size_t i = 0; i < size; ++i) {
        retval |= UA_copy((void*)ptrs, (void*)ptrd, type);
        ptrs += type->memSize;
        ptrd += type->memSize;
    }
    if(retval != UA_STATUSCODE_GOOD) {
        UA_Array_delete(*dst, size, type);
        *dst = NULL;
    }
    return retval;
}

UA_StatusCode
UA_Array_resize(void **p, size_t *size, size_t newSize,
                const UA_DataType *type) {
    if(*size == newSize)
        return UA_STATUSCODE_GOOD;

    /* Empty array? */
    if(newSize == 0) {
        UA_Array_delete(*p, *size, type);
        *p = UA_EMPTY_ARRAY_SENTINEL;
        *size = 0;
        return UA_STATUSCODE_GOOD;
    }

    /* Make a copy of the members that shall be removed. Realloc can fail during
     * trimming. So we cannot clear the members already here. */
    void *deleteMembers = NULL;
    if(newSize < *size && !type->pointerFree) {
        size_t deleteSize = *size - newSize;
        deleteMembers = UA_malloc(deleteSize * type->memSize);
        if(!deleteMembers)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        memcpy(deleteMembers, (void*)((uintptr_t)*p + (newSize * type->memSize)),
               deleteSize * type->memSize); /* shallow copy */
    }

    void *oldP = *p;
    if(oldP == UA_EMPTY_ARRAY_SENTINEL)
        oldP = NULL;

    /* Realloc */
    void *newP = UA_realloc(oldP, newSize * type->memSize);
    if(!newP) {
        if(deleteMembers)
            UA_free(deleteMembers);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    /* Clear removed members or initialize the new ones. Note that deleteMembers
     * depends on type->pointerFree. */
    if(newSize > *size) {
        memset((void*)((uintptr_t)newP + (*size * type->memSize)), 0,
               (newSize - *size) * type->memSize);
    } else if(deleteMembers) {
        UA_Array_delete(deleteMembers, *size - newSize, type);
    }

    /* Set the new array */
    *p = newP;
    *size = newSize;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Array_append(void **p, size_t *size, void *newElem,
                const UA_DataType *type) {
    /* Resize the array */
    size_t oldSize = *size;
    UA_StatusCode res = UA_Array_resize(p, size, oldSize+1, type);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Move the value */
    memcpy((void*)((uintptr_t)*p + (oldSize * type->memSize)),
           newElem, type->memSize);
    UA_init(newElem, type);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode UA_EXPORT
UA_Array_appendCopy(void **p, size_t *size, const void *newElem,
                    const UA_DataType *type) {
    char scratch[512];
    if(type->memSize > 512)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Copy the value */
    UA_StatusCode res = UA_copy(newElem, (void*)scratch, type);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Append */
    res = UA_Array_append(p, size, (void*)scratch, type);
    if(res != UA_STATUSCODE_GOOD)
        UA_clear((void*)scratch, type);
    return res;
}

void
UA_Array_delete(void *p, size_t size, const UA_DataType *type) {
    if(!type->pointerFree) {
        uintptr_t ptr = (uintptr_t)p;
        for(size_t i = 0; i < size; ++i) {
            UA_clear((void*)ptr, type);
            ptr += type->memSize;
        }
    }
    UA_free((void*)((uintptr_t)p & ~(uintptr_t)UA_EMPTY_ARRAY_SENTINEL));
}

#ifdef UA_ENABLE_TYPEDESCRIPTION
UA_Boolean
UA_DataType_getStructMember(const UA_DataType *type, const char *memberName,
                            size_t *outOffset, const UA_DataType **outMemberType,
                            UA_Boolean *outIsArray) {
    if(type->typeKind != UA_DATATYPEKIND_STRUCTURE &&
       type->typeKind != UA_DATATYPEKIND_OPTSTRUCT)
        return false;

    size_t offset = 0;
    for(size_t i = 0; i < type->membersSize; ++i) {
        const UA_DataTypeMember *m = &type->members[i];
        const UA_DataType *mt = m->memberType;
        offset += m->padding;

        if(strcmp(memberName, m->memberName) == 0) {
            *outOffset = offset;
            *outMemberType = mt;
            *outIsArray = m->isArray;
            return true;
        }

        if(!m->isOptional) {
            if(!m->isArray) {
                offset += mt->memSize;
            } else {
                offset += sizeof(size_t);
                offset += sizeof(void*);
            }
        } else { /* field is optional */
            if(!m->isArray) {
                offset += sizeof(void *);
            } else {
                offset += sizeof(size_t);
                offset += sizeof(void *);
            }
        }
    }

    return false;
}
#endif

UA_Boolean
UA_DataType_isNumeric(const UA_DataType *type) {
    switch(type->typeKind) {
    case UA_DATATYPEKIND_SBYTE:
    case UA_DATATYPEKIND_BYTE:
    case UA_DATATYPEKIND_INT16:
    case UA_DATATYPEKIND_UINT16:
    case UA_DATATYPEKIND_INT32:
    case UA_DATATYPEKIND_UINT32:
    case UA_DATATYPEKIND_INT64:
    case UA_DATATYPEKIND_UINT64:
    case UA_DATATYPEKIND_FLOAT:
    case UA_DATATYPEKIND_DOUBLE:
    /* not implemented: UA_DATATYPEKIND_DECIMAL */
        return true;
    default:
        return false;
    }
}

/**********************/
/* Parse NumericRange */
/**********************/

static size_t
readDimension(UA_Byte *buf, size_t buflen, UA_NumericRangeDimension *dim) {
    size_t progress = UA_readNumber(buf, buflen, &dim->min);
    if(progress == 0)
        return 0;
    if(buflen <= progress + 1 || buf[progress] != ':') {
        dim->max = dim->min;
        return progress;
    }

    ++progress;
    size_t progress2 = UA_readNumber(&buf[progress], buflen - progress, &dim->max);
    if(progress2 == 0)
        return 0;

    /* invalid range */
    if(dim->min >= dim->max)
        return 0;

    return progress + progress2;
}

UA_StatusCode
UA_NumericRange_parse(UA_NumericRange *range, const UA_String str) {
    size_t idx = 0;
    size_t dimensionsMax = 0;
    UA_NumericRangeDimension *dimensions = NULL;
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    size_t offset = 0;
    while(true) {
        /* alloc dimensions */
        if(idx >= dimensionsMax) {
            UA_NumericRangeDimension *newds;
            size_t newdssize = sizeof(UA_NumericRangeDimension) * (dimensionsMax + 2);
            newds = (UA_NumericRangeDimension*)UA_realloc(dimensions, newdssize);
            if(!newds) {
                retval = UA_STATUSCODE_BADOUTOFMEMORY;
                break;
            }
            dimensions = newds;
            dimensionsMax = dimensionsMax + 2;
        }

        /* read the dimension */
        size_t progress = readDimension(&str.data[offset], str.length - offset,
                                        &dimensions[idx]);
        if(progress == 0) {
            retval = UA_STATUSCODE_BADINDEXRANGEINVALID;
            break;
        }
        offset += progress;
        ++idx;

        /* loop into the next dimension */
        if(offset >= str.length)
            break;

        if(str.data[offset] != ',') {
            retval = UA_STATUSCODE_BADINDEXRANGEINVALID;
            break;
        }
        ++offset;
    }

    if(retval == UA_STATUSCODE_GOOD && idx > 0) {
        range->dimensions = dimensions;
        range->dimensionsSize = idx;
    } else {
        UA_free(dimensions);
    }

    return retval;
}

/**** amalgamated original file "/src/ua_types_encoding_binary.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2020 (c) Fraunhofer IOSB (Author: Andreas Ebner)
 *    Copyright 2020 (c) Grigory Friedman
 *    Copyright 2014-2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014-2017 (c) Florian Palm
 *    Copyright 2014-2016 (c) Sten Grüner
 *    Copyright 2014 (c) Leon Urbas
 *    Copyright 2015 (c) LEvertz
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2016 (c) Lorenz Haas
 *    Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2017 (c) Henrik Norrman
 */



/**
 * Type Encoding and Decoding
 * --------------------------
 * The following methods contain encoding and decoding functions for the builtin
 * data types and generic functions that operate on all types and arrays. This
 * requires the type description from a UA_DataType structure.
 *
 * Breaking a message up into chunks is integrated with the encoding. When the
 * end of a buffer is reached, a callback is executed that sends the current
 * buffer as a chunk and exchanges the encoding buffer "underneath" the ongoing
 * encoding. This reduces the RAM requirements and unnecessary copying. */

/* Part 6 §5.1.5: Decoders shall support at least 100 nesting levels */
#define UA_ENCODING_MAX_RECURSION 100

typedef struct {
    /* Pointers to the current and last buffer position */
    u8 *pos;
    const u8 *end;

    /* How often did we en-/decoding recurse? */
    u16 depth;

    const UA_DataTypeArray *customTypes;
    UA_exchangeEncodeBuffer exchangeBufferCallback;
    void *exchangeBufferCallbackHandle;
} Ctx;

typedef status
(*encodeBinarySignature)(const void *UA_RESTRICT src, const UA_DataType *type,
                         Ctx *UA_RESTRICT ctx);
typedef status
(*decodeBinarySignature)(void *UA_RESTRICT dst, const UA_DataType *type,
                         Ctx *UA_RESTRICT ctx);
#define ENCODE_BINARY(TYPE) static status                               \
    TYPE##_encodeBinary(const UA_##TYPE *UA_RESTRICT src,               \
                        const UA_DataType *type, Ctx *UA_RESTRICT ctx)
#define DECODE_BINARY(TYPE) static status                               \
    TYPE##_decodeBinary(UA_##TYPE *UA_RESTRICT dst,                     \
                        const UA_DataType *type, Ctx *UA_RESTRICT ctx)
#define ENCODE_DIRECT(SRC, TYPE) TYPE##_encodeBinary((const UA_##TYPE*)SRC, NULL, ctx)
#define DECODE_DIRECT(DST, TYPE) TYPE##_decodeBinary((UA_##TYPE*)DST, NULL, ctx)

#define IF_CHECK_BUFSIZE(check)                             \
    if(!UA_LIKELY(check)) {                                 \
        if(ctx->end != NULL)                                \
            return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED; \
    } else                                                  \

/* Jumptables for de-/encoding and computing the buffer length. The methods in
 * the decoding jumptable do not all clean up their allocated memory when an
 * error occurs. So a final _clear needs to be called before returning to the
 * user. */
extern const encodeBinarySignature encodeBinaryJumpTable[UA_DATATYPEKINDS];
extern const decodeBinarySignature decodeBinaryJumpTable[UA_DATATYPEKINDS];

/* Send the current chunk and replace the buffer */
static status exchangeBuffer(Ctx *ctx) {
    if(!ctx->exchangeBufferCallback)
        return UA_STATUSCODE_BADENCODINGERROR;
    return ctx->exchangeBufferCallback(ctx->exchangeBufferCallbackHandle,
                                       &ctx->pos, &ctx->end);
}

/* If encoding fails, exchange the buffer and try again. */
static status
encodeWithExchangeBuffer(const void *ptr, const UA_DataType *type, Ctx *ctx) {
    u8 *oldpos = ctx->pos; /* Last known good position */
/**
 * It is often forgotten to include -DNDEBUG in the compiler flags when using the single-file release.
 * So we make assertions dependent on the UA_DEBUG definition handled by CMake. */
#ifdef UA_DEBUG
    /* We have to ensure that the buffer was not exchanged AND
     * BADENCODINGLIMITSEXCEEDED was returned. If that were the case, oldpos
     * would be invalid. That means, a type encoding must never return
     * BADENCODINGLIMITSEXCEEDED once the buffer could have been exchanged. This
     * is achieved by the use of encodeWithExchangeBuffer. */
    const u8 *oldend = ctx->end;
    (void)oldend; /* For compilers who don't understand NDEBUG... */
#endif
    status ret = encodeBinaryJumpTable[type->typeKind](ptr, type, ctx);
    if(ret == UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED) {
        UA_assert(ctx->end == oldend);
        ctx->pos = oldpos; /* Set to the last known good position and exchange */
        ret = exchangeBuffer(ctx);
        UA_CHECK_STATUS(ret, return ret);
        ret = encodeBinaryJumpTable[type->typeKind](ptr, type, ctx);
    }
    return ret;
}

/*****************/
/* Integer Types */
/*****************/

#if !UA_BINARY_OVERLAYABLE_INTEGER

#pragma message "Integer endianness could not be detected to be little endian. Use slow generic encoding."

/* These en/decoding functions are only used when the architecture isn't little-endian. */
static void
UA_encode16(const u16 v, u8 buf[2]) {
    buf[0] = (u8)v;
    buf[1] = (u8)(v >> 8);
}

static void
UA_decode16(const u8 buf[2], u16 *v) {
    *v = (u16)((u16)buf[0] + (((u16)buf[1]) << 8));
}

static void
UA_encode32(const u32 v, u8 buf[4]) {
    buf[0] = (u8)v;
    buf[1] = (u8)(v >> 8);
    buf[2] = (u8)(v >> 16);
    buf[3] = (u8)(v >> 24);
}

static void
UA_decode32(const u8 buf[4], u32 *v) {
    *v = (u32)((u32)buf[0] + (((u32)buf[1]) << 8) +
             (((u32)buf[2]) << 16) + (((u32)buf[3]) << 24));
}

static void
UA_encode64(const u64 v, u8 buf[8]) {
    buf[0] = (u8)v;
    buf[1] = (u8)(v >> 8);
    buf[2] = (u8)(v >> 16);
    buf[3] = (u8)(v >> 24);
    buf[4] = (u8)(v >> 32);
    buf[5] = (u8)(v >> 40);
    buf[6] = (u8)(v >> 48);
    buf[7] = (u8)(v >> 56);
}

static void
UA_decode64(const u8 buf[8], u64 *v) {
    *v = (u64)((u64)buf[0] + (((u64)buf[1]) << 8) +
             (((u64)buf[2]) << 16) + (((u64)buf[3]) << 24) +
             (((u64)buf[4]) << 32) + (((u64)buf[5]) << 40) +
             (((u64)buf[6]) << 48) + (((u64)buf[7]) << 56));
}

#endif /* !UA_BINARY_OVERLAYABLE_INTEGER */

/* Boolean */
/* Note that sizeof(bool) != 1 on some platforms. Overlayable integer encoding
 * is disabled in those cases. */
ENCODE_BINARY(Boolean) {
    IF_CHECK_BUFSIZE(ctx->pos + 1 <= ctx->end) {
        *ctx->pos = *(const u8*)src;
    }
    ++ctx->pos;
    return UA_STATUSCODE_GOOD;
}

DECODE_BINARY(Boolean) {
    UA_CHECK(ctx->pos + 1 <= ctx->end, return UA_STATUSCODE_BADDECODINGERROR);
    *dst = (*ctx->pos > 0) ? true : false;
    ++ctx->pos;
    return UA_STATUSCODE_GOOD;
}

/* Byte */
ENCODE_BINARY(Byte) {
    IF_CHECK_BUFSIZE(ctx->pos + sizeof(u8) <= ctx->end) {
        *ctx->pos = *(const u8*)src;
    }
    ++ctx->pos;
    return UA_STATUSCODE_GOOD;
}

DECODE_BINARY(Byte) {
    UA_CHECK(ctx->pos + sizeof(u8) <= ctx->end,
             return UA_STATUSCODE_BADDECODINGERROR);
    *dst = *ctx->pos;
    ++ctx->pos;
    return UA_STATUSCODE_GOOD;
}

/* UInt16 */
ENCODE_BINARY(UInt16) {
    IF_CHECK_BUFSIZE(ctx->pos + sizeof(u16) <= ctx->end) {
#if UA_BINARY_OVERLAYABLE_INTEGER
        memcpy(ctx->pos, src, sizeof(u16));
#else
        UA_encode16(*src, ctx->pos);
#endif
    }
    ctx->pos += 2;
    return UA_STATUSCODE_GOOD;
}

DECODE_BINARY(UInt16) {
    UA_CHECK(ctx->pos + sizeof(u16) <= ctx->end,
             return UA_STATUSCODE_BADDECODINGERROR);
#if UA_BINARY_OVERLAYABLE_INTEGER
    memcpy(dst, ctx->pos, sizeof(u16));
#else
    UA_decode16(ctx->pos, dst);
#endif
    ctx->pos += 2;
    return UA_STATUSCODE_GOOD;
}

/* UInt32 */
ENCODE_BINARY(UInt32) {
    IF_CHECK_BUFSIZE(ctx->pos + sizeof(u32) <= ctx->end) {
#if UA_BINARY_OVERLAYABLE_INTEGER
        memcpy(ctx->pos, src, sizeof(u32));
#else
        UA_encode32(*src, ctx->pos);
#endif
    }
    ctx->pos += 4;
    return UA_STATUSCODE_GOOD;
}

DECODE_BINARY(UInt32) {
    UA_CHECK(ctx->pos + sizeof(u32) <= ctx->end,
             return UA_STATUSCODE_BADDECODINGERROR);
#if UA_BINARY_OVERLAYABLE_INTEGER
    memcpy(dst, ctx->pos, sizeof(u32));
#else
    UA_decode32(ctx->pos, dst);
#endif
    ctx->pos += 4;
    return UA_STATUSCODE_GOOD;
}

/* UInt64 */
ENCODE_BINARY(UInt64) {
    IF_CHECK_BUFSIZE(ctx->pos + sizeof(u64) <= ctx->end) {
#if UA_BINARY_OVERLAYABLE_INTEGER
        memcpy(ctx->pos, src, sizeof(u64));
#else
        UA_encode64(*src, ctx->pos);
#endif
    }
    ctx->pos += 8;
    return UA_STATUSCODE_GOOD;
}

DECODE_BINARY(UInt64) {
    UA_CHECK(ctx->pos + sizeof(u64) <= ctx->end,
             return UA_STATUSCODE_BADDECODINGERROR);
#if UA_BINARY_OVERLAYABLE_INTEGER
    memcpy(dst, ctx->pos, sizeof(u64));
#else
    UA_decode64(ctx->pos, dst);
#endif
    ctx->pos += 8;
    return UA_STATUSCODE_GOOD;
}

/************************/
/* Floating Point Types */
/************************/

/* Can we reuse the integer encoding mechanism by casting floating point
 * values? */
#if (UA_FLOAT_IEEE754 == 1) && (UA_LITTLE_ENDIAN == UA_FLOAT_LITTLE_ENDIAN)
# define Float_encodeBinary UInt32_encodeBinary
# define Float_decodeBinary UInt32_decodeBinary
# define Double_encodeBinary UInt64_encodeBinary
# define Double_decodeBinary UInt64_decodeBinary
#else

#include <math.h>

#pragma message "No native IEEE 754 format detected. Use slow generic encoding."

/* Handling of IEEE754 floating point values was taken from Beej's Guide to
 * Network Programming (http://beej.us/guide/bgnet/) and enhanced to cover the
 * edge cases +/-0, +/-inf and nan. */
static uint64_t
pack754(long double f, unsigned bits, unsigned expbits) {
    unsigned significandbits = bits - expbits - 1;
    long double fnorm;
    long long sign;
    if(f < 0) { sign = 1; fnorm = -f; }
    else { sign = 0; fnorm = f; }
    int shift = 0;
    while(fnorm >= 2.0) { fnorm /= 2.0; ++shift; }
    while(fnorm < 1.0) { fnorm *= 2.0; --shift; }
    fnorm = fnorm - 1.0;
    long long significand = (long long)(fnorm * ((float)(1LL<<significandbits) + 0.5f));
    long long exponent = shift + ((1<<(expbits-1)) - 1);
    return (uint64_t)((sign<<(bits-1)) | (exponent<<(bits-expbits-1)) | significand);
}

static long double
unpack754(uint64_t i, unsigned bits, unsigned expbits) {
    unsigned significandbits = bits - expbits - 1;
    long double result = (long double)(i&(uint64_t)((1LL<<significandbits)-1));
    result /= (long double)(1LL<<significandbits);
    result += 1.0f;
    unsigned bias = (unsigned)(1<<(expbits-1)) - 1;
    long long shift = (long long)((i>>significandbits) & (uint64_t)((1LL<<expbits)-1)) - bias;
    while(shift > 0) { result *= 2.0; --shift; }
    while(shift < 0) { result /= 2.0; ++shift; }
    result *= ((i>>(bits-1))&1)? -1.0: 1.0;
    return result;
}

/* Float */
#define FLOAT_NAN 0xffc00000
#define FLOAT_INF 0x7f800000
#define FLOAT_NEG_INF 0xff800000
#define FLOAT_NEG_ZERO 0x80000000

ENCODE_BINARY(Float) {
    UA_Float f = *src;
    u32 encoded;
    /* cppcheck-suppress duplicateExpression */
    if(f != f) encoded = FLOAT_NAN;
    else if(f == 0.0f) encoded = signbit(f) ? FLOAT_NEG_ZERO : 0;
    else if(f/f != f/f) encoded = f > 0 ? FLOAT_INF : FLOAT_NEG_INF;
    else encoded = (u32)pack754(f, 32, 8);
    return ENCODE_DIRECT(&encoded, UInt32);
}

DECODE_BINARY(Float) {
    u32 decoded;
    status ret = DECODE_DIRECT(&decoded, UInt32);
    if(ret != UA_STATUSCODE_GOOD)
        return ret;
    if(decoded == 0) *dst = 0.0f;
    else if(decoded == FLOAT_NEG_ZERO) *dst = -0.0f;
    else if(decoded == FLOAT_INF) *dst = INFINITY;
    else if(decoded == FLOAT_NEG_INF) *dst = -INFINITY;
    else if((decoded >= 0x7f800001 && decoded <= 0x7fffffff) ||
       (decoded >= 0xff800001)) *dst = NAN;
    else *dst = (UA_Float)unpack754(decoded, 32, 8);
    return UA_STATUSCODE_GOOD;
}

/* Double */
#define DOUBLE_NAN 0xfff8000000000000L
#define DOUBLE_INF 0x7ff0000000000000L
#define DOUBLE_NEG_INF 0xfff0000000000000L
#define DOUBLE_NEG_ZERO 0x8000000000000000L

ENCODE_BINARY(Double) {
    UA_Double d = *src;
    u64 encoded;
    /* cppcheck-suppress duplicateExpression */
    if(d != d) encoded = DOUBLE_NAN;
    else if(d == 0.0) encoded = signbit(d) ? DOUBLE_NEG_ZERO : 0;
    else if(d/d != d/d) encoded = d > 0 ? DOUBLE_INF : DOUBLE_NEG_INF;
    else encoded = pack754(d, 64, 11);
    return ENCODE_DIRECT(&encoded, UInt64);
}

DECODE_BINARY(Double) {
    u64 decoded;
    status ret = DECODE_DIRECT(&decoded, UInt64);
    UA_CHECK_STATUS(ret, return ret);
    if(decoded == 0) *dst = 0.0;
    else if(decoded == DOUBLE_NEG_ZERO) *dst = -0.0;
    else if(decoded == DOUBLE_INF) *dst = INFINITY;
    else if(decoded == DOUBLE_NEG_INF) *dst = -INFINITY;
    else if((decoded >= 0x7ff0000000000001L && decoded <= 0x7fffffffffffffffL) ||
       (decoded >= 0xfff0000000000001L)) *dst = NAN;
    else *dst = (UA_Double)unpack754(decoded, 64, 11);
    return UA_STATUSCODE_GOOD;
}

#endif

/******************/
/* Array Handling */
/******************/

static status
Array_encodeBinaryOverlayable(uintptr_t ptr, size_t memSize, Ctx *ctx) {
    /* CalcSize only */
    if(ctx->end == NULL) {
        ctx->pos += memSize;
        return UA_STATUSCODE_GOOD;
    }

    /* Loop as long as more elements remain than fit into the chunk */
    while(ctx->end < ctx->pos + memSize) {
        size_t possible = ((uintptr_t)ctx->end - (uintptr_t)ctx->pos);
        memcpy(ctx->pos, (void*)ptr, possible);
        ctx->pos += possible;
        ptr += possible;
        status ret = exchangeBuffer(ctx);
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
        UA_CHECK_STATUS(ret, return ret);
        memSize -= possible;
    }

    /* Encode the remaining elements */
    memcpy(ctx->pos, (void*)ptr, memSize);
    ctx->pos += memSize;
    return UA_STATUSCODE_GOOD;
}

static status
Array_encodeBinaryComplex(uintptr_t ptr, size_t length,
                          const UA_DataType *type, Ctx *ctx) {
    /* Encode every element */
    for(size_t i = 0; i < length; ++i) {
        status ret = encodeWithExchangeBuffer((const void*)ptr, type, ctx);
        ptr += type->memSize;
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
        UA_CHECK_STATUS(ret, return ret); /* Unrecoverable fail */
    }
    return UA_STATUSCODE_GOOD;
}

static status
Array_encodeBinary(const void *src, size_t length, const UA_DataType *type, Ctx *ctx) {
    /* Check and convert the array length to int32 */
    i32 signed_length = -1;
    if(length > UA_INT32_MAX)
        return UA_STATUSCODE_BADINTERNALERROR;
    if(length > 0)
        signed_length = (i32)length;
    else if(src == UA_EMPTY_ARRAY_SENTINEL)
        signed_length = 0;

    /* Encode the array length */
    status ret = encodeWithExchangeBuffer(&signed_length, &UA_TYPES[UA_TYPES_INT32], ctx);
    UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
    UA_CHECK_STATUS(ret, return ret);

    /* Encode the content */
    if(length > 0) {
        if(type->overlayable)
            ret = Array_encodeBinaryOverlayable((uintptr_t)src, length * type->memSize, ctx);
        else
            ret = Array_encodeBinaryComplex((uintptr_t)src, length, type, ctx);
    }
    UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
    return ret;
}

static status
Array_decodeBinary(void *UA_RESTRICT *UA_RESTRICT dst, size_t *out_length,
                   const UA_DataType *type, Ctx *ctx) {
    /* Decode the length */
    i32 signed_length;
    status ret = DECODE_DIRECT(&signed_length, UInt32); /* Int32 */
    UA_CHECK_STATUS(ret, return ret);

    /* Return early for empty arrays */
    if(signed_length <= 0) {
        *out_length = 0;
        if(signed_length < 0)
            *dst = NULL;
        else
            *dst = UA_EMPTY_ARRAY_SENTINEL;
        return UA_STATUSCODE_GOOD;
    }

    /* Filter out arrays that can obviously not be decoded, because the message
     * is too small for the array length. This prevents the allocation of very
     * long arrays for bogus messages.
     *
     * The worst known case (so far) is UA_DataValue. It has
     * sizeof(UA_DataValue) == 80 and an empty DataValue is encoded with just
     * one byte. We use 128 as the smallest power of 2 larger than 80. */
    size_t length = (size_t)signed_length;
    UA_CHECK(ctx->pos + ((type->memSize * length) / 128) <= ctx->end,
             return UA_STATUSCODE_BADDECODINGERROR);

    /* Allocate memory */
    *dst = UA_calloc(length, type->memSize);
    UA_CHECK_MEM(*dst, return UA_STATUSCODE_BADOUTOFMEMORY);

    if(type->overlayable) {
        /* memcpy overlayable array */
        UA_CHECK(ctx->pos + (type->memSize * length) <= ctx->end,
                 UA_free(*dst); *dst = NULL; return UA_STATUSCODE_BADDECODINGERROR);
        memcpy(*dst, ctx->pos, type->memSize * length);
        ctx->pos += type->memSize * length;
    } else {
        /* Decode array members */
        uintptr_t ptr = (uintptr_t)*dst;
        for(size_t i = 0; i < length; ++i) {
            ret = decodeBinaryJumpTable[type->typeKind]((void*)ptr, type, ctx);
            UA_CHECK_STATUS(ret, /* +1 because last element is also already initialized */
                            UA_Array_delete(*dst, i+1, type); *dst = NULL; return ret);
            ptr += type->memSize;
        }
    }
    *out_length = length;
    return UA_STATUSCODE_GOOD;
}

/*****************/
/* Builtin Types */
/*****************/

ENCODE_BINARY(String) {
    return Array_encodeBinary(src->data, src->length, &UA_TYPES[UA_TYPES_BYTE], ctx);
}

DECODE_BINARY(String) {
    return Array_decodeBinary((void**)&dst->data, &dst->length, &UA_TYPES[UA_TYPES_BYTE], ctx);
}

/* Guid */
ENCODE_BINARY(Guid) {
    status ret = UA_STATUSCODE_GOOD;
    ret |= ENCODE_DIRECT(&src->data1, UInt32);
    ret |= ENCODE_DIRECT(&src->data2, UInt16);
    ret |= ENCODE_DIRECT(&src->data3, UInt16);
    IF_CHECK_BUFSIZE(ctx->pos + (8*sizeof(u8)) <= ctx->end) {
        memcpy(ctx->pos, src->data4, 8*sizeof(u8));
    }
    ctx->pos += 8;
    return ret;
}

DECODE_BINARY(Guid) {
    status ret = UA_STATUSCODE_GOOD;
    ret |= DECODE_DIRECT(&dst->data1, UInt32);
    ret |= DECODE_DIRECT(&dst->data2, UInt16);
    ret |= DECODE_DIRECT(&dst->data3, UInt16);
    UA_CHECK(ctx->pos + (8*sizeof(u8)) <= ctx->end,
             return UA_STATUSCODE_BADDECODINGERROR);
    memcpy(dst->data4, ctx->pos, 8*sizeof(u8));
    ctx->pos += 8;
    return ret;
}

/* NodeId */
#define UA_NODEIDTYPE_NUMERIC_TWOBYTE 0u
#define UA_NODEIDTYPE_NUMERIC_FOURBYTE 1u
#define UA_NODEIDTYPE_NUMERIC_COMPLETE 2u

#define UA_EXPANDEDNODEID_SERVERINDEX_FLAG 0x40u
#define UA_EXPANDEDNODEID_NAMESPACEURI_FLAG 0x80u

/* For ExpandedNodeId, we prefill the encoding mask. */
static status
NodeId_encodeBinaryWithEncodingMask(UA_NodeId const *src, u8 encoding, Ctx *ctx) {
    status ret = UA_STATUSCODE_GOOD;
    switch(src->identifierType) {
    case UA_NODEIDTYPE_NUMERIC:
        if(src->identifier.numeric > UA_UINT16_MAX || src->namespaceIndex > UA_BYTE_MAX) {
            encoding |= UA_NODEIDTYPE_NUMERIC_COMPLETE;
            ret |= ENCODE_DIRECT(&encoding, Byte);
            ret |= ENCODE_DIRECT(&src->namespaceIndex, UInt16);
            ret |= ENCODE_DIRECT(&src->identifier.numeric, UInt32);
        } else if(src->identifier.numeric > UA_BYTE_MAX || src->namespaceIndex > 0) {
            encoding |= UA_NODEIDTYPE_NUMERIC_FOURBYTE;
            ret |= ENCODE_DIRECT(&encoding, Byte);
            u8 nsindex = (u8)src->namespaceIndex;
            ret |= ENCODE_DIRECT(&nsindex, Byte);
            u16 identifier16 = (u16)src->identifier.numeric;
            ret |= ENCODE_DIRECT(&identifier16, UInt16);
        } else {
            encoding |= UA_NODEIDTYPE_NUMERIC_TWOBYTE;
            ret |= ENCODE_DIRECT(&encoding, Byte);
            u8 identifier8 = (u8)src->identifier.numeric;
            ret |= ENCODE_DIRECT(&identifier8, Byte);
        }
        break;
    case UA_NODEIDTYPE_STRING:
        encoding |= (u8)UA_NODEIDTYPE_STRING;
        ret |= ENCODE_DIRECT(&encoding, Byte);
        ret |= ENCODE_DIRECT(&src->namespaceIndex, UInt16);
        UA_CHECK_STATUS(ret, return ret);
        /* Can exchange the buffer */
        ret = ENCODE_DIRECT(&src->identifier.string, String);
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
        break;
    case UA_NODEIDTYPE_GUID:
        encoding |= (u8)UA_NODEIDTYPE_GUID;
        ret |= ENCODE_DIRECT(&encoding, Byte);
        ret |= ENCODE_DIRECT(&src->namespaceIndex, UInt16);
        ret |= ENCODE_DIRECT(&src->identifier.guid, Guid);
        break;
    case UA_NODEIDTYPE_BYTESTRING:
        encoding |= (u8)UA_NODEIDTYPE_BYTESTRING;
        ret |= ENCODE_DIRECT(&encoding, Byte);
        ret |= ENCODE_DIRECT(&src->namespaceIndex, UInt16);
        UA_CHECK_STATUS(ret, return ret);
        /* Can exchange the buffer */
        ret = ENCODE_DIRECT(&src->identifier.byteString, String); /* ByteString */
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
        break;
    default:
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return ret;
}

ENCODE_BINARY(NodeId) {
    return NodeId_encodeBinaryWithEncodingMask(src, 0, ctx);
}

DECODE_BINARY(NodeId) {
    u8 dstByte = 0, encodingByte = 0;
    u16 dstUInt16 = 0;

    /* Decode the encoding bitfield */
    status ret = DECODE_DIRECT(&encodingByte, Byte);
    UA_CHECK_STATUS(ret, return ret);

    /* Filter out the bits used only for ExpandedNodeIds */
    encodingByte &= (u8)~(u8)(UA_EXPANDEDNODEID_SERVERINDEX_FLAG |
                              UA_EXPANDEDNODEID_NAMESPACEURI_FLAG);

    /* Decode the namespace and identifier */
    switch(encodingByte) {
    case UA_NODEIDTYPE_NUMERIC_TWOBYTE:
        dst->identifierType = UA_NODEIDTYPE_NUMERIC;
        ret = DECODE_DIRECT(&dstByte, Byte);
        dst->identifier.numeric = dstByte;
        dst->namespaceIndex = 0;
        break;
    case UA_NODEIDTYPE_NUMERIC_FOURBYTE:
        dst->identifierType = UA_NODEIDTYPE_NUMERIC;
        ret |= DECODE_DIRECT(&dstByte, Byte);
        dst->namespaceIndex = dstByte;
        ret |= DECODE_DIRECT(&dstUInt16, UInt16);
        dst->identifier.numeric = dstUInt16;
        break;
    case UA_NODEIDTYPE_NUMERIC_COMPLETE:
        dst->identifierType = UA_NODEIDTYPE_NUMERIC;
        ret |= DECODE_DIRECT(&dst->namespaceIndex, UInt16);
        ret |= DECODE_DIRECT(&dst->identifier.numeric, UInt32);
        break;
    case UA_NODEIDTYPE_STRING:
        dst->identifierType = UA_NODEIDTYPE_STRING;
        ret |= DECODE_DIRECT(&dst->namespaceIndex, UInt16);
        ret |= DECODE_DIRECT(&dst->identifier.string, String);
        break;
    case UA_NODEIDTYPE_GUID:
        dst->identifierType = UA_NODEIDTYPE_GUID;
        ret |= DECODE_DIRECT(&dst->namespaceIndex, UInt16);
        ret |= DECODE_DIRECT(&dst->identifier.guid, Guid);
        break;
    case UA_NODEIDTYPE_BYTESTRING:
        dst->identifierType = UA_NODEIDTYPE_BYTESTRING;
        ret |= DECODE_DIRECT(&dst->namespaceIndex, UInt16);
        ret |= DECODE_DIRECT(&dst->identifier.byteString, String); /* ByteString */
        break;
    default:
        ret |= UA_STATUSCODE_BADINTERNALERROR;
        break;
    }
    return ret;
}

/* ExpandedNodeId */
ENCODE_BINARY(ExpandedNodeId) {
    /* Set up the encoding mask */
    u8 encoding = 0;
    if((void*)src->namespaceUri.data > UA_EMPTY_ARRAY_SENTINEL)
        encoding |= UA_EXPANDEDNODEID_NAMESPACEURI_FLAG;
    if(src->serverIndex > 0)
        encoding |= UA_EXPANDEDNODEID_SERVERINDEX_FLAG;

    /* Encode the NodeId. Can exchange the buffer. */
    status ret = NodeId_encodeBinaryWithEncodingMask(&src->nodeId, encoding, ctx);
    UA_CHECK_STATUS(ret, return ret);

    /* Encode the namespace. Internally uses encodeWithExchangeBuffer
     * everywhere. So it will never return
     * UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED. */
    if((void*)src->namespaceUri.data > UA_EMPTY_ARRAY_SENTINEL) {
        ret = ENCODE_DIRECT(&src->namespaceUri, String);
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
        UA_CHECK_STATUS(ret, return ret);
    }

    /* Encode the serverIndex */
    if(src->serverIndex > 0)
        ret = encodeWithExchangeBuffer(&src->serverIndex, &UA_TYPES[UA_TYPES_UINT32], ctx);
    UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
    return ret;
}

DECODE_BINARY(ExpandedNodeId) {
    /* Decode the encoding mask */
    UA_CHECK(ctx->pos + 1 <= ctx->end, return UA_STATUSCODE_BADDECODINGERROR);
    u8 encoding = *ctx->pos;

    /* Decode the NodeId */
    status ret = DECODE_DIRECT(&dst->nodeId, NodeId);

    /* Decode the NamespaceUri */
    if(encoding & UA_EXPANDEDNODEID_NAMESPACEURI_FLAG) {
        dst->nodeId.namespaceIndex = 0;
        ret |= DECODE_DIRECT(&dst->namespaceUri, String);
    }

    /* Decode the ServerIndex */
    if(encoding & UA_EXPANDEDNODEID_SERVERINDEX_FLAG)
        ret |= DECODE_DIRECT(&dst->serverIndex, UInt32);
    return ret;
}

/* QualifiedName */
ENCODE_BINARY(QualifiedName) {
    status ret = ENCODE_DIRECT(&src->namespaceIndex, UInt16);
    /* Must check here so we can exchange the buffer in the string encoding */
    UA_CHECK_STATUS(ret, return ret);
    ret |= ENCODE_DIRECT(&src->name, String);
    return ret;
}

DECODE_BINARY(QualifiedName) {
    status ret = DECODE_DIRECT(&dst->namespaceIndex, UInt16);
    ret |= DECODE_DIRECT(&dst->name, String);
    return ret;
}

/* LocalizedText */
#define UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE 0x01u
#define UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT 0x02u

ENCODE_BINARY(LocalizedText) {
    /* Set up the encoding mask */
    u8 encoding = 0;
    if(src->locale.data)
        encoding |= UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE;
    if(src->text.data)
        encoding |= UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT;

    /* Encode the encoding byte */
    status ret = ENCODE_DIRECT(&encoding, Byte);
    /* Must check here so we can exchange the buffer in the string encoding */
    UA_CHECK_STATUS(ret, return ret);

    /* Encode the strings */
    if(encoding & UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE)
        ret |= ENCODE_DIRECT(&src->locale, String);
    if(encoding & UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT)
        ret |= ENCODE_DIRECT(&src->text, String);
    UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
    return ret;
}

DECODE_BINARY(LocalizedText) {
    /* Decode the encoding mask */
    u8 encoding = 0;
    status ret = DECODE_DIRECT(&encoding, Byte);

    /* Decode the content */
    if(encoding & UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_LOCALE)
        ret |= DECODE_DIRECT(&dst->locale, String);
    if(encoding & UA_LOCALIZEDTEXT_ENCODINGMASKTYPE_TEXT)
        ret |= DECODE_DIRECT(&dst->text, String);
    return ret;
}

/* The binary encoding has a different nodeid from the data type. So it is not
 * possible to reuse UA_findDataType */
static const UA_DataType *
UA_findDataTypeByBinaryInternal(const UA_NodeId *typeId, Ctx *ctx) {
    /* Always look in the built-in types first. Assume that only numeric
     * identifiers are used for the builtin types. (They may contain data types
     * from all namespaces though.) */
    if(typeId->identifierType == UA_NODEIDTYPE_NUMERIC) {
        for(size_t i = 0; i < UA_TYPES_COUNT; ++i) {
            if(UA_TYPES[i].binaryEncodingId.identifier.numeric == typeId->identifier.numeric &&
               UA_TYPES[i].binaryEncodingId.namespaceIndex == typeId->namespaceIndex)
                return &UA_TYPES[i];
        }
    }

    const UA_DataTypeArray *customTypes = ctx->customTypes;
    while(customTypes) {
        for(size_t i = 0; i < customTypes->typesSize; ++i) {
            if(UA_NodeId_equal(typeId, &customTypes->types[i].binaryEncodingId))
                return &customTypes->types[i];
        }
        customTypes = customTypes->next;
    }

    return NULL;
}

const UA_DataType *
UA_findDataTypeByBinary(const UA_NodeId *typeId) {
    Ctx ctx;
    ctx.customTypes = NULL;
    return UA_findDataTypeByBinaryInternal(typeId, &ctx);
}

/* ExtensionObject */
ENCODE_BINARY(ExtensionObject) {
    u8 encoding = (u8)src->encoding;

    /* No content or already encoded content. */
    if(encoding <= UA_EXTENSIONOBJECT_ENCODED_XML) {
        /* Can exchange the buffer */
        status ret = ENCODE_DIRECT(&src->content.encoded.typeId, NodeId);
        UA_CHECK_STATUS(ret, return ret);
        ret = encodeWithExchangeBuffer(&encoding, &UA_TYPES[UA_TYPES_BYTE], ctx);
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
        UA_CHECK_STATUS(ret, return ret);
        switch(src->encoding) {
        case UA_EXTENSIONOBJECT_ENCODED_NOBODY:
            break;
        case UA_EXTENSIONOBJECT_ENCODED_BYTESTRING:
        case UA_EXTENSIONOBJECT_ENCODED_XML:
            /* ByteString in disguise. Array encoding can exchange the buffer */
            ret = ENCODE_DIRECT(&src->content.encoded.body, String);
            break;
        default:
            ret = UA_STATUSCODE_BADINTERNALERROR;
        }
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
        return ret;
    }

    /* Cannot encode with no data or no type description */
    if(!src->content.decoded.type || !src->content.decoded.data)
        return UA_STATUSCODE_BADENCODINGERROR;

    /* Write the NodeId for the binary encoded type. This could perform a buffer
     * exchange, but can also return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED. */
    status ret = ENCODE_DIRECT(&src->content.decoded.type->binaryEncodingId, NodeId);
    UA_CHECK_STATUS(ret, return ret);

    /* Encode the encoding byte */
    encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING;
    ret = encodeWithExchangeBuffer(&encoding, &UA_TYPES[UA_TYPES_BYTE], ctx);
    UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
    UA_CHECK_STATUS(ret, return ret);

    const UA_DataType *contentType = src->content.decoded.type;

    /* Compute the content length. But only if we are not already in the
     * calcSizeBinary mode. This is avoids recursive cycles.*/
    i32 signed_len = 0;
    if(ctx->end != NULL) {
        size_t len = UA_calcSizeBinary(src->content.decoded.data, contentType);
        UA_CHECK(len <= UA_INT32_MAX, return UA_STATUSCODE_BADENCODINGERROR);
        signed_len = (i32)len;
    }
    ret = encodeWithExchangeBuffer(&signed_len, &UA_TYPES[UA_TYPES_INT32], ctx);
    UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
    UA_CHECK_STATUS(ret, return ret);

    /* Encode the content */
    ret = encodeWithExchangeBuffer(src->content.decoded.data, contentType, ctx);
    UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
    return ret;
}

static status
ExtensionObject_decodeBinaryContent(UA_ExtensionObject *dst, const UA_NodeId *typeId,
                                    Ctx *ctx) {
    /* Lookup the datatype */
    const UA_DataType *type = UA_findDataTypeByBinaryInternal(typeId, ctx);

    /* Unknown type, just take the binary content */
    if(!type) {
        dst->encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING;
        UA_NodeId_copy(typeId, &dst->content.encoded.typeId);
        return DECODE_DIRECT(&dst->content.encoded.body, String); /* ByteString */
    }

    /* Allocate memory */
    dst->content.decoded.data = UA_new(type);
    UA_CHECK_MEM(dst->content.decoded.data, return UA_STATUSCODE_BADOUTOFMEMORY);

    /* Jump over the length field (TODO: check if the decoded length matches) */
    ctx->pos += 4;

    /* Decode */
    dst->encoding = UA_EXTENSIONOBJECT_DECODED;
    dst->content.decoded.type = type;
    return decodeBinaryJumpTable[type->typeKind](dst->content.decoded.data, type, ctx);
}

DECODE_BINARY(ExtensionObject) {
    u8 encoding = 0;
    UA_NodeId binTypeId;
    UA_NodeId_init(&binTypeId);

    status ret = UA_STATUSCODE_GOOD;
    ret |= DECODE_DIRECT(&binTypeId, NodeId);
    ret |= DECODE_DIRECT(&encoding, Byte);
    UA_CHECK_STATUS(ret, UA_NodeId_clear(&binTypeId); return ret);

    switch(encoding) {
    case UA_EXTENSIONOBJECT_ENCODED_BYTESTRING:
        ret = ExtensionObject_decodeBinaryContent(dst, &binTypeId, ctx);
        UA_NodeId_clear(&binTypeId);
        break;
    case UA_EXTENSIONOBJECT_ENCODED_NOBODY:
        dst->encoding = (UA_ExtensionObjectEncoding)encoding;
        dst->content.encoded.typeId = binTypeId; /* move to dst */
        dst->content.encoded.body = UA_BYTESTRING_NULL;
        break;
    case UA_EXTENSIONOBJECT_ENCODED_XML:
        dst->encoding = (UA_ExtensionObjectEncoding)encoding;
        dst->content.encoded.typeId = binTypeId; /* move to dst */
        ret = DECODE_DIRECT(&dst->content.encoded.body, String); /* ByteString */
        UA_CHECK_STATUS(ret, UA_NodeId_clear(&dst->content.encoded.typeId));
        break;
    default:
        UA_NodeId_clear(&binTypeId);
        ret = UA_STATUSCODE_BADDECODINGERROR;
        break;
    }

    return ret;
}

/* Variant */

static status
Variant_encodeBinaryWrapExtensionObject(const UA_Variant *src,
                                        const UA_Boolean isArray, Ctx *ctx) {
    size_t length = 1; /* Default to 1 for a scalar. */

    /* Encode the array length if required */
    status ret = UA_STATUSCODE_GOOD;
    if(isArray) {
        UA_CHECK(src->arrayLength <= UA_INT32_MAX, return UA_STATUSCODE_BADENCODINGERROR);
        length = src->arrayLength;

        i32 encodedLength = (i32)src->arrayLength;
        ret = encodeWithExchangeBuffer(&encodedLength, &UA_TYPES[UA_TYPES_INT32], ctx);
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
        UA_CHECK_STATUS(ret, return ret);
    }

    /* Set up the ExtensionObject */
    UA_ExtensionObject eo;
    UA_ExtensionObject_init(&eo);
    eo.encoding = UA_EXTENSIONOBJECT_DECODED;
    eo.content.decoded.type = src->type;
    const u16 memSize = src->type->memSize;
    uintptr_t ptr = (uintptr_t)src->data;

    /* Iterate over the array */
    for(size_t i = 0; i < length && ret == UA_STATUSCODE_GOOD; ++i) {
        eo.content.decoded.data = (void*)ptr;
        ret = encodeWithExchangeBuffer(&eo, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], ctx);
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
        ptr += memSize;
    }
    return ret;
}

enum UA_VARIANT_ENCODINGMASKTYPE {
    UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK = 0x3Fu,        /* bits 0:5 */
    UA_VARIANT_ENCODINGMASKTYPE_DIMENSIONS = (u8)(0x01u << 6u), /* bit 6 */
    UA_VARIANT_ENCODINGMASKTYPE_ARRAY = (u8)(0x01u << 7u)  /* bit 7 */
};

ENCODE_BINARY(Variant) {
    /* Quit early for the empty variant */
    u8 encoding = 0;
    if(!src->type)
        return ENCODE_DIRECT(&encoding, Byte);

    /* Set the content type in the encoding mask */
    const UA_Boolean isBuiltin = (src->type->typeKind <= UA_DATATYPEKIND_DIAGNOSTICINFO);
    const UA_Boolean isEnum = (src->type->typeKind == UA_DATATYPEKIND_ENUM);
    if(isBuiltin)
        encoding = (u8)(encoding | (u8)((u8)UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK & (u8)(src->type->typeKind + 1u)));
    else if(isEnum)
        encoding = (u8)(encoding | (u8)((u8)UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK & (u8)(UA_TYPES_INT32 + 1u)));
    else
        encoding = (u8)(encoding | (u8)((u8)UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK & (u8)(UA_TYPES_EXTENSIONOBJECT + 1u)));

    /* Set the array type in the encoding mask */
    const UA_Boolean isArray = src->arrayLength > 0 || src->data <= UA_EMPTY_ARRAY_SENTINEL;
    const UA_Boolean hasDimensions = isArray && src->arrayDimensionsSize > 0;
    if(isArray) {
        encoding |= (u8)UA_VARIANT_ENCODINGMASKTYPE_ARRAY;
        if(hasDimensions) {
            encoding |= (u8)UA_VARIANT_ENCODINGMASKTYPE_DIMENSIONS;
            size_t totalRequiredSize = 1;
            for(size_t i = 0; i < src->arrayDimensionsSize; ++i)
                totalRequiredSize *= src->arrayDimensions[i];
            if(totalRequiredSize != src->arrayLength) return UA_STATUSCODE_BADENCODINGERROR;
        }
    }

    /* Encode the encoding byte */
    status ret = ENCODE_DIRECT(&encoding, Byte);
    UA_CHECK_STATUS(ret, return ret);

    /* Encode the content. This can exchange the buffer. */
    if(!isBuiltin && !isEnum) {
        /* This could return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED. But we
         * have not exchanged the buffer so far. */
        ret = Variant_encodeBinaryWrapExtensionObject(src, isArray, ctx);
    } else if(!isArray) {
        ret = encodeWithExchangeBuffer(src->data, src->type, ctx);
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
    } else {
        ret = Array_encodeBinary(src->data, src->arrayLength, src->type, ctx);
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
    }
    UA_CHECK_STATUS(ret, return ret);

    /* Encode the array dimensions */
    if(hasDimensions && ret == UA_STATUSCODE_GOOD)
        ret = Array_encodeBinary(src->arrayDimensions, src->arrayDimensionsSize,
                                 &UA_TYPES[UA_TYPES_INT32], ctx);
    UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
    return ret;
}

static status
Variant_decodeBinaryUnwrapExtensionObject(UA_Variant *dst, Ctx *ctx) {
    /* Save the position in the ByteString. If unwrapping is not possible, start
     * from here to decode a normal ExtensionObject. */
    u8 *old_pos = ctx->pos;

    /* Decode the DataType */
    UA_NodeId typeId;
    UA_NodeId_init(&typeId);
    status ret = DECODE_DIRECT(&typeId, NodeId);
    UA_CHECK_STATUS(ret, return ret);

    /* Decode the EncodingByte */
    u8 encoding;
    ret = DECODE_DIRECT(&encoding, Byte);
    UA_CHECK_STATUS(ret, UA_NodeId_clear(&typeId); return ret);

    /* Search for the datatype. Default to ExtensionObject. */
    if(encoding == UA_EXTENSIONOBJECT_ENCODED_BYTESTRING &&
       (dst->type = UA_findDataTypeByBinaryInternal(&typeId, ctx)) != NULL) {
        /* Jump over the length field (TODO: check if length matches) */
        ctx->pos += 4;
    } else {
        /* Reset and decode as ExtensionObject */
        dst->type = &UA_TYPES[UA_TYPES_EXTENSIONOBJECT];
        ctx->pos = old_pos;
    }
    UA_NodeId_clear(&typeId);

    /* Allocate memory */
    dst->data = UA_new(dst->type);
    UA_CHECK_MEM(dst->data, return UA_STATUSCODE_BADOUTOFMEMORY);

    /* Decode the content */
    return decodeBinaryJumpTable[dst->type->typeKind](dst->data, dst->type, ctx);
}

/* Unwraps all ExtensionObjects in an array if they have the same type.
 * For that we check whether all ExtensionObjects have the same header. */
static status
Variant_decodeBinaryUnwrapExtensionObjectArray(void *UA_RESTRICT *UA_RESTRICT dst,
                                               size_t *out_length, const UA_DataType **type,
                                               Ctx *ctx) {
    u8 *orig_pos = ctx->pos;

    /* Decode the length */
    i32 signed_length;
    status ret = DECODE_DIRECT(&signed_length, UInt32); /* Int32 */
    UA_CHECK_STATUS(ret, return ret);

    /* Return early for empty arrays */
    if(signed_length <= 0) {
        *out_length = 0;
        if(signed_length < 0)
            *dst = NULL;
        else
            *dst = UA_EMPTY_ARRAY_SENTINEL;
        /* The *type field stays an ExtensionObject, as we did not decode any
         * member who's type is known. */
        return UA_STATUSCODE_GOOD;
    }

    /* Protect against memory exhaustion by unrealistic array lengths. An
     * ExtensionObject is at least 4 byte long (3 byte NodeId + 1 Byte encoding
     * field). */
    size_t length = (size_t)signed_length;
    UA_CHECK(ctx->pos + ((4 * length) / 32) <= ctx->end,
             return UA_STATUSCODE_BADDECODINGERROR);

    /* Decode the type NodeId of the first member */
    UA_NodeId binTypeId;
    UA_NodeId_init(&binTypeId);
    ret |= DECODE_DIRECT(&binTypeId, NodeId);
    UA_CHECK_STATUS(ret, return ret);

    /* Lookup the data type */
    const UA_DataType *contentType = UA_findDataTypeByBinaryInternal(&binTypeId, ctx);
    UA_NodeId_clear(&binTypeId);
    if(!contentType) {
        /* DataType unknown, decode as ExtensionObject array */
        ctx->pos = orig_pos;
        return Array_decodeBinary(dst, out_length, *type, ctx);
    }

    /* Check that the encoding is binary */
    u8 encoding = 0;
    ret |= DECODE_DIRECT(&encoding, Byte);
    UA_CHECK_STATUS(ret, return ret);
    if(encoding != UA_EXTENSIONOBJECT_ENCODED_BYTESTRING) {
        /* Encoding format is not automatically decoded, decode as
         * ExtensionObject array */
        ctx->pos = orig_pos;
        return Array_decodeBinary(dst, out_length, *type, ctx);
    }

    /* Compare the header of all array members if the array can be unwrapped */
    UA_ByteString header = {(uintptr_t)ctx->pos - (uintptr_t)orig_pos - 4, &orig_pos[4]};
    UA_ByteString compare_header = header;
    ctx->pos = &orig_pos[4];

    for(size_t i = 0; i < length; i++) {
        compare_header.data = ctx->pos;
        UA_CHECK(compare_header.data + compare_header.length <= ctx->end,
                 return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
        if(!UA_ByteString_equal(&header, &compare_header)) {
            /* Different member types, decode as ExtensionObject array */
            ctx->pos = orig_pos;
            return Array_decodeBinary(dst, out_length, *type, ctx);
        }

        /* Decode the length field and jump to the next element */
        ctx->pos += header.length;
        u32 member_length = 0;
        ret = DECODE_DIRECT(&member_length, UInt32);
        UA_CHECK_STATUS(ret, return ret);
        ctx->pos += member_length;
    }

    /* Allocate memory for the unwrapped members */
    *dst = UA_calloc(length, contentType->memSize);
    UA_CHECK_MEM(*dst, return UA_STATUSCODE_BADOUTOFMEMORY);
    *out_length = length;
    *type = contentType;

    /* Decode unwrapped members */
    uintptr_t array_pos = (uintptr_t)*dst;
    ctx->pos = &orig_pos[4];
    for(size_t i = 0; i < length && ret == UA_STATUSCODE_GOOD; i++) {
        ctx->pos += header.length + 4; /* Jump over the header and length field */
        ret = decodeBinaryJumpTable[contentType->typeKind]
            ((void*)array_pos, contentType, ctx);
        array_pos += contentType->memSize;
    }
    return ret;
}

/* The resulting variant always has the storagetype UA_VARIANT_DATA. */
DECODE_BINARY(Variant) {
    /* Decode the encoding byte */
    u8 encodingByte;
    status ret = DECODE_DIRECT(&encodingByte, Byte);
    UA_CHECK_STATUS(ret, return ret);

    /* Return early for an empty variant (was already _inited) */
    if(encodingByte == 0)
        return UA_STATUSCODE_GOOD;

    /* Does the variant contain an array? */
    const UA_Boolean isArray = (encodingByte & (u8)UA_VARIANT_ENCODINGMASKTYPE_ARRAY) > 0;

    /* Get the datatype of the content. The type must be a builtin data type.
     * All not-builtin types are wrapped in an ExtensionObject. The "type kind"
     * for types up to DiagnsticInfo equals to the index in the encoding
     * byte. */
    size_t typeKind = (size_t)((encodingByte & (u8)UA_VARIANT_ENCODINGMASKTYPE_TYPEID_MASK) - 1);
    UA_CHECK(typeKind <= UA_DATATYPEKIND_DIAGNOSTICINFO, return UA_STATUSCODE_BADDECODINGERROR);

    /* A variant cannot contain a variant. But it can contain an array of
     * variants */
    UA_CHECK(typeKind != UA_DATATYPEKIND_VARIANT || isArray,
             return UA_STATUSCODE_BADDECODINGERROR);

    /* Check the recursion limit */
    UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION, return UA_STATUSCODE_BADENCODINGERROR);
    ctx->depth++;

    /* Decode the content */
    dst->type = &UA_TYPES[typeKind];
    if(!isArray) {
        /* Decode scalar */
        if(typeKind != UA_DATATYPEKIND_EXTENSIONOBJECT) {
            dst->data = UA_new(dst->type);
            UA_CHECK_MEM(dst->data, ctx->depth--; return UA_STATUSCODE_BADOUTOFMEMORY);
            ret = decodeBinaryJumpTable[typeKind](dst->data, dst->type, ctx);
        } else {
            ret = Variant_decodeBinaryUnwrapExtensionObject(dst, ctx);
        }
    } else {
        /* Decode array */
        if(typeKind != UA_DATATYPEKIND_EXTENSIONOBJECT) {
            ret = Array_decodeBinary(&dst->data, &dst->arrayLength, dst->type, ctx);
        } else {
            ret = Variant_decodeBinaryUnwrapExtensionObjectArray(&dst->data, &dst->arrayLength,
                                                                 &dst->type, ctx);
        }

        /* Decode array dimensions */
        if((encodingByte & (u8)UA_VARIANT_ENCODINGMASKTYPE_DIMENSIONS) > 0)
            ret |= Array_decodeBinary((void**)&dst->arrayDimensions, &dst->arrayDimensionsSize,
                                      &UA_TYPES[UA_TYPES_INT32], ctx);
    }

    ctx->depth--;
    return ret;
}

/* DataValue */
ENCODE_BINARY(DataValue) {
    /* Set up the encoding mask */
    u8 encodingMask = src->hasValue;
    encodingMask |= (u8)(src->hasStatus << 1u);
    encodingMask |= (u8)(src->hasSourceTimestamp << 2u);
    encodingMask |= (u8)(src->hasServerTimestamp << 3u);
    encodingMask |= (u8)(src->hasSourcePicoseconds << 4u);
    encodingMask |= (u8)(src->hasServerPicoseconds << 5u);

    /* Encode the encoding byte */
    status ret = ENCODE_DIRECT(&encodingMask, Byte);
    UA_CHECK_STATUS(ret, return ret);

    /* Encode the variant. */
    if(src->hasValue) {
        ret = ENCODE_DIRECT(&src->value, Variant);
        if(ret != UA_STATUSCODE_GOOD)
            return ret;
    }

    if(src->hasStatus)
        ret |= encodeWithExchangeBuffer(&src->status, &UA_TYPES[UA_TYPES_STATUSCODE], ctx);
    if(src->hasSourceTimestamp)
        ret |= encodeWithExchangeBuffer(&src->sourceTimestamp, &UA_TYPES[UA_TYPES_DATETIME], ctx);
    if(src->hasSourcePicoseconds)
        ret |= encodeWithExchangeBuffer(&src->sourcePicoseconds, &UA_TYPES[UA_TYPES_UINT16], ctx);
    if(src->hasServerTimestamp)
        ret |= encodeWithExchangeBuffer(&src->serverTimestamp, &UA_TYPES[UA_TYPES_DATETIME], ctx);
    if(src->hasServerPicoseconds)
        ret |= encodeWithExchangeBuffer(&src->serverPicoseconds, &UA_TYPES[UA_TYPES_UINT16], ctx);
    UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
    return ret;
}

#define MAX_PICO_SECONDS 9999

DECODE_BINARY(DataValue) {
    /* Decode the encoding mask */
    u8 encodingMask;
    status ret = DECODE_DIRECT(&encodingMask, Byte);
    UA_CHECK_STATUS(ret, return ret);

    /* Check the recursion limit */
    UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION, return UA_STATUSCODE_BADENCODINGERROR);
    ctx->depth++;

    /* Decode the content */
    if(encodingMask & 0x01u) {
        dst->hasValue = true;
        ret |= DECODE_DIRECT(&dst->value, Variant);
    }
    if(encodingMask & 0x02u) {
        dst->hasStatus = true;
        ret |= DECODE_DIRECT(&dst->status, UInt32); /* StatusCode */
    }
    if(encodingMask & 0x04u) {
        dst->hasSourceTimestamp = true;
        ret |= DECODE_DIRECT(&dst->sourceTimestamp, UInt64); /* DateTime */
    }
    if(encodingMask & 0x10u) {
        dst->hasSourcePicoseconds = true;
        ret |= DECODE_DIRECT(&dst->sourcePicoseconds, UInt16);
        if(dst->sourcePicoseconds > MAX_PICO_SECONDS)
            dst->sourcePicoseconds = MAX_PICO_SECONDS;
    }
    if(encodingMask & 0x08u) {
        dst->hasServerTimestamp = true;
        ret |= DECODE_DIRECT(&dst->serverTimestamp, UInt64); /* DateTime */
    }
    if(encodingMask & 0x20u) {
        dst->hasServerPicoseconds = true;
        ret |= DECODE_DIRECT(&dst->serverPicoseconds, UInt16);
        if(dst->serverPicoseconds > MAX_PICO_SECONDS)
            dst->serverPicoseconds = MAX_PICO_SECONDS;
    }

    ctx->depth--;
    return ret;
}

/* DiagnosticInfo */
ENCODE_BINARY(DiagnosticInfo) {
    /* Set up the encoding mask */
    u8 encodingMask = src->hasSymbolicId;
    encodingMask |= (u8)(src->hasNamespaceUri << 1u);
    encodingMask |= (u8)(src->hasLocalizedText << 2u);
    encodingMask |= (u8)(src->hasLocale << 3u);
    encodingMask |= (u8)(src->hasAdditionalInfo << 4u);
    encodingMask |= (u8)(src->hasInnerStatusCode << 5u);
    encodingMask |= (u8)(src->hasInnerDiagnosticInfo << 6u);

    /* Encode the numeric content */
    status ret = ENCODE_DIRECT(&encodingMask, Byte);
    if(src->hasSymbolicId)
        ret |= ENCODE_DIRECT(&src->symbolicId, UInt32); /* Int32 */
    if(src->hasNamespaceUri)
        ret |= ENCODE_DIRECT(&src->namespaceUri, UInt32); /* Int32 */
    if(src->hasLocalizedText)
        ret |= ENCODE_DIRECT(&src->localizedText, UInt32); /* Int32 */
    if(src->hasLocale)
        ret |= ENCODE_DIRECT(&src->locale, UInt32); /* Int32 */
    if(ret != UA_STATUSCODE_GOOD)
        return ret;

    /* Encode the additional info. Can exchange the buffer. */
    if(src->hasAdditionalInfo) {
        ret = ENCODE_DIRECT(&src->additionalInfo, String);
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
        UA_CHECK_STATUS(ret, return ret);
    }

    /* Encode the inner status code */
    if(src->hasInnerStatusCode) {
        ret = encodeWithExchangeBuffer(&src->innerStatusCode, &UA_TYPES[UA_TYPES_UINT32], ctx);
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
        UA_CHECK_STATUS(ret, return ret);
    }

    /* Encode the inner diagnostic info */
    if(src->hasInnerDiagnosticInfo) {
        ret = encodeWithExchangeBuffer(src->innerDiagnosticInfo,
                                       &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], ctx);
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
    }

    return ret;
}

DECODE_BINARY(DiagnosticInfo) {
    /* Decode the encoding mask */
    u8 encodingMask;
    status ret = DECODE_DIRECT(&encodingMask, Byte);
    UA_CHECK_STATUS(ret, return ret);

    /* Decode the content */
    if(encodingMask & 0x01u) {
        dst->hasSymbolicId = true;
        ret |= DECODE_DIRECT(&dst->symbolicId, UInt32); /* Int32 */
    }
    if(encodingMask & 0x02u) {
        dst->hasNamespaceUri = true;
        ret |= DECODE_DIRECT(&dst->namespaceUri, UInt32); /* Int32 */
    }
    if(encodingMask & 0x04u) {
        dst->hasLocalizedText = true;
        ret |= DECODE_DIRECT(&dst->localizedText, UInt32); /* Int32 */
    }
    if(encodingMask & 0x08u) {
        dst->hasLocale = true;
        ret |= DECODE_DIRECT(&dst->locale, UInt32); /* Int32 */
    }
    if(encodingMask & 0x10u) {
        dst->hasAdditionalInfo = true;
        ret |= DECODE_DIRECT(&dst->additionalInfo, String);
    }
    if(encodingMask & 0x20u) {
        dst->hasInnerStatusCode = true;
        ret |= DECODE_DIRECT(&dst->innerStatusCode, UInt32); /* StatusCode */
    }
    if(encodingMask & 0x40u) {
        /* innerDiagnosticInfo is allocated on the heap */
        dst->innerDiagnosticInfo = (UA_DiagnosticInfo*)
            UA_calloc(1, sizeof(UA_DiagnosticInfo));
        UA_CHECK_MEM(dst->innerDiagnosticInfo, return UA_STATUSCODE_BADOUTOFMEMORY);
        dst->hasInnerDiagnosticInfo = true;

        /* Check the recursion limit */
        UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION,
                 return UA_STATUSCODE_BADENCODINGERROR);

        ctx->depth++;
        ret |= DECODE_DIRECT(dst->innerDiagnosticInfo, DiagnosticInfo);
        ctx->depth--;
    }
    return ret;
}

/********************/
/* Structured Types */
/********************/

static status
encodeBinaryStruct(const void *src, const UA_DataType *type, Ctx *ctx) {
    /* Check the recursion limit */
    UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION,
             return UA_STATUSCODE_BADENCODINGERROR);
    ctx->depth++;

    /* Loop over members */
    uintptr_t ptr = (uintptr_t)src;
    status ret = UA_STATUSCODE_GOOD;
    for(size_t i = 0; i < type->membersSize && ret == UA_STATUSCODE_GOOD; ++i) {
        const UA_DataTypeMember *m = &type->members[i];
        const UA_DataType *mt = m->memberType;
        ptr += m->padding;

        /* Array. Buffer-exchange is done inside Array_encodeBinary if required. */
        if(m->isArray) {
            const size_t length = *((const size_t*)ptr);
            ptr += sizeof(size_t);
            ret = Array_encodeBinary(*(void *UA_RESTRICT const *)ptr, length, mt, ctx);
            UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
            ptr += sizeof(void*);
            continue;
        }

        /* Scalar */
        ret = encodeWithExchangeBuffer((const void*)ptr, mt, ctx);
        UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);
        ptr += mt->memSize;
    }

    ctx->depth--;
    return ret;
}

static status
encodeBinaryStructWithOptFields(const void *src, const UA_DataType *type, Ctx *ctx) {
    /* Check the recursion limit */
    if(ctx->depth > UA_ENCODING_MAX_RECURSION)
        return UA_STATUSCODE_BADENCODINGERROR;
    ctx->depth++;

    /* Creating the encoding mask, marking the available optional fields */
    uintptr_t ptr = (uintptr_t)src;
    size_t optFieldCounter = 0;
    UA_UInt32 encodingMask = 0;
    for(size_t j = 0; j < type->membersSize; ++j) {
        const UA_DataTypeMember *m = &type->members[j];
        const UA_DataType *mt = m->memberType;
        ptr += m->padding;
        if(m->isOptional) {
            if(m->isArray)
                ptr += sizeof(size_t);
            if(*(void* const*)ptr != NULL)
                encodingMask |= (UA_UInt32) 1 << optFieldCounter;
            ptr += sizeof(void *);
            optFieldCounter++;
        } else if (m->isArray) {
            ptr += sizeof(size_t);
            ptr += sizeof(void *);
        } else {
            ptr += mt->memSize;
        }
    }

    /* Encode the mask */
    status ret = ENCODE_DIRECT(&encodingMask, UInt32);
    UA_CHECK_STATUS(ret, ctx->depth--; return ret);

    /* Loop over members */
    ptr = (uintptr_t)src;
    for(size_t i = 0, o = 0; i < type->membersSize && UA_LIKELY(ret == UA_STATUSCODE_GOOD); ++i) {
        const UA_DataTypeMember *m = &type->members[i];
        const UA_DataType *mt = m->memberType;
        ptr += m->padding;

        if(m->isOptional) {
            if(!(encodingMask & (UA_UInt32) ( (UA_UInt32) 1<<(o++)))) {
                /* Optional and not contained */
                if(m->isArray)
                    ptr += sizeof(size_t);
            } else if(m->isArray) {
                /* Optional Array */
                const size_t length = *((const size_t *) ptr);
                ptr += sizeof(size_t);
                ret = Array_encodeBinary(*(void *UA_RESTRICT const *) ptr, length, mt, ctx);
            } else {
                /* Optional Scalar */
                ret = encodeWithExchangeBuffer(*(void* const*) ptr, mt, ctx);
            }
            ptr += sizeof(void *);
            continue;
        }

        /* Mandatory Array */
        if(m->isArray) {
            const size_t length = *((const size_t *) ptr);
            ptr += sizeof(size_t);
            ret = Array_encodeBinary(*(void *UA_RESTRICT const *) ptr, length, mt, ctx);
            ptr += sizeof(void *);
            continue;
        }

        /* Mandatory Scalar */
        ret = encodeWithExchangeBuffer((const void*)ptr, mt, ctx);
        ptr += mt->memSize;
    }
    UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);

    ctx->depth--;
    return ret;
}

static status
encodeBinaryUnion(const void *src, const UA_DataType *type, Ctx *ctx) {
    /* Check the recursion limit */
    UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION,
             return UA_STATUSCODE_BADENCODINGERROR);
    ctx->depth++;

    /* Encode the selection */
    const UA_UInt32 selection = *(const UA_UInt32*)src;
    status ret = ENCODE_DIRECT(&selection, UInt32);
    if(UA_UNLIKELY(ret != UA_STATUSCODE_GOOD) || selection == 0) {
        ctx->depth--;
        return ret;
    }

    /* Select the member */
    const UA_DataTypeMember *m = &type->members[selection-1];
    const UA_DataType *mt = m->memberType;

    /* Encode the member */
    uintptr_t ptr = ((uintptr_t)src) + m->padding; /* includes the switchfield length */
    if(!m->isArray) {
        ret = encodeWithExchangeBuffer((const void*)ptr, mt, ctx);
    } else {
        const size_t length = *((const size_t*)ptr);
        ptr += sizeof(size_t);
        ret = Array_encodeBinary(*(void *UA_RESTRICT const *)ptr, length, mt, ctx);
    }

    UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);

    ctx->depth--;
    return ret;
}

static status
encodeBinaryNotImplemented(const void *src, const UA_DataType *type, Ctx *ctx) {
    (void)src, (void)type, (void)ctx;
    return UA_STATUSCODE_BADNOTIMPLEMENTED;
}

const encodeBinarySignature encodeBinaryJumpTable[UA_DATATYPEKINDS] = {
    (encodeBinarySignature)Boolean_encodeBinary,
    (encodeBinarySignature)Byte_encodeBinary, /* SByte */
    (encodeBinarySignature)Byte_encodeBinary,
    (encodeBinarySignature)UInt16_encodeBinary, /* Int16 */
    (encodeBinarySignature)UInt16_encodeBinary,
    (encodeBinarySignature)UInt32_encodeBinary, /* Int32 */
    (encodeBinarySignature)UInt32_encodeBinary,
    (encodeBinarySignature)UInt64_encodeBinary, /* Int64 */
    (encodeBinarySignature)UInt64_encodeBinary,
    (encodeBinarySignature)Float_encodeBinary,
    (encodeBinarySignature)Double_encodeBinary,
    (encodeBinarySignature)String_encodeBinary,
    (encodeBinarySignature)UInt64_encodeBinary, /* DateTime */
    (encodeBinarySignature)Guid_encodeBinary,
    (encodeBinarySignature)String_encodeBinary, /* ByteString */
    (encodeBinarySignature)String_encodeBinary, /* XmlElement */
    (encodeBinarySignature)NodeId_encodeBinary,
    (encodeBinarySignature)ExpandedNodeId_encodeBinary,
    (encodeBinarySignature)UInt32_encodeBinary, /* StatusCode */
    (encodeBinarySignature)QualifiedName_encodeBinary,
    (encodeBinarySignature)LocalizedText_encodeBinary,
    (encodeBinarySignature)ExtensionObject_encodeBinary,
    (encodeBinarySignature)DataValue_encodeBinary,
    (encodeBinarySignature)Variant_encodeBinary,
    (encodeBinarySignature)DiagnosticInfo_encodeBinary,
    (encodeBinarySignature)encodeBinaryNotImplemented, /* Decimal */
    (encodeBinarySignature)UInt32_encodeBinary, /* Enumeration */
    (encodeBinarySignature)encodeBinaryStruct,
    (encodeBinarySignature)encodeBinaryStructWithOptFields, /* Structure with Optional Fields */
    (encodeBinarySignature)encodeBinaryUnion, /* Union */
    (encodeBinarySignature)encodeBinaryStruct /* BitfieldCluster */
};

status
UA_encodeBinaryInternal(const void *src, const UA_DataType *type,
                        u8 **bufPos, const u8 **bufEnd,
                        UA_exchangeEncodeBuffer exchangeCallback,
                        void *exchangeHandle) {
    if(!type || !src)
        return UA_STATUSCODE_BADENCODINGERROR;

    /* Set up the context */
    Ctx ctx;
    ctx.pos = *bufPos;
    ctx.end = *bufEnd;
    ctx.depth = 0;
    ctx.exchangeBufferCallback = exchangeCallback;
    ctx.exchangeBufferCallbackHandle = exchangeHandle;

    /* Encode */
    status ret = encodeWithExchangeBuffer(src, type, &ctx);
    UA_assert(ret != UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED);

    /* Set the new buffer position for the output. Beware that the buffer might
     * have been exchanged internally. */
    *bufPos = ctx.pos;
    *bufEnd = ctx.end;
    return ret;
}

UA_StatusCode
UA_encodeBinary(const void *p, const UA_DataType *type,
                UA_ByteString *outBuf) {
    /* Allocate buffer */
    UA_Boolean allocated = false;
    status res = UA_STATUSCODE_GOOD;
    if(outBuf->length == 0) {
        size_t len = UA_calcSizeBinary(p, type);
        res = UA_ByteString_allocBuffer(outBuf, len);
        if(res != UA_STATUSCODE_GOOD)
            return res;
        allocated = true;
    }

    /* Encode */
    u8 *pos = outBuf->data;
    const u8 *posEnd = &outBuf->data[outBuf->length];
    res = UA_encodeBinaryInternal(p, type, &pos, &posEnd, NULL, NULL);

    /* Clean up */
    if(res == UA_STATUSCODE_GOOD) {
        outBuf->length = (size_t)((uintptr_t)pos - (uintptr_t)outBuf->data);
    } else if(allocated) {
        UA_ByteString_clear(outBuf);
    }
    return res;
}

static status
decodeBinaryNotImplemented(void *dst, const UA_DataType *type, Ctx *ctx) {
    (void)dst, (void)type, (void)ctx;
    return UA_STATUSCODE_BADNOTIMPLEMENTED;
}

static status
decodeBinaryStructure(void *dst, const UA_DataType *type, Ctx *ctx) {
    /* Check the recursion limit */
    UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION,
             return UA_STATUSCODE_BADENCODINGERROR);
    ctx->depth++;

    uintptr_t ptr = (uintptr_t)dst;
    status ret = UA_STATUSCODE_GOOD;
    u8 membersSize = type->membersSize;

    /* Loop over members */
    for(size_t i = 0; i < membersSize && ret == UA_STATUSCODE_GOOD; ++i) {
        const UA_DataTypeMember *m = &type->members[i];
        const UA_DataType *mt = m->memberType;
        ptr += m->padding;

        /* Array */
        if(m->isArray) {
            size_t *length = (size_t*)ptr;
            ptr += sizeof(size_t);
            ret = Array_decodeBinary((void *UA_RESTRICT *UA_RESTRICT)ptr, length, mt , ctx);
            ptr += sizeof(void*);
            continue;
        }

        /* Scalar */
        ret = decodeBinaryJumpTable[mt->typeKind]((void *UA_RESTRICT)ptr, mt, ctx);
        ptr += mt->memSize;
    }

    ctx->depth--;
    return ret;
}

static status
decodeBinaryStructureWithOptFields(void *dst, const UA_DataType *type, Ctx *ctx) {
    /* Check the recursion limit */
    UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION, return UA_STATUSCODE_BADENCODINGERROR);
    ctx->depth++;

    uintptr_t ptr = (uintptr_t)dst;
    UA_UInt32 encodingMask = 0;
    status ret = UInt32_decodeBinary(&encodingMask, &UA_TYPES[UA_TYPES_UINT32], ctx);
    UA_CHECK_STATUS(ret, ctx->depth--; return ret);

    /* Loop over members */
    for(size_t i = 0, o = 0; i < type->membersSize && ret == UA_STATUSCODE_GOOD; ++i) {
        const UA_DataTypeMember *m = &type->members[i];
        const UA_DataType *mt = m->memberType;
        ptr += m->padding;
        if(m->isOptional) {
            if(!(encodingMask & (UA_UInt32) ( (UA_UInt32) 1<<(o++)))) {
                /* Optional field is not contained */
                if(m->isArray)
                    ptr += sizeof(size_t);
            } else if(m->isArray) {
                /* Optional Array */
                size_t *length = (size_t*)ptr;
                ptr += sizeof(size_t);
                ret = Array_decodeBinary((void *UA_RESTRICT *UA_RESTRICT)ptr, length, mt , ctx);
            } else {
                /* Optional Scalar */
                *(void *UA_RESTRICT *UA_RESTRICT) ptr = UA_calloc(1, mt->memSize);
                UA_CHECK_MEM(*(void *UA_RESTRICT *UA_RESTRICT) ptr, return UA_STATUSCODE_BADOUTOFMEMORY);
                ret = decodeBinaryJumpTable[mt->typeKind](*(void *UA_RESTRICT *UA_RESTRICT) ptr, mt, ctx);
            }
            ptr += sizeof(void *);
            continue;
        }

        /* Array */
        if(m->isArray) {
            size_t *length = (size_t *)ptr;
            ptr += sizeof(size_t);
            ret = Array_decodeBinary((void *UA_RESTRICT *UA_RESTRICT)ptr, length, mt, ctx);
            ptr += sizeof(void *);
            continue;
        }

        /* Scalar */
        ret = decodeBinaryJumpTable[mt->typeKind]((void *UA_RESTRICT)ptr, mt, ctx);
        ptr += mt->memSize;
    }
    ctx->depth--;
    return ret;
}

static status
decodeBinaryUnion(void *UA_RESTRICT dst, const UA_DataType *type, Ctx *ctx) {
    /* Check the recursion limit */
    UA_CHECK(ctx->depth <= UA_ENCODING_MAX_RECURSION,
             return UA_STATUSCODE_BADENCODINGERROR);

    /* Decode the selection directly into the switchfield */
    status ret = DECODE_DIRECT(dst, UInt32);
    UA_CHECK_STATUS(ret, return ret);

    /* No content? */
    UA_UInt32 selection = *(UA_UInt32*)dst;
    if(selection == 0)
        return UA_STATUSCODE_GOOD;

    /* Sanity check the selection */
    UA_CHECK(selection-1 < type->membersSize,
             return UA_STATUSCODE_BADDECODINGERROR);

    /* Select the member */
    const UA_DataTypeMember *m = &type->members[selection-1];
    const UA_DataType *mt = m->memberType;

    /* Decode */
    ctx->depth++;
    uintptr_t ptr = ((uintptr_t)dst) + m->padding; /* includes the switchfield */
    if(!m->isArray) {
        ret = decodeBinaryJumpTable[mt->typeKind]((void *UA_RESTRICT)ptr, mt, ctx);
    } else {
        size_t *length = (size_t *)ptr;
        ptr += sizeof(size_t);
        ret = Array_decodeBinary((void *UA_RESTRICT *UA_RESTRICT)ptr, length, mt, ctx);
    }
    ctx->depth--;
    return ret;
}

const decodeBinarySignature decodeBinaryJumpTable[UA_DATATYPEKINDS] = {
    (decodeBinarySignature)Boolean_decodeBinary,
    (decodeBinarySignature)Byte_decodeBinary, /* SByte */
    (decodeBinarySignature)Byte_decodeBinary,
    (decodeBinarySignature)UInt16_decodeBinary, /* Int16 */
    (decodeBinarySignature)UInt16_decodeBinary,
    (decodeBinarySignature)UInt32_decodeBinary, /* Int32 */
    (decodeBinarySignature)UInt32_decodeBinary,
    (decodeBinarySignature)UInt64_decodeBinary, /* Int64 */
    (decodeBinarySignature)UInt64_decodeBinary,
    (decodeBinarySignature)Float_decodeBinary,
    (decodeBinarySignature)Double_decodeBinary,
    (decodeBinarySignature)String_decodeBinary,
    (decodeBinarySignature)UInt64_decodeBinary, /* DateTime */
    (decodeBinarySignature)Guid_decodeBinary,
    (decodeBinarySignature)String_decodeBinary, /* ByteString */
    (decodeBinarySignature)String_decodeBinary, /* XmlElement */
    (decodeBinarySignature)NodeId_decodeBinary,
    (decodeBinarySignature)ExpandedNodeId_decodeBinary,
    (decodeBinarySignature)UInt32_decodeBinary, /* StatusCode */
    (decodeBinarySignature)QualifiedName_decodeBinary,
    (decodeBinarySignature)LocalizedText_decodeBinary,
    (decodeBinarySignature)ExtensionObject_decodeBinary,
    (decodeBinarySignature)DataValue_decodeBinary,
    (decodeBinarySignature)Variant_decodeBinary,
    (decodeBinarySignature)DiagnosticInfo_decodeBinary,
    (decodeBinarySignature)decodeBinaryNotImplemented, /* Decimal */
    (decodeBinarySignature)UInt32_decodeBinary, /* Enumeration */
    (decodeBinarySignature)decodeBinaryStructure,
    (decodeBinarySignature)decodeBinaryStructureWithOptFields, /* Structure with optional fields */
    (decodeBinarySignature)decodeBinaryUnion, /* Union */
    (decodeBinarySignature)decodeBinaryNotImplemented /* BitfieldCluster */
};

status
UA_decodeBinaryInternal(const UA_ByteString *src, size_t *offset,
                        void *dst, const UA_DataType *type,
                        const UA_DataTypeArray *customTypes) {
    /* Set up the context */
    Ctx ctx;
    ctx.pos = &src->data[*offset];
    ctx.end = &src->data[src->length];
    ctx.depth = 0;
    ctx.customTypes = customTypes;

    /* Decode */
    memset(dst, 0, type->memSize); /* Initialize the value */
    status ret = decodeBinaryJumpTable[type->typeKind](dst, type, &ctx);

    if(UA_LIKELY(ret == UA_STATUSCODE_GOOD)) {
        /* Set the new offset */
        *offset = (size_t)(ctx.pos - src->data) / sizeof(u8);
    } else {
        /* Clean up */
        UA_clear(dst, type);
        memset(dst, 0, type->memSize);
    }
    return ret;
}

UA_StatusCode
UA_decodeBinary(const UA_ByteString *inBuf,
                void *p, const UA_DataType *type,
                const UA_DecodeBinaryOptions *options) {
    size_t offset = 0;
    const UA_DataTypeArray *customTypes = options ? options->customTypes : NULL;
    return UA_decodeBinaryInternal(inBuf, &offset, p, type, customTypes);
}

/**
 * Compute the Message Size
 * ------------------------
 * The following methods are used to compute the length of a datum in binary
 * encoding. If the end-ptr is NULL, then the normal encoding functions do not
 * throw an error when the buffer limits are exceeded. */

size_t
UA_calcSizeBinary(const void *p, const UA_DataType *type) {
    u8 *pos = NULL;
    const u8 *posEnd = NULL;
    UA_StatusCode res = UA_encodeBinaryInternal(p, type, &pos, &posEnd, NULL, NULL);
    if(res != UA_STATUSCODE_GOOD)
        return 0;
    return (size_t)(uintptr_t)pos;
}

/**** amalgamated original file "/build/src_generated/open62541/types_generated.c" ****/

/**********************************
 * Autogenerated -- do not modify *
 **********************************/


/* Boolean */
#define Boolean_members NULL

/* SByte */
#define SByte_members NULL

/* Byte */
#define Byte_members NULL

/* Int16 */
#define Int16_members NULL

/* UInt16 */
#define UInt16_members NULL

/* Int32 */
#define Int32_members NULL

/* UInt32 */
#define UInt32_members NULL

/* Int64 */
#define Int64_members NULL

/* UInt64 */
#define UInt64_members NULL

/* Float */
#define Float_members NULL

/* Double */
#define Double_members NULL

/* String */
#define String_members NULL

/* DateTime */
#define DateTime_members NULL

/* Guid */
#define Guid_members NULL

/* ByteString */
#define ByteString_members NULL

/* XmlElement */
#define XmlElement_members NULL

/* NodeId */
#define NodeId_members NULL

/* ExpandedNodeId */
#define ExpandedNodeId_members NULL

/* StatusCode */
#define StatusCode_members NULL

/* QualifiedName */
#define QualifiedName_members NULL

/* LocalizedText */
#define LocalizedText_members NULL

/* ExtensionObject */
#define ExtensionObject_members NULL

/* DataValue */
#define DataValue_members NULL

/* Variant */
#define Variant_members NULL

/* DiagnosticInfo */
#define DiagnosticInfo_members NULL

/* NamingRuleType */
#define NamingRuleType_members NULL

/* KeyValuePair */
static UA_DataTypeMember KeyValuePair_members[2] = {
{
    UA_TYPENAME("Key") /* .memberName */
    &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Value") /* .memberName */
    &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */
    offsetof(UA_KeyValuePair, value) - offsetof(UA_KeyValuePair, key) - sizeof(UA_QualifiedName), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* TrustListDataType */
static UA_DataTypeMember TrustListDataType_members[5] = {
{
    UA_TYPENAME("SpecifiedLists") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TrustedCertificates") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_TrustListDataType, trustedCertificatesSize) - offsetof(UA_TrustListDataType, specifiedLists) - sizeof(UA_UInt32), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TrustedCrls") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_TrustListDataType, trustedCrlsSize) - offsetof(UA_TrustListDataType, trustedCertificates) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IssuerCertificates") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_TrustListDataType, issuerCertificatesSize) - offsetof(UA_TrustListDataType, trustedCrls) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IssuerCrls") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_TrustListDataType, issuerCrlsSize) - offsetof(UA_TrustListDataType, issuerCertificates) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* NodeClass */
#define NodeClass_members NULL

/* StructureType */
#define StructureType_members NULL

/* StructureField */
static UA_DataTypeMember StructureField_members[7] = {
{
    UA_TYPENAME("Name") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_StructureField, description) - offsetof(UA_StructureField, name) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataType") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_StructureField, dataType) - offsetof(UA_StructureField, description) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ValueRank") /* .memberName */
    &UA_TYPES[UA_TYPES_INT32], /* .memberType */
    offsetof(UA_StructureField, valueRank) - offsetof(UA_StructureField, dataType) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ArrayDimensions") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_StructureField, arrayDimensionsSize) - offsetof(UA_StructureField, valueRank) - sizeof(UA_Int32), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxStringLength") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_StructureField, maxStringLength) - offsetof(UA_StructureField, arrayDimensions) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IsOptional") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_StructureField, isOptional) - offsetof(UA_StructureField, maxStringLength) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* StructureDefinition */
static UA_DataTypeMember StructureDefinition_members[4] = {
{
    UA_TYPENAME("DefaultEncodingId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("BaseDataType") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_StructureDefinition, baseDataType) - offsetof(UA_StructureDefinition, defaultEncodingId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("StructureType") /* .memberName */
    &UA_TYPES[UA_TYPES_STRUCTURETYPE], /* .memberType */
    offsetof(UA_StructureDefinition, structureType) - offsetof(UA_StructureDefinition, baseDataType) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Fields") /* .memberName */
    &UA_TYPES[UA_TYPES_STRUCTUREFIELD], /* .memberType */
    offsetof(UA_StructureDefinition, fieldsSize) - offsetof(UA_StructureDefinition, structureType) - sizeof(UA_StructureType), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* Argument */
static UA_DataTypeMember Argument_members[5] = {
{
    UA_TYPENAME("Name") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataType") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_Argument, dataType) - offsetof(UA_Argument, name) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ValueRank") /* .memberName */
    &UA_TYPES[UA_TYPES_INT32], /* .memberType */
    offsetof(UA_Argument, valueRank) - offsetof(UA_Argument, dataType) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ArrayDimensions") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_Argument, arrayDimensionsSize) - offsetof(UA_Argument, valueRank) - sizeof(UA_Int32), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_Argument, description) - offsetof(UA_Argument, arrayDimensions) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* EnumValueType */
static UA_DataTypeMember EnumValueType_members[3] = {
{
    UA_TYPENAME("Value") /* .memberName */
    &UA_TYPES[UA_TYPES_INT64], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisplayName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_EnumValueType, displayName) - offsetof(UA_EnumValueType, value) - sizeof(UA_Int64), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_EnumValueType, description) - offsetof(UA_EnumValueType, displayName) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* EnumField */
static UA_DataTypeMember EnumField_members[4] = {
{
    UA_TYPENAME("Value") /* .memberName */
    &UA_TYPES[UA_TYPES_INT64], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisplayName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_EnumField, displayName) - offsetof(UA_EnumField, value) - sizeof(UA_Int64), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_EnumField, description) - offsetof(UA_EnumField, displayName) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Name") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_EnumField, name) - offsetof(UA_EnumField, description) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* Duration */
#define Duration_members NULL

/* UtcTime */
#define UtcTime_members NULL

/* LocaleId */
#define LocaleId_members NULL

/* TimeZoneDataType */
static UA_DataTypeMember TimeZoneDataType_members[2] = {
{
    UA_TYPENAME("Offset") /* .memberName */
    &UA_TYPES[UA_TYPES_INT16], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DaylightSavingInOffset") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_TimeZoneDataType, daylightSavingInOffset) - offsetof(UA_TimeZoneDataType, offset) - sizeof(UA_Int16), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* ApplicationType */
#define ApplicationType_members NULL

/* ApplicationDescription */
static UA_DataTypeMember ApplicationDescription_members[7] = {
{
    UA_TYPENAME("ApplicationUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ProductUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_ApplicationDescription, productUri) - offsetof(UA_ApplicationDescription, applicationUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ApplicationName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_ApplicationDescription, applicationName) - offsetof(UA_ApplicationDescription, productUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ApplicationType") /* .memberName */
    &UA_TYPES[UA_TYPES_APPLICATIONTYPE], /* .memberType */
    offsetof(UA_ApplicationDescription, applicationType) - offsetof(UA_ApplicationDescription, applicationName) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("GatewayServerUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_ApplicationDescription, gatewayServerUri) - offsetof(UA_ApplicationDescription, applicationType) - sizeof(UA_ApplicationType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiscoveryProfileUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_ApplicationDescription, discoveryProfileUri) - offsetof(UA_ApplicationDescription, gatewayServerUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiscoveryUrls") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_ApplicationDescription, discoveryUrlsSize) - offsetof(UA_ApplicationDescription, discoveryProfileUri) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* RequestHeader */
static UA_DataTypeMember RequestHeader_members[7] = {
{
    UA_TYPENAME("AuthenticationToken") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Timestamp") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_RequestHeader, timestamp) - offsetof(UA_RequestHeader, authenticationToken) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestHandle") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_RequestHeader, requestHandle) - offsetof(UA_RequestHeader, timestamp) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReturnDiagnostics") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_RequestHeader, returnDiagnostics) - offsetof(UA_RequestHeader, requestHandle) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AuditEntryId") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_RequestHeader, auditEntryId) - offsetof(UA_RequestHeader, returnDiagnostics) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TimeoutHint") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_RequestHeader, timeoutHint) - offsetof(UA_RequestHeader, auditEntryId) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AdditionalHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_RequestHeader, additionalHeader) - offsetof(UA_RequestHeader, timeoutHint) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* ResponseHeader */
static UA_DataTypeMember ResponseHeader_members[6] = {
{
    UA_TYPENAME("Timestamp") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestHandle") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ResponseHeader, requestHandle) - offsetof(UA_ResponseHeader, timestamp) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServiceResult") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_ResponseHeader, serviceResult) - offsetof(UA_ResponseHeader, requestHandle) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServiceDiagnostics") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_ResponseHeader, serviceDiagnostics) - offsetof(UA_ResponseHeader, serviceResult) - sizeof(UA_StatusCode), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("StringTable") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_ResponseHeader, stringTableSize) - offsetof(UA_ResponseHeader, serviceDiagnostics) - sizeof(UA_DiagnosticInfo), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AdditionalHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_ResponseHeader, additionalHeader) - offsetof(UA_ResponseHeader, stringTable) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* ServiceFault */
static UA_DataTypeMember ServiceFault_members[1] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* FindServersRequest */
static UA_DataTypeMember FindServersRequest_members[4] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EndpointUrl") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_FindServersRequest, endpointUrl) - offsetof(UA_FindServersRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LocaleIds") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_FindServersRequest, localeIdsSize) - offsetof(UA_FindServersRequest, endpointUrl) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerUris") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_FindServersRequest, serverUrisSize) - offsetof(UA_FindServersRequest, localeIds) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* FindServersResponse */
static UA_DataTypeMember FindServersResponse_members[2] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Servers") /* .memberName */
    &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION], /* .memberType */
    offsetof(UA_FindServersResponse, serversSize) - offsetof(UA_FindServersResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* ServerOnNetwork */
static UA_DataTypeMember ServerOnNetwork_members[4] = {
{
    UA_TYPENAME("RecordId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerName") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_ServerOnNetwork, serverName) - offsetof(UA_ServerOnNetwork, recordId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiscoveryUrl") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_ServerOnNetwork, discoveryUrl) - offsetof(UA_ServerOnNetwork, serverName) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerCapabilities") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_ServerOnNetwork, serverCapabilitiesSize) - offsetof(UA_ServerOnNetwork, discoveryUrl) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* FindServersOnNetworkRequest */
static UA_DataTypeMember FindServersOnNetworkRequest_members[4] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("StartingRecordId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_FindServersOnNetworkRequest, startingRecordId) - offsetof(UA_FindServersOnNetworkRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxRecordsToReturn") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_FindServersOnNetworkRequest, maxRecordsToReturn) - offsetof(UA_FindServersOnNetworkRequest, startingRecordId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerCapabilityFilter") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_FindServersOnNetworkRequest, serverCapabilityFilterSize) - offsetof(UA_FindServersOnNetworkRequest, maxRecordsToReturn) - sizeof(UA_UInt32), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* FindServersOnNetworkResponse */
static UA_DataTypeMember FindServersOnNetworkResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LastCounterResetTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_FindServersOnNetworkResponse, lastCounterResetTime) - offsetof(UA_FindServersOnNetworkResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Servers") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVERONNETWORK], /* .memberType */
    offsetof(UA_FindServersOnNetworkResponse, serversSize) - offsetof(UA_FindServersOnNetworkResponse, lastCounterResetTime) - sizeof(UA_DateTime), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* MessageSecurityMode */
#define MessageSecurityMode_members NULL

/* UserTokenType */
#define UserTokenType_members NULL

/* UserTokenPolicy */
static UA_DataTypeMember UserTokenPolicy_members[5] = {
{
    UA_TYPENAME("PolicyId") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TokenType") /* .memberName */
    &UA_TYPES[UA_TYPES_USERTOKENTYPE], /* .memberType */
    offsetof(UA_UserTokenPolicy, tokenType) - offsetof(UA_UserTokenPolicy, policyId) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IssuedTokenType") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_UserTokenPolicy, issuedTokenType) - offsetof(UA_UserTokenPolicy, tokenType) - sizeof(UA_UserTokenType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IssuerEndpointUrl") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_UserTokenPolicy, issuerEndpointUrl) - offsetof(UA_UserTokenPolicy, issuedTokenType) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityPolicyUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_UserTokenPolicy, securityPolicyUri) - offsetof(UA_UserTokenPolicy, issuerEndpointUrl) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* EndpointDescription */
static UA_DataTypeMember EndpointDescription_members[8] = {
{
    UA_TYPENAME("EndpointUrl") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Server") /* .memberName */
    &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION], /* .memberType */
    offsetof(UA_EndpointDescription, server) - offsetof(UA_EndpointDescription, endpointUrl) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerCertificate") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_EndpointDescription, serverCertificate) - offsetof(UA_EndpointDescription, server) - sizeof(UA_ApplicationDescription), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityMode") /* .memberName */
    &UA_TYPES[UA_TYPES_MESSAGESECURITYMODE], /* .memberType */
    offsetof(UA_EndpointDescription, securityMode) - offsetof(UA_EndpointDescription, serverCertificate) - sizeof(UA_ByteString), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityPolicyUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_EndpointDescription, securityPolicyUri) - offsetof(UA_EndpointDescription, securityMode) - sizeof(UA_MessageSecurityMode), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserIdentityTokens") /* .memberName */
    &UA_TYPES[UA_TYPES_USERTOKENPOLICY], /* .memberType */
    offsetof(UA_EndpointDescription, userIdentityTokensSize) - offsetof(UA_EndpointDescription, securityPolicyUri) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TransportProfileUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_EndpointDescription, transportProfileUri) - offsetof(UA_EndpointDescription, userIdentityTokens) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityLevel") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTE], /* .memberType */
    offsetof(UA_EndpointDescription, securityLevel) - offsetof(UA_EndpointDescription, transportProfileUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* GetEndpointsRequest */
static UA_DataTypeMember GetEndpointsRequest_members[4] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EndpointUrl") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_GetEndpointsRequest, endpointUrl) - offsetof(UA_GetEndpointsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LocaleIds") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_GetEndpointsRequest, localeIdsSize) - offsetof(UA_GetEndpointsRequest, endpointUrl) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ProfileUris") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_GetEndpointsRequest, profileUrisSize) - offsetof(UA_GetEndpointsRequest, localeIds) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* GetEndpointsResponse */
static UA_DataTypeMember GetEndpointsResponse_members[2] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Endpoints") /* .memberName */
    &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION], /* .memberType */
    offsetof(UA_GetEndpointsResponse, endpointsSize) - offsetof(UA_GetEndpointsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* RegisteredServer */
static UA_DataTypeMember RegisteredServer_members[8] = {
{
    UA_TYPENAME("ServerUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ProductUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_RegisteredServer, productUri) - offsetof(UA_RegisteredServer, serverUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerNames") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_RegisteredServer, serverNamesSize) - offsetof(UA_RegisteredServer, productUri) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerType") /* .memberName */
    &UA_TYPES[UA_TYPES_APPLICATIONTYPE], /* .memberType */
    offsetof(UA_RegisteredServer, serverType) - offsetof(UA_RegisteredServer, serverNames) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("GatewayServerUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_RegisteredServer, gatewayServerUri) - offsetof(UA_RegisteredServer, serverType) - sizeof(UA_ApplicationType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiscoveryUrls") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_RegisteredServer, discoveryUrlsSize) - offsetof(UA_RegisteredServer, gatewayServerUri) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SemaphoreFilePath") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_RegisteredServer, semaphoreFilePath) - offsetof(UA_RegisteredServer, discoveryUrls) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IsOnline") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_RegisteredServer, isOnline) - offsetof(UA_RegisteredServer, semaphoreFilePath) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* RegisterServerRequest */
static UA_DataTypeMember RegisterServerRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Server") /* .memberName */
    &UA_TYPES[UA_TYPES_REGISTEREDSERVER], /* .memberType */
    offsetof(UA_RegisterServerRequest, server) - offsetof(UA_RegisterServerRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* RegisterServerResponse */
static UA_DataTypeMember RegisterServerResponse_members[1] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* MdnsDiscoveryConfiguration */
static UA_DataTypeMember MdnsDiscoveryConfiguration_members[2] = {
{
    UA_TYPENAME("MdnsServerName") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerCapabilities") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_MdnsDiscoveryConfiguration, serverCapabilitiesSize) - offsetof(UA_MdnsDiscoveryConfiguration, mdnsServerName) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* RegisterServer2Request */
static UA_DataTypeMember RegisterServer2Request_members[3] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Server") /* .memberName */
    &UA_TYPES[UA_TYPES_REGISTEREDSERVER], /* .memberType */
    offsetof(UA_RegisterServer2Request, server) - offsetof(UA_RegisterServer2Request, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiscoveryConfiguration") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_RegisterServer2Request, discoveryConfigurationSize) - offsetof(UA_RegisterServer2Request, server) - sizeof(UA_RegisteredServer), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* RegisterServer2Response */
static UA_DataTypeMember RegisterServer2Response_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ConfigurationResults") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_RegisterServer2Response, configurationResultsSize) - offsetof(UA_RegisterServer2Response, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_RegisterServer2Response, diagnosticInfosSize) - offsetof(UA_RegisterServer2Response, configurationResults) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* SecurityTokenRequestType */
#define SecurityTokenRequestType_members NULL

/* ChannelSecurityToken */
static UA_DataTypeMember ChannelSecurityToken_members[4] = {
{
    UA_TYPENAME("ChannelId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TokenId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ChannelSecurityToken, tokenId) - offsetof(UA_ChannelSecurityToken, channelId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CreatedAt") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_ChannelSecurityToken, createdAt) - offsetof(UA_ChannelSecurityToken, tokenId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RevisedLifetime") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ChannelSecurityToken, revisedLifetime) - offsetof(UA_ChannelSecurityToken, createdAt) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* OpenSecureChannelRequest */
static UA_DataTypeMember OpenSecureChannelRequest_members[6] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ClientProtocolVersion") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_OpenSecureChannelRequest, clientProtocolVersion) - offsetof(UA_OpenSecureChannelRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestType") /* .memberName */
    &UA_TYPES[UA_TYPES_SECURITYTOKENREQUESTTYPE], /* .memberType */
    offsetof(UA_OpenSecureChannelRequest, requestType) - offsetof(UA_OpenSecureChannelRequest, clientProtocolVersion) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityMode") /* .memberName */
    &UA_TYPES[UA_TYPES_MESSAGESECURITYMODE], /* .memberType */
    offsetof(UA_OpenSecureChannelRequest, securityMode) - offsetof(UA_OpenSecureChannelRequest, requestType) - sizeof(UA_SecurityTokenRequestType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ClientNonce") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_OpenSecureChannelRequest, clientNonce) - offsetof(UA_OpenSecureChannelRequest, securityMode) - sizeof(UA_MessageSecurityMode), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestedLifetime") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_OpenSecureChannelRequest, requestedLifetime) - offsetof(UA_OpenSecureChannelRequest, clientNonce) - sizeof(UA_ByteString), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* OpenSecureChannelResponse */
static UA_DataTypeMember OpenSecureChannelResponse_members[4] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerProtocolVersion") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_OpenSecureChannelResponse, serverProtocolVersion) - offsetof(UA_OpenSecureChannelResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityToken") /* .memberName */
    &UA_TYPES[UA_TYPES_CHANNELSECURITYTOKEN], /* .memberType */
    offsetof(UA_OpenSecureChannelResponse, securityToken) - offsetof(UA_OpenSecureChannelResponse, serverProtocolVersion) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerNonce") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_OpenSecureChannelResponse, serverNonce) - offsetof(UA_OpenSecureChannelResponse, securityToken) - sizeof(UA_ChannelSecurityToken), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* CloseSecureChannelRequest */
static UA_DataTypeMember CloseSecureChannelRequest_members[1] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* CloseSecureChannelResponse */
static UA_DataTypeMember CloseSecureChannelResponse_members[1] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* SignedSoftwareCertificate */
static UA_DataTypeMember SignedSoftwareCertificate_members[2] = {
{
    UA_TYPENAME("CertificateData") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Signature") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_SignedSoftwareCertificate, signature) - offsetof(UA_SignedSoftwareCertificate, certificateData) - sizeof(UA_ByteString), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* SignatureData */
static UA_DataTypeMember SignatureData_members[2] = {
{
    UA_TYPENAME("Algorithm") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Signature") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_SignatureData, signature) - offsetof(UA_SignatureData, algorithm) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* CreateSessionRequest */
static UA_DataTypeMember CreateSessionRequest_members[9] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ClientDescription") /* .memberName */
    &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION], /* .memberType */
    offsetof(UA_CreateSessionRequest, clientDescription) - offsetof(UA_CreateSessionRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_CreateSessionRequest, serverUri) - offsetof(UA_CreateSessionRequest, clientDescription) - sizeof(UA_ApplicationDescription), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EndpointUrl") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_CreateSessionRequest, endpointUrl) - offsetof(UA_CreateSessionRequest, serverUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SessionName") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_CreateSessionRequest, sessionName) - offsetof(UA_CreateSessionRequest, endpointUrl) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ClientNonce") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_CreateSessionRequest, clientNonce) - offsetof(UA_CreateSessionRequest, sessionName) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ClientCertificate") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_CreateSessionRequest, clientCertificate) - offsetof(UA_CreateSessionRequest, clientNonce) - sizeof(UA_ByteString), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestedSessionTimeout") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_CreateSessionRequest, requestedSessionTimeout) - offsetof(UA_CreateSessionRequest, clientCertificate) - sizeof(UA_ByteString), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxResponseMessageSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_CreateSessionRequest, maxResponseMessageSize) - offsetof(UA_CreateSessionRequest, requestedSessionTimeout) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* CreateSessionResponse */
static UA_DataTypeMember CreateSessionResponse_members[10] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SessionId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_CreateSessionResponse, sessionId) - offsetof(UA_CreateSessionResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AuthenticationToken") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_CreateSessionResponse, authenticationToken) - offsetof(UA_CreateSessionResponse, sessionId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RevisedSessionTimeout") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_CreateSessionResponse, revisedSessionTimeout) - offsetof(UA_CreateSessionResponse, authenticationToken) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerNonce") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_CreateSessionResponse, serverNonce) - offsetof(UA_CreateSessionResponse, revisedSessionTimeout) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerCertificate") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_CreateSessionResponse, serverCertificate) - offsetof(UA_CreateSessionResponse, serverNonce) - sizeof(UA_ByteString), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerEndpoints") /* .memberName */
    &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION], /* .memberType */
    offsetof(UA_CreateSessionResponse, serverEndpointsSize) - offsetof(UA_CreateSessionResponse, serverCertificate) - sizeof(UA_ByteString), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerSoftwareCertificates") /* .memberName */
    &UA_TYPES[UA_TYPES_SIGNEDSOFTWARECERTIFICATE], /* .memberType */
    offsetof(UA_CreateSessionResponse, serverSoftwareCertificatesSize) - offsetof(UA_CreateSessionResponse, serverEndpoints) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerSignature") /* .memberName */
    &UA_TYPES[UA_TYPES_SIGNATUREDATA], /* .memberType */
    offsetof(UA_CreateSessionResponse, serverSignature) - offsetof(UA_CreateSessionResponse, serverSoftwareCertificates) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxRequestMessageSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_CreateSessionResponse, maxRequestMessageSize) - offsetof(UA_CreateSessionResponse, serverSignature) - sizeof(UA_SignatureData), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* UserIdentityToken */
static UA_DataTypeMember UserIdentityToken_members[1] = {
{
    UA_TYPENAME("PolicyId") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* AnonymousIdentityToken */
static UA_DataTypeMember AnonymousIdentityToken_members[1] = {
{
    UA_TYPENAME("PolicyId") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* UserNameIdentityToken */
static UA_DataTypeMember UserNameIdentityToken_members[4] = {
{
    UA_TYPENAME("PolicyId") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserName") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_UserNameIdentityToken, userName) - offsetof(UA_UserNameIdentityToken, policyId) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Password") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_UserNameIdentityToken, password) - offsetof(UA_UserNameIdentityToken, userName) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EncryptionAlgorithm") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_UserNameIdentityToken, encryptionAlgorithm) - offsetof(UA_UserNameIdentityToken, password) - sizeof(UA_ByteString), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* X509IdentityToken */
static UA_DataTypeMember X509IdentityToken_members[2] = {
{
    UA_TYPENAME("PolicyId") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CertificateData") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_X509IdentityToken, certificateData) - offsetof(UA_X509IdentityToken, policyId) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* IssuedIdentityToken */
static UA_DataTypeMember IssuedIdentityToken_members[3] = {
{
    UA_TYPENAME("PolicyId") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TokenData") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_IssuedIdentityToken, tokenData) - offsetof(UA_IssuedIdentityToken, policyId) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EncryptionAlgorithm") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_IssuedIdentityToken, encryptionAlgorithm) - offsetof(UA_IssuedIdentityToken, tokenData) - sizeof(UA_ByteString), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* ActivateSessionRequest */
static UA_DataTypeMember ActivateSessionRequest_members[6] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ClientSignature") /* .memberName */
    &UA_TYPES[UA_TYPES_SIGNATUREDATA], /* .memberType */
    offsetof(UA_ActivateSessionRequest, clientSignature) - offsetof(UA_ActivateSessionRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ClientSoftwareCertificates") /* .memberName */
    &UA_TYPES[UA_TYPES_SIGNEDSOFTWARECERTIFICATE], /* .memberType */
    offsetof(UA_ActivateSessionRequest, clientSoftwareCertificatesSize) - offsetof(UA_ActivateSessionRequest, clientSignature) - sizeof(UA_SignatureData), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LocaleIds") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_ActivateSessionRequest, localeIdsSize) - offsetof(UA_ActivateSessionRequest, clientSoftwareCertificates) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserIdentityToken") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_ActivateSessionRequest, userIdentityToken) - offsetof(UA_ActivateSessionRequest, localeIds) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserTokenSignature") /* .memberName */
    &UA_TYPES[UA_TYPES_SIGNATUREDATA], /* .memberType */
    offsetof(UA_ActivateSessionRequest, userTokenSignature) - offsetof(UA_ActivateSessionRequest, userIdentityToken) - sizeof(UA_ExtensionObject), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* ActivateSessionResponse */
static UA_DataTypeMember ActivateSessionResponse_members[4] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerNonce") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_ActivateSessionResponse, serverNonce) - offsetof(UA_ActivateSessionResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_ActivateSessionResponse, resultsSize) - offsetof(UA_ActivateSessionResponse, serverNonce) - sizeof(UA_ByteString), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_ActivateSessionResponse, diagnosticInfosSize) - offsetof(UA_ActivateSessionResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* CloseSessionRequest */
static UA_DataTypeMember CloseSessionRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DeleteSubscriptions") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_CloseSessionRequest, deleteSubscriptions) - offsetof(UA_CloseSessionRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* CloseSessionResponse */
static UA_DataTypeMember CloseSessionResponse_members[1] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* CancelRequest */
static UA_DataTypeMember CancelRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestHandle") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_CancelRequest, requestHandle) - offsetof(UA_CancelRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* CancelResponse */
static UA_DataTypeMember CancelResponse_members[2] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CancelCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_CancelResponse, cancelCount) - offsetof(UA_CancelResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* NodeAttributesMask */
#define NodeAttributesMask_members NULL

/* NodeAttributes */
static UA_DataTypeMember NodeAttributes_members[5] = {
{
    UA_TYPENAME("SpecifiedAttributes") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisplayName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_NodeAttributes, displayName) - offsetof(UA_NodeAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_NodeAttributes, description) - offsetof(UA_NodeAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("WriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_NodeAttributes, writeMask) - offsetof(UA_NodeAttributes, description) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserWriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_NodeAttributes, userWriteMask) - offsetof(UA_NodeAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* ObjectAttributes */
static UA_DataTypeMember ObjectAttributes_members[6] = {
{
    UA_TYPENAME("SpecifiedAttributes") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisplayName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_ObjectAttributes, displayName) - offsetof(UA_ObjectAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_ObjectAttributes, description) - offsetof(UA_ObjectAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("WriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ObjectAttributes, writeMask) - offsetof(UA_ObjectAttributes, description) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserWriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ObjectAttributes, userWriteMask) - offsetof(UA_ObjectAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EventNotifier") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTE], /* .memberType */
    offsetof(UA_ObjectAttributes, eventNotifier) - offsetof(UA_ObjectAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* VariableAttributes */
static UA_DataTypeMember VariableAttributes_members[13] = {
{
    UA_TYPENAME("SpecifiedAttributes") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisplayName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_VariableAttributes, displayName) - offsetof(UA_VariableAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_VariableAttributes, description) - offsetof(UA_VariableAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("WriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_VariableAttributes, writeMask) - offsetof(UA_VariableAttributes, description) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserWriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_VariableAttributes, userWriteMask) - offsetof(UA_VariableAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Value") /* .memberName */
    &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */
    offsetof(UA_VariableAttributes, value) - offsetof(UA_VariableAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataType") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_VariableAttributes, dataType) - offsetof(UA_VariableAttributes, value) - sizeof(UA_Variant), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ValueRank") /* .memberName */
    &UA_TYPES[UA_TYPES_INT32], /* .memberType */
    offsetof(UA_VariableAttributes, valueRank) - offsetof(UA_VariableAttributes, dataType) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ArrayDimensions") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_VariableAttributes, arrayDimensionsSize) - offsetof(UA_VariableAttributes, valueRank) - sizeof(UA_Int32), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AccessLevel") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTE], /* .memberType */
    offsetof(UA_VariableAttributes, accessLevel) - offsetof(UA_VariableAttributes, arrayDimensions) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserAccessLevel") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTE], /* .memberType */
    offsetof(UA_VariableAttributes, userAccessLevel) - offsetof(UA_VariableAttributes, accessLevel) - sizeof(UA_Byte), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MinimumSamplingInterval") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_VariableAttributes, minimumSamplingInterval) - offsetof(UA_VariableAttributes, userAccessLevel) - sizeof(UA_Byte), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Historizing") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_VariableAttributes, historizing) - offsetof(UA_VariableAttributes, minimumSamplingInterval) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* MethodAttributes */
static UA_DataTypeMember MethodAttributes_members[7] = {
{
    UA_TYPENAME("SpecifiedAttributes") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisplayName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_MethodAttributes, displayName) - offsetof(UA_MethodAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_MethodAttributes, description) - offsetof(UA_MethodAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("WriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_MethodAttributes, writeMask) - offsetof(UA_MethodAttributes, description) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserWriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_MethodAttributes, userWriteMask) - offsetof(UA_MethodAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Executable") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_MethodAttributes, executable) - offsetof(UA_MethodAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserExecutable") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_MethodAttributes, userExecutable) - offsetof(UA_MethodAttributes, executable) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* ObjectTypeAttributes */
static UA_DataTypeMember ObjectTypeAttributes_members[6] = {
{
    UA_TYPENAME("SpecifiedAttributes") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisplayName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_ObjectTypeAttributes, displayName) - offsetof(UA_ObjectTypeAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_ObjectTypeAttributes, description) - offsetof(UA_ObjectTypeAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("WriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ObjectTypeAttributes, writeMask) - offsetof(UA_ObjectTypeAttributes, description) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserWriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ObjectTypeAttributes, userWriteMask) - offsetof(UA_ObjectTypeAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IsAbstract") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_ObjectTypeAttributes, isAbstract) - offsetof(UA_ObjectTypeAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* VariableTypeAttributes */
static UA_DataTypeMember VariableTypeAttributes_members[10] = {
{
    UA_TYPENAME("SpecifiedAttributes") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisplayName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_VariableTypeAttributes, displayName) - offsetof(UA_VariableTypeAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_VariableTypeAttributes, description) - offsetof(UA_VariableTypeAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("WriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_VariableTypeAttributes, writeMask) - offsetof(UA_VariableTypeAttributes, description) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserWriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_VariableTypeAttributes, userWriteMask) - offsetof(UA_VariableTypeAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Value") /* .memberName */
    &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */
    offsetof(UA_VariableTypeAttributes, value) - offsetof(UA_VariableTypeAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataType") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_VariableTypeAttributes, dataType) - offsetof(UA_VariableTypeAttributes, value) - sizeof(UA_Variant), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ValueRank") /* .memberName */
    &UA_TYPES[UA_TYPES_INT32], /* .memberType */
    offsetof(UA_VariableTypeAttributes, valueRank) - offsetof(UA_VariableTypeAttributes, dataType) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ArrayDimensions") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_VariableTypeAttributes, arrayDimensionsSize) - offsetof(UA_VariableTypeAttributes, valueRank) - sizeof(UA_Int32), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IsAbstract") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_VariableTypeAttributes, isAbstract) - offsetof(UA_VariableTypeAttributes, arrayDimensions) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* ReferenceTypeAttributes */
static UA_DataTypeMember ReferenceTypeAttributes_members[8] = {
{
    UA_TYPENAME("SpecifiedAttributes") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisplayName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_ReferenceTypeAttributes, displayName) - offsetof(UA_ReferenceTypeAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_ReferenceTypeAttributes, description) - offsetof(UA_ReferenceTypeAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("WriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ReferenceTypeAttributes, writeMask) - offsetof(UA_ReferenceTypeAttributes, description) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserWriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ReferenceTypeAttributes, userWriteMask) - offsetof(UA_ReferenceTypeAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IsAbstract") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_ReferenceTypeAttributes, isAbstract) - offsetof(UA_ReferenceTypeAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Symmetric") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_ReferenceTypeAttributes, symmetric) - offsetof(UA_ReferenceTypeAttributes, isAbstract) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("InverseName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_ReferenceTypeAttributes, inverseName) - offsetof(UA_ReferenceTypeAttributes, symmetric) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* DataTypeAttributes */
static UA_DataTypeMember DataTypeAttributes_members[6] = {
{
    UA_TYPENAME("SpecifiedAttributes") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisplayName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_DataTypeAttributes, displayName) - offsetof(UA_DataTypeAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_DataTypeAttributes, description) - offsetof(UA_DataTypeAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("WriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_DataTypeAttributes, writeMask) - offsetof(UA_DataTypeAttributes, description) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserWriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_DataTypeAttributes, userWriteMask) - offsetof(UA_DataTypeAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IsAbstract") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_DataTypeAttributes, isAbstract) - offsetof(UA_DataTypeAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* ViewAttributes */
static UA_DataTypeMember ViewAttributes_members[7] = {
{
    UA_TYPENAME("SpecifiedAttributes") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisplayName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_ViewAttributes, displayName) - offsetof(UA_ViewAttributes, specifiedAttributes) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_ViewAttributes, description) - offsetof(UA_ViewAttributes, displayName) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("WriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ViewAttributes, writeMask) - offsetof(UA_ViewAttributes, description) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserWriteMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ViewAttributes, userWriteMask) - offsetof(UA_ViewAttributes, writeMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ContainsNoLoops") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_ViewAttributes, containsNoLoops) - offsetof(UA_ViewAttributes, userWriteMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EventNotifier") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTE], /* .memberType */
    offsetof(UA_ViewAttributes, eventNotifier) - offsetof(UA_ViewAttributes, containsNoLoops) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* AddNodesItem */
static UA_DataTypeMember AddNodesItem_members[7] = {
{
    UA_TYPENAME("ParentNodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReferenceTypeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_AddNodesItem, referenceTypeId) - offsetof(UA_AddNodesItem, parentNodeId) - sizeof(UA_ExpandedNodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestedNewNodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */
    offsetof(UA_AddNodesItem, requestedNewNodeId) - offsetof(UA_AddNodesItem, referenceTypeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("BrowseName") /* .memberName */
    &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */
    offsetof(UA_AddNodesItem, browseName) - offsetof(UA_AddNodesItem, requestedNewNodeId) - sizeof(UA_ExpandedNodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NodeClass") /* .memberName */
    &UA_TYPES[UA_TYPES_NODECLASS], /* .memberType */
    offsetof(UA_AddNodesItem, nodeClass) - offsetof(UA_AddNodesItem, browseName) - sizeof(UA_QualifiedName), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NodeAttributes") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_AddNodesItem, nodeAttributes) - offsetof(UA_AddNodesItem, nodeClass) - sizeof(UA_NodeClass), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TypeDefinition") /* .memberName */
    &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */
    offsetof(UA_AddNodesItem, typeDefinition) - offsetof(UA_AddNodesItem, nodeAttributes) - sizeof(UA_ExtensionObject), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* AddNodesResult */
static UA_DataTypeMember AddNodesResult_members[2] = {
{
    UA_TYPENAME("StatusCode") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AddedNodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_AddNodesResult, addedNodeId) - offsetof(UA_AddNodesResult, statusCode) - sizeof(UA_StatusCode), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* AddNodesRequest */
static UA_DataTypeMember AddNodesRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NodesToAdd") /* .memberName */
    &UA_TYPES[UA_TYPES_ADDNODESITEM], /* .memberType */
    offsetof(UA_AddNodesRequest, nodesToAddSize) - offsetof(UA_AddNodesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* AddNodesResponse */
static UA_DataTypeMember AddNodesResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_ADDNODESRESULT], /* .memberType */
    offsetof(UA_AddNodesResponse, resultsSize) - offsetof(UA_AddNodesResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_AddNodesResponse, diagnosticInfosSize) - offsetof(UA_AddNodesResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* AddReferencesItem */
static UA_DataTypeMember AddReferencesItem_members[6] = {
{
    UA_TYPENAME("SourceNodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReferenceTypeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_AddReferencesItem, referenceTypeId) - offsetof(UA_AddReferencesItem, sourceNodeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IsForward") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_AddReferencesItem, isForward) - offsetof(UA_AddReferencesItem, referenceTypeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TargetServerUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_AddReferencesItem, targetServerUri) - offsetof(UA_AddReferencesItem, isForward) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TargetNodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */
    offsetof(UA_AddReferencesItem, targetNodeId) - offsetof(UA_AddReferencesItem, targetServerUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TargetNodeClass") /* .memberName */
    &UA_TYPES[UA_TYPES_NODECLASS], /* .memberType */
    offsetof(UA_AddReferencesItem, targetNodeClass) - offsetof(UA_AddReferencesItem, targetNodeId) - sizeof(UA_ExpandedNodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* AddReferencesRequest */
static UA_DataTypeMember AddReferencesRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReferencesToAdd") /* .memberName */
    &UA_TYPES[UA_TYPES_ADDREFERENCESITEM], /* .memberType */
    offsetof(UA_AddReferencesRequest, referencesToAddSize) - offsetof(UA_AddReferencesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* AddReferencesResponse */
static UA_DataTypeMember AddReferencesResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_AddReferencesResponse, resultsSize) - offsetof(UA_AddReferencesResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_AddReferencesResponse, diagnosticInfosSize) - offsetof(UA_AddReferencesResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* DeleteNodesItem */
static UA_DataTypeMember DeleteNodesItem_members[2] = {
{
    UA_TYPENAME("NodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DeleteTargetReferences") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_DeleteNodesItem, deleteTargetReferences) - offsetof(UA_DeleteNodesItem, nodeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* DeleteNodesRequest */
static UA_DataTypeMember DeleteNodesRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NodesToDelete") /* .memberName */
    &UA_TYPES[UA_TYPES_DELETENODESITEM], /* .memberType */
    offsetof(UA_DeleteNodesRequest, nodesToDeleteSize) - offsetof(UA_DeleteNodesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* DeleteNodesResponse */
static UA_DataTypeMember DeleteNodesResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_DeleteNodesResponse, resultsSize) - offsetof(UA_DeleteNodesResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_DeleteNodesResponse, diagnosticInfosSize) - offsetof(UA_DeleteNodesResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* DeleteReferencesItem */
static UA_DataTypeMember DeleteReferencesItem_members[5] = {
{
    UA_TYPENAME("SourceNodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReferenceTypeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_DeleteReferencesItem, referenceTypeId) - offsetof(UA_DeleteReferencesItem, sourceNodeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IsForward") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_DeleteReferencesItem, isForward) - offsetof(UA_DeleteReferencesItem, referenceTypeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TargetNodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */
    offsetof(UA_DeleteReferencesItem, targetNodeId) - offsetof(UA_DeleteReferencesItem, isForward) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DeleteBidirectional") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_DeleteReferencesItem, deleteBidirectional) - offsetof(UA_DeleteReferencesItem, targetNodeId) - sizeof(UA_ExpandedNodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* DeleteReferencesRequest */
static UA_DataTypeMember DeleteReferencesRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReferencesToDelete") /* .memberName */
    &UA_TYPES[UA_TYPES_DELETEREFERENCESITEM], /* .memberType */
    offsetof(UA_DeleteReferencesRequest, referencesToDeleteSize) - offsetof(UA_DeleteReferencesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* DeleteReferencesResponse */
static UA_DataTypeMember DeleteReferencesResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_DeleteReferencesResponse, resultsSize) - offsetof(UA_DeleteReferencesResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_DeleteReferencesResponse, diagnosticInfosSize) - offsetof(UA_DeleteReferencesResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* BrowseDirection */
#define BrowseDirection_members NULL

/* ViewDescription */
static UA_DataTypeMember ViewDescription_members[3] = {
{
    UA_TYPENAME("ViewId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Timestamp") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_ViewDescription, timestamp) - offsetof(UA_ViewDescription, viewId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ViewVersion") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ViewDescription, viewVersion) - offsetof(UA_ViewDescription, timestamp) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* BrowseDescription */
static UA_DataTypeMember BrowseDescription_members[6] = {
{
    UA_TYPENAME("NodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("BrowseDirection") /* .memberName */
    &UA_TYPES[UA_TYPES_BROWSEDIRECTION], /* .memberType */
    offsetof(UA_BrowseDescription, browseDirection) - offsetof(UA_BrowseDescription, nodeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReferenceTypeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_BrowseDescription, referenceTypeId) - offsetof(UA_BrowseDescription, browseDirection) - sizeof(UA_BrowseDirection), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IncludeSubtypes") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_BrowseDescription, includeSubtypes) - offsetof(UA_BrowseDescription, referenceTypeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NodeClassMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_BrowseDescription, nodeClassMask) - offsetof(UA_BrowseDescription, includeSubtypes) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ResultMask") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_BrowseDescription, resultMask) - offsetof(UA_BrowseDescription, nodeClassMask) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* BrowseResultMask */
#define BrowseResultMask_members NULL

/* ReferenceDescription */
static UA_DataTypeMember ReferenceDescription_members[7] = {
{
    UA_TYPENAME("ReferenceTypeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IsForward") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_ReferenceDescription, isForward) - offsetof(UA_ReferenceDescription, referenceTypeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */
    offsetof(UA_ReferenceDescription, nodeId) - offsetof(UA_ReferenceDescription, isForward) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("BrowseName") /* .memberName */
    &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */
    offsetof(UA_ReferenceDescription, browseName) - offsetof(UA_ReferenceDescription, nodeId) - sizeof(UA_ExpandedNodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisplayName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_ReferenceDescription, displayName) - offsetof(UA_ReferenceDescription, browseName) - sizeof(UA_QualifiedName), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NodeClass") /* .memberName */
    &UA_TYPES[UA_TYPES_NODECLASS], /* .memberType */
    offsetof(UA_ReferenceDescription, nodeClass) - offsetof(UA_ReferenceDescription, displayName) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TypeDefinition") /* .memberName */
    &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */
    offsetof(UA_ReferenceDescription, typeDefinition) - offsetof(UA_ReferenceDescription, nodeClass) - sizeof(UA_NodeClass), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* BrowseResult */
static UA_DataTypeMember BrowseResult_members[3] = {
{
    UA_TYPENAME("StatusCode") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ContinuationPoint") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_BrowseResult, continuationPoint) - offsetof(UA_BrowseResult, statusCode) - sizeof(UA_StatusCode), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("References") /* .memberName */
    &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION], /* .memberType */
    offsetof(UA_BrowseResult, referencesSize) - offsetof(UA_BrowseResult, continuationPoint) - sizeof(UA_ByteString), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* BrowseRequest */
static UA_DataTypeMember BrowseRequest_members[4] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("View") /* .memberName */
    &UA_TYPES[UA_TYPES_VIEWDESCRIPTION], /* .memberType */
    offsetof(UA_BrowseRequest, view) - offsetof(UA_BrowseRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestedMaxReferencesPerNode") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_BrowseRequest, requestedMaxReferencesPerNode) - offsetof(UA_BrowseRequest, view) - sizeof(UA_ViewDescription), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NodesToBrowse") /* .memberName */
    &UA_TYPES[UA_TYPES_BROWSEDESCRIPTION], /* .memberType */
    offsetof(UA_BrowseRequest, nodesToBrowseSize) - offsetof(UA_BrowseRequest, requestedMaxReferencesPerNode) - sizeof(UA_UInt32), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* BrowseResponse */
static UA_DataTypeMember BrowseResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_BROWSERESULT], /* .memberType */
    offsetof(UA_BrowseResponse, resultsSize) - offsetof(UA_BrowseResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_BrowseResponse, diagnosticInfosSize) - offsetof(UA_BrowseResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* BrowseNextRequest */
static UA_DataTypeMember BrowseNextRequest_members[3] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReleaseContinuationPoints") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_BrowseNextRequest, releaseContinuationPoints) - offsetof(UA_BrowseNextRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ContinuationPoints") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_BrowseNextRequest, continuationPointsSize) - offsetof(UA_BrowseNextRequest, releaseContinuationPoints) - sizeof(UA_Boolean), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* BrowseNextResponse */
static UA_DataTypeMember BrowseNextResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_BROWSERESULT], /* .memberType */
    offsetof(UA_BrowseNextResponse, resultsSize) - offsetof(UA_BrowseNextResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_BrowseNextResponse, diagnosticInfosSize) - offsetof(UA_BrowseNextResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* RelativePathElement */
static UA_DataTypeMember RelativePathElement_members[4] = {
{
    UA_TYPENAME("ReferenceTypeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IsInverse") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_RelativePathElement, isInverse) - offsetof(UA_RelativePathElement, referenceTypeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IncludeSubtypes") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_RelativePathElement, includeSubtypes) - offsetof(UA_RelativePathElement, isInverse) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TargetName") /* .memberName */
    &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */
    offsetof(UA_RelativePathElement, targetName) - offsetof(UA_RelativePathElement, includeSubtypes) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* RelativePath */
static UA_DataTypeMember RelativePath_members[1] = {
{
    UA_TYPENAME("Elements") /* .memberName */
    &UA_TYPES[UA_TYPES_RELATIVEPATHELEMENT], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* BrowsePath */
static UA_DataTypeMember BrowsePath_members[2] = {
{
    UA_TYPENAME("StartingNode") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RelativePath") /* .memberName */
    &UA_TYPES[UA_TYPES_RELATIVEPATH], /* .memberType */
    offsetof(UA_BrowsePath, relativePath) - offsetof(UA_BrowsePath, startingNode) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* BrowsePathTarget */
static UA_DataTypeMember BrowsePathTarget_members[2] = {
{
    UA_TYPENAME("TargetId") /* .memberName */
    &UA_TYPES[UA_TYPES_EXPANDEDNODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RemainingPathIndex") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_BrowsePathTarget, remainingPathIndex) - offsetof(UA_BrowsePathTarget, targetId) - sizeof(UA_ExpandedNodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* BrowsePathResult */
static UA_DataTypeMember BrowsePathResult_members[2] = {
{
    UA_TYPENAME("StatusCode") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Targets") /* .memberName */
    &UA_TYPES[UA_TYPES_BROWSEPATHTARGET], /* .memberType */
    offsetof(UA_BrowsePathResult, targetsSize) - offsetof(UA_BrowsePathResult, statusCode) - sizeof(UA_StatusCode), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* TranslateBrowsePathsToNodeIdsRequest */
static UA_DataTypeMember TranslateBrowsePathsToNodeIdsRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("BrowsePaths") /* .memberName */
    &UA_TYPES[UA_TYPES_BROWSEPATH], /* .memberType */
    offsetof(UA_TranslateBrowsePathsToNodeIdsRequest, browsePathsSize) - offsetof(UA_TranslateBrowsePathsToNodeIdsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* TranslateBrowsePathsToNodeIdsResponse */
static UA_DataTypeMember TranslateBrowsePathsToNodeIdsResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_BROWSEPATHRESULT], /* .memberType */
    offsetof(UA_TranslateBrowsePathsToNodeIdsResponse, resultsSize) - offsetof(UA_TranslateBrowsePathsToNodeIdsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_TranslateBrowsePathsToNodeIdsResponse, diagnosticInfosSize) - offsetof(UA_TranslateBrowsePathsToNodeIdsResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* RegisterNodesRequest */
static UA_DataTypeMember RegisterNodesRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NodesToRegister") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_RegisterNodesRequest, nodesToRegisterSize) - offsetof(UA_RegisterNodesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* RegisterNodesResponse */
static UA_DataTypeMember RegisterNodesResponse_members[2] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RegisteredNodeIds") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_RegisterNodesResponse, registeredNodeIdsSize) - offsetof(UA_RegisterNodesResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* UnregisterNodesRequest */
static UA_DataTypeMember UnregisterNodesRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NodesToUnregister") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_UnregisterNodesRequest, nodesToUnregisterSize) - offsetof(UA_UnregisterNodesRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* UnregisterNodesResponse */
static UA_DataTypeMember UnregisterNodesResponse_members[1] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* FilterOperator */
#define FilterOperator_members NULL

/* ContentFilterElement */
static UA_DataTypeMember ContentFilterElement_members[2] = {
{
    UA_TYPENAME("FilterOperator") /* .memberName */
    &UA_TYPES[UA_TYPES_FILTEROPERATOR], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("FilterOperands") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_ContentFilterElement, filterOperandsSize) - offsetof(UA_ContentFilterElement, filterOperator) - sizeof(UA_FilterOperator), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* ContentFilter */
static UA_DataTypeMember ContentFilter_members[1] = {
{
    UA_TYPENAME("Elements") /* .memberName */
    &UA_TYPES[UA_TYPES_CONTENTFILTERELEMENT], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* ElementOperand */
static UA_DataTypeMember ElementOperand_members[1] = {
{
    UA_TYPENAME("Index") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* LiteralOperand */
static UA_DataTypeMember LiteralOperand_members[1] = {
{
    UA_TYPENAME("Value") /* .memberName */
    &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* AttributeOperand */
static UA_DataTypeMember AttributeOperand_members[5] = {
{
    UA_TYPENAME("NodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Alias") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_AttributeOperand, alias) - offsetof(UA_AttributeOperand, nodeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("BrowsePath") /* .memberName */
    &UA_TYPES[UA_TYPES_RELATIVEPATH], /* .memberType */
    offsetof(UA_AttributeOperand, browsePath) - offsetof(UA_AttributeOperand, alias) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AttributeId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_AttributeOperand, attributeId) - offsetof(UA_AttributeOperand, browsePath) - sizeof(UA_RelativePath), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IndexRange") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_AttributeOperand, indexRange) - offsetof(UA_AttributeOperand, attributeId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* SimpleAttributeOperand */
static UA_DataTypeMember SimpleAttributeOperand_members[4] = {
{
    UA_TYPENAME("TypeDefinitionId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("BrowsePath") /* .memberName */
    &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */
    offsetof(UA_SimpleAttributeOperand, browsePathSize) - offsetof(UA_SimpleAttributeOperand, typeDefinitionId) - sizeof(UA_NodeId), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AttributeId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SimpleAttributeOperand, attributeId) - offsetof(UA_SimpleAttributeOperand, browsePath) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IndexRange") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_SimpleAttributeOperand, indexRange) - offsetof(UA_SimpleAttributeOperand, attributeId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* ContentFilterElementResult */
static UA_DataTypeMember ContentFilterElementResult_members[3] = {
{
    UA_TYPENAME("StatusCode") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("OperandStatusCodes") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_ContentFilterElementResult, operandStatusCodesSize) - offsetof(UA_ContentFilterElementResult, statusCode) - sizeof(UA_StatusCode), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("OperandDiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_ContentFilterElementResult, operandDiagnosticInfosSize) - offsetof(UA_ContentFilterElementResult, operandStatusCodes) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* ContentFilterResult */
static UA_DataTypeMember ContentFilterResult_members[2] = {
{
    UA_TYPENAME("ElementResults") /* .memberName */
    &UA_TYPES[UA_TYPES_CONTENTFILTERELEMENTRESULT], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ElementDiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_ContentFilterResult, elementDiagnosticInfosSize) - offsetof(UA_ContentFilterResult, elementResults) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* TimestampsToReturn */
#define TimestampsToReturn_members NULL

/* ReadValueId */
static UA_DataTypeMember ReadValueId_members[4] = {
{
    UA_TYPENAME("NodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AttributeId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ReadValueId, attributeId) - offsetof(UA_ReadValueId, nodeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IndexRange") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_ReadValueId, indexRange) - offsetof(UA_ReadValueId, attributeId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataEncoding") /* .memberName */
    &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */
    offsetof(UA_ReadValueId, dataEncoding) - offsetof(UA_ReadValueId, indexRange) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* ReadRequest */
static UA_DataTypeMember ReadRequest_members[4] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxAge") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_ReadRequest, maxAge) - offsetof(UA_ReadRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TimestampsToReturn") /* .memberName */
    &UA_TYPES[UA_TYPES_TIMESTAMPSTORETURN], /* .memberType */
    offsetof(UA_ReadRequest, timestampsToReturn) - offsetof(UA_ReadRequest, maxAge) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NodesToRead") /* .memberName */
    &UA_TYPES[UA_TYPES_READVALUEID], /* .memberType */
    offsetof(UA_ReadRequest, nodesToReadSize) - offsetof(UA_ReadRequest, timestampsToReturn) - sizeof(UA_TimestampsToReturn), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* ReadResponse */
static UA_DataTypeMember ReadResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_DATAVALUE], /* .memberType */
    offsetof(UA_ReadResponse, resultsSize) - offsetof(UA_ReadResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_ReadResponse, diagnosticInfosSize) - offsetof(UA_ReadResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* HistoryReadValueId */
static UA_DataTypeMember HistoryReadValueId_members[4] = {
{
    UA_TYPENAME("NodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IndexRange") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_HistoryReadValueId, indexRange) - offsetof(UA_HistoryReadValueId, nodeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataEncoding") /* .memberName */
    &UA_TYPES[UA_TYPES_QUALIFIEDNAME], /* .memberType */
    offsetof(UA_HistoryReadValueId, dataEncoding) - offsetof(UA_HistoryReadValueId, indexRange) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ContinuationPoint") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_HistoryReadValueId, continuationPoint) - offsetof(UA_HistoryReadValueId, dataEncoding) - sizeof(UA_QualifiedName), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* HistoryReadResult */
static UA_DataTypeMember HistoryReadResult_members[3] = {
{
    UA_TYPENAME("StatusCode") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ContinuationPoint") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_HistoryReadResult, continuationPoint) - offsetof(UA_HistoryReadResult, statusCode) - sizeof(UA_StatusCode), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("HistoryData") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_HistoryReadResult, historyData) - offsetof(UA_HistoryReadResult, continuationPoint) - sizeof(UA_ByteString), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* ReadRawModifiedDetails */
static UA_DataTypeMember ReadRawModifiedDetails_members[5] = {
{
    UA_TYPENAME("IsReadModified") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("StartTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_ReadRawModifiedDetails, startTime) - offsetof(UA_ReadRawModifiedDetails, isReadModified) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EndTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_ReadRawModifiedDetails, endTime) - offsetof(UA_ReadRawModifiedDetails, startTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NumValuesPerNode") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ReadRawModifiedDetails, numValuesPerNode) - offsetof(UA_ReadRawModifiedDetails, endTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReturnBounds") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_ReadRawModifiedDetails, returnBounds) - offsetof(UA_ReadRawModifiedDetails, numValuesPerNode) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* ReadAtTimeDetails */
static UA_DataTypeMember ReadAtTimeDetails_members[2] = {
{
    UA_TYPENAME("ReqTimes") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UseSimpleBounds") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_ReadAtTimeDetails, useSimpleBounds) - offsetof(UA_ReadAtTimeDetails, reqTimes) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* HistoryData */
static UA_DataTypeMember HistoryData_members[1] = {
{
    UA_TYPENAME("DataValues") /* .memberName */
    &UA_TYPES[UA_TYPES_DATAVALUE], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* HistoryReadRequest */
static UA_DataTypeMember HistoryReadRequest_members[5] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("HistoryReadDetails") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_HistoryReadRequest, historyReadDetails) - offsetof(UA_HistoryReadRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TimestampsToReturn") /* .memberName */
    &UA_TYPES[UA_TYPES_TIMESTAMPSTORETURN], /* .memberType */
    offsetof(UA_HistoryReadRequest, timestampsToReturn) - offsetof(UA_HistoryReadRequest, historyReadDetails) - sizeof(UA_ExtensionObject), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReleaseContinuationPoints") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_HistoryReadRequest, releaseContinuationPoints) - offsetof(UA_HistoryReadRequest, timestampsToReturn) - sizeof(UA_TimestampsToReturn), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NodesToRead") /* .memberName */
    &UA_TYPES[UA_TYPES_HISTORYREADVALUEID], /* .memberType */
    offsetof(UA_HistoryReadRequest, nodesToReadSize) - offsetof(UA_HistoryReadRequest, releaseContinuationPoints) - sizeof(UA_Boolean), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* HistoryReadResponse */
static UA_DataTypeMember HistoryReadResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_HISTORYREADRESULT], /* .memberType */
    offsetof(UA_HistoryReadResponse, resultsSize) - offsetof(UA_HistoryReadResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_HistoryReadResponse, diagnosticInfosSize) - offsetof(UA_HistoryReadResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* WriteValue */
static UA_DataTypeMember WriteValue_members[4] = {
{
    UA_TYPENAME("NodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AttributeId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_WriteValue, attributeId) - offsetof(UA_WriteValue, nodeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IndexRange") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_WriteValue, indexRange) - offsetof(UA_WriteValue, attributeId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Value") /* .memberName */
    &UA_TYPES[UA_TYPES_DATAVALUE], /* .memberType */
    offsetof(UA_WriteValue, value) - offsetof(UA_WriteValue, indexRange) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* WriteRequest */
static UA_DataTypeMember WriteRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NodesToWrite") /* .memberName */
    &UA_TYPES[UA_TYPES_WRITEVALUE], /* .memberType */
    offsetof(UA_WriteRequest, nodesToWriteSize) - offsetof(UA_WriteRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* WriteResponse */
static UA_DataTypeMember WriteResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_WriteResponse, resultsSize) - offsetof(UA_WriteResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_WriteResponse, diagnosticInfosSize) - offsetof(UA_WriteResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* HistoryUpdateType */
#define HistoryUpdateType_members NULL

/* PerformUpdateType */
#define PerformUpdateType_members NULL

/* UpdateDataDetails */
static UA_DataTypeMember UpdateDataDetails_members[3] = {
{
    UA_TYPENAME("NodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PerformInsertReplace") /* .memberName */
    &UA_TYPES[UA_TYPES_PERFORMUPDATETYPE], /* .memberType */
    offsetof(UA_UpdateDataDetails, performInsertReplace) - offsetof(UA_UpdateDataDetails, nodeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UpdateValues") /* .memberName */
    &UA_TYPES[UA_TYPES_DATAVALUE], /* .memberType */
    offsetof(UA_UpdateDataDetails, updateValuesSize) - offsetof(UA_UpdateDataDetails, performInsertReplace) - sizeof(UA_PerformUpdateType), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* DeleteRawModifiedDetails */
static UA_DataTypeMember DeleteRawModifiedDetails_members[4] = {
{
    UA_TYPENAME("NodeId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("IsDeleteModified") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_DeleteRawModifiedDetails, isDeleteModified) - offsetof(UA_DeleteRawModifiedDetails, nodeId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("StartTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_DeleteRawModifiedDetails, startTime) - offsetof(UA_DeleteRawModifiedDetails, isDeleteModified) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EndTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_DeleteRawModifiedDetails, endTime) - offsetof(UA_DeleteRawModifiedDetails, startTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* HistoryUpdateResult */
static UA_DataTypeMember HistoryUpdateResult_members[3] = {
{
    UA_TYPENAME("StatusCode") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("OperationResults") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_HistoryUpdateResult, operationResultsSize) - offsetof(UA_HistoryUpdateResult, statusCode) - sizeof(UA_StatusCode), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_HistoryUpdateResult, diagnosticInfosSize) - offsetof(UA_HistoryUpdateResult, operationResults) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* HistoryUpdateRequest */
static UA_DataTypeMember HistoryUpdateRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("HistoryUpdateDetails") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_HistoryUpdateRequest, historyUpdateDetailsSize) - offsetof(UA_HistoryUpdateRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* HistoryUpdateResponse */
static UA_DataTypeMember HistoryUpdateResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_HISTORYUPDATERESULT], /* .memberType */
    offsetof(UA_HistoryUpdateResponse, resultsSize) - offsetof(UA_HistoryUpdateResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_HistoryUpdateResponse, diagnosticInfosSize) - offsetof(UA_HistoryUpdateResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* CallMethodRequest */
static UA_DataTypeMember CallMethodRequest_members[3] = {
{
    UA_TYPENAME("ObjectId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MethodId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_CallMethodRequest, methodId) - offsetof(UA_CallMethodRequest, objectId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("InputArguments") /* .memberName */
    &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */
    offsetof(UA_CallMethodRequest, inputArgumentsSize) - offsetof(UA_CallMethodRequest, methodId) - sizeof(UA_NodeId), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* CallMethodResult */
static UA_DataTypeMember CallMethodResult_members[4] = {
{
    UA_TYPENAME("StatusCode") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("InputArgumentResults") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_CallMethodResult, inputArgumentResultsSize) - offsetof(UA_CallMethodResult, statusCode) - sizeof(UA_StatusCode), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("InputArgumentDiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_CallMethodResult, inputArgumentDiagnosticInfosSize) - offsetof(UA_CallMethodResult, inputArgumentResults) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("OutputArguments") /* .memberName */
    &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */
    offsetof(UA_CallMethodResult, outputArgumentsSize) - offsetof(UA_CallMethodResult, inputArgumentDiagnosticInfos) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* CallRequest */
static UA_DataTypeMember CallRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MethodsToCall") /* .memberName */
    &UA_TYPES[UA_TYPES_CALLMETHODREQUEST], /* .memberType */
    offsetof(UA_CallRequest, methodsToCallSize) - offsetof(UA_CallRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* CallResponse */
static UA_DataTypeMember CallResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_CALLMETHODRESULT], /* .memberType */
    offsetof(UA_CallResponse, resultsSize) - offsetof(UA_CallResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_CallResponse, diagnosticInfosSize) - offsetof(UA_CallResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* MonitoringMode */
#define MonitoringMode_members NULL

/* DataChangeTrigger */
#define DataChangeTrigger_members NULL

/* DeadbandType */
#define DeadbandType_members NULL

/* DataChangeFilter */
static UA_DataTypeMember DataChangeFilter_members[3] = {
{
    UA_TYPENAME("Trigger") /* .memberName */
    &UA_TYPES[UA_TYPES_DATACHANGETRIGGER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DeadbandType") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_DataChangeFilter, deadbandType) - offsetof(UA_DataChangeFilter, trigger) - sizeof(UA_DataChangeTrigger), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DeadbandValue") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_DataChangeFilter, deadbandValue) - offsetof(UA_DataChangeFilter, deadbandType) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* EventFilter */
static UA_DataTypeMember EventFilter_members[2] = {
{
    UA_TYPENAME("SelectClauses") /* .memberName */
    &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("WhereClause") /* .memberName */
    &UA_TYPES[UA_TYPES_CONTENTFILTER], /* .memberType */
    offsetof(UA_EventFilter, whereClause) - offsetof(UA_EventFilter, selectClauses) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* AggregateConfiguration */
static UA_DataTypeMember AggregateConfiguration_members[5] = {
{
    UA_TYPENAME("UseServerCapabilitiesDefaults") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TreatUncertainAsBad") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_AggregateConfiguration, treatUncertainAsBad) - offsetof(UA_AggregateConfiguration, useServerCapabilitiesDefaults) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PercentDataBad") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTE], /* .memberType */
    offsetof(UA_AggregateConfiguration, percentDataBad) - offsetof(UA_AggregateConfiguration, treatUncertainAsBad) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PercentDataGood") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTE], /* .memberType */
    offsetof(UA_AggregateConfiguration, percentDataGood) - offsetof(UA_AggregateConfiguration, percentDataBad) - sizeof(UA_Byte), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UseSlopedExtrapolation") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_AggregateConfiguration, useSlopedExtrapolation) - offsetof(UA_AggregateConfiguration, percentDataGood) - sizeof(UA_Byte), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* AggregateFilter */
static UA_DataTypeMember AggregateFilter_members[4] = {
{
    UA_TYPENAME("StartTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AggregateType") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_AggregateFilter, aggregateType) - offsetof(UA_AggregateFilter, startTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ProcessingInterval") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_AggregateFilter, processingInterval) - offsetof(UA_AggregateFilter, aggregateType) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AggregateConfiguration") /* .memberName */
    &UA_TYPES[UA_TYPES_AGGREGATECONFIGURATION], /* .memberType */
    offsetof(UA_AggregateFilter, aggregateConfiguration) - offsetof(UA_AggregateFilter, processingInterval) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* EventFilterResult */
static UA_DataTypeMember EventFilterResult_members[3] = {
{
    UA_TYPENAME("SelectClauseResults") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SelectClauseDiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_EventFilterResult, selectClauseDiagnosticInfosSize) - offsetof(UA_EventFilterResult, selectClauseResults) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("WhereClauseResult") /* .memberName */
    &UA_TYPES[UA_TYPES_CONTENTFILTERRESULT], /* .memberType */
    offsetof(UA_EventFilterResult, whereClauseResult) - offsetof(UA_EventFilterResult, selectClauseDiagnosticInfos) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* MonitoringParameters */
static UA_DataTypeMember MonitoringParameters_members[5] = {
{
    UA_TYPENAME("ClientHandle") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SamplingInterval") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_MonitoringParameters, samplingInterval) - offsetof(UA_MonitoringParameters, clientHandle) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Filter") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_MonitoringParameters, filter) - offsetof(UA_MonitoringParameters, samplingInterval) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("QueueSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_MonitoringParameters, queueSize) - offsetof(UA_MonitoringParameters, filter) - sizeof(UA_ExtensionObject), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiscardOldest") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_MonitoringParameters, discardOldest) - offsetof(UA_MonitoringParameters, queueSize) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* MonitoredItemCreateRequest */
static UA_DataTypeMember MonitoredItemCreateRequest_members[3] = {
{
    UA_TYPENAME("ItemToMonitor") /* .memberName */
    &UA_TYPES[UA_TYPES_READVALUEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MonitoringMode") /* .memberName */
    &UA_TYPES[UA_TYPES_MONITORINGMODE], /* .memberType */
    offsetof(UA_MonitoredItemCreateRequest, monitoringMode) - offsetof(UA_MonitoredItemCreateRequest, itemToMonitor) - sizeof(UA_ReadValueId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestedParameters") /* .memberName */
    &UA_TYPES[UA_TYPES_MONITORINGPARAMETERS], /* .memberType */
    offsetof(UA_MonitoredItemCreateRequest, requestedParameters) - offsetof(UA_MonitoredItemCreateRequest, monitoringMode) - sizeof(UA_MonitoringMode), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* MonitoredItemCreateResult */
static UA_DataTypeMember MonitoredItemCreateResult_members[5] = {
{
    UA_TYPENAME("StatusCode") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MonitoredItemId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_MonitoredItemCreateResult, monitoredItemId) - offsetof(UA_MonitoredItemCreateResult, statusCode) - sizeof(UA_StatusCode), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RevisedSamplingInterval") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_MonitoredItemCreateResult, revisedSamplingInterval) - offsetof(UA_MonitoredItemCreateResult, monitoredItemId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RevisedQueueSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_MonitoredItemCreateResult, revisedQueueSize) - offsetof(UA_MonitoredItemCreateResult, revisedSamplingInterval) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("FilterResult") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_MonitoredItemCreateResult, filterResult) - offsetof(UA_MonitoredItemCreateResult, revisedQueueSize) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* CreateMonitoredItemsRequest */
static UA_DataTypeMember CreateMonitoredItemsRequest_members[4] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscriptionId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_CreateMonitoredItemsRequest, subscriptionId) - offsetof(UA_CreateMonitoredItemsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TimestampsToReturn") /* .memberName */
    &UA_TYPES[UA_TYPES_TIMESTAMPSTORETURN], /* .memberType */
    offsetof(UA_CreateMonitoredItemsRequest, timestampsToReturn) - offsetof(UA_CreateMonitoredItemsRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ItemsToCreate") /* .memberName */
    &UA_TYPES[UA_TYPES_MONITOREDITEMCREATEREQUEST], /* .memberType */
    offsetof(UA_CreateMonitoredItemsRequest, itemsToCreateSize) - offsetof(UA_CreateMonitoredItemsRequest, timestampsToReturn) - sizeof(UA_TimestampsToReturn), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* CreateMonitoredItemsResponse */
static UA_DataTypeMember CreateMonitoredItemsResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_MONITOREDITEMCREATERESULT], /* .memberType */
    offsetof(UA_CreateMonitoredItemsResponse, resultsSize) - offsetof(UA_CreateMonitoredItemsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_CreateMonitoredItemsResponse, diagnosticInfosSize) - offsetof(UA_CreateMonitoredItemsResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* MonitoredItemModifyRequest */
static UA_DataTypeMember MonitoredItemModifyRequest_members[2] = {
{
    UA_TYPENAME("MonitoredItemId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestedParameters") /* .memberName */
    &UA_TYPES[UA_TYPES_MONITORINGPARAMETERS], /* .memberType */
    offsetof(UA_MonitoredItemModifyRequest, requestedParameters) - offsetof(UA_MonitoredItemModifyRequest, monitoredItemId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* MonitoredItemModifyResult */
static UA_DataTypeMember MonitoredItemModifyResult_members[4] = {
{
    UA_TYPENAME("StatusCode") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RevisedSamplingInterval") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_MonitoredItemModifyResult, revisedSamplingInterval) - offsetof(UA_MonitoredItemModifyResult, statusCode) - sizeof(UA_StatusCode), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RevisedQueueSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_MonitoredItemModifyResult, revisedQueueSize) - offsetof(UA_MonitoredItemModifyResult, revisedSamplingInterval) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("FilterResult") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_MonitoredItemModifyResult, filterResult) - offsetof(UA_MonitoredItemModifyResult, revisedQueueSize) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* ModifyMonitoredItemsRequest */
static UA_DataTypeMember ModifyMonitoredItemsRequest_members[4] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscriptionId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ModifyMonitoredItemsRequest, subscriptionId) - offsetof(UA_ModifyMonitoredItemsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TimestampsToReturn") /* .memberName */
    &UA_TYPES[UA_TYPES_TIMESTAMPSTORETURN], /* .memberType */
    offsetof(UA_ModifyMonitoredItemsRequest, timestampsToReturn) - offsetof(UA_ModifyMonitoredItemsRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ItemsToModify") /* .memberName */
    &UA_TYPES[UA_TYPES_MONITOREDITEMMODIFYREQUEST], /* .memberType */
    offsetof(UA_ModifyMonitoredItemsRequest, itemsToModifySize) - offsetof(UA_ModifyMonitoredItemsRequest, timestampsToReturn) - sizeof(UA_TimestampsToReturn), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* ModifyMonitoredItemsResponse */
static UA_DataTypeMember ModifyMonitoredItemsResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_MONITOREDITEMMODIFYRESULT], /* .memberType */
    offsetof(UA_ModifyMonitoredItemsResponse, resultsSize) - offsetof(UA_ModifyMonitoredItemsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_ModifyMonitoredItemsResponse, diagnosticInfosSize) - offsetof(UA_ModifyMonitoredItemsResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* SetMonitoringModeRequest */
static UA_DataTypeMember SetMonitoringModeRequest_members[4] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscriptionId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SetMonitoringModeRequest, subscriptionId) - offsetof(UA_SetMonitoringModeRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MonitoringMode") /* .memberName */
    &UA_TYPES[UA_TYPES_MONITORINGMODE], /* .memberType */
    offsetof(UA_SetMonitoringModeRequest, monitoringMode) - offsetof(UA_SetMonitoringModeRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MonitoredItemIds") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SetMonitoringModeRequest, monitoredItemIdsSize) - offsetof(UA_SetMonitoringModeRequest, monitoringMode) - sizeof(UA_MonitoringMode), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* SetMonitoringModeResponse */
static UA_DataTypeMember SetMonitoringModeResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_SetMonitoringModeResponse, resultsSize) - offsetof(UA_SetMonitoringModeResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_SetMonitoringModeResponse, diagnosticInfosSize) - offsetof(UA_SetMonitoringModeResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* SetTriggeringRequest */
static UA_DataTypeMember SetTriggeringRequest_members[5] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscriptionId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SetTriggeringRequest, subscriptionId) - offsetof(UA_SetTriggeringRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TriggeringItemId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SetTriggeringRequest, triggeringItemId) - offsetof(UA_SetTriggeringRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LinksToAdd") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SetTriggeringRequest, linksToAddSize) - offsetof(UA_SetTriggeringRequest, triggeringItemId) - sizeof(UA_UInt32), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LinksToRemove") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SetTriggeringRequest, linksToRemoveSize) - offsetof(UA_SetTriggeringRequest, linksToAdd) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* SetTriggeringResponse */
static UA_DataTypeMember SetTriggeringResponse_members[5] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AddResults") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_SetTriggeringResponse, addResultsSize) - offsetof(UA_SetTriggeringResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AddDiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_SetTriggeringResponse, addDiagnosticInfosSize) - offsetof(UA_SetTriggeringResponse, addResults) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RemoveResults") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_SetTriggeringResponse, removeResultsSize) - offsetof(UA_SetTriggeringResponse, addDiagnosticInfos) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RemoveDiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_SetTriggeringResponse, removeDiagnosticInfosSize) - offsetof(UA_SetTriggeringResponse, removeResults) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* DeleteMonitoredItemsRequest */
static UA_DataTypeMember DeleteMonitoredItemsRequest_members[3] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscriptionId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_DeleteMonitoredItemsRequest, subscriptionId) - offsetof(UA_DeleteMonitoredItemsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MonitoredItemIds") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_DeleteMonitoredItemsRequest, monitoredItemIdsSize) - offsetof(UA_DeleteMonitoredItemsRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* DeleteMonitoredItemsResponse */
static UA_DataTypeMember DeleteMonitoredItemsResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_DeleteMonitoredItemsResponse, resultsSize) - offsetof(UA_DeleteMonitoredItemsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_DeleteMonitoredItemsResponse, diagnosticInfosSize) - offsetof(UA_DeleteMonitoredItemsResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* CreateSubscriptionRequest */
static UA_DataTypeMember CreateSubscriptionRequest_members[7] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestedPublishingInterval") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_CreateSubscriptionRequest, requestedPublishingInterval) - offsetof(UA_CreateSubscriptionRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestedLifetimeCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_CreateSubscriptionRequest, requestedLifetimeCount) - offsetof(UA_CreateSubscriptionRequest, requestedPublishingInterval) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestedMaxKeepAliveCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_CreateSubscriptionRequest, requestedMaxKeepAliveCount) - offsetof(UA_CreateSubscriptionRequest, requestedLifetimeCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxNotificationsPerPublish") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_CreateSubscriptionRequest, maxNotificationsPerPublish) - offsetof(UA_CreateSubscriptionRequest, requestedMaxKeepAliveCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PublishingEnabled") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_CreateSubscriptionRequest, publishingEnabled) - offsetof(UA_CreateSubscriptionRequest, maxNotificationsPerPublish) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Priority") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTE], /* .memberType */
    offsetof(UA_CreateSubscriptionRequest, priority) - offsetof(UA_CreateSubscriptionRequest, publishingEnabled) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* CreateSubscriptionResponse */
static UA_DataTypeMember CreateSubscriptionResponse_members[5] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscriptionId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_CreateSubscriptionResponse, subscriptionId) - offsetof(UA_CreateSubscriptionResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RevisedPublishingInterval") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_CreateSubscriptionResponse, revisedPublishingInterval) - offsetof(UA_CreateSubscriptionResponse, subscriptionId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RevisedLifetimeCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_CreateSubscriptionResponse, revisedLifetimeCount) - offsetof(UA_CreateSubscriptionResponse, revisedPublishingInterval) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RevisedMaxKeepAliveCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_CreateSubscriptionResponse, revisedMaxKeepAliveCount) - offsetof(UA_CreateSubscriptionResponse, revisedLifetimeCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* ModifySubscriptionRequest */
static UA_DataTypeMember ModifySubscriptionRequest_members[7] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscriptionId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ModifySubscriptionRequest, subscriptionId) - offsetof(UA_ModifySubscriptionRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestedPublishingInterval") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_ModifySubscriptionRequest, requestedPublishingInterval) - offsetof(UA_ModifySubscriptionRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestedLifetimeCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ModifySubscriptionRequest, requestedLifetimeCount) - offsetof(UA_ModifySubscriptionRequest, requestedPublishingInterval) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestedMaxKeepAliveCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ModifySubscriptionRequest, requestedMaxKeepAliveCount) - offsetof(UA_ModifySubscriptionRequest, requestedLifetimeCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxNotificationsPerPublish") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ModifySubscriptionRequest, maxNotificationsPerPublish) - offsetof(UA_ModifySubscriptionRequest, requestedMaxKeepAliveCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Priority") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTE], /* .memberType */
    offsetof(UA_ModifySubscriptionRequest, priority) - offsetof(UA_ModifySubscriptionRequest, maxNotificationsPerPublish) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* ModifySubscriptionResponse */
static UA_DataTypeMember ModifySubscriptionResponse_members[4] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RevisedPublishingInterval") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_ModifySubscriptionResponse, revisedPublishingInterval) - offsetof(UA_ModifySubscriptionResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RevisedLifetimeCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ModifySubscriptionResponse, revisedLifetimeCount) - offsetof(UA_ModifySubscriptionResponse, revisedPublishingInterval) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RevisedMaxKeepAliveCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ModifySubscriptionResponse, revisedMaxKeepAliveCount) - offsetof(UA_ModifySubscriptionResponse, revisedLifetimeCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* SetPublishingModeRequest */
static UA_DataTypeMember SetPublishingModeRequest_members[3] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PublishingEnabled") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_SetPublishingModeRequest, publishingEnabled) - offsetof(UA_SetPublishingModeRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscriptionIds") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SetPublishingModeRequest, subscriptionIdsSize) - offsetof(UA_SetPublishingModeRequest, publishingEnabled) - sizeof(UA_Boolean), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* SetPublishingModeResponse */
static UA_DataTypeMember SetPublishingModeResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_SetPublishingModeResponse, resultsSize) - offsetof(UA_SetPublishingModeResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_SetPublishingModeResponse, diagnosticInfosSize) - offsetof(UA_SetPublishingModeResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* NotificationMessage */
static UA_DataTypeMember NotificationMessage_members[3] = {
{
    UA_TYPENAME("SequenceNumber") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PublishTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_NotificationMessage, publishTime) - offsetof(UA_NotificationMessage, sequenceNumber) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NotificationData") /* .memberName */
    &UA_TYPES[UA_TYPES_EXTENSIONOBJECT], /* .memberType */
    offsetof(UA_NotificationMessage, notificationDataSize) - offsetof(UA_NotificationMessage, publishTime) - sizeof(UA_DateTime), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* MonitoredItemNotification */
static UA_DataTypeMember MonitoredItemNotification_members[2] = {
{
    UA_TYPENAME("ClientHandle") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Value") /* .memberName */
    &UA_TYPES[UA_TYPES_DATAVALUE], /* .memberType */
    offsetof(UA_MonitoredItemNotification, value) - offsetof(UA_MonitoredItemNotification, clientHandle) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* EventFieldList */
static UA_DataTypeMember EventFieldList_members[2] = {
{
    UA_TYPENAME("ClientHandle") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EventFields") /* .memberName */
    &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */
    offsetof(UA_EventFieldList, eventFieldsSize) - offsetof(UA_EventFieldList, clientHandle) - sizeof(UA_UInt32), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* HistoryEventFieldList */
static UA_DataTypeMember HistoryEventFieldList_members[1] = {
{
    UA_TYPENAME("EventFields") /* .memberName */
    &UA_TYPES[UA_TYPES_VARIANT], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* StatusChangeNotification */
static UA_DataTypeMember StatusChangeNotification_members[2] = {
{
    UA_TYPENAME("Status") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfo") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_StatusChangeNotification, diagnosticInfo) - offsetof(UA_StatusChangeNotification, status) - sizeof(UA_StatusCode), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* SubscriptionAcknowledgement */
static UA_DataTypeMember SubscriptionAcknowledgement_members[2] = {
{
    UA_TYPENAME("SubscriptionId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SequenceNumber") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionAcknowledgement, sequenceNumber) - offsetof(UA_SubscriptionAcknowledgement, subscriptionId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* PublishRequest */
static UA_DataTypeMember PublishRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscriptionAcknowledgements") /* .memberName */
    &UA_TYPES[UA_TYPES_SUBSCRIPTIONACKNOWLEDGEMENT], /* .memberType */
    offsetof(UA_PublishRequest, subscriptionAcknowledgementsSize) - offsetof(UA_PublishRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* PublishResponse */
static UA_DataTypeMember PublishResponse_members[7] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscriptionId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_PublishResponse, subscriptionId) - offsetof(UA_PublishResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AvailableSequenceNumbers") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_PublishResponse, availableSequenceNumbersSize) - offsetof(UA_PublishResponse, subscriptionId) - sizeof(UA_UInt32), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MoreNotifications") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_PublishResponse, moreNotifications) - offsetof(UA_PublishResponse, availableSequenceNumbers) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NotificationMessage") /* .memberName */
    &UA_TYPES[UA_TYPES_NOTIFICATIONMESSAGE], /* .memberType */
    offsetof(UA_PublishResponse, notificationMessage) - offsetof(UA_PublishResponse, moreNotifications) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_PublishResponse, resultsSize) - offsetof(UA_PublishResponse, notificationMessage) - sizeof(UA_NotificationMessage), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_PublishResponse, diagnosticInfosSize) - offsetof(UA_PublishResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* RepublishRequest */
static UA_DataTypeMember RepublishRequest_members[3] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscriptionId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_RepublishRequest, subscriptionId) - offsetof(UA_RepublishRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RetransmitSequenceNumber") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_RepublishRequest, retransmitSequenceNumber) - offsetof(UA_RepublishRequest, subscriptionId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* RepublishResponse */
static UA_DataTypeMember RepublishResponse_members[2] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NotificationMessage") /* .memberName */
    &UA_TYPES[UA_TYPES_NOTIFICATIONMESSAGE], /* .memberType */
    offsetof(UA_RepublishResponse, notificationMessage) - offsetof(UA_RepublishResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* TransferResult */
static UA_DataTypeMember TransferResult_members[2] = {
{
    UA_TYPENAME("StatusCode") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AvailableSequenceNumbers") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_TransferResult, availableSequenceNumbersSize) - offsetof(UA_TransferResult, statusCode) - sizeof(UA_StatusCode), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* TransferSubscriptionsRequest */
static UA_DataTypeMember TransferSubscriptionsRequest_members[3] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscriptionIds") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_TransferSubscriptionsRequest, subscriptionIdsSize) - offsetof(UA_TransferSubscriptionsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SendInitialValues") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_TransferSubscriptionsRequest, sendInitialValues) - offsetof(UA_TransferSubscriptionsRequest, subscriptionIds) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* TransferSubscriptionsResponse */
static UA_DataTypeMember TransferSubscriptionsResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_TRANSFERRESULT], /* .memberType */
    offsetof(UA_TransferSubscriptionsResponse, resultsSize) - offsetof(UA_TransferSubscriptionsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_TransferSubscriptionsResponse, diagnosticInfosSize) - offsetof(UA_TransferSubscriptionsResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* DeleteSubscriptionsRequest */
static UA_DataTypeMember DeleteSubscriptionsRequest_members[2] = {
{
    UA_TYPENAME("RequestHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_REQUESTHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscriptionIds") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_DeleteSubscriptionsRequest, subscriptionIdsSize) - offsetof(UA_DeleteSubscriptionsRequest, requestHeader) - sizeof(UA_RequestHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* DeleteSubscriptionsResponse */
static UA_DataTypeMember DeleteSubscriptionsResponse_members[3] = {
{
    UA_TYPENAME("ResponseHeader") /* .memberName */
    &UA_TYPES[UA_TYPES_RESPONSEHEADER], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Results") /* .memberName */
    &UA_TYPES[UA_TYPES_STATUSCODE], /* .memberType */
    offsetof(UA_DeleteSubscriptionsResponse, resultsSize) - offsetof(UA_DeleteSubscriptionsResponse, responseHeader) - sizeof(UA_ResponseHeader), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_DeleteSubscriptionsResponse, diagnosticInfosSize) - offsetof(UA_DeleteSubscriptionsResponse, results) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* BuildInfo */
static UA_DataTypeMember BuildInfo_members[6] = {
{
    UA_TYPENAME("ProductUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ManufacturerName") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_BuildInfo, manufacturerName) - offsetof(UA_BuildInfo, productUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ProductName") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_BuildInfo, productName) - offsetof(UA_BuildInfo, manufacturerName) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SoftwareVersion") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_BuildInfo, softwareVersion) - offsetof(UA_BuildInfo, productName) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("BuildNumber") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_BuildInfo, buildNumber) - offsetof(UA_BuildInfo, softwareVersion) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("BuildDate") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_BuildInfo, buildDate) - offsetof(UA_BuildInfo, buildNumber) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* RedundancySupport */
#define RedundancySupport_members NULL

/* ServerState */
#define ServerState_members NULL

/* ServerDiagnosticsSummaryDataType */
static UA_DataTypeMember ServerDiagnosticsSummaryDataType_members[12] = {
{
    UA_TYPENAME("ServerViewCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CurrentSessionCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ServerDiagnosticsSummaryDataType, currentSessionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, serverViewCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CumulatedSessionCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ServerDiagnosticsSummaryDataType, cumulatedSessionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, currentSessionCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityRejectedSessionCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ServerDiagnosticsSummaryDataType, securityRejectedSessionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, cumulatedSessionCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RejectedSessionCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ServerDiagnosticsSummaryDataType, rejectedSessionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, securityRejectedSessionCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SessionTimeoutCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ServerDiagnosticsSummaryDataType, sessionTimeoutCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, rejectedSessionCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SessionAbortCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ServerDiagnosticsSummaryDataType, sessionAbortCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, sessionTimeoutCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CurrentSubscriptionCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ServerDiagnosticsSummaryDataType, currentSubscriptionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, sessionAbortCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CumulatedSubscriptionCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ServerDiagnosticsSummaryDataType, cumulatedSubscriptionCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, currentSubscriptionCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PublishingIntervalCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ServerDiagnosticsSummaryDataType, publishingIntervalCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, cumulatedSubscriptionCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityRejectedRequestsCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ServerDiagnosticsSummaryDataType, securityRejectedRequestsCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, publishingIntervalCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RejectedRequestsCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ServerDiagnosticsSummaryDataType, rejectedRequestsCount) - offsetof(UA_ServerDiagnosticsSummaryDataType, securityRejectedRequestsCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* ServerStatusDataType */
static UA_DataTypeMember ServerStatusDataType_members[6] = {
{
    UA_TYPENAME("StartTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CurrentTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_ServerStatusDataType, currentTime) - offsetof(UA_ServerStatusDataType, startTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("State") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVERSTATE], /* .memberType */
    offsetof(UA_ServerStatusDataType, state) - offsetof(UA_ServerStatusDataType, currentTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("BuildInfo") /* .memberName */
    &UA_TYPES[UA_TYPES_BUILDINFO], /* .memberType */
    offsetof(UA_ServerStatusDataType, buildInfo) - offsetof(UA_ServerStatusDataType, state) - sizeof(UA_ServerState), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecondsTillShutdown") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ServerStatusDataType, secondsTillShutdown) - offsetof(UA_ServerStatusDataType, buildInfo) - sizeof(UA_BuildInfo), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ShutdownReason") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_ServerStatusDataType, shutdownReason) - offsetof(UA_ServerStatusDataType, secondsTillShutdown) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* SessionSecurityDiagnosticsDataType */
static UA_DataTypeMember SessionSecurityDiagnosticsDataType_members[9] = {
{
    UA_TYPENAME("SessionId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ClientUserIdOfSession") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_SessionSecurityDiagnosticsDataType, clientUserIdOfSession) - offsetof(UA_SessionSecurityDiagnosticsDataType, sessionId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ClientUserIdHistory") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_SessionSecurityDiagnosticsDataType, clientUserIdHistorySize) - offsetof(UA_SessionSecurityDiagnosticsDataType, clientUserIdOfSession) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AuthenticationMechanism") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_SessionSecurityDiagnosticsDataType, authenticationMechanism) - offsetof(UA_SessionSecurityDiagnosticsDataType, clientUserIdHistory) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Encoding") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_SessionSecurityDiagnosticsDataType, encoding) - offsetof(UA_SessionSecurityDiagnosticsDataType, authenticationMechanism) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TransportProtocol") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_SessionSecurityDiagnosticsDataType, transportProtocol) - offsetof(UA_SessionSecurityDiagnosticsDataType, encoding) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityMode") /* .memberName */
    &UA_TYPES[UA_TYPES_MESSAGESECURITYMODE], /* .memberType */
    offsetof(UA_SessionSecurityDiagnosticsDataType, securityMode) - offsetof(UA_SessionSecurityDiagnosticsDataType, transportProtocol) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SecurityPolicyUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_SessionSecurityDiagnosticsDataType, securityPolicyUri) - offsetof(UA_SessionSecurityDiagnosticsDataType, securityMode) - sizeof(UA_MessageSecurityMode), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ClientCertificate") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_SessionSecurityDiagnosticsDataType, clientCertificate) - offsetof(UA_SessionSecurityDiagnosticsDataType, securityPolicyUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* ServiceCounterDataType */
static UA_DataTypeMember ServiceCounterDataType_members[2] = {
{
    UA_TYPENAME("TotalCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ErrorCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_ServiceCounterDataType, errorCount) - offsetof(UA_ServiceCounterDataType, totalCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* SubscriptionDiagnosticsDataType */
static UA_DataTypeMember SubscriptionDiagnosticsDataType_members[31] = {
{
    UA_TYPENAME("SessionId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SubscriptionId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, subscriptionId) - offsetof(UA_SubscriptionDiagnosticsDataType, sessionId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Priority") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTE], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, priority) - offsetof(UA_SubscriptionDiagnosticsDataType, subscriptionId) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PublishingInterval") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, publishingInterval) - offsetof(UA_SubscriptionDiagnosticsDataType, priority) - sizeof(UA_Byte), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxKeepAliveCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, maxKeepAliveCount) - offsetof(UA_SubscriptionDiagnosticsDataType, publishingInterval) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxLifetimeCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, maxLifetimeCount) - offsetof(UA_SubscriptionDiagnosticsDataType, maxKeepAliveCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxNotificationsPerPublish") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, maxNotificationsPerPublish) - offsetof(UA_SubscriptionDiagnosticsDataType, maxLifetimeCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PublishingEnabled") /* .memberName */
    &UA_TYPES[UA_TYPES_BOOLEAN], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, publishingEnabled) - offsetof(UA_SubscriptionDiagnosticsDataType, maxNotificationsPerPublish) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ModifyCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, modifyCount) - offsetof(UA_SubscriptionDiagnosticsDataType, publishingEnabled) - sizeof(UA_Boolean), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EnableCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, enableCount) - offsetof(UA_SubscriptionDiagnosticsDataType, modifyCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisableCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, disableCount) - offsetof(UA_SubscriptionDiagnosticsDataType, enableCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RepublishRequestCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, republishRequestCount) - offsetof(UA_SubscriptionDiagnosticsDataType, disableCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RepublishMessageRequestCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, republishMessageRequestCount) - offsetof(UA_SubscriptionDiagnosticsDataType, republishRequestCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RepublishMessageCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, republishMessageCount) - offsetof(UA_SubscriptionDiagnosticsDataType, republishMessageRequestCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TransferRequestCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, transferRequestCount) - offsetof(UA_SubscriptionDiagnosticsDataType, republishMessageCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TransferredToAltClientCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, transferredToAltClientCount) - offsetof(UA_SubscriptionDiagnosticsDataType, transferRequestCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TransferredToSameClientCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, transferredToSameClientCount) - offsetof(UA_SubscriptionDiagnosticsDataType, transferredToAltClientCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PublishRequestCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, publishRequestCount) - offsetof(UA_SubscriptionDiagnosticsDataType, transferredToSameClientCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DataChangeNotificationsCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, dataChangeNotificationsCount) - offsetof(UA_SubscriptionDiagnosticsDataType, publishRequestCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EventNotificationsCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, eventNotificationsCount) - offsetof(UA_SubscriptionDiagnosticsDataType, dataChangeNotificationsCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NotificationsCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, notificationsCount) - offsetof(UA_SubscriptionDiagnosticsDataType, eventNotificationsCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LatePublishRequestCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, latePublishRequestCount) - offsetof(UA_SubscriptionDiagnosticsDataType, notificationsCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CurrentKeepAliveCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, currentKeepAliveCount) - offsetof(UA_SubscriptionDiagnosticsDataType, latePublishRequestCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CurrentLifetimeCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, currentLifetimeCount) - offsetof(UA_SubscriptionDiagnosticsDataType, currentKeepAliveCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UnacknowledgedMessageCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, unacknowledgedMessageCount) - offsetof(UA_SubscriptionDiagnosticsDataType, currentLifetimeCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiscardedMessageCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, discardedMessageCount) - offsetof(UA_SubscriptionDiagnosticsDataType, unacknowledgedMessageCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MonitoredItemCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, monitoredItemCount) - offsetof(UA_SubscriptionDiagnosticsDataType, discardedMessageCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisabledMonitoredItemCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, disabledMonitoredItemCount) - offsetof(UA_SubscriptionDiagnosticsDataType, monitoredItemCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MonitoringQueueOverflowCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, monitoringQueueOverflowCount) - offsetof(UA_SubscriptionDiagnosticsDataType, disabledMonitoredItemCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("NextSequenceNumber") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, nextSequenceNumber) - offsetof(UA_SubscriptionDiagnosticsDataType, monitoringQueueOverflowCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EventQueueOverFlowCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SubscriptionDiagnosticsDataType, eventQueueOverFlowCount) - offsetof(UA_SubscriptionDiagnosticsDataType, nextSequenceNumber) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* Range */
static UA_DataTypeMember Range_members[2] = {
{
    UA_TYPENAME("Low") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("High") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_Range, high) - offsetof(UA_Range, low) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* EUInformation */
static UA_DataTypeMember EUInformation_members[4] = {
{
    UA_TYPENAME("NamespaceUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UnitId") /* .memberName */
    &UA_TYPES[UA_TYPES_INT32], /* .memberType */
    offsetof(UA_EUInformation, unitId) - offsetof(UA_EUInformation, namespaceUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DisplayName") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_EUInformation, displayName) - offsetof(UA_EUInformation, unitId) - sizeof(UA_Int32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Description") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_EUInformation, description) - offsetof(UA_EUInformation, displayName) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* AxisScaleEnumeration */
#define AxisScaleEnumeration_members NULL

/* ComplexNumberType */
static UA_DataTypeMember ComplexNumberType_members[2] = {
{
    UA_TYPENAME("Real") /* .memberName */
    &UA_TYPES[UA_TYPES_FLOAT], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Imaginary") /* .memberName */
    &UA_TYPES[UA_TYPES_FLOAT], /* .memberType */
    offsetof(UA_ComplexNumberType, imaginary) - offsetof(UA_ComplexNumberType, real) - sizeof(UA_Float), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* DoubleComplexNumberType */
static UA_DataTypeMember DoubleComplexNumberType_members[2] = {
{
    UA_TYPENAME("Real") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Imaginary") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_DoubleComplexNumberType, imaginary) - offsetof(UA_DoubleComplexNumberType, real) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* AxisInformation */
static UA_DataTypeMember AxisInformation_members[5] = {
{
    UA_TYPENAME("EngineeringUnits") /* .memberName */
    &UA_TYPES[UA_TYPES_EUINFORMATION], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EURange") /* .memberName */
    &UA_TYPES[UA_TYPES_RANGE], /* .memberType */
    offsetof(UA_AxisInformation, eURange) - offsetof(UA_AxisInformation, engineeringUnits) - sizeof(UA_EUInformation), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Title") /* .memberName */
    &UA_TYPES[UA_TYPES_LOCALIZEDTEXT], /* .memberType */
    offsetof(UA_AxisInformation, title) - offsetof(UA_AxisInformation, eURange) - sizeof(UA_Range), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AxisScaleType") /* .memberName */
    &UA_TYPES[UA_TYPES_AXISSCALEENUMERATION], /* .memberType */
    offsetof(UA_AxisInformation, axisScaleType) - offsetof(UA_AxisInformation, title) - sizeof(UA_LocalizedText), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AxisSteps") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_AxisInformation, axisStepsSize) - offsetof(UA_AxisInformation, axisScaleType) - sizeof(UA_AxisScaleEnumeration), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* XVType */
static UA_DataTypeMember XVType_members[2] = {
{
    UA_TYPENAME("X") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Value") /* .memberName */
    &UA_TYPES[UA_TYPES_FLOAT], /* .memberType */
    offsetof(UA_XVType, value) - offsetof(UA_XVType, x) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* EnumDefinition */
static UA_DataTypeMember EnumDefinition_members[1] = {
{
    UA_TYPENAME("Fields") /* .memberName */
    &UA_TYPES[UA_TYPES_ENUMFIELD], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* ReadEventDetails */
static UA_DataTypeMember ReadEventDetails_members[4] = {
{
    UA_TYPENAME("NumValuesPerNode") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("StartTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_ReadEventDetails, startTime) - offsetof(UA_ReadEventDetails, numValuesPerNode) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EndTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_ReadEventDetails, endTime) - offsetof(UA_ReadEventDetails, startTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Filter") /* .memberName */
    &UA_TYPES[UA_TYPES_EVENTFILTER], /* .memberType */
    offsetof(UA_ReadEventDetails, filter) - offsetof(UA_ReadEventDetails, endTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* ReadProcessedDetails */
static UA_DataTypeMember ReadProcessedDetails_members[5] = {
{
    UA_TYPENAME("StartTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EndTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_ReadProcessedDetails, endTime) - offsetof(UA_ReadProcessedDetails, startTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ProcessingInterval") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_ReadProcessedDetails, processingInterval) - offsetof(UA_ReadProcessedDetails, endTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AggregateType") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    offsetof(UA_ReadProcessedDetails, aggregateTypeSize) - offsetof(UA_ReadProcessedDetails, processingInterval) - sizeof(UA_Double), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AggregateConfiguration") /* .memberName */
    &UA_TYPES[UA_TYPES_AGGREGATECONFIGURATION], /* .memberType */
    offsetof(UA_ReadProcessedDetails, aggregateConfiguration) - offsetof(UA_ReadProcessedDetails, aggregateType) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* ModificationInfo */
static UA_DataTypeMember ModificationInfo_members[3] = {
{
    UA_TYPENAME("ModificationTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UpdateType") /* .memberName */
    &UA_TYPES[UA_TYPES_HISTORYUPDATETYPE], /* .memberType */
    offsetof(UA_ModificationInfo, updateType) - offsetof(UA_ModificationInfo, modificationTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UserName") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_ModificationInfo, userName) - offsetof(UA_ModificationInfo, updateType) - sizeof(UA_HistoryUpdateType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* HistoryModifiedData */
static UA_DataTypeMember HistoryModifiedData_members[2] = {
{
    UA_TYPENAME("DataValues") /* .memberName */
    &UA_TYPES[UA_TYPES_DATAVALUE], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ModificationInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_MODIFICATIONINFO], /* .memberType */
    offsetof(UA_HistoryModifiedData, modificationInfosSize) - offsetof(UA_HistoryModifiedData, dataValues) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* HistoryEvent */
static UA_DataTypeMember HistoryEvent_members[1] = {
{
    UA_TYPENAME("Events") /* .memberName */
    &UA_TYPES[UA_TYPES_HISTORYEVENTFIELDLIST], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* DataChangeNotification */
static UA_DataTypeMember DataChangeNotification_members[2] = {
{
    UA_TYPENAME("MonitoredItems") /* .memberName */
    &UA_TYPES[UA_TYPES_MONITOREDITEMNOTIFICATION], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DiagnosticInfos") /* .memberName */
    &UA_TYPES[UA_TYPES_DIAGNOSTICINFO], /* .memberType */
    offsetof(UA_DataChangeNotification, diagnosticInfosSize) - offsetof(UA_DataChangeNotification, monitoredItems) - sizeof(void *), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* EventNotificationList */
static UA_DataTypeMember EventNotificationList_members[1] = {
{
    UA_TYPENAME("Events") /* .memberName */
    &UA_TYPES[UA_TYPES_EVENTFIELDLIST], /* .memberType */
    0, /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},};

/* SessionDiagnosticsDataType */
static UA_DataTypeMember SessionDiagnosticsDataType_members[43] = {
{
    UA_TYPENAME("SessionId") /* .memberName */
    &UA_TYPES[UA_TYPES_NODEID], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SessionName") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, sessionName) - offsetof(UA_SessionDiagnosticsDataType, sessionId) - sizeof(UA_NodeId), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ClientDescription") /* .memberName */
    &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, clientDescription) - offsetof(UA_SessionDiagnosticsDataType, sessionName) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ServerUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, serverUri) - offsetof(UA_SessionDiagnosticsDataType, clientDescription) - sizeof(UA_ApplicationDescription), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EndpointUrl") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, endpointUrl) - offsetof(UA_SessionDiagnosticsDataType, serverUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("LocaleIds") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, localeIdsSize) - offsetof(UA_SessionDiagnosticsDataType, endpointUrl) - sizeof(UA_String), /* .padding */
    true, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ActualSessionTimeout") /* .memberName */
    &UA_TYPES[UA_TYPES_DOUBLE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, actualSessionTimeout) - offsetof(UA_SessionDiagnosticsDataType, localeIds) - sizeof(void *), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxResponseMessageSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, maxResponseMessageSize) - offsetof(UA_SessionDiagnosticsDataType, actualSessionTimeout) - sizeof(UA_Double), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ClientConnectionTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, clientConnectionTime) - offsetof(UA_SessionDiagnosticsDataType, maxResponseMessageSize) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ClientLastContactTime") /* .memberName */
    &UA_TYPES[UA_TYPES_DATETIME], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, clientLastContactTime) - offsetof(UA_SessionDiagnosticsDataType, clientConnectionTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CurrentSubscriptionsCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, currentSubscriptionsCount) - offsetof(UA_SessionDiagnosticsDataType, clientLastContactTime) - sizeof(UA_DateTime), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CurrentMonitoredItemsCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, currentMonitoredItemsCount) - offsetof(UA_SessionDiagnosticsDataType, currentSubscriptionsCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CurrentPublishRequestsInQueue") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, currentPublishRequestsInQueue) - offsetof(UA_SessionDiagnosticsDataType, currentMonitoredItemsCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TotalRequestCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, totalRequestCount) - offsetof(UA_SessionDiagnosticsDataType, currentPublishRequestsInQueue) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UnauthorizedRequestCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, unauthorizedRequestCount) - offsetof(UA_SessionDiagnosticsDataType, totalRequestCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReadCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, readCount) - offsetof(UA_SessionDiagnosticsDataType, unauthorizedRequestCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("HistoryReadCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, historyReadCount) - offsetof(UA_SessionDiagnosticsDataType, readCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("WriteCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, writeCount) - offsetof(UA_SessionDiagnosticsDataType, historyReadCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("HistoryUpdateCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, historyUpdateCount) - offsetof(UA_SessionDiagnosticsDataType, writeCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CallCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, callCount) - offsetof(UA_SessionDiagnosticsDataType, historyUpdateCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CreateMonitoredItemsCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, createMonitoredItemsCount) - offsetof(UA_SessionDiagnosticsDataType, callCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ModifyMonitoredItemsCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, modifyMonitoredItemsCount) - offsetof(UA_SessionDiagnosticsDataType, createMonitoredItemsCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SetMonitoringModeCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, setMonitoringModeCount) - offsetof(UA_SessionDiagnosticsDataType, modifyMonitoredItemsCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SetTriggeringCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, setTriggeringCount) - offsetof(UA_SessionDiagnosticsDataType, setMonitoringModeCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DeleteMonitoredItemsCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, deleteMonitoredItemsCount) - offsetof(UA_SessionDiagnosticsDataType, setTriggeringCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("CreateSubscriptionCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, createSubscriptionCount) - offsetof(UA_SessionDiagnosticsDataType, deleteMonitoredItemsCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ModifySubscriptionCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, modifySubscriptionCount) - offsetof(UA_SessionDiagnosticsDataType, createSubscriptionCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SetPublishingModeCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, setPublishingModeCount) - offsetof(UA_SessionDiagnosticsDataType, modifySubscriptionCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("PublishCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, publishCount) - offsetof(UA_SessionDiagnosticsDataType, setPublishingModeCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RepublishCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, republishCount) - offsetof(UA_SessionDiagnosticsDataType, publishCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TransferSubscriptionsCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, transferSubscriptionsCount) - offsetof(UA_SessionDiagnosticsDataType, republishCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DeleteSubscriptionsCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, deleteSubscriptionsCount) - offsetof(UA_SessionDiagnosticsDataType, transferSubscriptionsCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AddNodesCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, addNodesCount) - offsetof(UA_SessionDiagnosticsDataType, deleteSubscriptionsCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("AddReferencesCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, addReferencesCount) - offsetof(UA_SessionDiagnosticsDataType, addNodesCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DeleteNodesCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, deleteNodesCount) - offsetof(UA_SessionDiagnosticsDataType, addReferencesCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("DeleteReferencesCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, deleteReferencesCount) - offsetof(UA_SessionDiagnosticsDataType, deleteNodesCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("BrowseCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, browseCount) - offsetof(UA_SessionDiagnosticsDataType, deleteReferencesCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("BrowseNextCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, browseNextCount) - offsetof(UA_SessionDiagnosticsDataType, browseCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("TranslateBrowsePathsToNodeIdsCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, translateBrowsePathsToNodeIdsCount) - offsetof(UA_SessionDiagnosticsDataType, browseNextCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("QueryFirstCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, queryFirstCount) - offsetof(UA_SessionDiagnosticsDataType, translateBrowsePathsToNodeIdsCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("QueryNextCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, queryNextCount) - offsetof(UA_SessionDiagnosticsDataType, queryFirstCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RegisterNodesCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, registerNodesCount) - offsetof(UA_SessionDiagnosticsDataType, queryNextCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("UnregisterNodesCount") /* .memberName */
    &UA_TYPES[UA_TYPES_SERVICECOUNTERDATATYPE], /* .memberType */
    offsetof(UA_SessionDiagnosticsDataType, unregisterNodesCount) - offsetof(UA_SessionDiagnosticsDataType, registerNodesCount) - sizeof(UA_ServiceCounterDataType), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};
UA_DataType UA_TYPES[UA_TYPES_COUNT] = {
/* Boolean */
{
    UA_TYPENAME("Boolean") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {1LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_Boolean), /* .memSize */
    UA_DATATYPEKIND_BOOLEAN, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    Boolean_members  /* .members */
},
/* SByte */
{
    UA_TYPENAME("SByte") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {2LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_SByte), /* .memSize */
    UA_DATATYPEKIND_SBYTE, /* .typeKind */
    true, /* .pointerFree */
    true, /* .overlayable */
    0, /* .membersSize */
    SByte_members  /* .members */
},
/* Byte */
{
    UA_TYPENAME("Byte") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {3LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_Byte), /* .memSize */
    UA_DATATYPEKIND_BYTE, /* .typeKind */
    true, /* .pointerFree */
    true, /* .overlayable */
    0, /* .membersSize */
    Byte_members  /* .members */
},
/* Int16 */
{
    UA_TYPENAME("Int16") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {4LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_Int16), /* .memSize */
    UA_DATATYPEKIND_INT16, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    Int16_members  /* .members */
},
/* UInt16 */
{
    UA_TYPENAME("UInt16") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {5LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_UInt16), /* .memSize */
    UA_DATATYPEKIND_UINT16, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    UInt16_members  /* .members */
},
/* Int32 */
{
    UA_TYPENAME("Int32") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {6LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_Int32), /* .memSize */
    UA_DATATYPEKIND_INT32, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    Int32_members  /* .members */
},
/* UInt32 */
{
    UA_TYPENAME("UInt32") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {7LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_UInt32), /* .memSize */
    UA_DATATYPEKIND_UINT32, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    UInt32_members  /* .members */
},
/* Int64 */
{
    UA_TYPENAME("Int64") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {8LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_Int64), /* .memSize */
    UA_DATATYPEKIND_INT64, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    Int64_members  /* .members */
},
/* UInt64 */
{
    UA_TYPENAME("UInt64") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {9LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_UInt64), /* .memSize */
    UA_DATATYPEKIND_UINT64, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    UInt64_members  /* .members */
},
/* Float */
{
    UA_TYPENAME("Float") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {10LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_Float), /* .memSize */
    UA_DATATYPEKIND_FLOAT, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_FLOAT, /* .overlayable */
    0, /* .membersSize */
    Float_members  /* .members */
},
/* Double */
{
    UA_TYPENAME("Double") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {11LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_Double), /* .memSize */
    UA_DATATYPEKIND_DOUBLE, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_FLOAT, /* .overlayable */
    0, /* .membersSize */
    Double_members  /* .members */
},
/* String */
{
    UA_TYPENAME("String") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_String), /* .memSize */
    UA_DATATYPEKIND_STRING, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    String_members  /* .members */
},
/* DateTime */
{
    UA_TYPENAME("DateTime") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {13LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_DateTime), /* .memSize */
    UA_DATATYPEKIND_DATETIME, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    DateTime_members  /* .members */
},
/* Guid */
{
    UA_TYPENAME("Guid") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {14LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_Guid), /* .memSize */
    UA_DATATYPEKIND_GUID, /* .typeKind */
    true, /* .pointerFree */
    (UA_BINARY_OVERLAYABLE_INTEGER && offsetof(UA_Guid, data2) == sizeof(UA_UInt32) && offsetof(UA_Guid, data3) == (sizeof(UA_UInt16) + sizeof(UA_UInt32)) && offsetof(UA_Guid, data4) == (2*sizeof(UA_UInt32))), /* .overlayable */
    0, /* .membersSize */
    Guid_members  /* .members */
},
/* ByteString */
{
    UA_TYPENAME("ByteString") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {15LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_ByteString), /* .memSize */
    UA_DATATYPEKIND_BYTESTRING, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    ByteString_members  /* .members */
},
/* XmlElement */
{
    UA_TYPENAME("XmlElement") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {16LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_XmlElement), /* .memSize */
    UA_DATATYPEKIND_XMLELEMENT, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    XmlElement_members  /* .members */
},
/* NodeId */
{
    UA_TYPENAME("NodeId") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {17LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_NodeId), /* .memSize */
    UA_DATATYPEKIND_NODEID, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    NodeId_members  /* .members */
},
/* ExpandedNodeId */
{
    UA_TYPENAME("ExpandedNodeId") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {18LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_ExpandedNodeId), /* .memSize */
    UA_DATATYPEKIND_EXPANDEDNODEID, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    ExpandedNodeId_members  /* .members */
},
/* StatusCode */
{
    UA_TYPENAME("StatusCode") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {19LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_StatusCode), /* .memSize */
    UA_DATATYPEKIND_STATUSCODE, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    StatusCode_members  /* .members */
},
/* QualifiedName */
{
    UA_TYPENAME("QualifiedName") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {20LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_QualifiedName), /* .memSize */
    UA_DATATYPEKIND_QUALIFIEDNAME, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    QualifiedName_members  /* .members */
},
/* LocalizedText */
{
    UA_TYPENAME("LocalizedText") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {21LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_LocalizedText), /* .memSize */
    UA_DATATYPEKIND_LOCALIZEDTEXT, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    LocalizedText_members  /* .members */
},
/* ExtensionObject */
{
    UA_TYPENAME("ExtensionObject") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {22LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_ExtensionObject), /* .memSize */
    UA_DATATYPEKIND_EXTENSIONOBJECT, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    ExtensionObject_members  /* .members */
},
/* DataValue */
{
    UA_TYPENAME("DataValue") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {23LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_DataValue), /* .memSize */
    UA_DATATYPEKIND_DATAVALUE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    DataValue_members  /* .members */
},
/* Variant */
{
    UA_TYPENAME("Variant") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {24LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_Variant), /* .memSize */
    UA_DATATYPEKIND_VARIANT, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    Variant_members  /* .members */
},
/* DiagnosticInfo */
{
    UA_TYPENAME("DiagnosticInfo") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {25LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_DiagnosticInfo), /* .memSize */
    UA_DATATYPEKIND_DIAGNOSTICINFO, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    DiagnosticInfo_members  /* .members */
},
/* NamingRuleType */
{
    UA_TYPENAME("NamingRuleType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {120LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_NamingRuleType), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    NamingRuleType_members  /* .members */
},
/* KeyValuePair */
{
    UA_TYPENAME("KeyValuePair") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {14533LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {14846LU}}, /* .binaryEncodingId */
    sizeof(UA_KeyValuePair), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    KeyValuePair_members  /* .members */
},
/* TrustListDataType */
{
    UA_TYPENAME("TrustListDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12554LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {12680LU}}, /* .binaryEncodingId */
    sizeof(UA_TrustListDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    TrustListDataType_members  /* .members */
},
/* NodeClass */
{
    UA_TYPENAME("NodeClass") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {257LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_NodeClass), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    NodeClass_members  /* .members */
},
/* StructureType */
{
    UA_TYPENAME("StructureType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {98LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_StructureType), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    StructureType_members  /* .members */
},
/* StructureField */
{
    UA_TYPENAME("StructureField") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {101LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {14844LU}}, /* .binaryEncodingId */
    sizeof(UA_StructureField), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    7, /* .membersSize */
    StructureField_members  /* .members */
},
/* StructureDefinition */
{
    UA_TYPENAME("StructureDefinition") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {99LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {122LU}}, /* .binaryEncodingId */
    sizeof(UA_StructureDefinition), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    StructureDefinition_members  /* .members */
},
/* Argument */
{
    UA_TYPENAME("Argument") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {296LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {298LU}}, /* .binaryEncodingId */
    sizeof(UA_Argument), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    Argument_members  /* .members */
},
/* EnumValueType */
{
    UA_TYPENAME("EnumValueType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {7594LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {8251LU}}, /* .binaryEncodingId */
    sizeof(UA_EnumValueType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    EnumValueType_members  /* .members */
},
/* EnumField */
{
    UA_TYPENAME("EnumField") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {102LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {14845LU}}, /* .binaryEncodingId */
    sizeof(UA_EnumField), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    EnumField_members  /* .members */
},
/* Duration */
{
    UA_TYPENAME("Duration") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {290LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_Duration), /* .memSize */
    UA_DATATYPEKIND_DOUBLE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    Duration_members  /* .members */
},
/* UtcTime */
{
    UA_TYPENAME("UtcTime") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {294LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_UtcTime), /* .memSize */
    UA_DATATYPEKIND_DATETIME, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    UtcTime_members  /* .members */
},
/* LocaleId */
{
    UA_TYPENAME("LocaleId") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {295LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_LocaleId), /* .memSize */
    UA_DATATYPEKIND_STRING, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    0, /* .membersSize */
    LocaleId_members  /* .members */
},
/* TimeZoneDataType */
{
    UA_TYPENAME("TimeZoneDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {8912LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {8917LU}}, /* .binaryEncodingId */
    sizeof(UA_TimeZoneDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    TimeZoneDataType_members  /* .members */
},
/* ApplicationType */
{
    UA_TYPENAME("ApplicationType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {307LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_ApplicationType), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    ApplicationType_members  /* .members */
},
/* ApplicationDescription */
{
    UA_TYPENAME("ApplicationDescription") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {308LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {310LU}}, /* .binaryEncodingId */
    sizeof(UA_ApplicationDescription), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    7, /* .membersSize */
    ApplicationDescription_members  /* .members */
},
/* RequestHeader */
{
    UA_TYPENAME("RequestHeader") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {389LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {391LU}}, /* .binaryEncodingId */
    sizeof(UA_RequestHeader), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    7, /* .membersSize */
    RequestHeader_members  /* .members */
},
/* ResponseHeader */
{
    UA_TYPENAME("ResponseHeader") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {392LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {394LU}}, /* .binaryEncodingId */
    sizeof(UA_ResponseHeader), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    6, /* .membersSize */
    ResponseHeader_members  /* .members */
},
/* ServiceFault */
{
    UA_TYPENAME("ServiceFault") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {395LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {397LU}}, /* .binaryEncodingId */
    sizeof(UA_ServiceFault), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    ServiceFault_members  /* .members */
},
/* FindServersRequest */
{
    UA_TYPENAME("FindServersRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {420LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {422LU}}, /* .binaryEncodingId */
    sizeof(UA_FindServersRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    FindServersRequest_members  /* .members */
},
/* FindServersResponse */
{
    UA_TYPENAME("FindServersResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {423LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {425LU}}, /* .binaryEncodingId */
    sizeof(UA_FindServersResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    FindServersResponse_members  /* .members */
},
/* ServerOnNetwork */
{
    UA_TYPENAME("ServerOnNetwork") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12189LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {12207LU}}, /* .binaryEncodingId */
    sizeof(UA_ServerOnNetwork), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    ServerOnNetwork_members  /* .members */
},
/* FindServersOnNetworkRequest */
{
    UA_TYPENAME("FindServersOnNetworkRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12190LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {12208LU}}, /* .binaryEncodingId */
    sizeof(UA_FindServersOnNetworkRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    FindServersOnNetworkRequest_members  /* .members */
},
/* FindServersOnNetworkResponse */
{
    UA_TYPENAME("FindServersOnNetworkResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12191LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {12209LU}}, /* .binaryEncodingId */
    sizeof(UA_FindServersOnNetworkResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    FindServersOnNetworkResponse_members  /* .members */
},
/* MessageSecurityMode */
{
    UA_TYPENAME("MessageSecurityMode") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {302LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_MessageSecurityMode), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    MessageSecurityMode_members  /* .members */
},
/* UserTokenType */
{
    UA_TYPENAME("UserTokenType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {303LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_UserTokenType), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    UserTokenType_members  /* .members */
},
/* UserTokenPolicy */
{
    UA_TYPENAME("UserTokenPolicy") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {304LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {306LU}}, /* .binaryEncodingId */
    sizeof(UA_UserTokenPolicy), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    UserTokenPolicy_members  /* .members */
},
/* EndpointDescription */
{
    UA_TYPENAME("EndpointDescription") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {312LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {314LU}}, /* .binaryEncodingId */
    sizeof(UA_EndpointDescription), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    8, /* .membersSize */
    EndpointDescription_members  /* .members */
},
/* GetEndpointsRequest */
{
    UA_TYPENAME("GetEndpointsRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {426LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {428LU}}, /* .binaryEncodingId */
    sizeof(UA_GetEndpointsRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    GetEndpointsRequest_members  /* .members */
},
/* GetEndpointsResponse */
{
    UA_TYPENAME("GetEndpointsResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {429LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {431LU}}, /* .binaryEncodingId */
    sizeof(UA_GetEndpointsResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    GetEndpointsResponse_members  /* .members */
},
/* RegisteredServer */
{
    UA_TYPENAME("RegisteredServer") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {432LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {434LU}}, /* .binaryEncodingId */
    sizeof(UA_RegisteredServer), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    8, /* .membersSize */
    RegisteredServer_members  /* .members */
},
/* RegisterServerRequest */
{
    UA_TYPENAME("RegisterServerRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {435LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {437LU}}, /* .binaryEncodingId */
    sizeof(UA_RegisterServerRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    RegisterServerRequest_members  /* .members */
},
/* RegisterServerResponse */
{
    UA_TYPENAME("RegisterServerResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {438LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {440LU}}, /* .binaryEncodingId */
    sizeof(UA_RegisterServerResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    RegisterServerResponse_members  /* .members */
},
/* MdnsDiscoveryConfiguration */
{
    UA_TYPENAME("MdnsDiscoveryConfiguration") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12891LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {12901LU}}, /* .binaryEncodingId */
    sizeof(UA_MdnsDiscoveryConfiguration), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    MdnsDiscoveryConfiguration_members  /* .members */
},
/* RegisterServer2Request */
{
    UA_TYPENAME("RegisterServer2Request") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12193LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {12211LU}}, /* .binaryEncodingId */
    sizeof(UA_RegisterServer2Request), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    RegisterServer2Request_members  /* .members */
},
/* RegisterServer2Response */
{
    UA_TYPENAME("RegisterServer2Response") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12194LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {12212LU}}, /* .binaryEncodingId */
    sizeof(UA_RegisterServer2Response), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    RegisterServer2Response_members  /* .members */
},
/* SecurityTokenRequestType */
{
    UA_TYPENAME("SecurityTokenRequestType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {315LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_SecurityTokenRequestType), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    SecurityTokenRequestType_members  /* .members */
},
/* ChannelSecurityToken */
{
    UA_TYPENAME("ChannelSecurityToken") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {441LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {443LU}}, /* .binaryEncodingId */
    sizeof(UA_ChannelSecurityToken), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    ChannelSecurityToken_members  /* .members */
},
/* OpenSecureChannelRequest */
{
    UA_TYPENAME("OpenSecureChannelRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {444LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {446LU}}, /* .binaryEncodingId */
    sizeof(UA_OpenSecureChannelRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    6, /* .membersSize */
    OpenSecureChannelRequest_members  /* .members */
},
/* OpenSecureChannelResponse */
{
    UA_TYPENAME("OpenSecureChannelResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {447LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {449LU}}, /* .binaryEncodingId */
    sizeof(UA_OpenSecureChannelResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    OpenSecureChannelResponse_members  /* .members */
},
/* CloseSecureChannelRequest */
{
    UA_TYPENAME("CloseSecureChannelRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {450LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {452LU}}, /* .binaryEncodingId */
    sizeof(UA_CloseSecureChannelRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    CloseSecureChannelRequest_members  /* .members */
},
/* CloseSecureChannelResponse */
{
    UA_TYPENAME("CloseSecureChannelResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {453LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {455LU}}, /* .binaryEncodingId */
    sizeof(UA_CloseSecureChannelResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    CloseSecureChannelResponse_members  /* .members */
},
/* SignedSoftwareCertificate */
{
    UA_TYPENAME("SignedSoftwareCertificate") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {344LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {346LU}}, /* .binaryEncodingId */
    sizeof(UA_SignedSoftwareCertificate), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    SignedSoftwareCertificate_members  /* .members */
},
/* SignatureData */
{
    UA_TYPENAME("SignatureData") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {456LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {458LU}}, /* .binaryEncodingId */
    sizeof(UA_SignatureData), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    SignatureData_members  /* .members */
},
/* CreateSessionRequest */
{
    UA_TYPENAME("CreateSessionRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {459LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {461LU}}, /* .binaryEncodingId */
    sizeof(UA_CreateSessionRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    9, /* .membersSize */
    CreateSessionRequest_members  /* .members */
},
/* CreateSessionResponse */
{
    UA_TYPENAME("CreateSessionResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {462LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {464LU}}, /* .binaryEncodingId */
    sizeof(UA_CreateSessionResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    10, /* .membersSize */
    CreateSessionResponse_members  /* .members */
},
/* UserIdentityToken */
{
    UA_TYPENAME("UserIdentityToken") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {316LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {318LU}}, /* .binaryEncodingId */
    sizeof(UA_UserIdentityToken), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    UserIdentityToken_members  /* .members */
},
/* AnonymousIdentityToken */
{
    UA_TYPENAME("AnonymousIdentityToken") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {319LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {321LU}}, /* .binaryEncodingId */
    sizeof(UA_AnonymousIdentityToken), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    AnonymousIdentityToken_members  /* .members */
},
/* UserNameIdentityToken */
{
    UA_TYPENAME("UserNameIdentityToken") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {322LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {324LU}}, /* .binaryEncodingId */
    sizeof(UA_UserNameIdentityToken), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    UserNameIdentityToken_members  /* .members */
},
/* X509IdentityToken */
{
    UA_TYPENAME("X509IdentityToken") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {325LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {327LU}}, /* .binaryEncodingId */
    sizeof(UA_X509IdentityToken), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    X509IdentityToken_members  /* .members */
},
/* IssuedIdentityToken */
{
    UA_TYPENAME("IssuedIdentityToken") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {938LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {940LU}}, /* .binaryEncodingId */
    sizeof(UA_IssuedIdentityToken), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    IssuedIdentityToken_members  /* .members */
},
/* ActivateSessionRequest */
{
    UA_TYPENAME("ActivateSessionRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {465LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {467LU}}, /* .binaryEncodingId */
    sizeof(UA_ActivateSessionRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    6, /* .membersSize */
    ActivateSessionRequest_members  /* .members */
},
/* ActivateSessionResponse */
{
    UA_TYPENAME("ActivateSessionResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {468LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {470LU}}, /* .binaryEncodingId */
    sizeof(UA_ActivateSessionResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    ActivateSessionResponse_members  /* .members */
},
/* CloseSessionRequest */
{
    UA_TYPENAME("CloseSessionRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {471LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {473LU}}, /* .binaryEncodingId */
    sizeof(UA_CloseSessionRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    CloseSessionRequest_members  /* .members */
},
/* CloseSessionResponse */
{
    UA_TYPENAME("CloseSessionResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {474LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {476LU}}, /* .binaryEncodingId */
    sizeof(UA_CloseSessionResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    CloseSessionResponse_members  /* .members */
},
/* CancelRequest */
{
    UA_TYPENAME("CancelRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {477LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {479LU}}, /* .binaryEncodingId */
    sizeof(UA_CancelRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    CancelRequest_members  /* .members */
},
/* CancelResponse */
{
    UA_TYPENAME("CancelResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {480LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {482LU}}, /* .binaryEncodingId */
    sizeof(UA_CancelResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    CancelResponse_members  /* .members */
},
/* NodeAttributesMask */
{
    UA_TYPENAME("NodeAttributesMask") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {348LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_NodeAttributesMask), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    NodeAttributesMask_members  /* .members */
},
/* NodeAttributes */
{
    UA_TYPENAME("NodeAttributes") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {349LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {351LU}}, /* .binaryEncodingId */
    sizeof(UA_NodeAttributes), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    NodeAttributes_members  /* .members */
},
/* ObjectAttributes */
{
    UA_TYPENAME("ObjectAttributes") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {352LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {354LU}}, /* .binaryEncodingId */
    sizeof(UA_ObjectAttributes), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    6, /* .membersSize */
    ObjectAttributes_members  /* .members */
},
/* VariableAttributes */
{
    UA_TYPENAME("VariableAttributes") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {355LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {357LU}}, /* .binaryEncodingId */
    sizeof(UA_VariableAttributes), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    13, /* .membersSize */
    VariableAttributes_members  /* .members */
},
/* MethodAttributes */
{
    UA_TYPENAME("MethodAttributes") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {358LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {360LU}}, /* .binaryEncodingId */
    sizeof(UA_MethodAttributes), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    7, /* .membersSize */
    MethodAttributes_members  /* .members */
},
/* ObjectTypeAttributes */
{
    UA_TYPENAME("ObjectTypeAttributes") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {361LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {363LU}}, /* .binaryEncodingId */
    sizeof(UA_ObjectTypeAttributes), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    6, /* .membersSize */
    ObjectTypeAttributes_members  /* .members */
},
/* VariableTypeAttributes */
{
    UA_TYPENAME("VariableTypeAttributes") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {364LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {366LU}}, /* .binaryEncodingId */
    sizeof(UA_VariableTypeAttributes), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    10, /* .membersSize */
    VariableTypeAttributes_members  /* .members */
},
/* ReferenceTypeAttributes */
{
    UA_TYPENAME("ReferenceTypeAttributes") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {367LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {369LU}}, /* .binaryEncodingId */
    sizeof(UA_ReferenceTypeAttributes), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    8, /* .membersSize */
    ReferenceTypeAttributes_members  /* .members */
},
/* DataTypeAttributes */
{
    UA_TYPENAME("DataTypeAttributes") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {370LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {372LU}}, /* .binaryEncodingId */
    sizeof(UA_DataTypeAttributes), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    6, /* .membersSize */
    DataTypeAttributes_members  /* .members */
},
/* ViewAttributes */
{
    UA_TYPENAME("ViewAttributes") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {373LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {375LU}}, /* .binaryEncodingId */
    sizeof(UA_ViewAttributes), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    7, /* .membersSize */
    ViewAttributes_members  /* .members */
},
/* AddNodesItem */
{
    UA_TYPENAME("AddNodesItem") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {376LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {378LU}}, /* .binaryEncodingId */
    sizeof(UA_AddNodesItem), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    7, /* .membersSize */
    AddNodesItem_members  /* .members */
},
/* AddNodesResult */
{
    UA_TYPENAME("AddNodesResult") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {483LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {485LU}}, /* .binaryEncodingId */
    sizeof(UA_AddNodesResult), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    AddNodesResult_members  /* .members */
},
/* AddNodesRequest */
{
    UA_TYPENAME("AddNodesRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {486LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {488LU}}, /* .binaryEncodingId */
    sizeof(UA_AddNodesRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    AddNodesRequest_members  /* .members */
},
/* AddNodesResponse */
{
    UA_TYPENAME("AddNodesResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {489LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {491LU}}, /* .binaryEncodingId */
    sizeof(UA_AddNodesResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    AddNodesResponse_members  /* .members */
},
/* AddReferencesItem */
{
    UA_TYPENAME("AddReferencesItem") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {379LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {381LU}}, /* .binaryEncodingId */
    sizeof(UA_AddReferencesItem), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    6, /* .membersSize */
    AddReferencesItem_members  /* .members */
},
/* AddReferencesRequest */
{
    UA_TYPENAME("AddReferencesRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {492LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {494LU}}, /* .binaryEncodingId */
    sizeof(UA_AddReferencesRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    AddReferencesRequest_members  /* .members */
},
/* AddReferencesResponse */
{
    UA_TYPENAME("AddReferencesResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {495LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {497LU}}, /* .binaryEncodingId */
    sizeof(UA_AddReferencesResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    AddReferencesResponse_members  /* .members */
},
/* DeleteNodesItem */
{
    UA_TYPENAME("DeleteNodesItem") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {382LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {384LU}}, /* .binaryEncodingId */
    sizeof(UA_DeleteNodesItem), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    DeleteNodesItem_members  /* .members */
},
/* DeleteNodesRequest */
{
    UA_TYPENAME("DeleteNodesRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {498LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {500LU}}, /* .binaryEncodingId */
    sizeof(UA_DeleteNodesRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    DeleteNodesRequest_members  /* .members */
},
/* DeleteNodesResponse */
{
    UA_TYPENAME("DeleteNodesResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {501LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {503LU}}, /* .binaryEncodingId */
    sizeof(UA_DeleteNodesResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    DeleteNodesResponse_members  /* .members */
},
/* DeleteReferencesItem */
{
    UA_TYPENAME("DeleteReferencesItem") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {385LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {387LU}}, /* .binaryEncodingId */
    sizeof(UA_DeleteReferencesItem), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    DeleteReferencesItem_members  /* .members */
},
/* DeleteReferencesRequest */
{
    UA_TYPENAME("DeleteReferencesRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {504LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {506LU}}, /* .binaryEncodingId */
    sizeof(UA_DeleteReferencesRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    DeleteReferencesRequest_members  /* .members */
},
/* DeleteReferencesResponse */
{
    UA_TYPENAME("DeleteReferencesResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {507LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {509LU}}, /* .binaryEncodingId */
    sizeof(UA_DeleteReferencesResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    DeleteReferencesResponse_members  /* .members */
},
/* BrowseDirection */
{
    UA_TYPENAME("BrowseDirection") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {510LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_BrowseDirection), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    BrowseDirection_members  /* .members */
},
/* ViewDescription */
{
    UA_TYPENAME("ViewDescription") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {511LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {513LU}}, /* .binaryEncodingId */
    sizeof(UA_ViewDescription), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    ViewDescription_members  /* .members */
},
/* BrowseDescription */
{
    UA_TYPENAME("BrowseDescription") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {514LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {516LU}}, /* .binaryEncodingId */
    sizeof(UA_BrowseDescription), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    6, /* .membersSize */
    BrowseDescription_members  /* .members */
},
/* BrowseResultMask */
{
    UA_TYPENAME("BrowseResultMask") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {517LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_BrowseResultMask), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    BrowseResultMask_members  /* .members */
},
/* ReferenceDescription */
{
    UA_TYPENAME("ReferenceDescription") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {518LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {520LU}}, /* .binaryEncodingId */
    sizeof(UA_ReferenceDescription), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    7, /* .membersSize */
    ReferenceDescription_members  /* .members */
},
/* BrowseResult */
{
    UA_TYPENAME("BrowseResult") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {522LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {524LU}}, /* .binaryEncodingId */
    sizeof(UA_BrowseResult), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    BrowseResult_members  /* .members */
},
/* BrowseRequest */
{
    UA_TYPENAME("BrowseRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {525LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {527LU}}, /* .binaryEncodingId */
    sizeof(UA_BrowseRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    BrowseRequest_members  /* .members */
},
/* BrowseResponse */
{
    UA_TYPENAME("BrowseResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {528LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {530LU}}, /* .binaryEncodingId */
    sizeof(UA_BrowseResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    BrowseResponse_members  /* .members */
},
/* BrowseNextRequest */
{
    UA_TYPENAME("BrowseNextRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {531LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {533LU}}, /* .binaryEncodingId */
    sizeof(UA_BrowseNextRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    BrowseNextRequest_members  /* .members */
},
/* BrowseNextResponse */
{
    UA_TYPENAME("BrowseNextResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {534LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {536LU}}, /* .binaryEncodingId */
    sizeof(UA_BrowseNextResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    BrowseNextResponse_members  /* .members */
},
/* RelativePathElement */
{
    UA_TYPENAME("RelativePathElement") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {537LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {539LU}}, /* .binaryEncodingId */
    sizeof(UA_RelativePathElement), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    RelativePathElement_members  /* .members */
},
/* RelativePath */
{
    UA_TYPENAME("RelativePath") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {540LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {542LU}}, /* .binaryEncodingId */
    sizeof(UA_RelativePath), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    RelativePath_members  /* .members */
},
/* BrowsePath */
{
    UA_TYPENAME("BrowsePath") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {543LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {545LU}}, /* .binaryEncodingId */
    sizeof(UA_BrowsePath), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    BrowsePath_members  /* .members */
},
/* BrowsePathTarget */
{
    UA_TYPENAME("BrowsePathTarget") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {546LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {548LU}}, /* .binaryEncodingId */
    sizeof(UA_BrowsePathTarget), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    BrowsePathTarget_members  /* .members */
},
/* BrowsePathResult */
{
    UA_TYPENAME("BrowsePathResult") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {549LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {551LU}}, /* .binaryEncodingId */
    sizeof(UA_BrowsePathResult), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    BrowsePathResult_members  /* .members */
},
/* TranslateBrowsePathsToNodeIdsRequest */
{
    UA_TYPENAME("TranslateBrowsePathsToNodeIdsRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {552LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {554LU}}, /* .binaryEncodingId */
    sizeof(UA_TranslateBrowsePathsToNodeIdsRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    TranslateBrowsePathsToNodeIdsRequest_members  /* .members */
},
/* TranslateBrowsePathsToNodeIdsResponse */
{
    UA_TYPENAME("TranslateBrowsePathsToNodeIdsResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {555LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {557LU}}, /* .binaryEncodingId */
    sizeof(UA_TranslateBrowsePathsToNodeIdsResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    TranslateBrowsePathsToNodeIdsResponse_members  /* .members */
},
/* RegisterNodesRequest */
{
    UA_TYPENAME("RegisterNodesRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {558LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {560LU}}, /* .binaryEncodingId */
    sizeof(UA_RegisterNodesRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    RegisterNodesRequest_members  /* .members */
},
/* RegisterNodesResponse */
{
    UA_TYPENAME("RegisterNodesResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {561LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {563LU}}, /* .binaryEncodingId */
    sizeof(UA_RegisterNodesResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    RegisterNodesResponse_members  /* .members */
},
/* UnregisterNodesRequest */
{
    UA_TYPENAME("UnregisterNodesRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {564LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {566LU}}, /* .binaryEncodingId */
    sizeof(UA_UnregisterNodesRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    UnregisterNodesRequest_members  /* .members */
},
/* UnregisterNodesResponse */
{
    UA_TYPENAME("UnregisterNodesResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {567LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {569LU}}, /* .binaryEncodingId */
    sizeof(UA_UnregisterNodesResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    UnregisterNodesResponse_members  /* .members */
},
/* FilterOperator */
{
    UA_TYPENAME("FilterOperator") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {576LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_FilterOperator), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    FilterOperator_members  /* .members */
},
/* ContentFilterElement */
{
    UA_TYPENAME("ContentFilterElement") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {583LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {585LU}}, /* .binaryEncodingId */
    sizeof(UA_ContentFilterElement), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    ContentFilterElement_members  /* .members */
},
/* ContentFilter */
{
    UA_TYPENAME("ContentFilter") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {586LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {588LU}}, /* .binaryEncodingId */
    sizeof(UA_ContentFilter), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    ContentFilter_members  /* .members */
},
/* ElementOperand */
{
    UA_TYPENAME("ElementOperand") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {592LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {594LU}}, /* .binaryEncodingId */
    sizeof(UA_ElementOperand), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    ElementOperand_members  /* .members */
},
/* LiteralOperand */
{
    UA_TYPENAME("LiteralOperand") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {595LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {597LU}}, /* .binaryEncodingId */
    sizeof(UA_LiteralOperand), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    LiteralOperand_members  /* .members */
},
/* AttributeOperand */
{
    UA_TYPENAME("AttributeOperand") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {598LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {600LU}}, /* .binaryEncodingId */
    sizeof(UA_AttributeOperand), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    AttributeOperand_members  /* .members */
},
/* SimpleAttributeOperand */
{
    UA_TYPENAME("SimpleAttributeOperand") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {601LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {603LU}}, /* .binaryEncodingId */
    sizeof(UA_SimpleAttributeOperand), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    SimpleAttributeOperand_members  /* .members */
},
/* ContentFilterElementResult */
{
    UA_TYPENAME("ContentFilterElementResult") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {604LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {606LU}}, /* .binaryEncodingId */
    sizeof(UA_ContentFilterElementResult), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    ContentFilterElementResult_members  /* .members */
},
/* ContentFilterResult */
{
    UA_TYPENAME("ContentFilterResult") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {607LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {609LU}}, /* .binaryEncodingId */
    sizeof(UA_ContentFilterResult), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    ContentFilterResult_members  /* .members */
},
/* TimestampsToReturn */
{
    UA_TYPENAME("TimestampsToReturn") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {625LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_TimestampsToReturn), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    TimestampsToReturn_members  /* .members */
},
/* ReadValueId */
{
    UA_TYPENAME("ReadValueId") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {626LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {628LU}}, /* .binaryEncodingId */
    sizeof(UA_ReadValueId), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    ReadValueId_members  /* .members */
},
/* ReadRequest */
{
    UA_TYPENAME("ReadRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {629LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {631LU}}, /* .binaryEncodingId */
    sizeof(UA_ReadRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    ReadRequest_members  /* .members */
},
/* ReadResponse */
{
    UA_TYPENAME("ReadResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {632LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {634LU}}, /* .binaryEncodingId */
    sizeof(UA_ReadResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    ReadResponse_members  /* .members */
},
/* HistoryReadValueId */
{
    UA_TYPENAME("HistoryReadValueId") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {635LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {637LU}}, /* .binaryEncodingId */
    sizeof(UA_HistoryReadValueId), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    HistoryReadValueId_members  /* .members */
},
/* HistoryReadResult */
{
    UA_TYPENAME("HistoryReadResult") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {638LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {640LU}}, /* .binaryEncodingId */
    sizeof(UA_HistoryReadResult), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    HistoryReadResult_members  /* .members */
},
/* ReadRawModifiedDetails */
{
    UA_TYPENAME("ReadRawModifiedDetails") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {647LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {649LU}}, /* .binaryEncodingId */
    sizeof(UA_ReadRawModifiedDetails), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    ReadRawModifiedDetails_members  /* .members */
},
/* ReadAtTimeDetails */
{
    UA_TYPENAME("ReadAtTimeDetails") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {653LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {655LU}}, /* .binaryEncodingId */
    sizeof(UA_ReadAtTimeDetails), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    ReadAtTimeDetails_members  /* .members */
},
/* HistoryData */
{
    UA_TYPENAME("HistoryData") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {656LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {658LU}}, /* .binaryEncodingId */
    sizeof(UA_HistoryData), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    HistoryData_members  /* .members */
},
/* HistoryReadRequest */
{
    UA_TYPENAME("HistoryReadRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {662LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {664LU}}, /* .binaryEncodingId */
    sizeof(UA_HistoryReadRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    HistoryReadRequest_members  /* .members */
},
/* HistoryReadResponse */
{
    UA_TYPENAME("HistoryReadResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {665LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {667LU}}, /* .binaryEncodingId */
    sizeof(UA_HistoryReadResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    HistoryReadResponse_members  /* .members */
},
/* WriteValue */
{
    UA_TYPENAME("WriteValue") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {668LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {670LU}}, /* .binaryEncodingId */
    sizeof(UA_WriteValue), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    WriteValue_members  /* .members */
},
/* WriteRequest */
{
    UA_TYPENAME("WriteRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {671LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {673LU}}, /* .binaryEncodingId */
    sizeof(UA_WriteRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    WriteRequest_members  /* .members */
},
/* WriteResponse */
{
    UA_TYPENAME("WriteResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {674LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {676LU}}, /* .binaryEncodingId */
    sizeof(UA_WriteResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    WriteResponse_members  /* .members */
},
/* HistoryUpdateType */
{
    UA_TYPENAME("HistoryUpdateType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {11234LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_HistoryUpdateType), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    HistoryUpdateType_members  /* .members */
},
/* PerformUpdateType */
{
    UA_TYPENAME("PerformUpdateType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {11293LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_PerformUpdateType), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    PerformUpdateType_members  /* .members */
},
/* UpdateDataDetails */
{
    UA_TYPENAME("UpdateDataDetails") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {680LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {682LU}}, /* .binaryEncodingId */
    sizeof(UA_UpdateDataDetails), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    UpdateDataDetails_members  /* .members */
},
/* DeleteRawModifiedDetails */
{
    UA_TYPENAME("DeleteRawModifiedDetails") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {686LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {688LU}}, /* .binaryEncodingId */
    sizeof(UA_DeleteRawModifiedDetails), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    DeleteRawModifiedDetails_members  /* .members */
},
/* HistoryUpdateResult */
{
    UA_TYPENAME("HistoryUpdateResult") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {695LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {697LU}}, /* .binaryEncodingId */
    sizeof(UA_HistoryUpdateResult), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    HistoryUpdateResult_members  /* .members */
},
/* HistoryUpdateRequest */
{
    UA_TYPENAME("HistoryUpdateRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {698LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {700LU}}, /* .binaryEncodingId */
    sizeof(UA_HistoryUpdateRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    HistoryUpdateRequest_members  /* .members */
},
/* HistoryUpdateResponse */
{
    UA_TYPENAME("HistoryUpdateResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {701LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {703LU}}, /* .binaryEncodingId */
    sizeof(UA_HistoryUpdateResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    HistoryUpdateResponse_members  /* .members */
},
/* CallMethodRequest */
{
    UA_TYPENAME("CallMethodRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {704LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {706LU}}, /* .binaryEncodingId */
    sizeof(UA_CallMethodRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    CallMethodRequest_members  /* .members */
},
/* CallMethodResult */
{
    UA_TYPENAME("CallMethodResult") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {707LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {709LU}}, /* .binaryEncodingId */
    sizeof(UA_CallMethodResult), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    CallMethodResult_members  /* .members */
},
/* CallRequest */
{
    UA_TYPENAME("CallRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {710LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {712LU}}, /* .binaryEncodingId */
    sizeof(UA_CallRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    CallRequest_members  /* .members */
},
/* CallResponse */
{
    UA_TYPENAME("CallResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {713LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {715LU}}, /* .binaryEncodingId */
    sizeof(UA_CallResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    CallResponse_members  /* .members */
},
/* MonitoringMode */
{
    UA_TYPENAME("MonitoringMode") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {716LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_MonitoringMode), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    MonitoringMode_members  /* .members */
},
/* DataChangeTrigger */
{
    UA_TYPENAME("DataChangeTrigger") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {717LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_DataChangeTrigger), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    DataChangeTrigger_members  /* .members */
},
/* DeadbandType */
{
    UA_TYPENAME("DeadbandType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {718LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_DeadbandType), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    DeadbandType_members  /* .members */
},
/* DataChangeFilter */
{
    UA_TYPENAME("DataChangeFilter") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {722LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {724LU}}, /* .binaryEncodingId */
    sizeof(UA_DataChangeFilter), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    DataChangeFilter_members  /* .members */
},
/* EventFilter */
{
    UA_TYPENAME("EventFilter") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {725LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {727LU}}, /* .binaryEncodingId */
    sizeof(UA_EventFilter), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    EventFilter_members  /* .members */
},
/* AggregateConfiguration */
{
    UA_TYPENAME("AggregateConfiguration") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {948LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {950LU}}, /* .binaryEncodingId */
    sizeof(UA_AggregateConfiguration), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    AggregateConfiguration_members  /* .members */
},
/* AggregateFilter */
{
    UA_TYPENAME("AggregateFilter") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {728LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {730LU}}, /* .binaryEncodingId */
    sizeof(UA_AggregateFilter), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    AggregateFilter_members  /* .members */
},
/* EventFilterResult */
{
    UA_TYPENAME("EventFilterResult") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {734LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {736LU}}, /* .binaryEncodingId */
    sizeof(UA_EventFilterResult), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    EventFilterResult_members  /* .members */
},
/* MonitoringParameters */
{
    UA_TYPENAME("MonitoringParameters") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {740LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {742LU}}, /* .binaryEncodingId */
    sizeof(UA_MonitoringParameters), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    MonitoringParameters_members  /* .members */
},
/* MonitoredItemCreateRequest */
{
    UA_TYPENAME("MonitoredItemCreateRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {743LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {745LU}}, /* .binaryEncodingId */
    sizeof(UA_MonitoredItemCreateRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    MonitoredItemCreateRequest_members  /* .members */
},
/* MonitoredItemCreateResult */
{
    UA_TYPENAME("MonitoredItemCreateResult") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {746LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {748LU}}, /* .binaryEncodingId */
    sizeof(UA_MonitoredItemCreateResult), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    MonitoredItemCreateResult_members  /* .members */
},
/* CreateMonitoredItemsRequest */
{
    UA_TYPENAME("CreateMonitoredItemsRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {749LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {751LU}}, /* .binaryEncodingId */
    sizeof(UA_CreateMonitoredItemsRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    CreateMonitoredItemsRequest_members  /* .members */
},
/* CreateMonitoredItemsResponse */
{
    UA_TYPENAME("CreateMonitoredItemsResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {752LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {754LU}}, /* .binaryEncodingId */
    sizeof(UA_CreateMonitoredItemsResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    CreateMonitoredItemsResponse_members  /* .members */
},
/* MonitoredItemModifyRequest */
{
    UA_TYPENAME("MonitoredItemModifyRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {755LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {757LU}}, /* .binaryEncodingId */
    sizeof(UA_MonitoredItemModifyRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    MonitoredItemModifyRequest_members  /* .members */
},
/* MonitoredItemModifyResult */
{
    UA_TYPENAME("MonitoredItemModifyResult") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {758LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {760LU}}, /* .binaryEncodingId */
    sizeof(UA_MonitoredItemModifyResult), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    MonitoredItemModifyResult_members  /* .members */
},
/* ModifyMonitoredItemsRequest */
{
    UA_TYPENAME("ModifyMonitoredItemsRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {761LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {763LU}}, /* .binaryEncodingId */
    sizeof(UA_ModifyMonitoredItemsRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    ModifyMonitoredItemsRequest_members  /* .members */
},
/* ModifyMonitoredItemsResponse */
{
    UA_TYPENAME("ModifyMonitoredItemsResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {764LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {766LU}}, /* .binaryEncodingId */
    sizeof(UA_ModifyMonitoredItemsResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    ModifyMonitoredItemsResponse_members  /* .members */
},
/* SetMonitoringModeRequest */
{
    UA_TYPENAME("SetMonitoringModeRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {767LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {769LU}}, /* .binaryEncodingId */
    sizeof(UA_SetMonitoringModeRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    SetMonitoringModeRequest_members  /* .members */
},
/* SetMonitoringModeResponse */
{
    UA_TYPENAME("SetMonitoringModeResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {770LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {772LU}}, /* .binaryEncodingId */
    sizeof(UA_SetMonitoringModeResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    SetMonitoringModeResponse_members  /* .members */
},
/* SetTriggeringRequest */
{
    UA_TYPENAME("SetTriggeringRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {773LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {775LU}}, /* .binaryEncodingId */
    sizeof(UA_SetTriggeringRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    SetTriggeringRequest_members  /* .members */
},
/* SetTriggeringResponse */
{
    UA_TYPENAME("SetTriggeringResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {776LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {778LU}}, /* .binaryEncodingId */
    sizeof(UA_SetTriggeringResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    SetTriggeringResponse_members  /* .members */
},
/* DeleteMonitoredItemsRequest */
{
    UA_TYPENAME("DeleteMonitoredItemsRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {779LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {781LU}}, /* .binaryEncodingId */
    sizeof(UA_DeleteMonitoredItemsRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    DeleteMonitoredItemsRequest_members  /* .members */
},
/* DeleteMonitoredItemsResponse */
{
    UA_TYPENAME("DeleteMonitoredItemsResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {782LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {784LU}}, /* .binaryEncodingId */
    sizeof(UA_DeleteMonitoredItemsResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    DeleteMonitoredItemsResponse_members  /* .members */
},
/* CreateSubscriptionRequest */
{
    UA_TYPENAME("CreateSubscriptionRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {785LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {787LU}}, /* .binaryEncodingId */
    sizeof(UA_CreateSubscriptionRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    7, /* .membersSize */
    CreateSubscriptionRequest_members  /* .members */
},
/* CreateSubscriptionResponse */
{
    UA_TYPENAME("CreateSubscriptionResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {788LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {790LU}}, /* .binaryEncodingId */
    sizeof(UA_CreateSubscriptionResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    CreateSubscriptionResponse_members  /* .members */
},
/* ModifySubscriptionRequest */
{
    UA_TYPENAME("ModifySubscriptionRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {791LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {793LU}}, /* .binaryEncodingId */
    sizeof(UA_ModifySubscriptionRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    7, /* .membersSize */
    ModifySubscriptionRequest_members  /* .members */
},
/* ModifySubscriptionResponse */
{
    UA_TYPENAME("ModifySubscriptionResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {794LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {796LU}}, /* .binaryEncodingId */
    sizeof(UA_ModifySubscriptionResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    ModifySubscriptionResponse_members  /* .members */
},
/* SetPublishingModeRequest */
{
    UA_TYPENAME("SetPublishingModeRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {797LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {799LU}}, /* .binaryEncodingId */
    sizeof(UA_SetPublishingModeRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    SetPublishingModeRequest_members  /* .members */
},
/* SetPublishingModeResponse */
{
    UA_TYPENAME("SetPublishingModeResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {800LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {802LU}}, /* .binaryEncodingId */
    sizeof(UA_SetPublishingModeResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    SetPublishingModeResponse_members  /* .members */
},
/* NotificationMessage */
{
    UA_TYPENAME("NotificationMessage") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {803LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {805LU}}, /* .binaryEncodingId */
    sizeof(UA_NotificationMessage), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    NotificationMessage_members  /* .members */
},
/* MonitoredItemNotification */
{
    UA_TYPENAME("MonitoredItemNotification") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {806LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {808LU}}, /* .binaryEncodingId */
    sizeof(UA_MonitoredItemNotification), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    MonitoredItemNotification_members  /* .members */
},
/* EventFieldList */
{
    UA_TYPENAME("EventFieldList") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {917LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {919LU}}, /* .binaryEncodingId */
    sizeof(UA_EventFieldList), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    EventFieldList_members  /* .members */
},
/* HistoryEventFieldList */
{
    UA_TYPENAME("HistoryEventFieldList") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {920LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {922LU}}, /* .binaryEncodingId */
    sizeof(UA_HistoryEventFieldList), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    HistoryEventFieldList_members  /* .members */
},
/* StatusChangeNotification */
{
    UA_TYPENAME("StatusChangeNotification") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {818LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {820LU}}, /* .binaryEncodingId */
    sizeof(UA_StatusChangeNotification), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    StatusChangeNotification_members  /* .members */
},
/* SubscriptionAcknowledgement */
{
    UA_TYPENAME("SubscriptionAcknowledgement") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {821LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {823LU}}, /* .binaryEncodingId */
    sizeof(UA_SubscriptionAcknowledgement), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    SubscriptionAcknowledgement_members  /* .members */
},
/* PublishRequest */
{
    UA_TYPENAME("PublishRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {824LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {826LU}}, /* .binaryEncodingId */
    sizeof(UA_PublishRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    PublishRequest_members  /* .members */
},
/* PublishResponse */
{
    UA_TYPENAME("PublishResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {827LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {829LU}}, /* .binaryEncodingId */
    sizeof(UA_PublishResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    7, /* .membersSize */
    PublishResponse_members  /* .members */
},
/* RepublishRequest */
{
    UA_TYPENAME("RepublishRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {830LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {832LU}}, /* .binaryEncodingId */
    sizeof(UA_RepublishRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    RepublishRequest_members  /* .members */
},
/* RepublishResponse */
{
    UA_TYPENAME("RepublishResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {833LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {835LU}}, /* .binaryEncodingId */
    sizeof(UA_RepublishResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    RepublishResponse_members  /* .members */
},
/* TransferResult */
{
    UA_TYPENAME("TransferResult") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {836LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {838LU}}, /* .binaryEncodingId */
    sizeof(UA_TransferResult), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    TransferResult_members  /* .members */
},
/* TransferSubscriptionsRequest */
{
    UA_TYPENAME("TransferSubscriptionsRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {839LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {841LU}}, /* .binaryEncodingId */
    sizeof(UA_TransferSubscriptionsRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    TransferSubscriptionsRequest_members  /* .members */
},
/* TransferSubscriptionsResponse */
{
    UA_TYPENAME("TransferSubscriptionsResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {842LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {844LU}}, /* .binaryEncodingId */
    sizeof(UA_TransferSubscriptionsResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    TransferSubscriptionsResponse_members  /* .members */
},
/* DeleteSubscriptionsRequest */
{
    UA_TYPENAME("DeleteSubscriptionsRequest") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {845LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {847LU}}, /* .binaryEncodingId */
    sizeof(UA_DeleteSubscriptionsRequest), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    DeleteSubscriptionsRequest_members  /* .members */
},
/* DeleteSubscriptionsResponse */
{
    UA_TYPENAME("DeleteSubscriptionsResponse") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {848LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {850LU}}, /* .binaryEncodingId */
    sizeof(UA_DeleteSubscriptionsResponse), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    DeleteSubscriptionsResponse_members  /* .members */
},
/* BuildInfo */
{
    UA_TYPENAME("BuildInfo") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {338LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {340LU}}, /* .binaryEncodingId */
    sizeof(UA_BuildInfo), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    6, /* .membersSize */
    BuildInfo_members  /* .members */
},
/* RedundancySupport */
{
    UA_TYPENAME("RedundancySupport") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {851LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_RedundancySupport), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    RedundancySupport_members  /* .members */
},
/* ServerState */
{
    UA_TYPENAME("ServerState") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {852LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_ServerState), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    ServerState_members  /* .members */
},
/* ServerDiagnosticsSummaryDataType */
{
    UA_TYPENAME("ServerDiagnosticsSummaryDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {859LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {861LU}}, /* .binaryEncodingId */
    sizeof(UA_ServerDiagnosticsSummaryDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    12, /* .membersSize */
    ServerDiagnosticsSummaryDataType_members  /* .members */
},
/* ServerStatusDataType */
{
    UA_TYPENAME("ServerStatusDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {862LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {864LU}}, /* .binaryEncodingId */
    sizeof(UA_ServerStatusDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    6, /* .membersSize */
    ServerStatusDataType_members  /* .members */
},
/* SessionSecurityDiagnosticsDataType */
{
    UA_TYPENAME("SessionSecurityDiagnosticsDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {868LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {870LU}}, /* .binaryEncodingId */
    sizeof(UA_SessionSecurityDiagnosticsDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    9, /* .membersSize */
    SessionSecurityDiagnosticsDataType_members  /* .members */
},
/* ServiceCounterDataType */
{
    UA_TYPENAME("ServiceCounterDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {871LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {873LU}}, /* .binaryEncodingId */
    sizeof(UA_ServiceCounterDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    ServiceCounterDataType_members  /* .members */
},
/* SubscriptionDiagnosticsDataType */
{
    UA_TYPENAME("SubscriptionDiagnosticsDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {874LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {876LU}}, /* .binaryEncodingId */
    sizeof(UA_SubscriptionDiagnosticsDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    31, /* .membersSize */
    SubscriptionDiagnosticsDataType_members  /* .members */
},
/* Range */
{
    UA_TYPENAME("Range") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {884LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {886LU}}, /* .binaryEncodingId */
    sizeof(UA_Range), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    Range_members  /* .members */
},
/* EUInformation */
{
    UA_TYPENAME("EUInformation") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {887LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {889LU}}, /* .binaryEncodingId */
    sizeof(UA_EUInformation), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    EUInformation_members  /* .members */
},
/* AxisScaleEnumeration */
{
    UA_TYPENAME("AxisScaleEnumeration") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12077LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_AxisScaleEnumeration), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    AxisScaleEnumeration_members  /* .members */
},
/* ComplexNumberType */
{
    UA_TYPENAME("ComplexNumberType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12171LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {12181LU}}, /* .binaryEncodingId */
    sizeof(UA_ComplexNumberType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    ComplexNumberType_members  /* .members */
},
/* DoubleComplexNumberType */
{
    UA_TYPENAME("DoubleComplexNumberType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12172LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {12182LU}}, /* .binaryEncodingId */
    sizeof(UA_DoubleComplexNumberType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    DoubleComplexNumberType_members  /* .members */
},
/* AxisInformation */
{
    UA_TYPENAME("AxisInformation") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12079LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {12089LU}}, /* .binaryEncodingId */
    sizeof(UA_AxisInformation), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    AxisInformation_members  /* .members */
},
/* XVType */
{
    UA_TYPENAME("XVType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {12080LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {12090LU}}, /* .binaryEncodingId */
    sizeof(UA_XVType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    XVType_members  /* .members */
},
/* EnumDefinition */
{
    UA_TYPENAME("EnumDefinition") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {100LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {123LU}}, /* .binaryEncodingId */
    sizeof(UA_EnumDefinition), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    EnumDefinition_members  /* .members */
},
/* ReadEventDetails */
{
    UA_TYPENAME("ReadEventDetails") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {644LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {646LU}}, /* .binaryEncodingId */
    sizeof(UA_ReadEventDetails), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    4, /* .membersSize */
    ReadEventDetails_members  /* .members */
},
/* ReadProcessedDetails */
{
    UA_TYPENAME("ReadProcessedDetails") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {650LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {652LU}}, /* .binaryEncodingId */
    sizeof(UA_ReadProcessedDetails), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    ReadProcessedDetails_members  /* .members */
},
/* ModificationInfo */
{
    UA_TYPENAME("ModificationInfo") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {11216LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {11226LU}}, /* .binaryEncodingId */
    sizeof(UA_ModificationInfo), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    ModificationInfo_members  /* .members */
},
/* HistoryModifiedData */
{
    UA_TYPENAME("HistoryModifiedData") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {11217LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {11227LU}}, /* .binaryEncodingId */
    sizeof(UA_HistoryModifiedData), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    HistoryModifiedData_members  /* .members */
},
/* HistoryEvent */
{
    UA_TYPENAME("HistoryEvent") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {659LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {661LU}}, /* .binaryEncodingId */
    sizeof(UA_HistoryEvent), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    HistoryEvent_members  /* .members */
},
/* DataChangeNotification */
{
    UA_TYPENAME("DataChangeNotification") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {809LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {811LU}}, /* .binaryEncodingId */
    sizeof(UA_DataChangeNotification), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    DataChangeNotification_members  /* .members */
},
/* EventNotificationList */
{
    UA_TYPENAME("EventNotificationList") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {914LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {916LU}}, /* .binaryEncodingId */
    sizeof(UA_EventNotificationList), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    1, /* .membersSize */
    EventNotificationList_members  /* .members */
},
/* SessionDiagnosticsDataType */
{
    UA_TYPENAME("SessionDiagnosticsDataType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {865LU}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {867LU}}, /* .binaryEncodingId */
    sizeof(UA_SessionDiagnosticsDataType), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    43, /* .membersSize */
    SessionDiagnosticsDataType_members  /* .members */
},
};


/**** amalgamated original file "/build/src_generated/open62541/transport_generated.c" ****/

/**********************************
 * Autogenerated -- do not modify *
 **********************************/


/* MessageType */
#define MessageType_members NULL

/* ChunkType */
#define ChunkType_members NULL

/* TcpMessageHeader */
static UA_DataTypeMember TcpMessageHeader_members[2] = {
{
    UA_TYPENAME("MessageTypeAndChunkType") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MessageSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_TcpMessageHeader, messageSize) - offsetof(UA_TcpMessageHeader, messageTypeAndChunkType) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* TcpHelloMessage */
static UA_DataTypeMember TcpHelloMessage_members[6] = {
{
    UA_TYPENAME("ProtocolVersion") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReceiveBufferSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_TcpHelloMessage, receiveBufferSize) - offsetof(UA_TcpHelloMessage, protocolVersion) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SendBufferSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_TcpHelloMessage, sendBufferSize) - offsetof(UA_TcpHelloMessage, receiveBufferSize) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxMessageSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_TcpHelloMessage, maxMessageSize) - offsetof(UA_TcpHelloMessage, sendBufferSize) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxChunkCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_TcpHelloMessage, maxChunkCount) - offsetof(UA_TcpHelloMessage, maxMessageSize) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EndpointUrl") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_TcpHelloMessage, endpointUrl) - offsetof(UA_TcpHelloMessage, maxChunkCount) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* TcpReverseHelloMessage */
static UA_DataTypeMember TcpReverseHelloMessage_members[2] = {
{
    UA_TYPENAME("ServerUri") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("EndpointUrl") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_TcpReverseHelloMessage, endpointUrl) - offsetof(UA_TcpReverseHelloMessage, serverUri) - sizeof(UA_String), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* TcpAcknowledgeMessage */
static UA_DataTypeMember TcpAcknowledgeMessage_members[5] = {
{
    UA_TYPENAME("ProtocolVersion") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReceiveBufferSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_TcpAcknowledgeMessage, receiveBufferSize) - offsetof(UA_TcpAcknowledgeMessage, protocolVersion) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SendBufferSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_TcpAcknowledgeMessage, sendBufferSize) - offsetof(UA_TcpAcknowledgeMessage, receiveBufferSize) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxMessageSize") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_TcpAcknowledgeMessage, maxMessageSize) - offsetof(UA_TcpAcknowledgeMessage, sendBufferSize) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("MaxChunkCount") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_TcpAcknowledgeMessage, maxChunkCount) - offsetof(UA_TcpAcknowledgeMessage, maxMessageSize) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* TcpErrorMessage */
static UA_DataTypeMember TcpErrorMessage_members[2] = {
{
    UA_TYPENAME("Error") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("Reason") /* .memberName */
    &UA_TYPES[UA_TYPES_STRING], /* .memberType */
    offsetof(UA_TcpErrorMessage, reason) - offsetof(UA_TcpErrorMessage, error) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* AsymmetricAlgorithmSecurityHeader */
static UA_DataTypeMember AsymmetricAlgorithmSecurityHeader_members[3] = {
{
    UA_TYPENAME("SecurityPolicyUri") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("SenderCertificate") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_AsymmetricAlgorithmSecurityHeader, senderCertificate) - offsetof(UA_AsymmetricAlgorithmSecurityHeader, securityPolicyUri) - sizeof(UA_ByteString), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("ReceiverCertificateThumbprint") /* .memberName */
    &UA_TYPES[UA_TYPES_BYTESTRING], /* .memberType */
    offsetof(UA_AsymmetricAlgorithmSecurityHeader, receiverCertificateThumbprint) - offsetof(UA_AsymmetricAlgorithmSecurityHeader, senderCertificate) - sizeof(UA_ByteString), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};

/* SequenceHeader */
static UA_DataTypeMember SequenceHeader_members[2] = {
{
    UA_TYPENAME("SequenceNumber") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    0, /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},
{
    UA_TYPENAME("RequestId") /* .memberName */
    &UA_TYPES[UA_TYPES_UINT32], /* .memberType */
    offsetof(UA_SequenceHeader, requestId) - offsetof(UA_SequenceHeader, sequenceNumber) - sizeof(UA_UInt32), /* .padding */
    false, /* .isArray */
    false  /* .isOptional */
},};
UA_DataType UA_TRANSPORT[UA_TRANSPORT_COUNT] = {
/* MessageType */
{
    UA_TYPENAME("MessageType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_MessageType), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    MessageType_members  /* .members */
},
/* ChunkType */
{
    UA_TYPENAME("ChunkType") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_ChunkType), /* .memSize */
    UA_DATATYPEKIND_ENUM, /* .typeKind */
    true, /* .pointerFree */
    UA_BINARY_OVERLAYABLE_INTEGER, /* .overlayable */
    0, /* .membersSize */
    ChunkType_members  /* .members */
},
/* TcpMessageHeader */
{
    UA_TYPENAME("TcpMessageHeader") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_TcpMessageHeader), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    TcpMessageHeader_members  /* .members */
},
/* TcpHelloMessage */
{
    UA_TYPENAME("TcpHelloMessage") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_TcpHelloMessage), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    6, /* .membersSize */
    TcpHelloMessage_members  /* .members */
},
/* TcpReverseHelloMessage */
{
    UA_TYPENAME("TcpReverseHelloMessage") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_TcpReverseHelloMessage), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    TcpReverseHelloMessage_members  /* .members */
},
/* TcpAcknowledgeMessage */
{
    UA_TYPENAME("TcpAcknowledgeMessage") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_TcpAcknowledgeMessage), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    5, /* .membersSize */
    TcpAcknowledgeMessage_members  /* .members */
},
/* TcpErrorMessage */
{
    UA_TYPENAME("TcpErrorMessage") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_TcpErrorMessage), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    TcpErrorMessage_members  /* .members */
},
/* AsymmetricAlgorithmSecurityHeader */
{
    UA_TYPENAME("AsymmetricAlgorithmSecurityHeader") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_AsymmetricAlgorithmSecurityHeader), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    false, /* .pointerFree */
    false, /* .overlayable */
    3, /* .membersSize */
    AsymmetricAlgorithmSecurityHeader_members  /* .members */
},
/* SequenceHeader */
{
    UA_TYPENAME("SequenceHeader") /* .typeName */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .typeId */
    {0, UA_NODEIDTYPE_NUMERIC, {0}}, /* .binaryEncodingId */
    sizeof(UA_SequenceHeader), /* .memSize */
    UA_DATATYPEKIND_STRUCTURE, /* .typeKind */
    true, /* .pointerFree */
    false, /* .overlayable */
    2, /* .membersSize */
    SequenceHeader_members  /* .members */
},
};


/**** amalgamated original file "/build/src_generated/open62541/statuscodes.c" ****/

/**********************************
 * Autogenerated -- do not modify *
 **********************************/


typedef struct {
    UA_StatusCode code;
    const char *name;
} UA_StatusCodeName;

#ifndef UA_ENABLE_STATUSCODE_DESCRIPTIONS
static const char * emptyStatusCodeName = "";
const char * UA_StatusCode_name(UA_StatusCode code) {
    return emptyStatusCodeName;
}
#else
static const size_t statusCodeDescriptionsSize = 252;
static const UA_StatusCodeName statusCodeDescriptions[252] = {
    {UA_STATUSCODE_GOOD, "Good"},
    {UA_STATUSCODE_GOOD, "Good"},
    {UA_STATUSCODE_UNCERTAIN, "Uncertain"},
    {UA_STATUSCODE_BAD, "Bad"},
    {UA_STATUSCODE_BADUNEXPECTEDERROR, "BadUnexpectedError"},
    {UA_STATUSCODE_BADINTERNALERROR, "BadInternalError"},
    {UA_STATUSCODE_BADOUTOFMEMORY, "BadOutOfMemory"},
    {UA_STATUSCODE_BADRESOURCEUNAVAILABLE, "BadResourceUnavailable"},
    {UA_STATUSCODE_BADCOMMUNICATIONERROR, "BadCommunicationError"},
    {UA_STATUSCODE_BADENCODINGERROR, "BadEncodingError"},
    {UA_STATUSCODE_BADDECODINGERROR, "BadDecodingError"},
    {UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED, "BadEncodingLimitsExceeded"},
    {UA_STATUSCODE_BADREQUESTTOOLARGE, "BadRequestTooLarge"},
    {UA_STATUSCODE_BADRESPONSETOOLARGE, "BadResponseTooLarge"},
    {UA_STATUSCODE_BADUNKNOWNRESPONSE, "BadUnknownResponse"},
    {UA_STATUSCODE_BADTIMEOUT, "BadTimeout"},
    {UA_STATUSCODE_BADSERVICEUNSUPPORTED, "BadServiceUnsupported"},
    {UA_STATUSCODE_BADSHUTDOWN, "BadShutdown"},
    {UA_STATUSCODE_BADSERVERNOTCONNECTED, "BadServerNotConnected"},
    {UA_STATUSCODE_BADSERVERHALTED, "BadServerHalted"},
    {UA_STATUSCODE_BADNOTHINGTODO, "BadNothingToDo"},
    {UA_STATUSCODE_BADTOOMANYOPERATIONS, "BadTooManyOperations"},
    {UA_STATUSCODE_BADTOOMANYMONITOREDITEMS, "BadTooManyMonitoredItems"},
    {UA_STATUSCODE_BADDATATYPEIDUNKNOWN, "BadDataTypeIdUnknown"},
    {UA_STATUSCODE_BADCERTIFICATEINVALID, "BadCertificateInvalid"},
    {UA_STATUSCODE_BADSECURITYCHECKSFAILED, "BadSecurityChecksFailed"},
    {UA_STATUSCODE_BADCERTIFICATEPOLICYCHECKFAILED, "BadCertificatePolicyCheckFailed"},
    {UA_STATUSCODE_BADCERTIFICATETIMEINVALID, "BadCertificateTimeInvalid"},
    {UA_STATUSCODE_BADCERTIFICATEISSUERTIMEINVALID, "BadCertificateIssuerTimeInvalid"},
    {UA_STATUSCODE_BADCERTIFICATEHOSTNAMEINVALID, "BadCertificateHostNameInvalid"},
    {UA_STATUSCODE_BADCERTIFICATEURIINVALID, "BadCertificateUriInvalid"},
    {UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED, "BadCertificateUseNotAllowed"},
    {UA_STATUSCODE_BADCERTIFICATEISSUERUSENOTALLOWED, "BadCertificateIssuerUseNotAllowed"},
    {UA_STATUSCODE_BADCERTIFICATEUNTRUSTED, "BadCertificateUntrusted"},
    {UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN, "BadCertificateRevocationUnknown"},
    {UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN, "BadCertificateIssuerRevocationUnknown"},
    {UA_STATUSCODE_BADCERTIFICATEREVOKED, "BadCertificateRevoked"},
    {UA_STATUSCODE_BADCERTIFICATEISSUERREVOKED, "BadCertificateIssuerRevoked"},
    {UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE, "BadCertificateChainIncomplete"},
    {UA_STATUSCODE_BADUSERACCESSDENIED, "BadUserAccessDenied"},
    {UA_STATUSCODE_BADIDENTITYTOKENINVALID, "BadIdentityTokenInvalid"},
    {UA_STATUSCODE_BADIDENTITYTOKENREJECTED, "BadIdentityTokenRejected"},
    {UA_STATUSCODE_BADSECURECHANNELIDINVALID, "BadSecureChannelIdInvalid"},
    {UA_STATUSCODE_BADINVALIDTIMESTAMP, "BadInvalidTimestamp"},
    {UA_STATUSCODE_BADNONCEINVALID, "BadNonceInvalid"},
    {UA_STATUSCODE_BADSESSIONIDINVALID, "BadSessionIdInvalid"},
    {UA_STATUSCODE_BADSESSIONCLOSED, "BadSessionClosed"},
    {UA_STATUSCODE_BADSESSIONNOTACTIVATED, "BadSessionNotActivated"},
    {UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID, "BadSubscriptionIdInvalid"},
    {UA_STATUSCODE_BADREQUESTHEADERINVALID, "BadRequestHeaderInvalid"},
    {UA_STATUSCODE_BADTIMESTAMPSTORETURNINVALID, "BadTimestampsToReturnInvalid"},
    {UA_STATUSCODE_BADREQUESTCANCELLEDBYCLIENT, "BadRequestCancelledByClient"},
    {UA_STATUSCODE_BADTOOMANYARGUMENTS, "BadTooManyArguments"},
    {UA_STATUSCODE_BADLICENSEEXPIRED, "BadLicenseExpired"},
    {UA_STATUSCODE_BADLICENSELIMITSEXCEEDED, "BadLicenseLimitsExceeded"},
    {UA_STATUSCODE_BADLICENSENOTAVAILABLE, "BadLicenseNotAvailable"},
    {UA_STATUSCODE_GOODSUBSCRIPTIONTRANSFERRED, "GoodSubscriptionTransferred"},
    {UA_STATUSCODE_GOODCOMPLETESASYNCHRONOUSLY, "GoodCompletesAsynchronously"},
    {UA_STATUSCODE_GOODOVERLOAD, "GoodOverload"},
    {UA_STATUSCODE_GOODCLAMPED, "GoodClamped"},
    {UA_STATUSCODE_BADNOCOMMUNICATION, "BadNoCommunication"},
    {UA_STATUSCODE_BADWAITINGFORINITIALDATA, "BadWaitingForInitialData"},
    {UA_STATUSCODE_BADNODEIDINVALID, "BadNodeIdInvalid"},
    {UA_STATUSCODE_BADNODEIDUNKNOWN, "BadNodeIdUnknown"},
    {UA_STATUSCODE_BADATTRIBUTEIDINVALID, "BadAttributeIdInvalid"},
    {UA_STATUSCODE_BADINDEXRANGEINVALID, "BadIndexRangeInvalid"},
    {UA_STATUSCODE_BADINDEXRANGENODATA, "BadIndexRangeNoData"},
    {UA_STATUSCODE_BADDATAENCODINGINVALID, "BadDataEncodingInvalid"},
    {UA_STATUSCODE_BADDATAENCODINGUNSUPPORTED, "BadDataEncodingUnsupported"},
    {UA_STATUSCODE_BADNOTREADABLE, "BadNotReadable"},
    {UA_STATUSCODE_BADNOTWRITABLE, "BadNotWritable"},
    {UA_STATUSCODE_BADOUTOFRANGE, "BadOutOfRange"},
    {UA_STATUSCODE_BADNOTSUPPORTED, "BadNotSupported"},
    {UA_STATUSCODE_BADNOTFOUND, "BadNotFound"},
    {UA_STATUSCODE_BADOBJECTDELETED, "BadObjectDeleted"},
    {UA_STATUSCODE_BADNOTIMPLEMENTED, "BadNotImplemented"},
    {UA_STATUSCODE_BADMONITORINGMODEINVALID, "BadMonitoringModeInvalid"},
    {UA_STATUSCODE_BADMONITOREDITEMIDINVALID, "BadMonitoredItemIdInvalid"},
    {UA_STATUSCODE_BADMONITOREDITEMFILTERINVALID, "BadMonitoredItemFilterInvalid"},
    {UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED, "BadMonitoredItemFilterUnsupported"},
    {UA_STATUSCODE_BADFILTERNOTALLOWED, "BadFilterNotAllowed"},
    {UA_STATUSCODE_BADSTRUCTUREMISSING, "BadStructureMissing"},
    {UA_STATUSCODE_BADEVENTFILTERINVALID, "BadEventFilterInvalid"},
    {UA_STATUSCODE_BADCONTENTFILTERINVALID, "BadContentFilterInvalid"},
    {UA_STATUSCODE_BADFILTEROPERATORINVALID, "BadFilterOperatorInvalid"},
    {UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED, "BadFilterOperatorUnsupported"},
    {UA_STATUSCODE_BADFILTEROPERANDCOUNTMISMATCH, "BadFilterOperandCountMismatch"},
    {UA_STATUSCODE_BADFILTEROPERANDINVALID, "BadFilterOperandInvalid"},
    {UA_STATUSCODE_BADFILTERELEMENTINVALID, "BadFilterElementInvalid"},
    {UA_STATUSCODE_BADFILTERLITERALINVALID, "BadFilterLiteralInvalid"},
    {UA_STATUSCODE_BADCONTINUATIONPOINTINVALID, "BadContinuationPointInvalid"},
    {UA_STATUSCODE_BADNOCONTINUATIONPOINTS, "BadNoContinuationPoints"},
    {UA_STATUSCODE_BADREFERENCETYPEIDINVALID, "BadReferenceTypeIdInvalid"},
    {UA_STATUSCODE_BADBROWSEDIRECTIONINVALID, "BadBrowseDirectionInvalid"},
    {UA_STATUSCODE_BADNODENOTINVIEW, "BadNodeNotInView"},
    {UA_STATUSCODE_BADNUMERICOVERFLOW, "BadNumericOverflow"},
    {UA_STATUSCODE_BADSERVERURIINVALID, "BadServerUriInvalid"},
    {UA_STATUSCODE_BADSERVERNAMEMISSING, "BadServerNameMissing"},
    {UA_STATUSCODE_BADDISCOVERYURLMISSING, "BadDiscoveryUrlMissing"},
    {UA_STATUSCODE_BADSEMPAHOREFILEMISSING, "BadSempahoreFileMissing"},
    {UA_STATUSCODE_BADREQUESTTYPEINVALID, "BadRequestTypeInvalid"},
    {UA_STATUSCODE_BADSECURITYMODEREJECTED, "BadSecurityModeRejected"},
    {UA_STATUSCODE_BADSECURITYPOLICYREJECTED, "BadSecurityPolicyRejected"},
    {UA_STATUSCODE_BADTOOMANYSESSIONS, "BadTooManySessions"},
    {UA_STATUSCODE_BADUSERSIGNATUREINVALID, "BadUserSignatureInvalid"},
    {UA_STATUSCODE_BADAPPLICATIONSIGNATUREINVALID, "BadApplicationSignatureInvalid"},
    {UA_STATUSCODE_BADNOVALIDCERTIFICATES, "BadNoValidCertificates"},
    {UA_STATUSCODE_BADIDENTITYCHANGENOTSUPPORTED, "BadIdentityChangeNotSupported"},
    {UA_STATUSCODE_BADREQUESTCANCELLEDBYREQUEST, "BadRequestCancelledByRequest"},
    {UA_STATUSCODE_BADPARENTNODEIDINVALID, "BadParentNodeIdInvalid"},
    {UA_STATUSCODE_BADREFERENCENOTALLOWED, "BadReferenceNotAllowed"},
    {UA_STATUSCODE_BADNODEIDREJECTED, "BadNodeIdRejected"},
    {UA_STATUSCODE_BADNODEIDEXISTS, "BadNodeIdExists"},
    {UA_STATUSCODE_BADNODECLASSINVALID, "BadNodeClassInvalid"},
    {UA_STATUSCODE_BADBROWSENAMEINVALID, "BadBrowseNameInvalid"},
    {UA_STATUSCODE_BADBROWSENAMEDUPLICATED, "BadBrowseNameDuplicated"},
    {UA_STATUSCODE_BADNODEATTRIBUTESINVALID, "BadNodeAttributesInvalid"},
    {UA_STATUSCODE_BADTYPEDEFINITIONINVALID, "BadTypeDefinitionInvalid"},
    {UA_STATUSCODE_BADSOURCENODEIDINVALID, "BadSourceNodeIdInvalid"},
    {UA_STATUSCODE_BADTARGETNODEIDINVALID, "BadTargetNodeIdInvalid"},
    {UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED, "BadDuplicateReferenceNotAllowed"},
    {UA_STATUSCODE_BADINVALIDSELFREFERENCE, "BadInvalidSelfReference"},
    {UA_STATUSCODE_BADREFERENCELOCALONLY, "BadReferenceLocalOnly"},
    {UA_STATUSCODE_BADNODELETERIGHTS, "BadNoDeleteRights"},
    {UA_STATUSCODE_UNCERTAINREFERENCENOTDELETED, "UncertainReferenceNotDeleted"},
    {UA_STATUSCODE_BADSERVERINDEXINVALID, "BadServerIndexInvalid"},
    {UA_STATUSCODE_BADVIEWIDUNKNOWN, "BadViewIdUnknown"},
    {UA_STATUSCODE_BADVIEWTIMESTAMPINVALID, "BadViewTimestampInvalid"},
    {UA_STATUSCODE_BADVIEWPARAMETERMISMATCH, "BadViewParameterMismatch"},
    {UA_STATUSCODE_BADVIEWVERSIONINVALID, "BadViewVersionInvalid"},
    {UA_STATUSCODE_UNCERTAINNOTALLNODESAVAILABLE, "UncertainNotAllNodesAvailable"},
    {UA_STATUSCODE_GOODRESULTSMAYBEINCOMPLETE, "GoodResultsMayBeIncomplete"},
    {UA_STATUSCODE_BADNOTTYPEDEFINITION, "BadNotTypeDefinition"},
    {UA_STATUSCODE_UNCERTAINREFERENCEOUTOFSERVER, "UncertainReferenceOutOfServer"},
    {UA_STATUSCODE_BADTOOMANYMATCHES, "BadTooManyMatches"},
    {UA_STATUSCODE_BADQUERYTOOCOMPLEX, "BadQueryTooComplex"},
    {UA_STATUSCODE_BADNOMATCH, "BadNoMatch"},
    {UA_STATUSCODE_BADMAXAGEINVALID, "BadMaxAgeInvalid"},
    {UA_STATUSCODE_BADSECURITYMODEINSUFFICIENT, "BadSecurityModeInsufficient"},
    {UA_STATUSCODE_BADHISTORYOPERATIONINVALID, "BadHistoryOperationInvalid"},
    {UA_STATUSCODE_BADHISTORYOPERATIONUNSUPPORTED, "BadHistoryOperationUnsupported"},
    {UA_STATUSCODE_BADINVALIDTIMESTAMPARGUMENT, "BadInvalidTimestampArgument"},
    {UA_STATUSCODE_BADWRITENOTSUPPORTED, "BadWriteNotSupported"},
    {UA_STATUSCODE_BADTYPEMISMATCH, "BadTypeMismatch"},
    {UA_STATUSCODE_BADMETHODINVALID, "BadMethodInvalid"},
    {UA_STATUSCODE_BADARGUMENTSMISSING, "BadArgumentsMissing"},
    {UA_STATUSCODE_BADNOTEXECUTABLE, "BadNotExecutable"},
    {UA_STATUSCODE_BADTOOMANYSUBSCRIPTIONS, "BadTooManySubscriptions"},
    {UA_STATUSCODE_BADTOOMANYPUBLISHREQUESTS, "BadTooManyPublishRequests"},
    {UA_STATUSCODE_BADNOSUBSCRIPTION, "BadNoSubscription"},
    {UA_STATUSCODE_BADSEQUENCENUMBERUNKNOWN, "BadSequenceNumberUnknown"},
    {UA_STATUSCODE_GOODRETRANSMISSIONQUEUENOTSUPPORTED, "GoodRetransmissionQueueNotSupported"},
    {UA_STATUSCODE_BADMESSAGENOTAVAILABLE, "BadMessageNotAvailable"},
    {UA_STATUSCODE_BADINSUFFICIENTCLIENTPROFILE, "BadInsufficientClientProfile"},
    {UA_STATUSCODE_BADSTATENOTACTIVE, "BadStateNotActive"},
    {UA_STATUSCODE_BADALREADYEXISTS, "BadAlreadyExists"},
    {UA_STATUSCODE_BADTCPSERVERTOOBUSY, "BadTcpServerTooBusy"},
    {UA_STATUSCODE_BADTCPMESSAGETYPEINVALID, "BadTcpMessageTypeInvalid"},
    {UA_STATUSCODE_BADTCPSECURECHANNELUNKNOWN, "BadTcpSecureChannelUnknown"},
    {UA_STATUSCODE_BADTCPMESSAGETOOLARGE, "BadTcpMessageTooLarge"},
    {UA_STATUSCODE_BADTCPNOTENOUGHRESOURCES, "BadTcpNotEnoughResources"},
    {UA_STATUSCODE_BADTCPINTERNALERROR, "BadTcpInternalError"},
    {UA_STATUSCODE_BADTCPENDPOINTURLINVALID, "BadTcpEndpointUrlInvalid"},
    {UA_STATUSCODE_BADREQUESTINTERRUPTED, "BadRequestInterrupted"},
    {UA_STATUSCODE_BADREQUESTTIMEOUT, "BadRequestTimeout"},
    {UA_STATUSCODE_BADSECURECHANNELCLOSED, "BadSecureChannelClosed"},
    {UA_STATUSCODE_BADSECURECHANNELTOKENUNKNOWN, "BadSecureChannelTokenUnknown"},
    {UA_STATUSCODE_BADSEQUENCENUMBERINVALID, "BadSequenceNumberInvalid"},
    {UA_STATUSCODE_BADPROTOCOLVERSIONUNSUPPORTED, "BadProtocolVersionUnsupported"},
    {UA_STATUSCODE_BADCONFIGURATIONERROR, "BadConfigurationError"},
    {UA_STATUSCODE_BADNOTCONNECTED, "BadNotConnected"},
    {UA_STATUSCODE_BADDEVICEFAILURE, "BadDeviceFailure"},
    {UA_STATUSCODE_BADSENSORFAILURE, "BadSensorFailure"},
    {UA_STATUSCODE_BADOUTOFSERVICE, "BadOutOfService"},
    {UA_STATUSCODE_BADDEADBANDFILTERINVALID, "BadDeadbandFilterInvalid"},
    {UA_STATUSCODE_UNCERTAINNOCOMMUNICATIONLASTUSABLEVALUE, "UncertainNoCommunicationLastUsableValue"},
    {UA_STATUSCODE_UNCERTAINLASTUSABLEVALUE, "UncertainLastUsableValue"},
    {UA_STATUSCODE_UNCERTAINSUBSTITUTEVALUE, "UncertainSubstituteValue"},
    {UA_STATUSCODE_UNCERTAININITIALVALUE, "UncertainInitialValue"},
    {UA_STATUSCODE_UNCERTAINSENSORNOTACCURATE, "UncertainSensorNotAccurate"},
    {UA_STATUSCODE_UNCERTAINENGINEERINGUNITSEXCEEDED, "UncertainEngineeringUnitsExceeded"},
    {UA_STATUSCODE_UNCERTAINSUBNORMAL, "UncertainSubNormal"},
    {UA_STATUSCODE_GOODLOCALOVERRIDE, "GoodLocalOverride"},
    {UA_STATUSCODE_BADREFRESHINPROGRESS, "BadRefreshInProgress"},
    {UA_STATUSCODE_BADCONDITIONALREADYDISABLED, "BadConditionAlreadyDisabled"},
    {UA_STATUSCODE_BADCONDITIONALREADYENABLED, "BadConditionAlreadyEnabled"},
    {UA_STATUSCODE_BADCONDITIONDISABLED, "BadConditionDisabled"},
    {UA_STATUSCODE_BADEVENTIDUNKNOWN, "BadEventIdUnknown"},
    {UA_STATUSCODE_BADEVENTNOTACKNOWLEDGEABLE, "BadEventNotAcknowledgeable"},
    {UA_STATUSCODE_BADDIALOGNOTACTIVE, "BadDialogNotActive"},
    {UA_STATUSCODE_BADDIALOGRESPONSEINVALID, "BadDialogResponseInvalid"},
    {UA_STATUSCODE_BADCONDITIONBRANCHALREADYACKED, "BadConditionBranchAlreadyAcked"},
    {UA_STATUSCODE_BADCONDITIONBRANCHALREADYCONFIRMED, "BadConditionBranchAlreadyConfirmed"},
    {UA_STATUSCODE_BADCONDITIONALREADYSHELVED, "BadConditionAlreadyShelved"},
    {UA_STATUSCODE_BADCONDITIONNOTSHELVED, "BadConditionNotShelved"},
    {UA_STATUSCODE_BADSHELVINGTIMEOUTOFRANGE, "BadShelvingTimeOutOfRange"},
    {UA_STATUSCODE_BADNODATA, "BadNoData"},
    {UA_STATUSCODE_BADBOUNDNOTFOUND, "BadBoundNotFound"},
    {UA_STATUSCODE_BADBOUNDNOTSUPPORTED, "BadBoundNotSupported"},
    {UA_STATUSCODE_BADDATALOST, "BadDataLost"},
    {UA_STATUSCODE_BADDATAUNAVAILABLE, "BadDataUnavailable"},
    {UA_STATUSCODE_BADENTRYEXISTS, "BadEntryExists"},
    {UA_STATUSCODE_BADNOENTRYEXISTS, "BadNoEntryExists"},
    {UA_STATUSCODE_BADTIMESTAMPNOTSUPPORTED, "BadTimestampNotSupported"},
    {UA_STATUSCODE_GOODENTRYINSERTED, "GoodEntryInserted"},
    {UA_STATUSCODE_GOODENTRYREPLACED, "GoodEntryReplaced"},
    {UA_STATUSCODE_UNCERTAINDATASUBNORMAL, "UncertainDataSubNormal"},
    {UA_STATUSCODE_GOODNODATA, "GoodNoData"},
    {UA_STATUSCODE_GOODMOREDATA, "GoodMoreData"},
    {UA_STATUSCODE_BADAGGREGATELISTMISMATCH, "BadAggregateListMismatch"},
    {UA_STATUSCODE_BADAGGREGATENOTSUPPORTED, "BadAggregateNotSupported"},
    {UA_STATUSCODE_BADAGGREGATEINVALIDINPUTS, "BadAggregateInvalidInputs"},
    {UA_STATUSCODE_BADAGGREGATECONFIGURATIONREJECTED, "BadAggregateConfigurationRejected"},
    {UA_STATUSCODE_GOODDATAIGNORED, "GoodDataIgnored"},
    {UA_STATUSCODE_BADREQUESTNOTALLOWED, "BadRequestNotAllowed"},
    {UA_STATUSCODE_BADREQUESTNOTCOMPLETE, "BadRequestNotComplete"},
    {UA_STATUSCODE_BADTICKETREQUIRED, "BadTicketRequired"},
    {UA_STATUSCODE_BADTICKETINVALID, "BadTicketInvalid"},
    {UA_STATUSCODE_GOODEDITED, "GoodEdited"},
    {UA_STATUSCODE_GOODPOSTACTIONFAILED, "GoodPostActionFailed"},
    {UA_STATUSCODE_UNCERTAINDOMINANTVALUECHANGED, "UncertainDominantValueChanged"},
    {UA_STATUSCODE_GOODDEPENDENTVALUECHANGED, "GoodDependentValueChanged"},
    {UA_STATUSCODE_BADDOMINANTVALUECHANGED, "BadDominantValueChanged"},
    {UA_STATUSCODE_UNCERTAINDEPENDENTVALUECHANGED, "UncertainDependentValueChanged"},
    {UA_STATUSCODE_BADDEPENDENTVALUECHANGED, "BadDependentValueChanged"},
    {UA_STATUSCODE_GOODEDITED_DEPENDENTVALUECHANGED, "GoodEdited_DependentValueChanged"},
    {UA_STATUSCODE_GOODEDITED_DOMINANTVALUECHANGED, "GoodEdited_DominantValueChanged"},
    {UA_STATUSCODE_GOODEDITED_DOMINANTVALUECHANGED_DEPENDENTVALUECHANGED, "GoodEdited_DominantValueChanged_DependentValueChanged"},
    {UA_STATUSCODE_BADEDITED_OUTOFRANGE, "BadEdited_OutOfRange"},
    {UA_STATUSCODE_BADINITIALVALUE_OUTOFRANGE, "BadInitialValue_OutOfRange"},
    {UA_STATUSCODE_BADOUTOFRANGE_DOMINANTVALUECHANGED, "BadOutOfRange_DominantValueChanged"},
    {UA_STATUSCODE_BADEDITED_OUTOFRANGE_DOMINANTVALUECHANGED, "BadEdited_OutOfRange_DominantValueChanged"},
    {UA_STATUSCODE_BADOUTOFRANGE_DOMINANTVALUECHANGED_DEPENDENTVALUECHANGED, "BadOutOfRange_DominantValueChanged_DependentValueChanged"},
    {UA_STATUSCODE_BADEDITED_OUTOFRANGE_DOMINANTVALUECHANGED_DEPENDENTVALUECHANGED, "BadEdited_OutOfRange_DominantValueChanged_DependentValueChanged"},
    {UA_STATUSCODE_GOODCOMMUNICATIONEVENT, "GoodCommunicationEvent"},
    {UA_STATUSCODE_GOODSHUTDOWNEVENT, "GoodShutdownEvent"},
    {UA_STATUSCODE_GOODCALLAGAIN, "GoodCallAgain"},
    {UA_STATUSCODE_GOODNONCRITICALTIMEOUT, "GoodNonCriticalTimeout"},
    {UA_STATUSCODE_BADINVALIDARGUMENT, "BadInvalidArgument"},
    {UA_STATUSCODE_BADCONNECTIONREJECTED, "BadConnectionRejected"},
    {UA_STATUSCODE_BADDISCONNECT, "BadDisconnect"},
    {UA_STATUSCODE_BADCONNECTIONCLOSED, "BadConnectionClosed"},
    {UA_STATUSCODE_BADINVALIDSTATE, "BadInvalidState"},
    {UA_STATUSCODE_BADENDOFSTREAM, "BadEndOfStream"},
    {UA_STATUSCODE_BADNODATAAVAILABLE, "BadNoDataAvailable"},
    {UA_STATUSCODE_BADWAITINGFORRESPONSE, "BadWaitingForResponse"},
    {UA_STATUSCODE_BADOPERATIONABANDONED, "BadOperationAbandoned"},
    {UA_STATUSCODE_BADEXPECTEDSTREAMTOBLOCK, "BadExpectedStreamToBlock"},
    {UA_STATUSCODE_BADWOULDBLOCK, "BadWouldBlock"},
    {UA_STATUSCODE_BADSYNTAXERROR, "BadSyntaxError"},
    {UA_STATUSCODE_BADMAXCONNECTIONSREACHED, "BadMaxConnectionsReached"},
    {0xffffffff, "Unknown StatusCode"}
};

const char * UA_StatusCode_name(UA_StatusCode code) {
    for (size_t i = 0; i < statusCodeDescriptionsSize; ++i) {
        if (UA_StatusCode_isEqualTop(statusCodeDescriptions[i].code,code))
            return statusCodeDescriptions[i].name;
    }
    return statusCodeDescriptions[statusCodeDescriptionsSize-1].name;
}

#endif

/**** amalgamated original file "/src/util/ua_util.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014, 2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014 (c) Florian Palm
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 */

/* If UA_ENABLE_INLINABLE_EXPORT is enabled, then this file is the compilation
 * unit for the generated code from UA_INLINABLE definitions. */
#define UA_INLINABLE_IMPL 1



const char * attributeIdNames[28] = {
    "Invalid", "NodeId", "NodeClass", "BrowseName", "DisplayName", "Description",
    "WriteMask", "UserWriteMask", "IsAbstract", "Symmetric", "InverseName",
    "ContainsNoLoops", "EventNotifier", "Value", "DataType", "ValueRank",
    "ArrayDimensions", "AccessLevel", "UserAccessLevel", "MinimumSamplingInterval",
    "Historizing", "Executable", "UserExecutable", "DataTypeDefinition",
    "RolePermissions", "UserRolePermissions", "AccessRestrictions", "AccessLevelEx"
};

const char *
UA_AttributeId_name(UA_AttributeId attrId) {
    if(attrId < 0 || attrId > UA_ATTRIBUTEID_ACCESSLEVELEX)
        return attributeIdNames[0];
    return attributeIdNames[attrId];
}

/* OR-ing 32 goes from upper-case to lower-case */
UA_AttributeId
UA_AttributeId_fromName(const UA_String name) {
    for(size_t i = 0; i < 28; i++) {
        if(strlen(attributeIdNames[i]) != name.length)
            continue;
        for(size_t j = 0; j < name.length; j++) {
            if((attributeIdNames[i][j] | 32) != (name.data[j] | 32))
                goto next;
        }
        return (UA_AttributeId)i;
    next:
        continue;
    }
    return UA_ATTRIBUTEID_INVALID;
}

size_t
UA_readNumberWithBase(const UA_Byte *buf, size_t buflen, UA_UInt32 *number, UA_Byte base) {
    UA_assert(buf);
    UA_assert(number);
    u32 n = 0;
    size_t progress = 0;
    /* read numbers until the end or a non-number character appears */
    while(progress < buflen) {
        u8 c = buf[progress];
        if(c >= '0' && c <= '9' && c <= '0' + (base-1))
           n = (n * base) + c - '0';
        else if(base > 9 && c >= 'a' && c <= 'z' && c <= 'a' + (base-11))
           n = (n * base) + c-'a' + 10;
        else if(base > 9 && c >= 'A' && c <= 'Z' && c <= 'A' + (base-11))
           n = (n * base) + c-'A' + 10;
        else
           break;
        ++progress;
    }
    *number = n;
    return progress;
}

size_t
UA_readNumber(const UA_Byte *buf, size_t buflen, UA_UInt32 *number) {
    return UA_readNumberWithBase(buf, buflen, number, 10);
}

struct urlSchema {
    const char *schema;
};

static const struct urlSchema schemas[] = {
    {"opc.tcp://"},
    {"opc.udp://"},
    {"opc.eth://"},
    {"opc.mqtt://"}
};

static const unsigned scNumSchemas = sizeof(schemas) / sizeof(schemas[0]);
static const unsigned scEthSchemaIdx = 2;

UA_StatusCode
UA_parseEndpointUrl(const UA_String *endpointUrl, UA_String *outHostname,
                    UA_UInt16 *outPort, UA_String *outPath) {
    /* Url must begin with "opc.tcp://" or opc.udp:// (if pubsub enabled) */
    if(endpointUrl->length < 11) {
        return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;
    }

    /* Which type of schema is this? */
    unsigned schemaType = 0;
    for(; schemaType < scNumSchemas; schemaType++) {
        if(strncmp((char*)endpointUrl->data,
                   schemas[schemaType].schema,
                   strlen(schemas[schemaType].schema)) == 0)
            break;
    }
    if(schemaType == scNumSchemas)
        return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;

    /* Forward the current position until the first colon or slash */
    size_t start = strlen(schemas[schemaType].schema);
    size_t curr = start;
    UA_Boolean ipv6 = false;
    if(endpointUrl->length > curr && endpointUrl->data[curr] == '[') {
        /* IPv6: opc.tcp://[2001:0db8:85a3::8a2e:0370:7334]:1234/path */
        for(; curr < endpointUrl->length; ++curr) {
            if(endpointUrl->data[curr] == ']')
                break;
        }
        if(curr == endpointUrl->length)
            return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;
        curr++;
        ipv6 = true;
    } else {
        /* IPv4 or hostname: opc.tcp://something.something:1234/path */
        for(; curr < endpointUrl->length; ++curr) {
            if(endpointUrl->data[curr] == ':' || endpointUrl->data[curr] == '/')
                break;
        }
    }

    /* Set the hostname */
    if(ipv6) {
        /* Skip the ipv6 '[]' container for getaddrinfo() later */
        outHostname->data = &endpointUrl->data[start+1];
        outHostname->length = curr - (start+2);
    } else {
        outHostname->data = &endpointUrl->data[start];
        outHostname->length = curr - start;
    }

    /* Empty string? */
    if(outHostname->length == 0)
        outHostname->data = NULL;

    /* Already at the end */
    if(curr == endpointUrl->length)
        return UA_STATUSCODE_GOOD;

    /* Set the port - and for ETH set the VID.PCP postfix in the outpath string.
     * We have to parse that externally. */
    if(endpointUrl->data[curr] == ':') {
        if(++curr == endpointUrl->length)
            return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;

        /* ETH schema */
        if(schemaType == scEthSchemaIdx) {
            if(outPath != NULL) {
                outPath->data = &endpointUrl->data[curr];
                outPath->length = endpointUrl->length - curr;
            }
            return UA_STATUSCODE_GOOD;
        }

        u32 largeNum;
        size_t progress = UA_readNumber(&endpointUrl->data[curr],
                                        endpointUrl->length - curr, &largeNum);
        if(progress == 0 || largeNum > 65535)
            return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;
        /* Test if the end of a valid port was reached */
        curr += progress;
        if(curr == endpointUrl->length || endpointUrl->data[curr] == '/')
            *outPort = (u16)largeNum;
        if(curr == endpointUrl->length)
            return UA_STATUSCODE_GOOD;
    }

    /* Set the path */
    UA_assert(curr < endpointUrl->length);
    if(endpointUrl->data[curr] != '/')
        return UA_STATUSCODE_BADTCPENDPOINTURLINVALID;
    if(++curr == endpointUrl->length)
        return UA_STATUSCODE_GOOD;
    if(outPath != NULL) {
        outPath->data = &endpointUrl->data[curr];
        outPath->length = endpointUrl->length - curr;

        /* Remove trailing slash from the path */
        if(endpointUrl->data[endpointUrl->length - 1] == '/')
            outPath->length--;

        /* Empty string? */
        if(outPath->length == 0)
            outPath->data = NULL;
    }

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_parseEndpointUrlEthernet(const UA_String *endpointUrl, UA_String *target,
                            UA_UInt16 *vid, UA_Byte *pcp) {
    /* Url must begin with "opc.eth://" */
    if(endpointUrl->length < 11) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    if(strncmp((char*) endpointUrl->data, "opc.eth://", 10) != 0) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Where does the host address end? */
    size_t curr = 10;
    for(; curr < endpointUrl->length; ++curr) {
        if(endpointUrl->data[curr] == ':') {
           break;
        }
    }

    /* set host address */
    target->data = &endpointUrl->data[10];
    target->length = curr - 10;
    if(curr == endpointUrl->length) {
        return UA_STATUSCODE_GOOD;
    }

    /* Set VLAN */
    u32 value = 0;
    curr++;  /* skip ':' */
    size_t progress = UA_readNumber(&endpointUrl->data[curr],
                                    endpointUrl->length - curr, &value);
    if(progress == 0 || value > 4096) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    curr += progress;
    if(curr == endpointUrl->length || endpointUrl->data[curr] == '.') {
        *vid = (UA_UInt16) value;
    }
    if(curr == endpointUrl->length) {
        return UA_STATUSCODE_GOOD;
    }

    /* Set priority */
    if(endpointUrl->data[curr] != '.') {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    curr++;  /* skip '.' */
    progress = UA_readNumber(&endpointUrl->data[curr],
                             endpointUrl->length - curr, &value);
    if(progress == 0 || value > 7) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    curr += progress;
    if(curr != endpointUrl->length) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    *pcp = (UA_Byte) value;

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_ByteString_toBase64(const UA_ByteString *byteString,
                       UA_String *str) {
    UA_String_init(str);
    if(!byteString || !byteString->data)
        return UA_STATUSCODE_GOOD;

    str->data = (UA_Byte*)
        UA_base64(byteString->data, byteString->length, &str->length);
    if(!str->data)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_ByteString_fromBase64(UA_ByteString *bs,
                         const UA_String *input) {
    UA_ByteString_init(bs);
    if(input->length == 0)
        return UA_STATUSCODE_GOOD;
    bs->data = UA_unbase64((const unsigned char*)input->data,
                           input->length, &bs->length);
    /* TODO: Differentiate between encoding and memory errors */
    if(!bs->data)
        return UA_STATUSCODE_BADINTERNALERROR;
    return UA_STATUSCODE_GOOD;
}

/* Key Value Map */

const UA_KeyValueMap UA_KEYVALUEMAP_NULL = {0, NULL};

UA_KeyValueMap *
UA_KeyValueMap_new(void) {
    return (UA_KeyValueMap*)UA_calloc(1, sizeof(UA_KeyValueMap));
}

UA_StatusCode
UA_KeyValueMap_set(UA_KeyValueMap *map,
                   const UA_QualifiedName key,
                   const UA_Variant *value) {
    if(map == NULL || value == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    /* Key exists already */
    const UA_Variant *v = UA_KeyValueMap_get(map, key);
    if(v) {
        UA_Variant copyV;
        UA_StatusCode res = UA_Variant_copy(value, &copyV);
        if(res != UA_STATUSCODE_GOOD)
            return res;
        UA_Variant *target = (UA_Variant*)(uintptr_t)v;
        UA_Variant_clear(target);
        *target = copyV;
        return UA_STATUSCODE_GOOD;
    }

    /* Append to the array */
    UA_KeyValuePair pair;
    pair.key = key;
    pair.value = *value;
    return UA_Array_appendCopy((void**)&map->map, &map->mapSize, &pair,
                               &UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
}

UA_StatusCode
UA_KeyValueMap_setScalar(UA_KeyValueMap *map,
                         const UA_QualifiedName key,
                         void * UA_RESTRICT p,
                         const UA_DataType *type) {
    if(p == NULL || type == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    UA_Variant v;
    UA_Variant_init(&v);
    v.type = type;
    v.arrayLength = 0;
    v.data = p;
    return UA_KeyValueMap_set(map, key, &v);
}

const UA_Variant *
UA_KeyValueMap_get(const UA_KeyValueMap *map,
                   const UA_QualifiedName key) {
    if(!map)
        return NULL;
    for(size_t i = 0; i < map->mapSize; i++) {
        if(map->map[i].key.namespaceIndex == key.namespaceIndex &&
           UA_String_equal(&map->map[i].key.name, &key.name))
            return &map->map[i].value;

    }
    return NULL;
}

UA_Boolean
UA_KeyValueMap_isEmpty(const UA_KeyValueMap *map) {
    if(!map)
        return true;
    return map->mapSize == 0;
}

const void *
UA_KeyValueMap_getScalar(const UA_KeyValueMap *map,
                         const UA_QualifiedName key,
                         const UA_DataType *type) {
    const UA_Variant *v = UA_KeyValueMap_get(map, key);
    if(!v || !UA_Variant_hasScalarType(v, type))
        return NULL;
    return v->data;
}

void
UA_KeyValueMap_clear(UA_KeyValueMap *map) {
    if(!map)
        return;
    if(map->mapSize > 0) {
        UA_Array_delete(map->map, map->mapSize, &UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
        map->mapSize = 0;
    }
}

void
UA_KeyValueMap_delete(UA_KeyValueMap *map) {
    UA_KeyValueMap_clear(map);
    UA_free(map);
}

UA_StatusCode
UA_KeyValueMap_remove(UA_KeyValueMap *map,
                      const UA_QualifiedName key) {
    if(!map)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_KeyValuePair *m = map->map;
    size_t s = map->mapSize;
    size_t i = 0;
    for(; i < s; i++) {
        if(m[i].key.namespaceIndex == key.namespaceIndex &&
           UA_String_equal(&m[i].key.name, &key.name))
            break;
    }
    if(i == s)
        return UA_STATUSCODE_BADNOTFOUND;

    /* Clean the slot and move the last entry to fill the slot */
    UA_KeyValuePair_clear(&m[i]);
    if(s > 1 && i < s - 1) {
        m[i] = m[s-1];
        UA_KeyValuePair_init(&m[s-1]);
    }
    
    /* Ignore the result. In case resize fails, keep the longer original array
     * around. Resize never fails when reducing the size to zero. Reduce the
     * size integer in any case. */
    UA_StatusCode res =
        UA_Array_resize((void**)&map->map, &map->mapSize, map->mapSize - 1,
                          &UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
    (void)res;
    map->mapSize--;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_KeyValueMap_copy(const UA_KeyValueMap *src, UA_KeyValueMap *dst) {
    if(!dst)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    if(!src) {
        dst->map = NULL;
        dst->mapSize = 0;
        return UA_STATUSCODE_GOOD;
    }
    UA_StatusCode res = UA_Array_copy(src->map, src->mapSize, (void**)&dst->map,
                                      &UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
    if(res == UA_STATUSCODE_GOOD)
        dst->mapSize = src->mapSize;
    return res;
}

UA_Boolean
UA_KeyValueMap_contains(const UA_KeyValueMap *map, const UA_QualifiedName key) {
    if(!map)
        return false;
    for(size_t i = 0; i < map->mapSize; ++i) {
        if(UA_QualifiedName_equal(&map->map[i].key, &key))
            return true;
    }
    return false;
}

UA_StatusCode
UA_KeyValueMap_merge(UA_KeyValueMap *lhs, const UA_KeyValueMap *rhs) {
    if(!lhs)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    if(!rhs)
        return UA_STATUSCODE_GOOD;

    UA_KeyValueMap merge;
    UA_StatusCode res = UA_KeyValueMap_copy(lhs, &merge);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    for(size_t i = 0; i < rhs->mapSize; ++i) {
        res = UA_KeyValueMap_set(&merge, rhs->map[i].key, &rhs->map[i].value);
        if(res != UA_STATUSCODE_GOOD) {
            UA_KeyValueMap_clear(&merge);
            return res;
        }
    }

    UA_KeyValueMap_clear(lhs);
    *lhs = merge;
    return UA_STATUSCODE_GOOD;
}

/***************************/
/* Random Number Generator */
/***************************/

/* TODO is this safe for multithreading? */
static pcg32_random_t UA_rng = PCG32_INITIALIZER;

void
UA_random_seed(u64 seed) {
    pcg32_srandom_r(&UA_rng, seed, (u64)UA_DateTime_now());
}

u32
UA_UInt32_random(void) {
    return (u32)pcg32_random_r(&UA_rng);
}

UA_Guid
UA_Guid_random(void) {
    UA_Guid result;
    result.data1 = (u32)pcg32_random_r(&UA_rng);
    u32 r = (u32)pcg32_random_r(&UA_rng);
    result.data2 = (u16) r;
    result.data3 = (u16) (r >> 16);
    r = (u32)pcg32_random_r(&UA_rng);
    result.data4[0] = (u8)r;
    result.data4[1] = (u8)(r >> 4);
    result.data4[2] = (u8)(r >> 8);
    result.data4[3] = (u8)(r >> 12);
    r = (u32)pcg32_random_r(&UA_rng);
    result.data4[4] = (u8)r;
    result.data4[5] = (u8)(r >> 4);
    result.data4[6] = (u8)(r >> 8);
    result.data4[7] = (u8)(r >> 12);
    return result;
}

/********************/
/* Malloc Singleton */
/********************/

#ifdef UA_ENABLE_MALLOC_SINGLETON
# include <stdlib.h>
UA_EXPORT UA_THREAD_LOCAL void * (*UA_mallocSingleton)(size_t size) = malloc;
UA_EXPORT UA_THREAD_LOCAL void (*UA_freeSingleton)(void *ptr) = free;
UA_EXPORT UA_THREAD_LOCAL void * (*UA_callocSingleton)(size_t nelem, size_t elsize) = calloc;
UA_EXPORT UA_THREAD_LOCAL void * (*UA_reallocSingleton)(void *ptr, size_t size) = realloc;
#endif

/************************/
/* ReferenceType Lookup */
/************************/

typedef struct {
    UA_String browseName;
    UA_UInt32 identifier;
} RefTypeName;

#define KNOWNREFTYPES 17
static const RefTypeName knownRefTypes[KNOWNREFTYPES] = {
    {UA_STRING_STATIC("References"), UA_NS0ID_REFERENCES},
    {UA_STRING_STATIC("HierachicalReferences"), UA_NS0ID_HIERARCHICALREFERENCES},
    {UA_STRING_STATIC("NonHierachicalReferences"), UA_NS0ID_NONHIERARCHICALREFERENCES},
    {UA_STRING_STATIC("HasChild"), UA_NS0ID_HASCHILD},
    {UA_STRING_STATIC("Aggregates"), UA_NS0ID_AGGREGATES},
    {UA_STRING_STATIC("HasComponent"), UA_NS0ID_HASCOMPONENT},
    {UA_STRING_STATIC("HasProperty"), UA_NS0ID_HASPROPERTY},
    {UA_STRING_STATIC("HasOrderedComponent"), UA_NS0ID_HASORDEREDCOMPONENT},
    {UA_STRING_STATIC("HasSubtype"), UA_NS0ID_HASSUBTYPE},
    {UA_STRING_STATIC("Organizes"), UA_NS0ID_ORGANIZES},
    {UA_STRING_STATIC("HasModellingRule"), UA_NS0ID_HASMODELLINGRULE},
    {UA_STRING_STATIC("HasTypeDefinition"), UA_NS0ID_HASTYPEDEFINITION},
    {UA_STRING_STATIC("HasEncoding"), UA_NS0ID_HASENCODING},
    {UA_STRING_STATIC("GeneratesEvent"), UA_NS0ID_GENERATESEVENT},
    {UA_STRING_STATIC("AlwaysGeneratesEvent"), UA_NS0ID_ALWAYSGENERATESEVENT},
    {UA_STRING_STATIC("HasEventSource"), UA_NS0ID_HASEVENTSOURCE},
    {UA_STRING_STATIC("HasNotifier"), UA_NS0ID_HASNOTIFIER}
};

UA_StatusCode
lookupRefType(UA_Server *server, UA_QualifiedName *qn, UA_NodeId *outRefTypeId) {
    /* Check well-known ReferenceTypes first */
    if(qn->namespaceIndex == 0) {
        for(size_t i = 0; i < KNOWNREFTYPES; i++) {
            if(UA_String_equal(&qn->name, &knownRefTypes[i].browseName)) {
                *outRefTypeId = UA_NODEID_NUMERIC(0, knownRefTypes[i].identifier);
                return UA_STATUSCODE_GOOD;
            }
        }
    }

    /* Browse the information model. Return the first results if the browse name
     * in the hierarchy is ambiguous. */
    if(server) {
        UA_BrowseDescription bd;
        UA_BrowseDescription_init(&bd);
        bd.nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_REFERENCES);
        bd.browseDirection = UA_BROWSEDIRECTION_FORWARD;
        bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE);
        bd.nodeClassMask = UA_NODECLASS_REFERENCETYPE;

        size_t resultsSize = 0;
        UA_ExpandedNodeId *results = NULL;
        UA_StatusCode res =
            UA_Server_browseRecursive(server, &bd, &resultsSize, &results);
        if(res != UA_STATUSCODE_GOOD)
            return res;
        for(size_t i = 0; i < resultsSize; i++) {
            UA_QualifiedName bn;
            UA_Server_readBrowseName(server, results[i].nodeId, &bn);
            if(UA_QualifiedName_equal(qn, &bn)) {
                UA_QualifiedName_clear(&bn);
                *outRefTypeId = results[i].nodeId;
                UA_NodeId_clear(&results[i].nodeId);
                UA_Array_delete(results, resultsSize, &UA_TYPES[UA_TYPES_NODEID]);
                return UA_STATUSCODE_GOOD;
            }
            UA_QualifiedName_clear(&bn);
        }

        UA_Array_delete(results, resultsSize, &UA_TYPES[UA_TYPES_NODEID]);
    }

    return UA_STATUSCODE_BADNOTFOUND;
}

UA_StatusCode
getRefTypeBrowseName(const UA_NodeId *refTypeId, UA_String *outBN) {
    /* Canonical name known? */
    if(refTypeId->namespaceIndex == 0 &&
       refTypeId->identifierType == UA_NODEIDTYPE_NUMERIC) {
        for(size_t i = 0; i < KNOWNREFTYPES; i++) {
            if(refTypeId->identifier.numeric != knownRefTypes[i].identifier)
                continue;
            memcpy(outBN->data, knownRefTypes[i].browseName.data, knownRefTypes[i].browseName.length);
            outBN->length = knownRefTypes[i].browseName.length;
            return UA_STATUSCODE_GOOD;
        }
    }

    /* Print the NodeId */
    return UA_NodeId_print(refTypeId, outBN);
}

/************************/
/* Printing and Parsing */
/************************/

static UA_INLINE UA_Boolean
isReserved(char c) {
    return (c == '/' || c == '.' || c == '<' || c == '>' ||
            c == ':' || c == '#' || c == '!' || c == '&');
}

static UA_INLINE UA_Boolean
isReservedExtended(char c) {
    return (isReserved(c) || c == ',' || c == '(' || c == ')' ||
            c == '[' || c == ']' || c == ' ' || c == '\t' ||
            c == '\n' || c == '\v' || c == '\f' || c == '\r');
}

char *
find_unescaped(char *pos, char *end, UA_Boolean extended) {
    while(pos < end) {
        if(*pos == '&') {
            pos += 2;
            continue;
        }
        UA_Boolean reserved = (extended) ? isReservedExtended(*pos) : isReserved(*pos);
        if(reserved)
            return pos;
        pos++;
    }
    return end;
}

void
UA_String_unescape(UA_String *s, UA_Boolean extended) {
    UA_Byte *writepos = s->data;
    UA_Byte *end = &s->data[s->length];
    for(UA_Byte *pos = s->data; pos < end; pos++,writepos++) {
        UA_Boolean skip = (extended) ? isReservedExtended(*pos) : isReserved(*pos);
        if(skip && ++pos >= end)
            break;
        *writepos = *pos;
    }
    s->length = (size_t)(writepos - s->data);
}

UA_StatusCode
UA_String_append(UA_String *s, const UA_String s2) {
    if(s2.length == 0)
        return UA_STATUSCODE_GOOD;
    UA_Byte *buf = (UA_Byte*)UA_realloc(s->data, s->length + s2.length);
    if(!buf)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    memcpy(buf + s->length, s2.data, s2.length);
    s->data = buf;
    s->length += s2.length;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_String_escapeAppend(UA_String *s, const UA_String s2, UA_Boolean extended) {
    /* Allocate memory for the qn name.
     * We allocate enough space to escape every character. */
    UA_Byte *buf = (UA_Byte*)UA_realloc(s->data, s->length + (s2.length*2));
    if(!buf)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    s->data = buf;

    /* Copy + escape s2 */
    for(size_t j = 0; j < s2.length; j++) {
        UA_Boolean reserved = (extended) ?
            isReservedExtended(s2.data[j]) : isReserved(s2.data[j]);
        if(reserved)
            s->data[s->length++] = '&';
        s->data[s->length++] = s2.data[j];
    }
    return UA_STATUSCODE_GOOD;
}

#ifdef UA_ENABLE_PARSING

static UA_StatusCode
moveTmpToOut(UA_String *tmp, UA_String *out) {
    /* Output has zero length */
    if(tmp->length == 0) {
        UA_assert(tmp->data == NULL);
        if(out->data == NULL)
            out->data = (UA_Byte*)UA_EMPTY_ARRAY_SENTINEL;
        out->length = 0;
        return UA_STATUSCODE_GOOD;
    }

    /* No output buffer provided, return the tmp buffer */
    if(out->length == 0) {
        *out = *tmp;
        return UA_STATUSCODE_GOOD;
    }

    /* The provided buffer is too short */
    if(out->length < tmp->length) {
        UA_String_clear(tmp);
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
    }

    /* Copy output to the provided buffer */
    memcpy(out->data, tmp->data, tmp->length);
    out->length = tmp->length;
    UA_String_clear(tmp);
    return UA_STATUSCODE_GOOD;
}

static const UA_NodeId hierarchicalRefs =
    {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HIERARCHICALREFERENCES}};
static const UA_NodeId aggregatesRefs =
    {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_AGGREGATES}};

UA_StatusCode
UA_RelativePath_print(const UA_RelativePath *rp, UA_String *out) {
    UA_String tmp = UA_STRING_NULL;
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    for(size_t i = 0; i < rp->elementsSize && res == UA_STATUSCODE_GOOD; i++) {
        /* Print the reference type */
        UA_RelativePathElement *elm = &rp->elements[i];
        if(UA_NodeId_equal(&hierarchicalRefs, &elm->referenceTypeId) &&
           !elm->isInverse && elm->includeSubtypes) {
            res |= UA_String_append(&tmp, UA_STRING("/"));
        } else if(UA_NodeId_equal(&aggregatesRefs, &elm->referenceTypeId) &&
                  !elm->isInverse && elm->includeSubtypes) {
            res |= UA_String_append(&tmp, UA_STRING("."));
        } else {
            res |= UA_String_append(&tmp, UA_STRING("<"));
            if(!elm->includeSubtypes)
                res |= UA_String_append(&tmp, UA_STRING("#"));
            if(elm->isInverse)
                res |= UA_String_append(&tmp, UA_STRING("!"));
            UA_Byte bnBuf[512];
            UA_String bnBufStr = {512, bnBuf};
            res |= getRefTypeBrowseName(&elm->referenceTypeId, &bnBufStr);
            if(res != UA_STATUSCODE_GOOD)
                break;
            res |= UA_String_escapeAppend(&tmp, bnBufStr, false);
            res |= UA_String_append(&tmp, UA_STRING(">"));
        }

        /* Print the qualified name namespace */
        UA_QualifiedName *qn = &elm->targetName;
        if(qn->namespaceIndex > 0) {
            char nsStr[8]; /* Enough for a uint16 */
            itoaUnsigned(qn->namespaceIndex, nsStr, 10);
            res |= UA_String_append(&tmp, UA_STRING(nsStr));
            res |= UA_String_append(&tmp, UA_STRING(":"));
        }
        res |= UA_String_escapeAppend(&tmp, qn->name, false);
    }

    /* Encoding failed, clean up */
    if(res != UA_STATUSCODE_GOOD) {
        UA_String_clear(&tmp);
        return res;
    }

    return moveTmpToOut(&tmp, out);
}

static UA_NodeId baseEventTypeId = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_BASEEVENTTYPE}};

UA_StatusCode
UA_SimpleAttributeOperand_print(const UA_SimpleAttributeOperand *sao,
                                UA_String *out) {
    UA_String tmp = UA_STRING_NULL;
    UA_StatusCode res = UA_STATUSCODE_GOOD;

    /* Print the TypeDefinitionId */
    if(!UA_NodeId_equal(&baseEventTypeId, &sao->typeDefinitionId)) {
        UA_Byte nodeIdBuf[512];
        UA_String nodeIdBufStr = {512, nodeIdBuf};
        res = UA_NodeId_print(&sao->typeDefinitionId, &nodeIdBufStr);
        if(res != UA_STATUSCODE_GOOD)
            goto cleanup;
        res = UA_String_escapeAppend(&tmp, nodeIdBufStr, true);
        if(res != UA_STATUSCODE_GOOD)
            goto cleanup;
    }

    /* Print the BrowsePath */
    for(size_t i = 0; i < sao->browsePathSize; i++) {
        res |= UA_String_append(&tmp, UA_STRING("/"));
        UA_QualifiedName *qn = &sao->browsePath[i];
        if(qn->namespaceIndex > 0) {
            char nsStr[8]; /* Enough for a uint16 */
            itoaUnsigned(qn->namespaceIndex, nsStr, 10);
            res |= UA_String_append(&tmp, UA_STRING(nsStr));
            res |= UA_String_append(&tmp, UA_STRING(":"));
        }
        res |= UA_String_escapeAppend(&tmp, qn->name, true);
        if(res != UA_STATUSCODE_GOOD)
            goto cleanup;
    }

    /* Print the attribute name */
    if(sao->attributeId != UA_ATTRIBUTEID_VALUE) {
        res |= UA_String_append(&tmp, UA_STRING("#"));
        const char *attrName= UA_AttributeId_name((UA_AttributeId)sao->attributeId);
        res |= UA_String_append(&tmp, UA_STRING((char*)(uintptr_t)attrName));
        if(res != UA_STATUSCODE_GOOD)
            goto cleanup;
    }

    /* Print the IndexRange
     * TODO: Validate the indexRange string */
    if(sao->indexRange.length > 0) {
        res |= UA_String_append(&tmp, UA_STRING("["));
        res |= UA_String_append(&tmp, sao->indexRange);
        res |= UA_String_append(&tmp, UA_STRING("]"));
    }

 cleanup:
    /* Encoding failed, clean up */
    if(res != UA_STATUSCODE_GOOD) {
        UA_String_clear(&tmp);
        return res;
    }

    return moveTmpToOut(&tmp, out);
}

#endif

/************************/
/* Cryptography Helpers */
/************************/

UA_ByteString
getLeafCertificate(UA_ByteString chain) {
    /* Detect DER encoded X.509 v3 certificate. If the DER detection fails,
     * return the entire chain.
     *
     * The OPC UA standard requires this to be DER. But we also allow other
     * formats like PEM. Afterwards it depends on the crypto backend to parse
     * it. mbedTLS and OpenSSL detect the format automatically. */
    if(chain.length < 4 || chain.data[0] != 0x30 || chain.data[1] != 0x82)
        return chain;

    /* The certificate length is encoded in the next 2 bytes. */
    size_t leafLen = 4; /* Magic numbers + length bytes */
    leafLen += (size_t)(((uint16_t)chain.data[2]) << 8);
    leafLen += chain.data[3];

    /* Consistency check */
    if(leafLen > chain.length)
        return UA_BYTESTRING_NULL;

    /* Adjust the length and return */
    chain.length = leafLen;
    return chain;
}

UA_Boolean
UA_constantTimeEqual(const void *ptr1, const void *ptr2, size_t length) {
    volatile const UA_Byte *a = (volatile const UA_Byte *)ptr1;
    volatile const UA_Byte *b = (volatile const UA_Byte *)ptr2;
    volatile UA_Byte c = 0;
    for(size_t i = 0; i < length; ++i) {
        UA_Byte x = a[i], y = b[i];
        c = c | (x ^ y);
    }
    return !c;
}

void
UA_ByteString_memZero(UA_ByteString *bs) {
#if defined(__STDC_LIB_EXT1__)
   memset_s(bs->data, bs->length, 0, bs->length);
#elif defined(_WIN32)
   SecureZeroMemory(bs->data, bs->length);
#else
   volatile unsigned char *volatile ptr =
       (volatile unsigned char *)bs->data;
   size_t i = 0;
   size_t maxLen = bs->length;
   while(i < maxLen) {
       ptr[i++] = 0;
   }
#endif
}

/**** amalgamated original file "/src/util/ua_clock.c" ****/

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
 *
 *    Copyright 2016-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Thomas Stalder, Blue Time Concept SA
 */


/* This file contains archicture-specific access to the system clock for
 * UA_DateTime_now. etc. Just add additional architecture below.
 *
 * Note that the EventLoop plugin provides its own internal time source (which
 * is typically just the normal system time). All internal access to the time
 * source should be through the EventLoop. The below is therefore for developer
 * convenience to just use UA_DateTime_now. */

#ifdef UA_ARCHITECTURE_POSIX

#include <time.h>
#include <sys/time.h>

#if defined(__APPLE__) || defined(__MACH__)
# include <mach/clock.h>
# include <mach/mach.h>
#endif

UA_DateTime UA_DateTime_now(void) {
    struct timeval tv;
    gettimeofday(&tv, NULL);
    return (tv.tv_sec * UA_DATETIME_SEC) +
        (tv.tv_usec * UA_DATETIME_USEC) +
        UA_DATETIME_UNIX_EPOCH;
}

/* Credit to https://stackoverflow.com/questions/13804095/get-the-time-zone-gmt-offset-in-c */
UA_Int64 UA_DateTime_localTimeUtcOffset(void) {
    time_t rawtime = time(NULL);
    struct tm gbuf;
    struct tm *ptm = gmtime_r(&rawtime, &gbuf);
    /* Request mktime() to look up dst in timezone database */
    ptm->tm_isdst = -1;
    time_t gmt = mktime(ptm);
    return (UA_Int64) (difftime(rawtime, gmt) * UA_DATETIME_SEC);
}

UA_DateTime UA_DateTime_nowMonotonic(void) {
#if defined(__APPLE__) || defined(__MACH__)
    /* OS X does not have clock_gettime, use clock_get_time */
    clock_serv_t cclock;
    mach_timespec_t mts;
    host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock);
    clock_get_time(cclock, &mts);
    mach_port_deallocate(mach_task_self(), cclock);
    return (mts.tv_sec * UA_DATETIME_SEC) + (mts.tv_nsec / 100);
#elif !defined(CLOCK_MONOTONIC_RAW)
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return (ts.tv_sec * UA_DATETIME_SEC) + (ts.tv_nsec / 100);
#else
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
    return (ts.tv_sec * UA_DATETIME_SEC) + (ts.tv_nsec / 100);
#endif
}

#endif /* UA_ARCHITECTURE_POSIX */

#ifdef UA_ARCHITECTURE_WIN32

#include <time.h>
/* Backup definition of SLIST_ENTRY on mingw winnt.h */
# ifdef SLIST_ENTRY
#  pragma push_macro("SLIST_ENTRY")
#  undef SLIST_ENTRY
#  define POP_SLIST_ENTRY
# endif
# include <windows.h>
/* restore definition */
# ifdef POP_SLIST_ENTRY
#  undef SLIST_ENTRY
#  undef POP_SLIST_ENTRY
#  pragma pop_macro("SLIST_ENTRY")
# endif

/* Windows filetime has the same definition as UA_DateTime */
UA_DateTime
UA_DateTime_now(void) {
    FILETIME ft;
    SYSTEMTIME st;
    GetSystemTime(&st);
    SystemTimeToFileTime(&st, &ft);
    ULARGE_INTEGER ul;
    ul.LowPart = ft.dwLowDateTime;
    ul.HighPart = ft.dwHighDateTime;
    return (UA_DateTime)ul.QuadPart;
}

/* Credit to https://stackoverflow.com/questions/13804095/get-the-time-zone-gmt-offset-in-c */
UA_Int64
UA_DateTime_localTimeUtcOffset(void) {
    time_t rawtime = time(NULL);
    struct tm ptm;
#ifdef __CODEGEARC__
    gmtime_s(&rawtime, &ptm);
#else
    gmtime_s(&ptm, &rawtime);
#endif

    /* Request mktime() to look up dst in timezone database */
    ptm.tm_isdst = -1;
    time_t gmt = mktime(&ptm);

    return (UA_Int64) (difftime(rawtime, gmt) * UA_DATETIME_SEC);
}

UA_DateTime
UA_DateTime_nowMonotonic(void) {
    LARGE_INTEGER freq, ticks;
    QueryPerformanceFrequency(&freq);
    QueryPerformanceCounter(&ticks);
    UA_Double ticks2dt = UA_DATETIME_SEC / (UA_Double)freq.QuadPart;
    return (UA_DateTime)(ticks.QuadPart * ticks2dt);
}

#endif /* UA_ARCHITECTURE_WIN32 */

/**** amalgamated original file "/src/ua_securechannel.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014, 2016-2017 (c) Florian Palm
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015 (c) Oleksiy Vasylyev
 *    Copyright 2016 (c) TorbenD
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017-2018 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2018-2019 (c) HMS Industrial Networks AB (Author: Jonas Green)
 */



#define UA_BITMASK_MESSAGETYPE 0x00ffffffu
#define UA_BITMASK_CHUNKTYPE 0xff000000u

const UA_String UA_SECURITY_POLICY_NONE_URI =
    {47, (UA_Byte *)"http://opcfoundation.org/UA/SecurityPolicy#None"};

void
UA_SecureChannel_init(UA_SecureChannel *channel) {
    /* Normal linked lists are initialized by zeroing out */
    memset(channel, 0, sizeof(UA_SecureChannel));
    SIMPLEQ_INIT(&channel->completeChunks);
    SIMPLEQ_INIT(&channel->decryptedChunks);
}

UA_StatusCode
UA_SecureChannel_setSecurityPolicy(UA_SecureChannel *channel,
                                   const UA_SecurityPolicy *securityPolicy,
                                   const UA_ByteString *remoteCertificate) {
    /* Is a policy already configured? */
    UA_CHECK_ERROR(!channel->securityPolicy, return UA_STATUSCODE_BADINTERNALERROR,
                   securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                   "Security policy already configured");

    /* Create the context */
    UA_StatusCode res = securityPolicy->channelModule.
        newContext(securityPolicy, remoteCertificate, &channel->channelContext);
    res |= UA_ByteString_copy(remoteCertificate, &channel->remoteCertificate);
    UA_CHECK_STATUS_WARN(res, return res, securityPolicy->logger,
                         UA_LOGCATEGORY_SECURITYPOLICY,
                         "Could not set up the SecureChannel context");

    /* Compute the certificate thumbprint */
    UA_ByteString remoteCertificateThumbprint =
        {20, channel->remoteCertificateThumbprint};
    res = securityPolicy->asymmetricModule.
        makeCertificateThumbprint(securityPolicy, &channel->remoteCertificate,
                                  &remoteCertificateThumbprint);
    UA_CHECK_STATUS_WARN(res, return res, securityPolicy->logger,
                         UA_LOGCATEGORY_SECURITYPOLICY,
                         "Could not create the certificate thumbprint");

    /* Set the policy */
    channel->securityPolicy = securityPolicy;
    return UA_STATUSCODE_GOOD;
}

/* Hides some errors before sending them to a client according to the
 * standard. */
static void
hideErrors(UA_TcpErrorMessage *const error) {
    switch(error->error) {
    case UA_STATUSCODE_BADCERTIFICATEUNTRUSTED:
    case UA_STATUSCODE_BADCERTIFICATEREVOKED:
        error->error = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        error->reason = UA_STRING_NULL;
        break;
        // TODO: Check if these are all cases that need to be covered.
    default:
        break;
    }
}

UA_Boolean
UA_SecureChannel_isConnected(UA_SecureChannel *channel) {
    return (channel->state > UA_SECURECHANNELSTATE_CLOSED &&
            channel->state < UA_SECURECHANNELSTATE_CLOSING);
}

void
UA_SecureChannel_sendError(UA_SecureChannel *channel, UA_TcpErrorMessage *error) {
    if(!UA_SecureChannel_isConnected(channel))
        return;

    hideErrors(error);

    UA_TcpMessageHeader header;
    header.messageTypeAndChunkType = UA_MESSAGETYPE_ERR + UA_CHUNKTYPE_FINAL;
    /* Header + ErrorMessage (error + reasonLength_field + length) */
    header.messageSize = 8 + (4 + 4 + (UA_UInt32)error->reason.length);

    /* Get the send buffer from the network layer */
    UA_ConnectionManager *cm = channel->connectionManager;
    UA_ByteString msg = UA_BYTESTRING_NULL;
    UA_StatusCode retval = cm->allocNetworkBuffer(cm, channel->connectionId,
                                                  &msg, header.messageSize);
    if(retval != UA_STATUSCODE_GOOD)
        return;

    /* Encode and send the response */
    UA_Byte *bufPos = msg.data;
    const UA_Byte *bufEnd = &msg.data[msg.length];
    retval |= UA_encodeBinaryInternal(&header,
                                      &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER],
                                      &bufPos, &bufEnd, NULL, NULL);
    retval |= UA_encodeBinaryInternal(error,
                                      &UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE],
                                      &bufPos, &bufEnd, NULL, NULL);
    (void)retval; /* Encoding of these cannot fail */
    msg.length = header.messageSize;
    cm->sendWithConnection(cm, channel->connectionId, &UA_KEYVALUEMAP_NULL, &msg);
}

static void
UA_Chunk_delete(UA_Chunk *chunk) {
    if(chunk->copied)
        UA_ByteString_clear(&chunk->bytes);
    UA_free(chunk);
}

static void
deleteChunks(UA_ChunkQueue *queue) {
    UA_Chunk *chunk;
    while((chunk = SIMPLEQ_FIRST(queue))) {
        SIMPLEQ_REMOVE_HEAD(queue, pointers);
        UA_Chunk_delete(chunk);
    }
}

void
UA_SecureChannel_deleteBuffered(UA_SecureChannel *channel) {
    deleteChunks(&channel->completeChunks);
    deleteChunks(&channel->decryptedChunks);
    UA_ByteString_clear(&channel->incompleteChunk);
}

void
UA_SecureChannel_shutdown(UA_SecureChannel *channel,
                          UA_ShutdownReason shutdownReason) {
    /* No open socket or already closing -> nothing to do */
    if(!UA_SecureChannel_isConnected(channel))
        return;

    /* Set the shutdown event for diagnostics */
    channel->shutdownReason= shutdownReason;

    /* Trigger the async closing of the connection */
    UA_ConnectionManager *cm = channel->connectionManager;
    cm->closeConnection(cm, channel->connectionId);
    channel->state = UA_SECURECHANNELSTATE_CLOSING;
}

void
UA_SecureChannel_clear(UA_SecureChannel *channel) {
    /* No sessions must be attached to this any longer */
    UA_assert(channel->sessions == NULL);

    /* Delete the channel context for the security policy */
    if(channel->securityPolicy) {
        channel->securityPolicy->channelModule.deleteContext(channel->channelContext);
        channel->securityPolicy = NULL;
        channel->channelContext = NULL;
    }

    /* The EventLoop connection is no longer valid */
    channel->connectionId = 0;
    channel->connectionManager = NULL;

    /* Clean up the SecurityToken */
    UA_ChannelSecurityToken_clear(&channel->securityToken);
    UA_ChannelSecurityToken_clear(&channel->altSecurityToken);

    /* Clean up certificate and nonces */
    UA_ByteString_clear(&channel->remoteCertificate);
    UA_ByteString_clear(&channel->localNonce);
    UA_ByteString_clear(&channel->remoteNonce);

    /* Delete remaining chunks */
    UA_SecureChannel_deleteBuffered(channel);

    /* Reset the SecureChannel for reuse (in the client) */
    channel->securityMode = UA_MESSAGESECURITYMODE_INVALID;
    channel->shutdownReason = UA_SHUTDOWNREASON_CLOSE;
    memset(&channel->config, 0, sizeof(UA_ConnectionConfig));
    channel->receiveSequenceNumber = 0;
    channel->sendSequenceNumber = 0;

    /* Set the state to closed */
    channel->state = UA_SECURECHANNELSTATE_CLOSED;
    channel->renewState = UA_SECURECHANNELRENEWSTATE_NORMAL;
}

UA_StatusCode
UA_SecureChannel_processHELACK(UA_SecureChannel *channel,
                               const UA_TcpAcknowledgeMessage *remoteConfig) {
    /* The lowest common version is used by both sides */
    if(channel->config.protocolVersion > remoteConfig->protocolVersion)
        channel->config.protocolVersion = remoteConfig->protocolVersion;

    /* Can we receive the max send size? */
    if(channel->config.sendBufferSize > remoteConfig->receiveBufferSize)
        channel->config.sendBufferSize = remoteConfig->receiveBufferSize;

    /* Can we send the max receive size? */
    if(channel->config.recvBufferSize > remoteConfig->sendBufferSize)
        channel->config.recvBufferSize = remoteConfig->sendBufferSize;

    channel->config.remoteMaxMessageSize = remoteConfig->maxMessageSize;
    channel->config.remoteMaxChunkCount = remoteConfig->maxChunkCount;

    /* Chunks of at least 8192 bytes must be permissible.
     * See Part 6, Clause 6.7.1 */
    if(channel->config.recvBufferSize < 8192 ||
       channel->config.sendBufferSize < 8192 ||
       (channel->config.remoteMaxMessageSize != 0 &&
        channel->config.remoteMaxMessageSize < 8192))
        return UA_STATUSCODE_BADINTERNALERROR;

    return UA_STATUSCODE_GOOD;
}

/* Sends an OPN message using asymmetric encryption if defined */
UA_StatusCode
UA_SecureChannel_sendAsymmetricOPNMessage(UA_SecureChannel *channel,
                                          UA_UInt32 requestId, const void *content,
                                          const UA_DataType *contentType) {
    UA_CHECK(channel->securityMode != UA_MESSAGESECURITYMODE_INVALID,
             return UA_STATUSCODE_BADSECURITYMODEREJECTED);

    /* Can we use the connection manager? */
    UA_ConnectionManager *cm = channel->connectionManager;
    if(!UA_SecureChannel_isConnected(channel))
        return UA_STATUSCODE_BADCONNECTIONCLOSED;

    const UA_SecurityPolicy *sp = channel->securityPolicy;
    UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR);

    /* Allocate the message buffer */
    UA_ByteString buf = UA_BYTESTRING_NULL;
    UA_StatusCode res = cm->allocNetworkBuffer(cm, channel->connectionId, &buf,
                                               channel->config.sendBufferSize);
    UA_CHECK_STATUS(res, return res);

    /* Restrict buffer to the available space for the payload */
    UA_Byte *buf_pos = buf.data;
    const UA_Byte *buf_end = &buf.data[buf.length];
    hideBytesAsym(channel, &buf_pos, &buf_end);

    /* Define variables here to pacify some compilers wrt goto */
    size_t securityHeaderLength, pre_sig_length, total_length, encryptedLength;

    /* Encode the message type and content */
    res |= UA_NodeId_encodeBinary(&contentType->binaryEncodingId, &buf_pos, buf_end);
    res |= UA_encodeBinaryInternal(content, contentType, &buf_pos, &buf_end, NULL, NULL);
    UA_CHECK_STATUS(res, goto error);

    /* Compute the header length */
    securityHeaderLength = calculateAsymAlgSecurityHeaderLength(channel);

    /* Add padding to the chunk. Also pad if the securityMode is SIGN_ONLY,
     * since we are using asymmetric communication to exchange keys and thus
     * need to encrypt. */
    if(channel->securityMode != UA_MESSAGESECURITYMODE_NONE)
        padChunk(channel, &channel->securityPolicy->asymmetricModule.cryptoModule,
                 &buf.data[UA_SECURECHANNEL_CHANNELHEADER_LENGTH + securityHeaderLength],
                 &buf_pos);

    /* The total message length */
    pre_sig_length = (uintptr_t)buf_pos - (uintptr_t)buf.data;
    total_length = pre_sig_length;
    if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
       channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
        total_length += sp->asymmetricModule.cryptoModule.signatureAlgorithm.
            getLocalSignatureSize(channel->channelContext);

    /* The total message length is known here which is why we encode the headers
     * at this step and not earlier. */
    res = prependHeadersAsym(channel, buf.data, buf_end, total_length,
                             securityHeaderLength, requestId, &encryptedLength);
    UA_CHECK_STATUS(res, goto error);

    res = signAndEncryptAsym(channel, pre_sig_length, &buf,
                             securityHeaderLength, total_length);
    UA_CHECK_STATUS(res, goto error);

    /* Send the message, the buffer is freed in the network layer */
    buf.length = encryptedLength;
    return cm->sendWithConnection(cm, channel->connectionId, &UA_KEYVALUEMAP_NULL, &buf);

 error:
    cm->freeNetworkBuffer(cm, channel->connectionId, &buf);
    return res;
}

/* Will this chunk surpass the capacity of the SecureChannel for the message? */
static UA_StatusCode
adjustCheckMessageLimitsSym(UA_MessageContext *mc, size_t bodyLength) {
    mc->messageSizeSoFar += bodyLength;
    mc->chunksSoFar++;

    UA_SecureChannel *channel = mc->channel;
    if(mc->messageSizeSoFar > channel->config.localMaxMessageSize &&
       channel->config.localMaxMessageSize != 0)
        return UA_STATUSCODE_BADRESPONSETOOLARGE;

    if(mc->chunksSoFar > channel->config.localMaxChunkCount &&
       channel->config.localMaxChunkCount != 0)
        return UA_STATUSCODE_BADRESPONSETOOLARGE;

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
encodeHeadersSym(UA_MessageContext *mc, size_t totalLength) {
    UA_SecureChannel *channel = mc->channel;
    UA_Byte *header_pos = mc->messageBuffer.data;

    UA_TcpMessageHeader header;
    header.messageTypeAndChunkType = mc->messageType;
    header.messageSize = (UA_UInt32)totalLength;
    if(mc->final)
        header.messageTypeAndChunkType += UA_CHUNKTYPE_FINAL;
    else
        header.messageTypeAndChunkType += UA_CHUNKTYPE_INTERMEDIATE;

    /* Increase the sequence number in the channel */
    channel->sendSequenceNumber++;

    UA_SequenceHeader seqHeader;
    seqHeader.requestId = mc->requestId;
    seqHeader.sequenceNumber = channel->sendSequenceNumber;

    UA_StatusCode res = UA_STATUSCODE_GOOD;
    res |= UA_encodeBinaryInternal(&header, &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER],
                                   &header_pos, &mc->buf_end, NULL, NULL);
    res |= UA_UInt32_encodeBinary(&channel->securityToken.channelId,
                                  &header_pos, mc->buf_end);
    res |= UA_UInt32_encodeBinary(&channel->securityToken.tokenId,
                                  &header_pos, mc->buf_end);
    res |= UA_encodeBinaryInternal(&seqHeader, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER],
                                   &header_pos, &mc->buf_end, NULL, NULL);
    return res;
}

static UA_StatusCode
sendSymmetricChunk(UA_MessageContext *mc) {
    UA_SecureChannel *channel = mc->channel;
    const UA_SecurityPolicy *sp = channel->securityPolicy;
    UA_ConnectionManager *cm = channel->connectionManager;
    if(!UA_SecureChannel_isConnected(channel))
        return UA_STATUSCODE_BADCONNECTIONCLOSED;

    /* The size of the message payload */
    size_t bodyLength = (uintptr_t)mc->buf_pos -
        (uintptr_t)&mc->messageBuffer.data[UA_SECURECHANNEL_SYMMETRIC_HEADER_TOTALLENGTH];

    /* Early-declare variables so we can use a goto in the error case */
    size_t total_length = 0;
    size_t pre_sig_length = 0;

    /* Check if chunk exceeds the limits for the overall message */
    UA_StatusCode res = adjustCheckMessageLimitsSym(mc, bodyLength);
    UA_CHECK_STATUS(res, goto error);

    UA_LOG_TRACE_CHANNEL(sp->logger, channel,
                         "Send from a symmetric message buffer of length %lu "
                         "a message of header+payload length of %lu",
                         (long unsigned int)mc->messageBuffer.length,
                         (long unsigned int)
                         ((uintptr_t)mc->buf_pos - (uintptr_t)mc->messageBuffer.data));

    /* Add padding if the message is encrypted */
    if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
        padChunk(channel, &sp->symmetricModule.cryptoModule,
                 &mc->messageBuffer.data[UA_SECURECHANNEL_SYMMETRIC_HEADER_UNENCRYPTEDLENGTH],
                 &mc->buf_pos);

    /* Compute the total message length */
    pre_sig_length = (uintptr_t)mc->buf_pos - (uintptr_t)mc->messageBuffer.data;
    total_length = pre_sig_length;
    if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
       channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
        total_length += sp->symmetricModule.cryptoModule.signatureAlgorithm.
            getLocalSignatureSize(channel->channelContext);

    UA_LOG_TRACE_CHANNEL(sp->logger, channel,
                         "Send from a symmetric message buffer of length %lu "
                         "a message of length %lu",
                         (long unsigned int)mc->messageBuffer.length,
                         (long unsigned int)total_length);

    /* Space for the padding and the signature have been reserved in setBufPos() */
    UA_assert(total_length <= channel->config.sendBufferSize);

    /* Adjust the buffer size of the network layer */
    mc->messageBuffer.length = total_length;

    /* Generate and encode the header for symmetric messages */
    res = encodeHeadersSym(mc, total_length);
    UA_CHECK_STATUS(res, goto error);

    /* Sign and encrypt the messge */
    res = signAndEncryptSym(mc, pre_sig_length, total_length);
    UA_CHECK_STATUS(res, goto error);

    /* Send the chunk. The buffer is freed in the network layer. If sending goes
     * wrong, the connection is removed in the next iteration of the
     * SecureChannel. Set the SecureChannel to closing already. */
    res = cm->sendWithConnection(cm, channel->connectionId,
                                 &UA_KEYVALUEMAP_NULL, &mc->messageBuffer);
    if(res != UA_STATUSCODE_GOOD && UA_SecureChannel_isConnected(channel))
        channel->state = UA_SECURECHANNELSTATE_CLOSING;

 error:
    /* Free the unused message buffer */
    cm->freeNetworkBuffer(cm, channel->connectionId, &mc->messageBuffer);
    return res;
}

/* Callback from the encoding layer. Send the chunk and replace the buffer. */
static UA_StatusCode
sendSymmetricEncodingCallback(void *data, UA_Byte **buf_pos,
                              const UA_Byte **buf_end) {
    /* Set buf values from encoding in the messagecontext */
    UA_MessageContext *mc = (UA_MessageContext *)data;
    mc->buf_pos = *buf_pos;
    mc->buf_end = *buf_end;

    /* Send out */
    UA_StatusCode res = sendSymmetricChunk(mc);
    UA_CHECK_STATUS(res, return res);

    /* Set a new buffer for the next chunk */
    UA_ConnectionManager *cm = mc->channel->connectionManager;
    if(!UA_SecureChannel_isConnected(mc->channel))
        return UA_STATUSCODE_BADCONNECTIONCLOSED;

    res = cm->allocNetworkBuffer(cm, mc->channel->connectionId,
                                 &mc->messageBuffer,
                                 mc->channel->config.sendBufferSize);
    UA_CHECK_STATUS(res, return res);

    /* Hide bytes for header, padding and signature */
    setBufPos(mc);
    *buf_pos = mc->buf_pos;
    *buf_end = mc->buf_end;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_MessageContext_begin(UA_MessageContext *mc, UA_SecureChannel *channel,
                        UA_UInt32 requestId, UA_MessageType messageType) {
    UA_CHECK(messageType == UA_MESSAGETYPE_MSG || messageType == UA_MESSAGETYPE_CLO,
             return UA_STATUSCODE_BADINTERNALERROR);

    UA_ConnectionManager *cm = channel->connectionManager;
    if(!UA_SecureChannel_isConnected(channel))
        return UA_STATUSCODE_BADCONNECTIONCLOSED;

    /* Create the chunking info structure */
    mc->channel = channel;
    mc->requestId = requestId;
    mc->chunksSoFar = 0;
    mc->messageSizeSoFar = 0;
    mc->final = false;
    mc->messageBuffer = UA_BYTESTRING_NULL;
    mc->messageType = messageType;

    /* Allocate the message buffer */
    UA_StatusCode res =
        cm->allocNetworkBuffer(cm, channel->connectionId,
                               &mc->messageBuffer,
                               channel->config.sendBufferSize);
    UA_CHECK_STATUS(res, return res);

    /* Hide bytes for header, padding and signature */
    setBufPos(mc);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_MessageContext_encode(UA_MessageContext *mc, const void *content,
                         const UA_DataType *contentType) {
    UA_StatusCode res =
        UA_encodeBinaryInternal(content, contentType, &mc->buf_pos, &mc->buf_end,
                                sendSymmetricEncodingCallback, mc);
    if(res != UA_STATUSCODE_GOOD && mc->messageBuffer.length > 0)
        UA_MessageContext_abort(mc);
    return res;
}

UA_StatusCode
UA_MessageContext_finish(UA_MessageContext *mc) {
    mc->final = true;
    return sendSymmetricChunk(mc);
}

void
UA_MessageContext_abort(UA_MessageContext *mc) {
    UA_ConnectionManager *cm = mc->channel->connectionManager;
    if(!UA_SecureChannel_isConnected(mc->channel))
        return;
    cm->freeNetworkBuffer(cm, mc->channel->connectionId, &mc->messageBuffer);
}

UA_StatusCode
UA_SecureChannel_sendSymmetricMessage(UA_SecureChannel *channel, UA_UInt32 requestId,
                                      UA_MessageType messageType, void *payload,
                                      const UA_DataType *payloadType) {
    if(!channel || !payload || !payloadType)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(channel->state != UA_SECURECHANNELSTATE_OPEN)
        return UA_STATUSCODE_BADCONNECTIONCLOSED;

    UA_MessageContext mc;
    UA_StatusCode res = UA_MessageContext_begin(&mc, channel, requestId, messageType);
    UA_CHECK_STATUS(res, return res);

    /* Assert's required for clang-analyzer */
    UA_assert(mc.buf_pos ==
              &mc.messageBuffer.data[UA_SECURECHANNEL_SYMMETRIC_HEADER_TOTALLENGTH]);
    UA_assert(mc.buf_end <= &mc.messageBuffer.data[mc.messageBuffer.length]);

    res = UA_MessageContext_encode(&mc, &payloadType->binaryEncodingId,
                                   &UA_TYPES[UA_TYPES_NODEID]);
    UA_CHECK_STATUS(res, return res);

    res = UA_MessageContext_encode(&mc, payload, payloadType);
    UA_CHECK_STATUS(res, return res);

    return UA_MessageContext_finish(&mc);
}

/********************************/
/* Receive and Process Messages */
/********************************/

/* Does the sequence number match? Otherwise try to rollover. See Part 6,
 * Section 6.7.2.4 of the standard. */
#define UA_SEQUENCENUMBER_ROLLOVER 4294966271

#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
static UA_StatusCode
processSequenceNumberSym(UA_SecureChannel *channel, UA_UInt32 sequenceNumber) {
    if(sequenceNumber != channel->receiveSequenceNumber + 1) {
        if(channel->receiveSequenceNumber + 1 <= UA_SEQUENCENUMBER_ROLLOVER ||
           sequenceNumber >= 1024)
            return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        channel->receiveSequenceNumber = sequenceNumber - 1; /* Roll over */
    }
    ++channel->receiveSequenceNumber;
    return UA_STATUSCODE_GOOD;
}
#endif

static UA_StatusCode
unpackPayloadOPN(UA_SecureChannel *channel, UA_Chunk *chunk, void *application) {
    UA_assert(chunk->bytes.length >= UA_SECURECHANNEL_MESSAGE_MIN_LENGTH);
    size_t offset = UA_SECURECHANNEL_MESSAGEHEADER_LENGTH; /* Skip the message header */
    UA_UInt32 secureChannelId;
    UA_StatusCode res = UA_UInt32_decodeBinary(&chunk->bytes, &offset, &secureChannelId);
    UA_assert(res == UA_STATUSCODE_GOOD);

    UA_AsymmetricAlgorithmSecurityHeader asymHeader;
    res = UA_decodeBinaryInternal(&chunk->bytes, &offset, &asymHeader,
             &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER], NULL);
    UA_CHECK_STATUS(res, return res);

    if(asymHeader.senderCertificate.length > 0) {
        if(channel->certificateVerification)
            res = channel->certificateVerification->
                verifyCertificate(channel->certificateVerification,
                                  &asymHeader.senderCertificate);
        else
            res = UA_STATUSCODE_BADINTERNALERROR;
        UA_CHECK_STATUS(res, goto error);
    }

    /* New channel, create a security policy context and attach */
    if(!channel->securityPolicy) {
        if(channel->processOPNHeader)
            res = channel->processOPNHeader(application, channel, &asymHeader);
        if(!channel->securityPolicy)
            res = UA_STATUSCODE_BADINTERNALERROR;
        UA_CHECK_STATUS(res, goto error);
    }

    /* On the client side, take the SecureChannelId from the first response */
    if(secureChannelId != 0 && channel->securityToken.channelId == 0)
        channel->securityToken.channelId = secureChannelId;

    /* Check the ChannelId */
#if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
    if(secureChannelId != channel->securityToken.channelId) {
        /* Allow the channel id to be different if the sent channel id is zero
         * and the SecurityToken is not initialized. This only happens on the
         * server side before we had a chance to tell the client which ChannelId
         * to use. */
        if(secureChannelId != 0 || channel->securityToken.tokenId != 0) {
            res = UA_STATUSCODE_BADSECURECHANNELIDINVALID;
            goto error;
        }
    }
#endif

    /* Check the header for the channel's security policy */
    res = checkAsymHeader(channel, &asymHeader);
    UA_AsymmetricAlgorithmSecurityHeader_clear(&asymHeader);
    UA_CHECK_STATUS(res, return res);

    /* Decrypt the chunk payload */
    res = decryptAndVerifyChunk(channel,
                                &channel->securityPolicy->asymmetricModule.cryptoModule,
                                chunk->messageType, &chunk->bytes, offset);
    UA_CHECK_STATUS(res, return res);

    /* Decode the SequenceHeader */
    UA_SequenceHeader sequenceHeader;
    res = UA_decodeBinaryInternal(&chunk->bytes, &offset, &sequenceHeader,
                                  &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER], NULL);
    UA_CHECK_STATUS(res, return res);

    /* Set the sequence number for the channel from which to count up */
    channel->receiveSequenceNumber = sequenceHeader.sequenceNumber;
    chunk->requestId = sequenceHeader.requestId; /* Set the RequestId of the chunk */

    /* Use only the payload */
    chunk->bytes.data += offset;
    chunk->bytes.length -= offset;
    return UA_STATUSCODE_GOOD;

error:
    UA_AsymmetricAlgorithmSecurityHeader_clear(&asymHeader);
    return res;
}

static UA_StatusCode
unpackPayloadMSG(UA_SecureChannel *channel, UA_Chunk *chunk,
                 UA_DateTime nowMonotonic) {
    UA_CHECK_MEM(channel->securityPolicy, return UA_STATUSCODE_BADINTERNALERROR);

    UA_assert(chunk->bytes.length >= UA_SECURECHANNEL_MESSAGE_MIN_LENGTH);
    size_t offset = UA_SECURECHANNEL_MESSAGEHEADER_LENGTH; /* Skip the message header */
    UA_UInt32 secureChannelId;
    UA_UInt32 tokenId; /* SymmetricAlgorithmSecurityHeader */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    res |= UA_UInt32_decodeBinary(&chunk->bytes, &offset, &secureChannelId);
    res |= UA_UInt32_decodeBinary(&chunk->bytes, &offset, &tokenId);
    UA_assert(offset == UA_SECURECHANNEL_MESSAGE_MIN_LENGTH);
    UA_assert(res == UA_STATUSCODE_GOOD);

#if !defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION)
    /* Check the ChannelId. Non-opened channels have the id zero. */
    if(secureChannelId != channel->securityToken.channelId)
        return UA_STATUSCODE_BADSECURECHANNELIDINVALID;
#endif

    /* Check (and revolve) the SecurityToken */
    res = checkSymHeader(channel, tokenId, nowMonotonic);
    UA_CHECK_STATUS(res, return res);

    /* Decrypt the chunk payload */
    res = decryptAndVerifyChunk(channel,
                                &channel->securityPolicy->symmetricModule.cryptoModule,
                                chunk->messageType, &chunk->bytes, offset);
    UA_CHECK_STATUS(res, return res);

    /* Check the sequence number. Skip sequence number checking for fuzzer to
     * improve coverage */
    UA_SequenceHeader sequenceHeader;
    res = UA_decodeBinaryInternal(&chunk->bytes, &offset, &sequenceHeader,
                                  &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER], NULL);
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
    res |= processSequenceNumberSym(channel, sequenceHeader.sequenceNumber);
#endif
    UA_CHECK_STATUS(res, return res);

    chunk->requestId = sequenceHeader.requestId; /* Set the RequestId of the chunk */

    /* Use only the payload */
    chunk->bytes.data += offset;
    chunk->bytes.length -= offset;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
assembleProcessMessage(UA_SecureChannel *channel, void *application,
                       UA_ProcessMessageCallback callback) {
    UA_Chunk *chunk = SIMPLEQ_FIRST(&channel->decryptedChunks);
    UA_assert(chunk != NULL);

    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(chunk->chunkType == UA_CHUNKTYPE_FINAL) {
        SIMPLEQ_REMOVE_HEAD(&channel->decryptedChunks, pointers);
        UA_assert(chunk->chunkType == UA_CHUNKTYPE_FINAL);
        res = callback(application, channel, chunk->messageType,
                       chunk->requestId, &chunk->bytes);
        UA_Chunk_delete(chunk);
        return res;
    }

    UA_UInt32 requestId = chunk->requestId;
    UA_MessageType messageType = chunk->messageType;
    UA_ChunkType chunkType = chunk->chunkType;
    UA_assert(chunkType == UA_CHUNKTYPE_INTERMEDIATE);

    size_t messageSize = 0;
    SIMPLEQ_FOREACH(chunk, &channel->decryptedChunks, pointers) {
        /* Consistency check */
        if(requestId != chunk->requestId)
            return UA_STATUSCODE_BADINTERNALERROR;
        if(chunkType != chunk->chunkType && chunk->chunkType != UA_CHUNKTYPE_FINAL)
            return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID;
        if(chunk->messageType != messageType)
            return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID;

        /* Sum up the lengths */
        messageSize += chunk->bytes.length;
        if(chunk->chunkType == UA_CHUNKTYPE_FINAL)
            break;
    }

    /* Allocate memory for the full message */
    UA_ByteString payload;
    res = UA_ByteString_allocBuffer(&payload, messageSize);
    UA_CHECK_STATUS(res, return res);

    /* Assemble the full message */
    size_t offset = 0;
    while(true) {
        chunk = SIMPLEQ_FIRST(&channel->decryptedChunks);
        memcpy(&payload.data[offset], chunk->bytes.data, chunk->bytes.length);
        offset += chunk->bytes.length;
        SIMPLEQ_REMOVE_HEAD(&channel->decryptedChunks, pointers);
        UA_ChunkType ct = chunk->chunkType;
        UA_Chunk_delete(chunk);
        if(ct == UA_CHUNKTYPE_FINAL)
            break;
    }

    /* Process the assembled message */
    res = callback(application, channel, messageType, requestId, &payload);
    UA_ByteString_clear(&payload);
    return res;
}

static UA_StatusCode
persistCompleteChunks(UA_ChunkQueue *queue) {
    UA_Chunk *chunk;
    SIMPLEQ_FOREACH(chunk, queue, pointers) {
        if(chunk->copied)
            continue;
        UA_ByteString copy;
        UA_StatusCode res = UA_ByteString_copy(&chunk->bytes, &copy);
        UA_CHECK_STATUS(res, return res);
        chunk->bytes = copy;
        chunk->copied = true;
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
persistIncompleteChunk(UA_SecureChannel *channel, const UA_ByteString *buffer,
                       size_t offset) {
    UA_assert(channel->incompleteChunk.length == 0);
    UA_assert(offset < buffer->length);
    size_t length = buffer->length - offset;
    UA_StatusCode res = UA_ByteString_allocBuffer(&channel->incompleteChunk, length);
    UA_CHECK_STATUS(res, return res);
    memcpy(channel->incompleteChunk.data, &buffer->data[offset], length);
    return UA_STATUSCODE_GOOD;
}

/* Processes chunks and puts them into the payloads queue. Once a final chunk is
 * put into the queue, the message is assembled and the callback is called. The
 * queue will be cleared for the next message. */
static UA_StatusCode
processChunks(UA_SecureChannel *channel, void *application,
              UA_ProcessMessageCallback callback,
              UA_DateTime nowMonotonic) {
    UA_Chunk *chunk;
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    while((chunk = SIMPLEQ_FIRST(&channel->completeChunks))) {
        /* Remove from the complete-chunk queue */
        SIMPLEQ_REMOVE_HEAD(&channel->completeChunks, pointers);

        /* Check, decrypt and unpack the payload */
        if(chunk->messageType == UA_MESSAGETYPE_OPN) {
            if(channel->state != UA_SECURECHANNELSTATE_OPEN &&
               channel->state != UA_SECURECHANNELSTATE_OPN_SENT &&
               channel->state != UA_SECURECHANNELSTATE_ACK_SENT)
                res = UA_STATUSCODE_BADINVALIDSTATE;
            else
                res = unpackPayloadOPN(channel, chunk, application);
        } else if(chunk->messageType == UA_MESSAGETYPE_MSG ||
                  chunk->messageType == UA_MESSAGETYPE_CLO) {
            if(channel->state == UA_SECURECHANNELSTATE_CLOSED)
                res = UA_STATUSCODE_BADSECURECHANNELCLOSED;
            else
                res = unpackPayloadMSG(channel, chunk, nowMonotonic);
        } else {
            chunk->bytes.data += UA_SECURECHANNEL_MESSAGEHEADER_LENGTH;
            chunk->bytes.length -= UA_SECURECHANNEL_MESSAGEHEADER_LENGTH;
        }

        if(res != UA_STATUSCODE_GOOD) {
            UA_Chunk_delete(chunk);
            return res;
        }

        /* Add to the decrypted-chunk queue */
        SIMPLEQ_INSERT_TAIL(&channel->decryptedChunks, chunk, pointers);

        /* Check the resource limits */
        channel->decryptedChunksCount++;
        channel->decryptedChunksLength += chunk->bytes.length;
        if((channel->config.localMaxChunkCount != 0 &&
            channel->decryptedChunksCount > channel->config.localMaxChunkCount) ||
           (channel->config.localMaxMessageSize != 0 &&
            channel->decryptedChunksLength > channel->config.localMaxMessageSize)) {
            return UA_STATUSCODE_BADTCPMESSAGETOOLARGE;
        }

        /* Waiting for additional chunks */
        if(chunk->chunkType == UA_CHUNKTYPE_INTERMEDIATE)
            continue;

        /* Final chunk or abort. Reset the counters. */
        channel->decryptedChunksCount = 0;
        channel->decryptedChunksLength = 0;

        /* Abort the message, remove all decrypted chunks
         * TODO: Log a warning with the error code */
        if(chunk->chunkType == UA_CHUNKTYPE_ABORT) {
            while((chunk = SIMPLEQ_FIRST(&channel->decryptedChunks))) {
                SIMPLEQ_REMOVE_HEAD(&channel->decryptedChunks, pointers);
                UA_Chunk_delete(chunk);
            }
            continue;
        }

        /* The decrypted queue contains a full message. Process it. */
        UA_assert(chunk->chunkType == UA_CHUNKTYPE_FINAL);
        res = assembleProcessMessage(channel, application, callback);
        UA_CHECK_STATUS(res, return res);
    }

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
extractCompleteChunk(UA_SecureChannel *channel, const UA_ByteString *buffer,
                     size_t *offset, UA_Boolean *done) {
    /* At least 8 byte needed for the header. Wait for the next chunk. */
    size_t initial_offset = *offset;
    size_t remaining = buffer->length - initial_offset;
    if(remaining < UA_SECURECHANNEL_MESSAGEHEADER_LENGTH) {
        *done = true;
        return UA_STATUSCODE_GOOD;
    }

    /* Decoding cannot fail */
    UA_TcpMessageHeader hdr;
    UA_StatusCode res =
        UA_decodeBinaryInternal(buffer, &initial_offset, &hdr,
                                &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER], NULL);
    UA_assert(res == UA_STATUSCODE_GOOD);
    (void)res; /* pacify compilers if assert is ignored */
    UA_MessageType msgType = (UA_MessageType)
        (hdr.messageTypeAndChunkType & UA_BITMASK_MESSAGETYPE);
    UA_ChunkType chunkType = (UA_ChunkType)
        (hdr.messageTypeAndChunkType & UA_BITMASK_CHUNKTYPE);

    /* The message size is not allowed */
    if(hdr.messageSize < UA_SECURECHANNEL_MESSAGE_MIN_LENGTH)
        return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID;
    if(hdr.messageSize > channel->config.recvBufferSize)
        return UA_STATUSCODE_BADTCPMESSAGETOOLARGE;

    /* Incomplete chunk */
    if(hdr.messageSize > remaining) {
        *done = true;
        return UA_STATUSCODE_GOOD;
    }

    /* ByteString with only this chunk. */
    UA_ByteString chunkPayload;
    chunkPayload.data = &buffer->data[*offset];
    chunkPayload.length = hdr.messageSize;

    if(msgType == UA_MESSAGETYPE_RHE || msgType == UA_MESSAGETYPE_HEL || msgType == UA_MESSAGETYPE_ACK ||
       msgType == UA_MESSAGETYPE_ERR || msgType == UA_MESSAGETYPE_OPN) {
        if(chunkType != UA_CHUNKTYPE_FINAL)
            return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID;
    } else {
        /* Only messages on SecureChannel-level with symmetric encryption afterwards */
        if(msgType != UA_MESSAGETYPE_MSG &&
           msgType != UA_MESSAGETYPE_CLO)
            return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID;

        /* Check the chunk type before decrypting */
        if(chunkType != UA_CHUNKTYPE_FINAL &&
           chunkType != UA_CHUNKTYPE_INTERMEDIATE &&
           chunkType != UA_CHUNKTYPE_ABORT)
            return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID;
    }

    /* Add the chunk; forward the offset */
    *offset += hdr.messageSize;
    UA_Chunk *chunk = (UA_Chunk*)UA_malloc(sizeof(UA_Chunk));
    UA_CHECK_MEM(chunk, return UA_STATUSCODE_BADOUTOFMEMORY);

    chunk->bytes = chunkPayload;
    chunk->messageType = msgType;
    chunk->chunkType = chunkType;
    chunk->requestId = 0;
    chunk->copied = false;

    SIMPLEQ_INSERT_TAIL(&channel->completeChunks, chunk, pointers);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_SecureChannel_processBuffer(UA_SecureChannel *channel, void *application,
                               UA_ProcessMessageCallback callback,
                               const UA_ByteString *buffer,
                               UA_DateTime nowMonotonic) {
    /* Prepend the incomplete last chunk. This is usually done in the
     * networklayer. But we test for a buffered incomplete chunk here again to
     * work around "lazy" network layers. */
    UA_ByteString appended = channel->incompleteChunk;
    if(appended.length > 0) {
        channel->incompleteChunk = UA_BYTESTRING_NULL;
        UA_Byte *t = (UA_Byte*)UA_realloc(appended.data, appended.length + buffer->length);
        UA_CHECK_MEM(t, UA_ByteString_clear(&appended);
                     return UA_STATUSCODE_BADOUTOFMEMORY);
        memcpy(&t[appended.length], buffer->data, buffer->length);
        appended.data = t;
        appended.length += buffer->length;
        buffer = &appended;
    }

    /* Loop over the received chunks */
    size_t offset = 0;
    UA_Boolean done = false;
    UA_StatusCode res;
    while(!done) {
        res = extractCompleteChunk(channel, buffer, &offset, &done);
        UA_CHECK_STATUS(res, goto cleanup);
    }

    /* Buffer half-received chunk. Before processing the messages so that
     * processing is reentrant. */
    if(offset < buffer->length) {
        res = persistIncompleteChunk(channel, buffer, offset);
        UA_CHECK_STATUS(res, goto cleanup);
    }

    /* Process whatever we can. Chunks of completed and processed messages are
     * removed. */
    res = processChunks(channel, application, callback, nowMonotonic);
    UA_CHECK_STATUS(res, goto cleanup);

    /* Persist full chunks that still point to the buffer. Can only return
     * UA_STATUSCODE_BADOUTOFMEMORY as an error code. So merging res works. */
    res |= persistCompleteChunks(&channel->completeChunks);
    res |= persistCompleteChunks(&channel->decryptedChunks);

 cleanup:
    UA_ByteString_clear(&appended);
    return res;
}

/**** amalgamated original file "/src/ua_securechannel_crypto.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014, 2016-2017 (c) Florian Palm
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015 (c) Oleksiy Vasylyev
 *    Copyright 2016 (c) TorbenD
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017-2018 (c) Mark Giraud, Fraunhofer IOSB
 */



UA_StatusCode
UA_SecureChannel_generateLocalNonce(UA_SecureChannel *channel) {
    const UA_SecurityPolicy *sp = channel->securityPolicy;
    UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR);
    UA_LOG_DEBUG_CHANNEL(sp->logger, channel, "Generating new local nonce");

    /* Is the length of the previous nonce correct? */
    size_t nonceLength = sp->symmetricModule.secureChannelNonceLength;
    if(channel->localNonce.length != nonceLength) {
        UA_ByteString_clear(&channel->localNonce);
        UA_StatusCode res = UA_ByteString_allocBuffer(&channel->localNonce, nonceLength);
        UA_CHECK_STATUS(res, return res);
    }

    /* Generate the nonce */
    return sp->symmetricModule.generateNonce(sp->policyContext, &channel->localNonce);
}

UA_StatusCode
UA_SecureChannel_generateLocalKeys(const UA_SecureChannel *channel) {
    const UA_SecurityPolicy *sp = channel->securityPolicy;
    UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR);
    UA_LOG_TRACE_CHANNEL(sp->logger, channel, "Generating new local keys");

    void *cc = channel->channelContext;
    const UA_SecurityPolicyChannelModule *cm = &sp->channelModule;
    const UA_SecurityPolicySymmetricModule *sm = &sp->symmetricModule;
    const UA_SecurityPolicyCryptoModule *crm = &sm->cryptoModule;

    /* Generate symmetric key buffer of the required length. The block size is
     * identical for local/remote. */
    UA_ByteString buf;
    size_t encrKL = crm->encryptionAlgorithm.getLocalKeyLength(cc);
    size_t encrBS = crm->encryptionAlgorithm.getRemoteBlockSize(cc);
    size_t signKL = crm->signatureAlgorithm.getLocalKeyLength(cc);
    if(encrBS + signKL + encrKL == 0)
        return UA_STATUSCODE_GOOD; /* No keys to generate */

    UA_StatusCode retval = UA_ByteString_allocBuffer(&buf, encrBS + signKL + encrKL);
    UA_CHECK_STATUS(retval, return retval);
    UA_ByteString localSigningKey = {signKL, buf.data};
    UA_ByteString localEncryptingKey = {encrKL, &buf.data[signKL]};
    UA_ByteString localIv = {encrBS, &buf.data[signKL + encrKL]};

    /* Generate key */
    retval = sm->generateKey(sp->policyContext, &channel->remoteNonce,
                             &channel->localNonce, &buf);
    UA_CHECK_STATUS(retval, goto error);

    /* Set the channel context */
    retval |= cm->setLocalSymSigningKey(cc, &localSigningKey);
    retval |= cm->setLocalSymEncryptingKey(cc, &localEncryptingKey);
    retval |= cm->setLocalSymIv(cc, &localIv);

 error:
    UA_CHECK_STATUS(retval, UA_LOG_WARNING_CHANNEL(sp->logger, channel,
                            "Could not generate local keys (statuscode: %s)",
                            UA_StatusCode_name(retval)));
    UA_ByteString_clear(&buf);
    return retval;
}

UA_StatusCode
generateRemoteKeys(const UA_SecureChannel *channel) {
    const UA_SecurityPolicy *sp = channel->securityPolicy;
    UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR);
    UA_LOG_TRACE_CHANNEL(sp->logger, channel, "Generating new remote keys");

    void *cc = channel->channelContext;
    const UA_SecurityPolicyChannelModule *cm = &sp->channelModule;
    const UA_SecurityPolicySymmetricModule *sm = &sp->symmetricModule;
    const UA_SecurityPolicyCryptoModule *crm = &sm->cryptoModule;

    /* Generate symmetric key buffer of the required length */
    UA_ByteString buf;
    size_t encrKL = crm->encryptionAlgorithm.getRemoteKeyLength(cc);
    size_t encrBS = crm->encryptionAlgorithm.getRemoteBlockSize(cc);
    size_t signKL = crm->signatureAlgorithm.getRemoteKeyLength(cc);
    if(encrBS + signKL + encrKL == 0)
        return UA_STATUSCODE_GOOD; /* No keys to generate */

    UA_StatusCode retval = UA_ByteString_allocBuffer(&buf, encrBS + signKL + encrKL);
    UA_CHECK_STATUS(retval, return retval);
    UA_ByteString remoteSigningKey = {signKL, buf.data};
    UA_ByteString remoteEncryptingKey = {encrKL, &buf.data[signKL]};
    UA_ByteString remoteIv = {encrBS, &buf.data[signKL + encrKL]};

    /* Generate key */
    retval = sm->generateKey(sp->policyContext, &channel->localNonce,
                             &channel->remoteNonce, &buf);
    UA_CHECK_STATUS(retval, goto error);

    /* Set the channel context */
    retval |= cm->setRemoteSymSigningKey(cc, &remoteSigningKey);
    retval |= cm->setRemoteSymEncryptingKey(cc, &remoteEncryptingKey);
    retval |= cm->setRemoteSymIv(cc, &remoteIv);

 error:
    UA_CHECK_STATUS(retval, UA_LOG_WARNING_CHANNEL(sp->logger, channel,
                            "Could not generate remote keys (statuscode: %s)",
                            UA_StatusCode_name(retval)));
    UA_ByteString_clear(&buf);
    return retval;
}

/***************************/
/* Send Asymmetric Message */
/***************************/

/* The length of the static header content */
#define UA_SECURECHANNEL_ASYMMETRIC_SECURITYHEADER_FIXED_LENGTH 12

size_t
calculateAsymAlgSecurityHeaderLength(const UA_SecureChannel *channel) {
    const UA_SecurityPolicy *sp = channel->securityPolicy;
    UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR);

    size_t asymHeaderLength = UA_SECURECHANNEL_ASYMMETRIC_SECURITYHEADER_FIXED_LENGTH +
                              sp->policyUri.length;
    if(channel->securityMode == UA_MESSAGESECURITYMODE_NONE)
        return asymHeaderLength;

    /* OPN is always encrypted even if the mode is sign only */
    asymHeaderLength += 20; /* Thumbprints are always 20 byte long */
    asymHeaderLength += sp->localCertificate.length;
    return asymHeaderLength;
}

UA_StatusCode
prependHeadersAsym(UA_SecureChannel *const channel, UA_Byte *header_pos,
                   const UA_Byte *buf_end, size_t totalLength,
                   size_t securityHeaderLength, UA_UInt32 requestId,
                   size_t *const encryptedLength) {
    const UA_SecurityPolicy *sp = channel->securityPolicy;
    UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR);

    if(channel->securityMode == UA_MESSAGESECURITYMODE_NONE) {
        *encryptedLength = totalLength;
    } else {
        size_t dataToEncryptLength = totalLength -
            (UA_SECURECHANNEL_CHANNELHEADER_LENGTH + securityHeaderLength);
        size_t plainTextBlockSize = sp->asymmetricModule.cryptoModule.
            encryptionAlgorithm.getRemotePlainTextBlockSize(channel->channelContext);
        size_t encryptedBlockSize = sp->asymmetricModule.cryptoModule.
            encryptionAlgorithm.getRemoteBlockSize(channel->channelContext);

        /* Padding always fills up the last block */
        UA_assert(dataToEncryptLength % plainTextBlockSize == 0);
        size_t blocks = dataToEncryptLength / plainTextBlockSize;
        *encryptedLength = totalLength + blocks * (encryptedBlockSize - plainTextBlockSize);
    }

    UA_TcpMessageHeader messageHeader;
    messageHeader.messageTypeAndChunkType = UA_MESSAGETYPE_OPN + UA_CHUNKTYPE_FINAL;
    messageHeader.messageSize = (UA_UInt32)*encryptedLength;
    UA_UInt32 secureChannelId = channel->securityToken.channelId;
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    retval |= UA_encodeBinaryInternal(&messageHeader,
                                      &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER],
                                      &header_pos, &buf_end, NULL, NULL);
    retval |= UA_UInt32_encodeBinary(&secureChannelId, &header_pos, buf_end);
    UA_CHECK_STATUS(retval, return retval);

    UA_AsymmetricAlgorithmSecurityHeader asymHeader;
    UA_AsymmetricAlgorithmSecurityHeader_init(&asymHeader);
    asymHeader.securityPolicyUri = sp->policyUri;
    if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
       channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
        asymHeader.senderCertificate = sp->localCertificate;
        asymHeader.receiverCertificateThumbprint.length = 20;
        asymHeader.receiverCertificateThumbprint.data = channel->remoteCertificateThumbprint;
    }
    retval = UA_encodeBinaryInternal(&asymHeader,
                &UA_TRANSPORT[UA_TRANSPORT_ASYMMETRICALGORITHMSECURITYHEADER],
                &header_pos, &buf_end, NULL, NULL);
    UA_CHECK_STATUS(retval, return retval);

    /* Increase the sequence number in the channel */
    channel->sendSequenceNumber++;

    UA_SequenceHeader seqHeader;
    seqHeader.requestId = requestId;
    seqHeader.sequenceNumber = channel->sendSequenceNumber;
    retval = UA_encodeBinaryInternal(&seqHeader, &UA_TRANSPORT[UA_TRANSPORT_SEQUENCEHEADER],
                                     &header_pos, &buf_end, NULL, NULL);
    return retval;
}

void
hideBytesAsym(const UA_SecureChannel *channel, UA_Byte **buf_start,
              const UA_Byte **buf_end) {
    /* Set buf_start to the beginning of the payload body */
    *buf_start += UA_SECURECHANNEL_CHANNELHEADER_LENGTH;
    *buf_start += calculateAsymAlgSecurityHeaderLength(channel);
    *buf_start += UA_SECURECHANNEL_SEQUENCEHEADER_LENGTH;

    if(channel->securityMode == UA_MESSAGESECURITYMODE_NONE)
        return;

    /* Make space for the certificate */
    const UA_SecurityPolicy *sp = channel->securityPolicy;
    *buf_end -= sp->asymmetricModule.cryptoModule.signatureAlgorithm.
        getLocalSignatureSize(channel->channelContext);

    /* Block sizes depend on the remote key (certificate) */
    size_t plainTextBlockSize = sp->asymmetricModule.cryptoModule.
        encryptionAlgorithm.getRemotePlainTextBlockSize(channel->channelContext);
    size_t encryptedBlockSize = sp->asymmetricModule.cryptoModule.
        encryptionAlgorithm.getRemoteBlockSize(channel->channelContext);
    UA_Boolean extraPadding = (sp->asymmetricModule.cryptoModule.encryptionAlgorithm.
                               getRemoteKeyLength(channel->channelContext) > 2048);

    /* Compute the maximum number of encrypted blocks that can fit entirely
     * before the signature. From that compute the maximum usable plaintext
     * size. */
    size_t maxEncrypted = (size_t)(*buf_end - *buf_start) +
        UA_SECURECHANNEL_SEQUENCEHEADER_LENGTH;
    size_t max_blocks = maxEncrypted / encryptedBlockSize;
    size_t paddingBytes = (UA_LIKELY(!extraPadding)) ? 1u : 2u;
    *buf_end = *buf_start + (max_blocks * plainTextBlockSize) -
        UA_SECURECHANNEL_SEQUENCEHEADER_LENGTH - paddingBytes;
}

/* Assumes that pos can be advanced to the end of the current block */
void
padChunk(UA_SecureChannel *channel, const UA_SecurityPolicyCryptoModule *cm,
         const UA_Byte *start, UA_Byte **pos) {
    const size_t bytesToWrite = (uintptr_t)*pos - (uintptr_t)start;
    size_t signatureSize = cm->signatureAlgorithm.
        getLocalSignatureSize(channel->channelContext);
    size_t plainTextBlockSize = cm->encryptionAlgorithm.
        getRemotePlainTextBlockSize(channel->channelContext);
    UA_Boolean extraPadding = (cm->encryptionAlgorithm.
        getRemoteKeyLength(channel->channelContext) > 2048);
    size_t paddingBytes = (UA_LIKELY(!extraPadding)) ? 1u : 2u;

    size_t lastBlock = ((bytesToWrite + signatureSize + paddingBytes) % plainTextBlockSize);
    size_t paddingLength = (lastBlock != 0) ? plainTextBlockSize - lastBlock : 0;

    UA_LOG_TRACE_CHANNEL(channel->securityPolicy->logger, channel,
                         "Add %lu bytes of padding plus %lu padding size bytes",
                         (long unsigned int)paddingLength,
                         (long unsigned int)paddingBytes);

    /* Write the padding. This is <= because the paddingSize byte also has to be
     * written */
    UA_Byte paddingByte = (UA_Byte)paddingLength;
    for(UA_UInt16 i = 0; i <= paddingLength; ++i) {
        **pos = paddingByte;
        ++*pos;
    }

    /* Write the extra padding byte if required */
    if(extraPadding) {
        **pos = (UA_Byte)(paddingLength >> 8u);
        ++*pos;
    }
}

UA_StatusCode
signAndEncryptAsym(UA_SecureChannel *channel, size_t preSignLength,
                   UA_ByteString *buf, size_t securityHeaderLength,
                   size_t totalLength) {
    if(channel->securityMode != UA_MESSAGESECURITYMODE_SIGN &&
       channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
        return UA_STATUSCODE_GOOD;

    /* Sign message */
    const UA_SecurityPolicy *sp = channel->securityPolicy;
    const UA_ByteString dataToSign = {preSignLength, buf->data};
    size_t sigsize = sp->asymmetricModule.cryptoModule.signatureAlgorithm.
        getLocalSignatureSize(channel->channelContext);
    UA_ByteString signature = {sigsize, buf->data + preSignLength};
    UA_StatusCode retval = sp->asymmetricModule.cryptoModule.signatureAlgorithm.
        sign(channel->channelContext, &dataToSign, &signature);
    UA_CHECK_STATUS(retval, return retval);

    /* Specification part 6, 6.7.4: The OpenSecureChannel Messages are
     * signed and encrypted if the SecurityMode is not None (even if the
     * SecurityMode is SignOnly). */
    size_t unencrypted_length =
        UA_SECURECHANNEL_CHANNELHEADER_LENGTH + securityHeaderLength;
    UA_ByteString dataToEncrypt = {totalLength - unencrypted_length,
                                   &buf->data[unencrypted_length]};
    return sp->asymmetricModule.cryptoModule.encryptionAlgorithm.
        encrypt(channel->channelContext, &dataToEncrypt);
}

/**************************/
/* Send Symmetric Message */
/**************************/

UA_StatusCode
signAndEncryptSym(UA_MessageContext *messageContext,
                  size_t preSigLength, size_t totalLength) {
    const UA_SecureChannel *channel = messageContext->channel;
    if(channel->securityMode == UA_MESSAGESECURITYMODE_NONE)
        return UA_STATUSCODE_GOOD;

    /* Sign */
    const UA_SecurityPolicy *sp = channel->securityPolicy;
    UA_ByteString dataToSign = messageContext->messageBuffer;
    dataToSign.length = preSigLength;
    UA_ByteString signature;
    signature.length = sp->symmetricModule.cryptoModule.signatureAlgorithm.
        getLocalSignatureSize(channel->channelContext);
    signature.data = messageContext->buf_pos;
    UA_StatusCode res = sp->symmetricModule.cryptoModule.signatureAlgorithm.
        sign(channel->channelContext, &dataToSign, &signature);
    UA_CHECK_STATUS(res, return res);

    if(channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
        return UA_STATUSCODE_GOOD;

    /* Encrypt */
    UA_ByteString dataToEncrypt;
    dataToEncrypt.data = messageContext->messageBuffer.data +
        UA_SECURECHANNEL_CHANNELHEADER_LENGTH +
        UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH;
    dataToEncrypt.length = totalLength -
        (UA_SECURECHANNEL_CHANNELHEADER_LENGTH +
         UA_SECURECHANNEL_SYMMETRIC_SECURITYHEADER_LENGTH);
    return sp->symmetricModule.cryptoModule.encryptionAlgorithm.
        encrypt(channel->channelContext, &dataToEncrypt);
}

void
setBufPos(UA_MessageContext *mc) {
    /* Forward the data pointer so that the payload is encoded after the message
     * header. This has to be a symmetric message because OPN (with asymmetric
     * encryption) does not support chunking. */
    mc->buf_pos = &mc->messageBuffer.data[UA_SECURECHANNEL_SYMMETRIC_HEADER_TOTALLENGTH];
    mc->buf_end = &mc->messageBuffer.data[mc->messageBuffer.length];

    if(mc->channel->securityMode == UA_MESSAGESECURITYMODE_NONE)
        return;

    const UA_SecureChannel *channel = mc->channel;
    const UA_SecurityPolicy *sp = channel->securityPolicy;
    size_t sigsize = sp->symmetricModule.cryptoModule.signatureAlgorithm.
        getLocalSignatureSize(channel->channelContext);
    size_t plainBlockSize = sp->symmetricModule.cryptoModule.
        encryptionAlgorithm.getRemotePlainTextBlockSize(channel->channelContext);

    /* Assuming that for symmetric encryption the plainTextBlockSize ==
     * cypherTextBlockSize. For symmetric encryption the remote/local block
     * sizes are identical. */
    UA_assert(sp->symmetricModule.cryptoModule.encryptionAlgorithm.
              getRemoteBlockSize(channel->channelContext) == plainBlockSize);

    /* Leave enough space for the signature and padding */
    mc->buf_end -= sigsize;
    mc->buf_end -= mc->messageBuffer.length % plainBlockSize;

    if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
        /* Reserve space for the padding bytes */
        UA_Boolean extraPadding =
            (sp->symmetricModule.cryptoModule.encryptionAlgorithm.
             getRemoteKeyLength(channel->channelContext) > 2048);
        mc->buf_end -= (UA_LIKELY(!extraPadding)) ? 1 : 2;
    }

    UA_LOG_TRACE_CHANNEL(sp->logger, channel,
                         "Prepare a symmetric message buffer of length %lu "
                         "with a usable maximum payload length of %lu",
                         (long unsigned)mc->messageBuffer.length,
                         (long unsigned)((uintptr_t)mc->buf_end -
                                         (uintptr_t)mc->messageBuffer.data));
}

/****************************/
/* Process a received Chunk */
/****************************/

static size_t
decodePadding(const UA_SecureChannel *channel,
              const UA_SecurityPolicyCryptoModule *cryptoModule,
              const UA_ByteString *chunk, size_t sigsize) {
    /* Read the byte with the padding size */
    size_t paddingSize = chunk->data[chunk->length - sigsize - 1];

    /* Extra padding size */
    if(cryptoModule->encryptionAlgorithm.
       getLocalKeyLength(channel->channelContext) > 2048) {
        paddingSize <<= 8u;
        paddingSize += chunk->data[chunk->length - sigsize - 2];
        paddingSize += 1; /* Extra padding byte itself */
    }

    /* Add one since the paddingSize byte itself needs to be removed as well */
    return paddingSize + 1;
}

static UA_StatusCode
verifySignature(const UA_SecureChannel *channel,
                const UA_SecurityPolicyCryptoModule *cryptoModule,
                const UA_ByteString *chunk, size_t sigsize) {
    UA_LOG_TRACE_CHANNEL(channel->securityPolicy->logger, channel,
                         "Verifying chunk signature");
    UA_CHECK(sigsize < chunk->length, return UA_STATUSCODE_BADSECURITYCHECKSFAILED);
    const UA_ByteString content = {chunk->length - sigsize, chunk->data};
    const UA_ByteString sig = {sigsize, chunk->data + chunk->length - sigsize};
    UA_StatusCode retval = cryptoModule->signatureAlgorithm.
        verify(channel->channelContext, &content, &sig);
    return retval;
}

/* Sets the payload to a pointer inside the chunk buffer. Returns the requestId
 * and the sequenceNumber */
UA_StatusCode
decryptAndVerifyChunk(const UA_SecureChannel *channel,
                      const UA_SecurityPolicyCryptoModule *cryptoModule,
                      UA_MessageType messageType, UA_ByteString *chunk,
                      size_t offset) {
    /* Decrypt the chunk */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT ||
       messageType == UA_MESSAGETYPE_OPN) {
        UA_ByteString cipher = {chunk->length - offset, chunk->data + offset};
        res = cryptoModule->encryptionAlgorithm.decrypt(channel->channelContext, &cipher);
        UA_CHECK_STATUS(res, return res);
        chunk->length = cipher.length + offset;
    }

    /* Does the message have a signature? */
    if(channel->securityMode != UA_MESSAGESECURITYMODE_SIGN &&
       channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT &&
       messageType != UA_MESSAGETYPE_OPN)
        return UA_STATUSCODE_GOOD;

    /* Verify the chunk signature */
    size_t sigsize = cryptoModule->signatureAlgorithm.
        getRemoteSignatureSize(channel->channelContext);
    res = verifySignature(channel, cryptoModule, chunk, sigsize);
    UA_CHECK_STATUS(res,
       UA_LOG_WARNING_CHANNEL(channel->securityPolicy->logger, channel,
                              "Could not verify the signature"); return res);

    /* Compute the padding if the payload as encrypted */
    size_t padSize = 0;
    if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT ||
       (messageType == UA_MESSAGETYPE_OPN &&
        cryptoModule->encryptionAlgorithm.uri.length > 0)) {
        padSize = decodePadding(channel, cryptoModule, chunk, sigsize);
        UA_LOG_TRACE_CHANNEL(channel->securityPolicy->logger, channel,
                             "Calculated padding size to be %lu",
                             (long unsigned)padSize);
    }

    /* Verify the content length. The encrypted payload has to be at least 9
     * bytes long: 8 byte for the SequenceHeader and one byte for the actual
     * message */
    UA_CHECK(offset + padSize + sigsize + 9 < chunk->length,
             UA_LOG_WARNING_CHANNEL(channel->securityPolicy->logger, channel,
                                    "Impossible padding value");
             return UA_STATUSCODE_BADSECURITYCHECKSFAILED);

    /* Hide the signature and padding */
    chunk->length -= (sigsize + padSize);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
checkAsymHeader(UA_SecureChannel *channel,
                const UA_AsymmetricAlgorithmSecurityHeader *asymHeader) {
    const UA_SecurityPolicy *sp = channel->securityPolicy;
    if(!UA_ByteString_equal(&sp->policyUri, &asymHeader->securityPolicyUri))
        return UA_STATUSCODE_BADSECURITYPOLICYREJECTED;

    return sp->asymmetricModule.
        compareCertificateThumbprint(sp, &asymHeader->receiverCertificateThumbprint);

    /* The certificate in the header is verified via the configured PKI plugin
     * as certificateVerification.verifyCertificate(...). We cannot do it here
     * because the client/server context is needed. */
}

UA_StatusCode
checkSymHeader(UA_SecureChannel *channel, const UA_UInt32 tokenId,
               UA_DateTime nowMonotonic) {
    /* If no match, try to revolve to the next token after a
     * RenewSecureChannel */
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    UA_ChannelSecurityToken *token = &channel->securityToken;
    switch(channel->renewState) {
    case UA_SECURECHANNELRENEWSTATE_NORMAL:
    case UA_SECURECHANNELRENEWSTATE_SENT:
    default:
        break;

    case UA_SECURECHANNELRENEWSTATE_NEWTOKEN_SERVER:
        /* Old token still in use */
        if(tokenId == channel->securityToken.tokenId)
            break;

        /* Not the new token */
        UA_CHECK(tokenId == channel->altSecurityToken.tokenId,
                 UA_LOG_WARNING_CHANNEL(channel->securityPolicy->logger, channel,
                                        "Unknown SecurityToken");
                 return UA_STATUSCODE_BADSECURECHANNELTOKENUNKNOWN);

        /* Roll over to the new token, generate new local and remote keys */
        channel->renewState = UA_SECURECHANNELRENEWSTATE_NORMAL;
        channel->securityToken = channel->altSecurityToken;
        UA_ChannelSecurityToken_init(&channel->altSecurityToken);
        retval |= UA_SecureChannel_generateLocalKeys(channel);
        retval |= generateRemoteKeys(channel);
        UA_CHECK_STATUS(retval, return retval);
        break;

    case UA_SECURECHANNELRENEWSTATE_NEWTOKEN_CLIENT:
        /* The server is still using the old token. That's okay. */
        if(tokenId == channel->altSecurityToken.tokenId) {
            token = &channel->altSecurityToken;
            break;
        }

        /* Not the new token */
        UA_CHECK(tokenId == channel->securityToken.tokenId,
                 UA_LOG_WARNING_CHANNEL(channel->securityPolicy->logger, channel,
                                        "Unknown SecurityToken");
                 return UA_STATUSCODE_BADSECURECHANNELTOKENUNKNOWN);

        /* The remote server uses the new token for the first time. Delete the
         * old token and roll the remote key over. The local key already uses
         * the nonce pair from the last OPN exchange. */
        channel->renewState = UA_SECURECHANNELRENEWSTATE_NORMAL;
        UA_ChannelSecurityToken_init(&channel->altSecurityToken);
        retval = generateRemoteKeys(channel);
        UA_CHECK_STATUS(retval, return retval);
    }

    UA_DateTime timeout = token->createdAt + (token->revisedLifetime * UA_DATETIME_MSEC);
    if(channel->state == UA_SECURECHANNELSTATE_OPEN &&
       timeout < nowMonotonic) {
        UA_LOG_WARNING_CHANNEL(channel->securityPolicy->logger, channel,
                               "SecurityToken timed out");
        UA_SecureChannel_shutdown(channel, UA_SHUTDOWNREASON_TIMEOUT);
        return UA_STATUSCODE_BADSECURECHANNELCLOSED;
    }

    return UA_STATUSCODE_GOOD;
}

UA_Boolean
UA_SecureChannel_checkTimeout(UA_SecureChannel *channel, UA_DateTime nowMonotonic) {
    /* Compute the timeout date of the SecurityToken */
    UA_DateTime timeout = channel->securityToken.createdAt +
        (UA_DateTime)(channel->securityToken.revisedLifetime * UA_DATETIME_MSEC);

    /* The token has timed out. Try to do the token revolving now instead of
     * shutting the channel down.
     *
     * Part 4, 5.5.2 says: Servers shall use the existing SecurityToken to
     * secure outgoing Messages until the SecurityToken expires or the
     * Server receives a Message secured with a new SecurityToken.*/
    if(timeout < nowMonotonic && channel->renewState == UA_SECURECHANNELRENEWSTATE_NEWTOKEN_SERVER) {
        /* Revolve the token manually. This is otherwise done in checkSymHeader. */
        channel->renewState = UA_SECURECHANNELRENEWSTATE_NORMAL;
        channel->securityToken = channel->altSecurityToken;
        UA_ChannelSecurityToken_init(&channel->altSecurityToken);
        UA_SecureChannel_generateLocalKeys(channel);
        generateRemoteKeys(channel);

        /* Use the timeout of the new SecurityToken */
        timeout = channel->securityToken.createdAt +
            (UA_DateTime)(channel->securityToken.revisedLifetime * UA_DATETIME_MSEC);
    }

    return (timeout < nowMonotonic);
}

/**** amalgamated original file "/src/server/ua_session.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2018 (c) Thomas Stalder, Blue Time Concept SA
 *    Copyright 2019 (c) HMS Industrial Networks AB (Author: Jonas Green)
 */

#ifdef UA_ENABLE_SUBSCRIPTIONS
#endif

#define UA_SESSION_NONCELENTH 32

void UA_Session_init(UA_Session *session) {
    memset(session, 0, sizeof(UA_Session));
    session->availableContinuationPoints = UA_MAXCONTINUATIONPOINTS;
#ifdef UA_ENABLE_SUBSCRIPTIONS
    SIMPLEQ_INIT(&session->responseQueue);
    TAILQ_INIT(&session->subscriptions);
#endif
}

void UA_Session_clear(UA_Session *session, UA_Server* server) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Remove all Subscriptions. This may send out remaining publish
     * responses. */
#ifdef UA_ENABLE_SUBSCRIPTIONS
    UA_Subscription *sub, *tempsub;
    TAILQ_FOREACH_SAFE(sub, &session->subscriptions, sessionListEntry, tempsub) {
        UA_Subscription_delete(server, sub);
    }
#endif

#ifdef UA_ENABLE_DIAGNOSTICS
    deleteNode(server, session->sessionId, true);
#endif

    UA_Session_detachFromSecureChannel(session);
    UA_ApplicationDescription_clear(&session->clientDescription);
    UA_NodeId_clear(&session->authenticationToken);
    UA_String_clear(&session->clientUserIdOfSession);
    UA_NodeId_clear(&session->sessionId);
    UA_String_clear(&session->sessionName);
    UA_ByteString_clear(&session->serverNonce);
    struct ContinuationPoint *cp, *next = session->continuationPoints;
    while((cp = next)) {
        next = ContinuationPoint_clear(cp);
        UA_free(cp);
    }
    session->continuationPoints = NULL;
    session->availableContinuationPoints = UA_MAXCONTINUATIONPOINTS;

    UA_KeyValueMap_delete(session->attributes);
    session->attributes = NULL;

    UA_Array_delete(session->localeIds, session->localeIdsSize,
                    &UA_TYPES[UA_TYPES_STRING]);
    session->localeIds = NULL;
    session->localeIdsSize = 0;

#ifdef UA_ENABLE_DIAGNOSTICS
    UA_SessionDiagnosticsDataType_clear(&session->diagnostics);
    UA_SessionSecurityDiagnosticsDataType_clear(&session->securityDiagnostics);
#endif
}

void
UA_Session_attachToSecureChannel(UA_Session *session, UA_SecureChannel *channel) {
    /* Ensure the Session is not attached to another SecureChannel */
    UA_Session_detachFromSecureChannel(session);

    /* Add to singly-linked list */
    session->next = channel->sessions;
    channel->sessions = session;

    /* Add backpointer */
    session->channel = channel;
}

void
UA_Session_detachFromSecureChannel(UA_Session *session) {
    /* Clean up the response queue. Their RequestId is bound to the
     * SecureChannel so they cannot be reused. */
#ifdef UA_ENABLE_SUBSCRIPTIONS
    UA_PublishResponseEntry *pre;
    while((pre = UA_Session_dequeuePublishReq(session))) {
        UA_PublishResponse_clear(&pre->response);
        UA_free(pre);
    }
#endif

    /* Remove from singly-linked list */
    UA_SecureChannel *channel = session->channel;
    if(!channel)
        return;

    if(channel->sessions == session) {
        channel->sessions = session->next;
    } else {
        UA_Session *elm =  channel->sessions;
        while(elm->next != session)
            elm = elm->next;
        elm->next = session->next;
    }

    /* Reset the backpointer */
    session->channel = NULL;
}

UA_StatusCode
UA_Session_generateNonce(UA_Session *session) {
    UA_SecureChannel *channel = session->channel;
    if(!channel || !channel->securityPolicy)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Is the length of the previous nonce correct? */
    if(session->serverNonce.length != UA_SESSION_NONCELENTH) {
        UA_ByteString_clear(&session->serverNonce);
        UA_StatusCode retval =
            UA_ByteString_allocBuffer(&session->serverNonce, UA_SESSION_NONCELENTH);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
    }

    return channel->securityPolicy->symmetricModule.
        generateNonce(channel->securityPolicy->policyContext, &session->serverNonce);
}

void
UA_Session_updateLifetime(UA_Session *session, UA_DateTime now,
                          UA_DateTime nowMonotonic) {
    session->validTill = nowMonotonic +
        (UA_DateTime)(session->timeout * UA_DATETIME_MSEC);
#ifdef UA_ENABLE_DIAGNOSTICS
    session->diagnostics.clientLastContactTime = now;
#endif
}

#ifdef UA_ENABLE_SUBSCRIPTIONS

void
UA_Session_attachSubscription(UA_Session *session, UA_Subscription *sub) {
    /* Attach to the session */
    sub->session = session;

    /* Increase the count */
    session->subscriptionsSize++;

    /* Increase the number of outstanding retransmissions */
    session->totalRetransmissionQueueSize += sub->retransmissionQueueSize;

    /* Insert at the end of the subscriptions of the same priority / just before
     * the subscriptions with the next lower priority. */
    UA_Subscription *after = NULL;
    TAILQ_FOREACH(after, &session->subscriptions, sessionListEntry) {
        if(after->priority < sub->priority) {
            TAILQ_INSERT_BEFORE(after, sub, sessionListEntry);
            return;
        }
    }
    TAILQ_INSERT_TAIL(&session->subscriptions, sub, sessionListEntry);
}

void
UA_Session_detachSubscription(UA_Server *server, UA_Session *session,
                              UA_Subscription *sub, UA_Boolean releasePublishResponses) {
    /* Detach from the session */
    sub->session = NULL;
    TAILQ_REMOVE(&session->subscriptions, sub, sessionListEntry);

    /* Reduce the count */
    UA_assert(session->subscriptionsSize > 0);
    session->subscriptionsSize--;

    /* Reduce the number of outstanding retransmissions */
    session->totalRetransmissionQueueSize -= sub->retransmissionQueueSize;

    /* Send remaining publish responses if the last subscription was removed */
    if(!releasePublishResponses || !TAILQ_EMPTY(&session->subscriptions))
        return;
    UA_PublishResponseEntry *pre;
    while((pre = UA_Session_dequeuePublishReq(session))) {
        UA_PublishResponse *response = &pre->response;
        response->responseHeader.serviceResult = UA_STATUSCODE_BADNOSUBSCRIPTION;
        sendResponse(server, session->channel, pre->requestId,
                     (UA_Response*)response, &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]);
        UA_PublishResponse_clear(response);
        UA_free(pre);
    }
}

UA_Subscription *
UA_Session_getSubscriptionById(UA_Session *session, UA_UInt32 subscriptionId) {
    UA_Subscription *sub;
    TAILQ_FOREACH(sub, &session->subscriptions, sessionListEntry) {
        /* Prevent lookup of subscriptions that are to be deleted with a statuschange */
        if(sub->statusChange != UA_STATUSCODE_GOOD)
            continue;
        if(sub->subscriptionId == subscriptionId)
            break;
    }
    return sub;
}

UA_Subscription *
getSubscriptionById(UA_Server *server, UA_UInt32 subscriptionId) {
    UA_Subscription *sub;
    LIST_FOREACH(sub, &server->subscriptions, serverListEntry) {
        /* Prevent lookup of subscriptions that are to be deleted with a statuschange */
        if(sub->statusChange != UA_STATUSCODE_GOOD)
            continue;
        if(sub->subscriptionId == subscriptionId)
            break;
    }
    return sub;
}

UA_PublishResponseEntry*
UA_Session_dequeuePublishReq(UA_Session *session) {
    UA_PublishResponseEntry *entry = SIMPLEQ_FIRST(&session->responseQueue);
    if(entry) {
        SIMPLEQ_REMOVE_HEAD(&session->responseQueue, listEntry);
        session->responseQueueSize--;
    }
    return entry;
}

void
UA_Session_queuePublishReq(UA_Session *session, UA_PublishResponseEntry* entry,
                           UA_Boolean head) {
    if(!head)
        SIMPLEQ_INSERT_TAIL(&session->responseQueue, entry, listEntry);
    else
        SIMPLEQ_INSERT_HEAD(&session->responseQueue, entry, listEntry);
    session->responseQueueSize++;
}

#endif

/* Session Handling */

UA_StatusCode
UA_Server_closeSession(UA_Server *server, const UA_NodeId *sessionId) {
    UA_LOCK(&server->serviceMutex);
    session_list_entry *entry;
    UA_StatusCode res = UA_STATUSCODE_BADSESSIONIDINVALID;
    LIST_FOREACH(entry, &server->sessions, pointers) {
        if(UA_NodeId_equal(&entry->session.sessionId, sessionId)) {
            UA_Server_removeSession(server, entry, UA_SHUTDOWNREASON_CLOSE);
            res = UA_STATUSCODE_GOOD;
            break;
        }
    }
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

/* Session Attributes */

#define UA_PROTECTEDATTRIBUTESSIZE 4
static const UA_QualifiedName protectedAttributes[UA_PROTECTEDATTRIBUTESSIZE] = {
    {0, UA_STRING_STATIC("localeIds")},
    {0, UA_STRING_STATIC("clientDescription")},
    {0, UA_STRING_STATIC("sessionName")},
    {0, UA_STRING_STATIC("clientUserId")}
};

static UA_Boolean
protectedAttribute(const UA_QualifiedName key) {
    for(size_t i = 0; i < UA_PROTECTEDATTRIBUTESSIZE; i++) {
        if(UA_QualifiedName_equal(&key, &protectedAttributes[i]))
            return true;
    }
    return false;
}

UA_StatusCode
UA_Server_setSessionAttribute(UA_Server *server, const UA_NodeId *sessionId,
                              const UA_QualifiedName key, const UA_Variant *value) {
    if(protectedAttribute(key))
        return UA_STATUSCODE_BADNOTWRITABLE;
    UA_LOCK(&server->serviceMutex);
    UA_Session *session = getSessionById(server, sessionId);
    UA_StatusCode res = UA_STATUSCODE_BADSESSIONIDINVALID;
    if(session)
        res = UA_KeyValueMap_set(session->attributes,
                                 key, value);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_Server_deleteSessionAttribute(UA_Server *server, const UA_NodeId *sessionId,
                                 const UA_QualifiedName key) {
    if(protectedAttribute(key))
        return UA_STATUSCODE_BADNOTWRITABLE;
    UA_LOCK(&server->serviceMutex);
    UA_Session *session = getSessionById(server, sessionId);
    if(!session) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADSESSIONIDINVALID;
    }
    UA_StatusCode res =
        UA_KeyValueMap_remove(session->attributes, key);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

static UA_StatusCode
getSessionAttribute(UA_Server *server, const UA_NodeId *sessionId,
                    const UA_QualifiedName key, UA_Variant *outValue,
                    UA_Boolean copy) {
    if(!outValue)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_Session *session = getSessionById(server, sessionId);
    if(!session)
        return UA_STATUSCODE_BADSESSIONIDINVALID;

    const UA_Variant *attr;
    UA_Variant localAttr;

    if(UA_QualifiedName_equal(&key, &protectedAttributes[0])) {
        /* Return LocaleIds */
        UA_Variant_setArray(&localAttr, session->localeIds,
                            session->localeIdsSize, &UA_TYPES[UA_TYPES_STRING]);
        attr = &localAttr;
    } else if(UA_QualifiedName_equal(&key, &protectedAttributes[1])) {
        /* Return client description */
        UA_Variant_setScalar(&localAttr, &session->clientDescription,
                             &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION]);
        attr = &localAttr;
    } else if(UA_QualifiedName_equal(&key, &protectedAttributes[2])) {
        /* Return session name */
        UA_Variant_setScalar(&localAttr, &session->sessionName,
                             &UA_TYPES[UA_TYPES_STRING]);
        attr = &localAttr;
    } else if(UA_QualifiedName_equal(&key, &protectedAttributes[3])) {
        /* Return client user id */
        UA_Variant_setScalar(&localAttr, &session->clientUserIdOfSession,
                             &UA_TYPES[UA_TYPES_STRING]);
        attr = &localAttr;
    } else {
        /* Get from the actual key-value list */
        attr = UA_KeyValueMap_get(session->attributes, key);
        if(!attr)
            return UA_STATUSCODE_BADNOTFOUND;
    }

    if(copy)
        return UA_Variant_copy(attr, outValue);

    *outValue = *attr;
    outValue->storageType = UA_VARIANT_DATA_NODELETE;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_getSessionAttribute(UA_Server *server, const UA_NodeId *sessionId,
                              const UA_QualifiedName key, UA_Variant *outValue) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = getSessionAttribute(server, sessionId, key, outValue, false);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_Server_getSessionAttributeCopy(UA_Server *server, const UA_NodeId *sessionId,
                                  const UA_QualifiedName key, UA_Variant *outValue) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = getSessionAttribute(server, sessionId, key, outValue, true);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_Server_getSessionAttribute_scalar(UA_Server *server,
                                     const UA_NodeId *sessionId,
                                     const UA_QualifiedName key,
                                     const UA_DataType *type,
                                     void *outValue) {
    UA_LOCK(&server->serviceMutex);

    UA_Variant attr;
    UA_StatusCode res = getSessionAttribute(server, sessionId, key, &attr, false);
    if(res != UA_STATUSCODE_GOOD) {
        UA_UNLOCK(&server->serviceMutex);
        return res;
    }

    if(!UA_Variant_hasScalarType(&attr, type)) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADNOTFOUND;
    }

    memcpy(outValue, attr.data, type->memSize);

    UA_UNLOCK(&server->serviceMutex);
    return UA_STATUSCODE_GOOD;
}

/**** amalgamated original file "/src/server/ua_nodes.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2015-2018, 2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015, 2017 (c) Florian Palm
 *    Copyright 2015 (c) Oleksiy Vasylyev
 *    Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Julian Grothoff
 */


/*********************/
/* ReferenceType Set */
/*********************/

#define UA_REFTYPES_ALL_MASK (~(UA_UInt32)0)
#define UA_REFTYPES_ALL_MASK2 UA_REFTYPES_ALL_MASK, UA_REFTYPES_ALL_MASK
#define UA_REFTYPES_ALL_MASK4 UA_REFTYPES_ALL_MASK2, UA_REFTYPES_ALL_MASK2
#if (UA_REFERENCETYPESET_MAX) / 32 > 8
# error Adjust macros to support than 256 reference types
#elif (UA_REFERENCETYPESET_MAX) / 32 == 8
# define UA_REFTYPES_ALL_ARRAY UA_REFTYPES_ALL_MASK4, UA_REFTYPES_ALL_MASK4
#elif (UA_REFERENCETYPESET_MAX) / 32 == 7
# define UA_REFTYPES_ALL_ARRAY                                          \
    UA_REFTYPES_ALL_MASK4, UA_REFTYPES_ALL_MASK2, UA_REFTYPES_ALL_MASK
#elif (UA_REFERENCETYPESET_MAX) / 32 == 6
# define UA_REFTYPES_ALL_ARRAY UA_REFTYPES_ALL_MASK4, UA_REFTYPES_ALL_MASK2
#elif (UA_REFERENCETYPESET_MAX) / 32 == 5
# define UA_REFTYPES_ALL_ARRAY UA_REFTYPES_ALL_MASK4, UA_REFTYPES_ALL_MASK
#elif (UA_REFERENCETYPESET_MAX) / 32 == 4
# define UA_REFTYPES_ALL_ARRAY UA_REFTYPES_ALL_MASK4
#elif (UA_REFERENCETYPESET_MAX) / 32 == 3
# define UA_REFTYPES_ALL_ARRAY UA_REFTYPES_ALL_MASK2, UA_REFTYPES_ALL_MASK
#elif (UA_REFERENCETYPESET_MAX) / 32 == 2
# define UA_REFTYPES_ALL_ARRAY UA_REFTYPES_ALL_MASK2
#else
# define UA_REFTYPES_ALL_ARRAY UA_REFTYPES_ALL_MASK
#endif

const UA_ReferenceTypeSet UA_REFERENCETYPESET_NONE = {{0}};
const UA_ReferenceTypeSet UA_REFERENCETYPESET_ALL = {{UA_REFTYPES_ALL_ARRAY}};

/*****************/
/* Node Pointers */
/*****************/

#define UA_NODEPOINTER_MASK 0x03
#define UA_NODEPOINTER_TAG_IMMEDIATE 0x00
#define UA_NODEPOINTER_TAG_NODEID 0x01
#define UA_NODEPOINTER_TAG_EXPANDEDNODEID 0x02
#define UA_NODEPOINTER_TAG_NODE 0x03

void
UA_NodePointer_clear(UA_NodePointer *np) {
    switch(np->immediate & UA_NODEPOINTER_MASK) {
    case UA_NODEPOINTER_TAG_NODEID:
        np->immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK;
        UA_NodeId_delete((UA_NodeId*)(uintptr_t)np->id);
        break;
    case UA_NODEPOINTER_TAG_EXPANDEDNODEID:
        np->immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK;
        UA_ExpandedNodeId_delete((UA_ExpandedNodeId*)(uintptr_t)
                                 np->expandedId);
        break;
    default:
        break;
    }
    UA_NodePointer_init(np);
}

UA_StatusCode
UA_NodePointer_copy(UA_NodePointer in, UA_NodePointer *out) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    UA_Byte tag = in.immediate & UA_NODEPOINTER_MASK;
    in.immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK;
    switch(tag) {
    case UA_NODEPOINTER_TAG_NODE:
        in.id = &in.node->nodeId;
        goto nodeid; /* fallthrough */
    case UA_NODEPOINTER_TAG_NODEID:
    nodeid:
        out->id = UA_NodeId_new();
        if(!out->id)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        res = UA_NodeId_copy(in.id, (UA_NodeId*)(uintptr_t)out->id);
        if(res != UA_STATUSCODE_GOOD) {
            UA_free((void*)out->immediate);
            out->immediate = 0;
            break;
        }
        out->immediate |= UA_NODEPOINTER_TAG_NODEID;
        break;
    case UA_NODEPOINTER_TAG_EXPANDEDNODEID:
        out->expandedId = UA_ExpandedNodeId_new();
        if(!out->expandedId)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        res = UA_ExpandedNodeId_copy(in.expandedId,
                                     (UA_ExpandedNodeId*)(uintptr_t)
                                     out->expandedId);
        if(res != UA_STATUSCODE_GOOD) {
            UA_free((void*)out->immediate);
            out->immediate = 0;
            break;
        }
        out->immediate |= UA_NODEPOINTER_TAG_EXPANDEDNODEID;
        break;
    default:
    case UA_NODEPOINTER_TAG_IMMEDIATE:
        *out = in;
        break;
    }
    return res;
}

UA_Boolean
UA_NodePointer_isLocal(UA_NodePointer np) {
    UA_Byte tag = np.immediate & UA_NODEPOINTER_MASK;
    return (tag != UA_NODEPOINTER_TAG_EXPANDEDNODEID);
}

UA_Order
UA_NodePointer_order(UA_NodePointer p1, UA_NodePointer p2) {
    if(p1.immediate == p2.immediate)
        return UA_ORDER_EQ;

    /* Extract the tag and resolve pointers to nodes */
    UA_Byte tag1 = p1.immediate & UA_NODEPOINTER_MASK;
    if(tag1 == UA_NODEPOINTER_TAG_NODE) {
        p1 = UA_NodePointer_fromNodeId(&p1.node->nodeId);
        tag1 = p1.immediate & UA_NODEPOINTER_MASK;
    }
    UA_Byte tag2 = p2.immediate & UA_NODEPOINTER_MASK;
    if(tag2 == UA_NODEPOINTER_TAG_NODE) {
        p2 = UA_NodePointer_fromNodeId(&p2.node->nodeId);
        tag2 = p2.immediate & UA_NODEPOINTER_MASK;
    }

    /* Different tags, cannot be identical */
    if(tag1 != tag2)
        return (tag1 > tag2) ? UA_ORDER_MORE : UA_ORDER_LESS;

    /* Immediate */
    if(UA_LIKELY(tag1 == UA_NODEPOINTER_TAG_IMMEDIATE))
        return (p1.immediate > p2.immediate) ?
            UA_ORDER_MORE : UA_ORDER_LESS;

    /* Compare from pointers */
    p1.immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK;
    p2.immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK;
    if(tag1 == UA_NODEPOINTER_TAG_EXPANDEDNODEID)
        return UA_ExpandedNodeId_order(p1.expandedId, p2.expandedId);
    return UA_NodeId_order(p1.id, p2.id);
}

UA_NodePointer
UA_NodePointer_fromNodeId(const UA_NodeId *id) {
    UA_NodePointer np;
    if(id->identifierType != UA_NODEIDTYPE_NUMERIC) {
        np.id = id;
        np.immediate |= UA_NODEPOINTER_TAG_NODEID;
        return np;
    }

#if SIZE_MAX > UA_UINT32_MAX
    /* 64bit: 4 Byte for the numeric identifier + 2 Byte for the namespaceIndex
     *        + 1 Byte for the tagging bit (zero) */
    np.immediate  = ((uintptr_t)id->identifier.numeric) << 32;
    np.immediate |= ((uintptr_t)id->namespaceIndex) << 8;
#else
    /* 32bit: 3 Byte for the numeric identifier + 6 Bit for the namespaceIndex
     *        + 2 Bit for the tagging bit (zero) */
    if(id->namespaceIndex < (0x01 << 6) &&
       id->identifier.numeric < (0x01 << 24)) {
        np.immediate  = ((uintptr_t)id->identifier.numeric) << 8;
        np.immediate |= ((uintptr_t)id->namespaceIndex) << 2;
    } else {
        np.id = id;
        np.immediate |= UA_NODEPOINTER_TAG_NODEID;
    }
#endif
    return np;
}

UA_NodeId
UA_NodePointer_toNodeId(UA_NodePointer np) {
    UA_Byte tag = np.immediate & UA_NODEPOINTER_MASK;
    np.immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK;
    switch(tag) {
    case UA_NODEPOINTER_TAG_NODE:
        return np.node->nodeId;
    case UA_NODEPOINTER_TAG_NODEID:
        return *np.id;
    case UA_NODEPOINTER_TAG_EXPANDEDNODEID:
        return np.expandedId->nodeId;
    default:
    case UA_NODEPOINTER_TAG_IMMEDIATE:
        break;
    }

    UA_NodeId id;
    id.identifierType = UA_NODEIDTYPE_NUMERIC;
#if SIZE_MAX > UA_UINT32_MAX /* 64bit */
    id.namespaceIndex = (UA_UInt16)(np.immediate >> 8);
    id.identifier.numeric = (UA_UInt32)(np.immediate >> 32);
#else                        /* 32bit */
    id.namespaceIndex = ((UA_Byte)np.immediate) >> 2;
    id.identifier.numeric = np.immediate >> 8;
#endif
    return id;
}

UA_NodePointer
UA_NodePointer_fromExpandedNodeId(const UA_ExpandedNodeId *id) {
    if(!UA_ExpandedNodeId_isLocal(id)) {
        UA_NodePointer np;
        np.expandedId = id;
        np.immediate |= UA_NODEPOINTER_TAG_EXPANDEDNODEID;
        return np;
    }
    return UA_NodePointer_fromNodeId(&id->nodeId);
}

UA_ExpandedNodeId
UA_NodePointer_toExpandedNodeId(UA_NodePointer np) {
    /* Resolve node pointer to get the NodeId */
    UA_Byte tag = np.immediate & UA_NODEPOINTER_MASK;
    if(tag == UA_NODEPOINTER_TAG_NODE) {
        np = UA_NodePointer_fromNodeId(&np.node->nodeId);
        tag = np.immediate & UA_NODEPOINTER_MASK;
    }

    /* ExpandedNodeId, make a shallow copy */
    if(tag == UA_NODEPOINTER_TAG_EXPANDEDNODEID) {
        np.immediate &= ~(uintptr_t)UA_NODEPOINTER_MASK;
        return *np.expandedId;
    }

    /* NodeId, either immediate or via a pointer */
    UA_ExpandedNodeId en;
    UA_ExpandedNodeId_init(&en);
    en.nodeId = UA_NodePointer_toNodeId(np);
    return en;
}

/**************/
/* References */
/**************/

static UA_StatusCode
addReferenceTarget(UA_NodeReferenceKind *refs, UA_NodePointer target,
                   UA_UInt32 targetNameHash);

static UA_StatusCode
addReferenceTargetToTree(UA_NodeReferenceKind *rk, UA_NodePointer targetId,
                         UA_UInt32 targetIdHash, UA_UInt32 targetNameHash);

enum ZIP_CMP
cmpRefTargetId(const void *a, const void *b) {
    const UA_ReferenceTargetTreeElem *aa = (const UA_ReferenceTargetTreeElem*)a;
    const UA_ReferenceTargetTreeElem *bb = (const UA_ReferenceTargetTreeElem*)b;
    if(aa->targetIdHash < bb->targetIdHash)
        return ZIP_CMP_LESS;
    if(aa->targetIdHash > bb->targetIdHash)
        return ZIP_CMP_MORE;
    return (enum ZIP_CMP)UA_NodePointer_order(aa->target.targetId,
                                              bb->target.targetId);
}

enum ZIP_CMP
cmpRefTargetName(const void *a, const void *b) {
    const UA_ReferenceTargetTreeElem *aa = (const UA_ReferenceTargetTreeElem*)a;
    const UA_ReferenceTargetTreeElem *bb = (const UA_ReferenceTargetTreeElem*)b;
    if(aa->target.targetNameHash == bb->target.targetNameHash)
        return ZIP_CMP_EQ;
    return (aa->target.targetNameHash < bb->target.targetNameHash) ?
        ZIP_CMP_LESS : ZIP_CMP_MORE;
}

/* Move to the array in-order, also deletes the tree elements */
static void
moveTreeToArray(UA_ReferenceTarget *array, size_t *pos,
                UA_ReferenceTargetTreeElem *elem) {
    if(!elem)
        return;
    moveTreeToArray(array, pos, elem->idTreeEntry.left);
    array[*pos] = elem->target;
    (*pos)++;
    moveTreeToArray(array, pos, elem->idTreeEntry.right);
    UA_free(elem);
}

static void *
removeTreeEntry(void *context, UA_ReferenceTargetTreeElem *elem) {
    (void)context;
    UA_NodePointer_clear(&elem->target.targetId);
    UA_free(elem);
    return NULL;
}

UA_StatusCode
UA_NodeReferenceKind_switch(UA_NodeReferenceKind *rk) {
    UA_assert(rk->targetsSize > 0);

    if(rk->hasRefTree) {
        /* From tree to array */
        UA_ReferenceTarget *array = (UA_ReferenceTarget*)
            UA_malloc(sizeof(UA_ReferenceTarget) * rk->targetsSize);
        if(!array)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        size_t pos = 0;
        moveTreeToArray(array, &pos, rk->targets.tree.idRoot);
        rk->targets.array = array;
        rk->hasRefTree = false;
        return UA_STATUSCODE_GOOD;
    }

    /* From array to tree */
    UA_NodeReferenceKind newRk = *rk;
    newRk.hasRefTree = true;
    newRk.targets.tree.idRoot = NULL;
    newRk.targets.tree.nameRoot = NULL;
    newRk.targetsSize = 0;
    for(size_t i = 0; i < rk->targetsSize; i++) {
        UA_StatusCode res =
            addReferenceTarget(&newRk, rk->targets.array[i].targetId,
                               rk->targets.array[i].targetNameHash);
        if(res != UA_STATUSCODE_GOOD) {
            ZIP_ITER(UA_ReferenceIdTree,
                     (UA_ReferenceIdTree*)&newRk.targets.tree.idRoot,
                     removeTreeEntry, NULL);
            return res;
        }
    }
    for(size_t i = 0; i < rk->targetsSize; i++)
        UA_NodePointer_clear(&rk->targets.array[i].targetId);
    UA_free(rk->targets.array);
    *rk = newRk;
    return UA_STATUSCODE_GOOD;
}

void *
UA_NodeReferenceKind_iterate(UA_NodeReferenceKind *rk,
                             UA_NodeReferenceKind_iterateCallback callback,
                             void *context) {
    if(rk->hasRefTree)
        return ZIP_ITER(UA_ReferenceIdTree,
                        (UA_ReferenceIdTree*)&rk->targets.tree.idRoot,
                        (UA_ReferenceIdTree_cb)callback, context);
    for(size_t i = 0; i < rk->targetsSize; i++) {
        void *res = callback(context, &rk->targets.array[i]);
        if(res)
            return res;
    }
    return NULL;
}

const UA_ReferenceTarget *
UA_NodeReferenceKind_findTarget(const UA_NodeReferenceKind *rk,
                                const UA_ExpandedNodeId *targetId) {
    UA_NodePointer targetP = UA_NodePointer_fromExpandedNodeId(targetId);
    if(rk->hasRefTree) {
        /* Return from the tree */
        UA_ReferenceTargetTreeElem tmpTarget;
        tmpTarget.target.targetId = targetP;
        tmpTarget.targetIdHash = UA_ExpandedNodeId_hash(targetId);
        UA_ReferenceTargetTreeElem *result =
            ZIP_FIND(UA_ReferenceIdTree, (UA_ReferenceIdTree*)
                     (uintptr_t)&rk->targets.tree.idRoot, &tmpTarget);
        if(result)
            return &result->target;
    } else {
        /* Return from the array */
        for(size_t i = 0; i < rk->targetsSize; i++) {
            if(UA_NodePointer_equal(targetP, rk->targets.array[i].targetId))
                return &rk->targets.array[i];
        }
    }
    return NULL;
}

/* General node handling methods. There is no UA_Node_new() method here.
 * Creating nodes is part of the Nodestore layer */

void UA_Node_clear(UA_Node *node) {
    /* Delete references */
    UA_Node_deleteReferences(node);

    /* Delete other head content */
    UA_NodeHead *head = &node->head;
    UA_NodeId_clear(&head->nodeId);
    UA_QualifiedName_clear(&head->browseName);

    UA_LocalizedTextListEntry *lt;

    while((lt = head->displayName)) {
        head->displayName = lt->next;
        UA_LocalizedText_clear(&lt->localizedText);
        UA_free(lt);
    }

    while((lt = head->description)) {
        head->description = lt->next;
        UA_LocalizedText_clear(&lt->localizedText);
        UA_free(lt);
    }

    /* Delete unique content of the nodeclass */
    switch(head->nodeClass) {
    case UA_NODECLASS_OBJECT:
        break;
    case UA_NODECLASS_METHOD:
        break;
    case UA_NODECLASS_OBJECTTYPE:
        break;
    case UA_NODECLASS_VARIABLE:
    case UA_NODECLASS_VARIABLETYPE: {
        UA_VariableNode *p = &node->variableNode;
        UA_NodeId_clear(&p->dataType);
        UA_Array_delete(p->arrayDimensions, p->arrayDimensionsSize,
                        &UA_TYPES[UA_TYPES_INT32]);
        p->arrayDimensions = NULL;
        p->arrayDimensionsSize = 0;
        if(p->valueSource == UA_VALUESOURCE_DATA)
            UA_DataValue_clear(&p->value.data.value);
        break;
    }
    case UA_NODECLASS_REFERENCETYPE: {
        UA_ReferenceTypeNode *p = &node->referenceTypeNode;
        UA_LocalizedText_clear(&p->inverseName);
        break;
    }
    case UA_NODECLASS_DATATYPE:
        break;
    case UA_NODECLASS_VIEW:
        break;
    default:
        break;
    }
}

static UA_StatusCode
UA_ObjectNode_copy(const UA_ObjectNode *src, UA_ObjectNode *dst) {
    dst->eventNotifier = src->eventNotifier;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_CommonVariableNode_copy(const UA_VariableNode *src, UA_VariableNode *dst) {
    UA_StatusCode retval =
        UA_Array_copy(src->arrayDimensions, src->arrayDimensionsSize,
                      (void**)&dst->arrayDimensions, &UA_TYPES[UA_TYPES_INT32]);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    dst->arrayDimensionsSize = src->arrayDimensionsSize;
    retval = UA_NodeId_copy(&src->dataType, &dst->dataType);
    dst->valueRank = src->valueRank;
    dst->valueBackend = src->valueBackend;
    dst->valueSource = src->valueSource;
    if(src->valueSource == UA_VALUESOURCE_DATA) {
        retval |= UA_DataValue_copy(&src->value.data.value,
                                    &dst->value.data.value);
        dst->value.data.callback = src->value.data.callback;
    } else {
        dst->value.dataSource = src->value.dataSource;
    }
    return retval;
}

static UA_StatusCode
UA_VariableNode_copy(const UA_VariableNode *src, UA_VariableNode *dst) {
    dst->accessLevel = src->accessLevel;
    dst->minimumSamplingInterval = src->minimumSamplingInterval;
    dst->historizing = src->historizing;
    dst->isDynamic = src->isDynamic;
    return UA_CommonVariableNode_copy(src, dst);
}

static UA_StatusCode
UA_VariableTypeNode_copy(const UA_VariableTypeNode *src,
                         UA_VariableTypeNode *dst) {
    dst->isAbstract = src->isAbstract;
    return UA_CommonVariableNode_copy((const UA_VariableNode*)src, (UA_VariableNode*)dst);
}

static UA_StatusCode
UA_MethodNode_copy(const UA_MethodNode *src, UA_MethodNode *dst) {
    dst->executable = src->executable;
    dst->method = src->method;
#if UA_MULTITHREADING >= 100
    dst->async = src->async;
#endif
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_ObjectTypeNode_copy(const UA_ObjectTypeNode *src, UA_ObjectTypeNode *dst) {
    dst->isAbstract = src->isAbstract;
    dst->lifecycle = src->lifecycle;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_ReferenceTypeNode_copy(const UA_ReferenceTypeNode *src,
                          UA_ReferenceTypeNode *dst) {
    dst->isAbstract = src->isAbstract;
    dst->symmetric = src->symmetric;
    dst->referenceTypeIndex = src->referenceTypeIndex;
    dst->subTypes = src->subTypes;
    return UA_LocalizedText_copy(&src->inverseName, &dst->inverseName);
}

static UA_StatusCode
UA_DataTypeNode_copy(const UA_DataTypeNode *src, UA_DataTypeNode *dst) {
    dst->isAbstract = src->isAbstract;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_ViewNode_copy(const UA_ViewNode *src, UA_ViewNode *dst) {
    dst->containsNoLoops = src->containsNoLoops;
    dst->eventNotifier = src->eventNotifier;
    return UA_STATUSCODE_GOOD;
}

static void *
copyTarget(void *context, UA_ReferenceTargetTreeElem *elm) {
    UA_NodeReferenceKind *drefs = (UA_NodeReferenceKind*)context;
    return (void*)(uintptr_t)
        addReferenceTargetToTree(drefs, elm->target.targetId,
                                 elm->targetIdHash,
                                 elm->target.targetNameHash);
}

UA_StatusCode
UA_Node_copy(const UA_Node *src, UA_Node *dst) {
    const UA_NodeHead *srchead = &src->head;
    UA_NodeHead *dsthead = &dst->head;
    if(srchead->nodeClass != dsthead->nodeClass)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Copy standard content */
    UA_StatusCode retval = UA_NodeId_copy(&srchead->nodeId, &dsthead->nodeId);
    retval |= UA_QualifiedName_copy(&srchead->browseName, &dsthead->browseName);

    /* Copy the display name in several languages */
    for(UA_LocalizedTextListEntry *lt = srchead->displayName; lt != NULL; lt = lt->next) {
        UA_LocalizedTextListEntry *newEntry = (UA_LocalizedTextListEntry *)
            UA_calloc(1, sizeof(UA_LocalizedTextListEntry));
        if(!newEntry) {
            retval |= UA_STATUSCODE_BADOUTOFMEMORY;
            break;
        }
        retval |= UA_LocalizedText_copy(&lt->localizedText, &newEntry->localizedText);

        /* Add to the linked list possibly in reverse order */
        newEntry->next = dsthead->displayName;
        dsthead->displayName = newEntry;
    }

    /* Copy the description in several languages */
    for(UA_LocalizedTextListEntry *lt = srchead->description; lt != NULL; lt = lt->next) {
        UA_LocalizedTextListEntry *newEntry = (UA_LocalizedTextListEntry *)
            UA_calloc(1, sizeof(UA_LocalizedTextListEntry));
        if(!newEntry) {
            retval |= UA_STATUSCODE_BADOUTOFMEMORY;
            break;
        }
        retval |= UA_LocalizedText_copy(&lt->localizedText, &newEntry->localizedText);

        /* Add to the linked list possibly in reverse order */
        newEntry->next = dsthead->description;
        dsthead->description= newEntry;
    }

    dsthead->writeMask = srchead->writeMask;
    dsthead->context = srchead->context;
    dsthead->constructed = srchead->constructed;
#ifdef UA_ENABLE_SUBSCRIPTIONS
    dsthead->monitoredItems = srchead->monitoredItems;
#endif
    if(retval != UA_STATUSCODE_GOOD) {
        UA_Node_clear(dst);
        return retval;
    }

    /* Copy the references */
    dsthead->references = NULL;
    if(srchead->referencesSize > 0) {
        dsthead->references = (UA_NodeReferenceKind*)
            UA_calloc(srchead->referencesSize, sizeof(UA_NodeReferenceKind));
        if(!dsthead->references) {
            UA_Node_clear(dst);
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }
        dsthead->referencesSize = srchead->referencesSize;

        for(size_t i = 0; i < srchead->referencesSize; ++i) {
            UA_NodeReferenceKind *srefs = &srchead->references[i];
            UA_NodeReferenceKind *drefs = &dsthead->references[i];
            drefs->referenceTypeIndex = srefs->referenceTypeIndex;
            drefs->isInverse = srefs->isInverse;
            drefs->hasRefTree = srefs->hasRefTree; /* initially empty */

            /* Copy all the targets */
            if(!srefs->hasRefTree) {
                drefs->targets.array = (UA_ReferenceTarget*)
                    UA_malloc(sizeof(UA_ReferenceTarget) * srefs->targetsSize);
                if(!drefs->targets.array) {
                    UA_Node_clear(dst);
                    return UA_STATUSCODE_BADOUTOFMEMORY;
                }
                for(size_t j = 0; j < srefs->targetsSize; j++) {
                    drefs->targets.array[j].targetNameHash =
                        srefs->targets.array[j].targetNameHash;
                    retval = UA_NodePointer_copy(srefs->targets.array[j].targetId,
                                                 &drefs->targets.array[j].targetId);
                    drefs->targetsSize++; /* avoid that targetsSize == 0 in error case */
                    if(retval != UA_STATUSCODE_GOOD) {
                        UA_Node_clear(dst);
                        return retval;
                    }
                }
            } else {
                void *res = ZIP_ITER(UA_ReferenceIdTree,
                                     (UA_ReferenceIdTree*)&srefs->targets.tree.idRoot,
                                     copyTarget, drefs);
                if(res != NULL) {
                    UA_Node_clear(dst);
                    return (UA_StatusCode)(uintptr_t)res;
                }
            }

            UA_assert(srefs->targetsSize > 0);
            UA_assert(srefs->targetsSize == drefs->targetsSize);
        }
    }

    /* Copy unique content of the nodeclass */
    switch(src->head.nodeClass) {
    case UA_NODECLASS_OBJECT:
        retval = UA_ObjectNode_copy(&src->objectNode, &dst->objectNode);
        break;
    case UA_NODECLASS_VARIABLE:
        retval = UA_VariableNode_copy(&src->variableNode, &dst->variableNode);
        break;
    case UA_NODECLASS_METHOD:
        retval = UA_MethodNode_copy(&src->methodNode, &dst->methodNode);
        break;
    case UA_NODECLASS_OBJECTTYPE:
        retval = UA_ObjectTypeNode_copy(&src->objectTypeNode, &dst->objectTypeNode);
        break;
    case UA_NODECLASS_VARIABLETYPE:
        retval = UA_VariableTypeNode_copy(&src->variableTypeNode, &dst->variableTypeNode);
        break;
    case UA_NODECLASS_REFERENCETYPE:
        retval = UA_ReferenceTypeNode_copy(&src->referenceTypeNode, &dst->referenceTypeNode);
        break;
    case UA_NODECLASS_DATATYPE:
        retval = UA_DataTypeNode_copy(&src->dataTypeNode, &dst->dataTypeNode);
        break;
    case UA_NODECLASS_VIEW:
        retval = UA_ViewNode_copy(&src->viewNode, &dst->viewNode);
        break;
    default:
        break;
    }

    if(retval != UA_STATUSCODE_GOOD)
        UA_Node_clear(dst);

    return retval;
}

UA_Node *
UA_Node_copy_alloc(const UA_Node *src) {
    size_t nodesize = 0;
    switch(src->head.nodeClass) {
        case UA_NODECLASS_OBJECT:
            nodesize = sizeof(UA_ObjectNode);
            break;
        case UA_NODECLASS_VARIABLE:
            nodesize = sizeof(UA_VariableNode);
            break;
        case UA_NODECLASS_METHOD:
            nodesize = sizeof(UA_MethodNode);
            break;
        case UA_NODECLASS_OBJECTTYPE:
            nodesize = sizeof(UA_ObjectTypeNode);
            break;
        case UA_NODECLASS_VARIABLETYPE:
            nodesize = sizeof(UA_VariableTypeNode);
            break;
        case UA_NODECLASS_REFERENCETYPE:
            nodesize = sizeof(UA_ReferenceTypeNode);
            break;
        case UA_NODECLASS_DATATYPE:
            nodesize = sizeof(UA_DataTypeNode);
            break;
        case UA_NODECLASS_VIEW:
            nodesize = sizeof(UA_ViewNode);
            break;
        default:
            return NULL;
    }

    UA_Node *dst = (UA_Node*)UA_calloc(1, nodesize);
    if(!dst)
        return NULL;

    dst->head.nodeClass = src->head.nodeClass;

    UA_StatusCode retval = UA_Node_copy(src, dst);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free(dst);
        return NULL;
    }
    return dst;
}
/******************************/
/* Copy Attributes into Nodes */
/******************************/

static UA_StatusCode
copyStandardAttributes(UA_NodeHead *head, const UA_NodeAttributes *attr) {
    /* UA_NodeId_copy(&item->requestedNewNodeId.nodeId, &node->nodeId); */
    /* UA_QualifiedName_copy(&item->browseName, &node->browseName); */

    head->writeMask = attr->writeMask;
    UA_StatusCode retval = UA_Node_insertOrUpdateDescription(head, &attr->description);
    /* The new nodeset format has optional display names:
     * https://github.com/open62541/open62541/issues/2627. If the display name
     * is NULL, take the name part of the browse name */
    if(attr->displayName.text.length == 0) {
        UA_LocalizedText lt;
        UA_LocalizedText_init(&lt);
        lt.text = head->browseName.name;
        retval |= UA_Node_insertOrUpdateDisplayName(head, &lt);
    } else
        retval |= UA_Node_insertOrUpdateDisplayName(head, &attr->displayName);
    return retval;
}

static UA_StatusCode
copyCommonVariableAttributes(UA_VariableNode *node,
                             const UA_VariableAttributes *attr) {
    /* Copy the array dimensions */
    UA_StatusCode retval =
        UA_Array_copy(attr->arrayDimensions, attr->arrayDimensionsSize,
                      (void**)&node->arrayDimensions, &UA_TYPES[UA_TYPES_UINT32]);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    node->arrayDimensionsSize = attr->arrayDimensionsSize;

    /* Data type and value rank */
    retval = UA_NodeId_copy(&attr->dataType, &node->dataType);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    node->valueRank = attr->valueRank;

    /* Copy the value */
    retval = UA_Variant_copy(&attr->value, &node->value.data.value.value);
    node->valueSource = UA_VALUESOURCE_DATA;
    node->value.data.value.hasValue = (node->value.data.value.value.type != NULL);

    return retval;
}

static UA_StatusCode
copyVariableNodeAttributes(UA_VariableNode *vnode,
                           const UA_VariableAttributes *attr) {
    vnode->accessLevel = attr->accessLevel;
    vnode->historizing = attr->historizing;
    vnode->minimumSamplingInterval = attr->minimumSamplingInterval;
    return copyCommonVariableAttributes(vnode, attr);
}

static UA_StatusCode
copyVariableTypeNodeAttributes(UA_VariableTypeNode *vtnode,
                               const UA_VariableTypeAttributes *attr) {
    vtnode->isAbstract = attr->isAbstract;
    return copyCommonVariableAttributes((UA_VariableNode*)vtnode,
                                        (const UA_VariableAttributes*)attr);
}

static UA_StatusCode
copyObjectNodeAttributes(UA_ObjectNode *onode, const UA_ObjectAttributes *attr) {
    onode->eventNotifier = attr->eventNotifier;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
copyReferenceTypeNodeAttributes(UA_ReferenceTypeNode *rtnode,
                                const UA_ReferenceTypeAttributes *attr) {
    rtnode->isAbstract = attr->isAbstract;
    rtnode->symmetric = attr->symmetric;
    return UA_LocalizedText_copy(&attr->inverseName, &rtnode->inverseName);
}

static UA_StatusCode
copyObjectTypeNodeAttributes(UA_ObjectTypeNode *otnode,
                             const UA_ObjectTypeAttributes *attr) {
    otnode->isAbstract = attr->isAbstract;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
copyViewNodeAttributes(UA_ViewNode *vnode, const UA_ViewAttributes *attr) {
    vnode->containsNoLoops = attr->containsNoLoops;
    vnode->eventNotifier = attr->eventNotifier;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
copyDataTypeNodeAttributes(UA_DataTypeNode *dtnode,
                           const UA_DataTypeAttributes *attr) {
    dtnode->isAbstract = attr->isAbstract;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
copyMethodNodeAttributes(UA_MethodNode *mnode,
                         const UA_MethodAttributes *attr) {
    mnode->executable = attr->executable;
    return UA_STATUSCODE_GOOD;
}

#define CHECK_ATTRIBUTES(TYPE)                           \
    if(attributeType != &UA_TYPES[UA_TYPES_##TYPE]) {    \
        retval = UA_STATUSCODE_BADNODEATTRIBUTESINVALID; \
        break;                                           \
    }

UA_StatusCode
UA_Node_setAttributes(UA_Node *node, const void *attributes, const UA_DataType *attributeType) {
    /* Copy the attributes into the node */
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    switch(node->head.nodeClass) {
    case UA_NODECLASS_OBJECT:
        CHECK_ATTRIBUTES(OBJECTATTRIBUTES);
        retval = copyObjectNodeAttributes(&node->objectNode,
                                          (const UA_ObjectAttributes*)attributes);
        break;
    case UA_NODECLASS_VARIABLE:
        CHECK_ATTRIBUTES(VARIABLEATTRIBUTES);
        retval = copyVariableNodeAttributes(&node->variableNode,
                                            (const UA_VariableAttributes*)attributes);
        break;
    case UA_NODECLASS_OBJECTTYPE:
        CHECK_ATTRIBUTES(OBJECTTYPEATTRIBUTES);
        retval = copyObjectTypeNodeAttributes(&node->objectTypeNode,
                                              (const UA_ObjectTypeAttributes*)attributes);
        break;
    case UA_NODECLASS_VARIABLETYPE:
        CHECK_ATTRIBUTES(VARIABLETYPEATTRIBUTES);
        retval = copyVariableTypeNodeAttributes(&node->variableTypeNode,
                                                (const UA_VariableTypeAttributes*)attributes);
        break;
    case UA_NODECLASS_REFERENCETYPE:
        CHECK_ATTRIBUTES(REFERENCETYPEATTRIBUTES);
        retval = copyReferenceTypeNodeAttributes(&node->referenceTypeNode,
                                                 (const UA_ReferenceTypeAttributes*)attributes);
        break;
    case UA_NODECLASS_DATATYPE:
        CHECK_ATTRIBUTES(DATATYPEATTRIBUTES);
        retval = copyDataTypeNodeAttributes(&node->dataTypeNode,
                                            (const UA_DataTypeAttributes*)attributes);
        break;
    case UA_NODECLASS_VIEW:
        CHECK_ATTRIBUTES(VIEWATTRIBUTES);
        retval = copyViewNodeAttributes(&node->viewNode, (const UA_ViewAttributes*)attributes);
        break;
    case UA_NODECLASS_METHOD:
        CHECK_ATTRIBUTES(METHODATTRIBUTES);
        retval = copyMethodNodeAttributes(&node->methodNode, (const UA_MethodAttributes*)attributes);
        break;
    case UA_NODECLASS_UNSPECIFIED:
    default:
        retval = UA_STATUSCODE_BADNODECLASSINVALID;
    }

    if(retval == UA_STATUSCODE_GOOD)
        retval = copyStandardAttributes(&node->head, (const UA_NodeAttributes*)attributes);
    if(retval != UA_STATUSCODE_GOOD)
        UA_Node_clear(node);
    return retval;
}

/*********************/
/* Manage References */
/*********************/

static UA_StatusCode
addReferenceTargetToTree(UA_NodeReferenceKind *rk, UA_NodePointer targetId,
                         UA_UInt32 targetIdHash, UA_UInt32 targetNameHash) {
    UA_ReferenceTargetTreeElem *entry = (UA_ReferenceTargetTreeElem*)
        UA_malloc(sizeof(UA_ReferenceTargetTreeElem));
    if(!entry)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode res = UA_NodePointer_copy(targetId, &entry->target.targetId);
    if(res != UA_STATUSCODE_GOOD) {
        UA_free(entry);
        return res;
    }

    entry->targetIdHash = targetIdHash;
    entry->target.targetNameHash = targetNameHash;

    ZIP_INSERT(UA_ReferenceIdTree,
               (UA_ReferenceIdTree*)&rk->targets.tree.idRoot, entry);
    ZIP_INSERT(UA_ReferenceNameTree,
               (UA_ReferenceNameTree*)&rk->targets.tree.nameRoot, entry);

    rk->targetsSize++;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
addReferenceTarget(UA_NodeReferenceKind *rk, UA_NodePointer targetId,
                   UA_UInt32 targetNameHash) {
    /* Insert into tree */
    if(rk->hasRefTree) {
        UA_ExpandedNodeId en = UA_NodePointer_toExpandedNodeId(targetId);
        return addReferenceTargetToTree(rk, targetId, UA_ExpandedNodeId_hash(&en),
                                        targetNameHash);
    }

    /* Insert to the array */
    UA_ReferenceTarget *newRefs = (UA_ReferenceTarget*)
        UA_realloc(rk->targets.array,
                   sizeof(UA_ReferenceTarget) * (rk->targetsSize + 1));
    if(!newRefs)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    rk->targets.array = newRefs;

    UA_StatusCode retval =
        UA_NodePointer_copy(targetId,
                            &rk->targets.array[rk->targetsSize].targetId);
    rk->targets.array[rk->targetsSize].targetNameHash = targetNameHash;
    if(retval != UA_STATUSCODE_GOOD) {
        if(rk->targetsSize == 0) {
            UA_free(rk->targets.array);
            rk->targets.array = NULL;
        }
        return retval;
    }

    rk->targetsSize++;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
addReferenceKind(UA_NodeHead *head, UA_Byte refTypeIndex, UA_Boolean isForward,
                 const UA_NodePointer target, UA_UInt32 targetBrowseNameHash) {
    UA_NodeReferenceKind *refs = (UA_NodeReferenceKind*)
        UA_realloc(head->references,
                   sizeof(UA_NodeReferenceKind) * (head->referencesSize+1));
    if(!refs)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    head->references = refs;

    UA_NodeReferenceKind *newRef = &refs[head->referencesSize];
    memset(newRef, 0, sizeof(UA_NodeReferenceKind));
    newRef->referenceTypeIndex = refTypeIndex;
    newRef->isInverse = !isForward;
    UA_StatusCode res = addReferenceTarget(newRef, target, targetBrowseNameHash);
    if(res != UA_STATUSCODE_GOOD) {
        if(head->referencesSize == 0) {
            UA_free(head->references);
            head->references = NULL;
        }
        return res;
    }

    head->referencesSize++;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Node_addReference(UA_Node *node, UA_Byte refTypeIndex, UA_Boolean isForward,
                     const UA_ExpandedNodeId *targetNodeId,
                     UA_UInt32 targetBrowseNameHash) {
    /* Find the matching reference kind */
    for(size_t i = 0; i < node->head.referencesSize; ++i) {
        UA_NodeReferenceKind *refs = &node->head.references[i];

        /* Reference direction does not match */
        if(refs->isInverse == isForward)
            continue;

        /* Reference type does not match */
        if(refs->referenceTypeIndex != refTypeIndex)
            continue;

        /* Does an identical reference already exist? */
        const UA_ReferenceTarget *found =
            UA_NodeReferenceKind_findTarget(refs, targetNodeId);
        if(found)
            return UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED;

        /* Add to existing ReferenceKind */
        return addReferenceTarget(refs, UA_NodePointer_fromExpandedNodeId(targetNodeId),
                                  targetBrowseNameHash);
    }

    /* Add new ReferenceKind for the target */
    return addReferenceKind(&node->head, refTypeIndex, isForward,
                            UA_NodePointer_fromExpandedNodeId(targetNodeId),
                            targetBrowseNameHash);

}

UA_StatusCode
UA_Node_deleteReference(UA_Node *node, UA_Byte refTypeIndex, UA_Boolean isForward,
                        const UA_ExpandedNodeId *targetNodeId) {
    UA_NodeHead *head = &node->head;
    for(size_t i = 0; i < head->referencesSize; i++) {
        UA_NodeReferenceKind *refs = &head->references[i];
        if(isForward == refs->isInverse)
            continue;
        if(refTypeIndex != refs->referenceTypeIndex)
            continue;

        /* Cast out the const qualifier (hack!) */
        UA_ReferenceTarget *target = (UA_ReferenceTarget*)(uintptr_t)
            UA_NodeReferenceKind_findTarget(refs, targetNodeId);
        if(!target)
            continue;

        /* Ok, delete the reference. Cannot fail */
        refs->targetsSize--;

        if(!refs->hasRefTree) {
            /* Remove from array */
            UA_NodePointer_clear(&target->targetId);

            /* Elements remaining. Realloc. */
            if(refs->targetsSize > 0) {
                if(target != &refs->targets.array[refs->targetsSize])
                    *target = refs->targets.array[refs->targetsSize];
                UA_ReferenceTarget *newRefs = (UA_ReferenceTarget*)
                    UA_realloc(refs->targets.array,
                               sizeof(UA_ReferenceTarget) * refs->targetsSize);
                if(newRefs)
                    refs->targets.array = newRefs;
                return UA_STATUSCODE_GOOD; /* Realloc allowed to fail */
            }

            /* Remove the last target. Remove the ReferenceKind below */
            UA_free(refs->targets.array);
        } else {
            UA_ReferenceTargetTreeElem *elem = (UA_ReferenceTargetTreeElem*)target;
            ZIP_REMOVE(UA_ReferenceIdTree,
                       (UA_ReferenceIdTree*)&refs->targets.tree.idRoot, elem);
            ZIP_REMOVE(UA_ReferenceNameTree,
                       (UA_ReferenceNameTree*)&refs->targets.tree.nameRoot, elem);
            UA_NodePointer_clear(&target->targetId);
            UA_free(target);
            if(refs->targetsSize > 0)
                return UA_STATUSCODE_GOOD;
        }

        /* No targets remaining. Remove the ReferenceKind. */
        head->referencesSize--;
        if(head->referencesSize > 0) {
            /* No target for the ReferenceType remaining. Remove and shrink down
             * allocated buffer. Ignore errors in case memory buffer could not
             * be shrinked down. */
            if(i != head->referencesSize)
                head->references[i] = head->references[node->head.referencesSize];
            UA_NodeReferenceKind *newRefs = (UA_NodeReferenceKind*)
                UA_realloc(head->references,
                           sizeof(UA_NodeReferenceKind) * head->referencesSize);
            if(newRefs)
                head->references = newRefs;
        } else {
            /* No remaining references of any ReferenceType */
            UA_free(head->references);
            head->references = NULL;
        }
        return UA_STATUSCODE_GOOD;
    }
    return UA_STATUSCODE_UNCERTAINREFERENCENOTDELETED;
}

void
UA_Node_deleteReferencesSubset(UA_Node *node, const UA_ReferenceTypeSet *keepSet) {
    UA_NodeHead *head = &node->head;
    for(size_t i = 0; i < head->referencesSize; i++) {
        /* Keep the references of this type? */
        UA_NodeReferenceKind *refs = &head->references[i];
        if(UA_ReferenceTypeSet_contains(keepSet, refs->referenceTypeIndex))
            continue;

        /* Remove all target entries. Don't remove entries from browseName tree.
         * The entire ReferenceKind will be removed anyway. */
        if(!refs->hasRefTree) {
            for(size_t j = 0; j < refs->targetsSize; j++)
                UA_NodePointer_clear(&refs->targets.array[j].targetId);
            UA_free(refs->targets.array);
        } else {
            ZIP_ITER(UA_ReferenceIdTree,
                     (UA_ReferenceIdTree*)&refs->targets.tree.idRoot,
                     removeTreeEntry, NULL);
        }

        /* Move last references-kind entry to this position. Don't memcpy over
         * the same position. Decrease i to repeat at this location. */
        head->referencesSize--;
        if(i != head->referencesSize) {
            head->references[i] = head->references[head->referencesSize];
            i--;
        }
    }

    if(head->referencesSize > 0) {
        /* Realloc to save memory. Ignore if realloc fails. */
        UA_NodeReferenceKind *refs = (UA_NodeReferenceKind*)
            UA_realloc(head->references,
                       sizeof(UA_NodeReferenceKind) * head->referencesSize);
        if(refs)
            head->references = refs;
    } else {
        /* The array is empty. Remove. */
        UA_free(head->references);
        head->references = NULL;
    }
}

void UA_Node_deleteReferences(UA_Node *node) {
    UA_ReferenceTypeSet noRefs;
    UA_ReferenceTypeSet_init(&noRefs);
    UA_Node_deleteReferencesSubset(node, &noRefs);
}

static UA_StatusCode
UA_Node_insertOrUpdateLocale(UA_LocalizedTextListEntry **root,
                             const UA_LocalizedText *value) {
    UA_StatusCode res;
    UA_LocalizedTextListEntry *lt, *prev = NULL;
    for(lt = *root; lt != NULL; prev = lt, lt = lt->next) {
        if(!UA_String_equal(&value->locale, &lt->localizedText.locale))
            continue;

        /* No text -> remove the entry for this locale */
        if(value->text.length == 0) {
            if(prev == NULL)
                *root = lt->next;
            else
                prev->next = lt->next;
            UA_LocalizedText_clear(&lt->localizedText);
            UA_free(lt);
            return UA_STATUSCODE_GOOD;
        }

        /* First make a copy of the text, if this succeeds replace the old
         * version */
        UA_String tmp;
        res = UA_String_copy(&value->text, &tmp);
        if(res != UA_STATUSCODE_GOOD)
            return res;

        UA_String_clear(&lt->localizedText.text);
        lt->localizedText.text = tmp;
        return UA_STATUSCODE_GOOD;
    }

    /* The locale does not exist so far */

    /* Do nothing if a non-existing locale should be removed */
    if(value->text.length == 0)
        return UA_STATUSCODE_GOOD;

    /* Add a new localized text */
    lt = (UA_LocalizedTextListEntry *)UA_malloc(sizeof(UA_LocalizedTextListEntry));
    if(!lt)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    res = UA_LocalizedText_copy(value, &lt->localizedText);
    if(res != UA_STATUSCODE_GOOD) {
        UA_free(lt);
        return res;
    }

    lt->next = *root;
    *root = lt;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Node_insertOrUpdateDisplayName(UA_NodeHead *head,
                                  const UA_LocalizedText *value) {
    return UA_Node_insertOrUpdateLocale(&head->displayName, value);
}

UA_StatusCode
UA_Node_insertOrUpdateDescription(UA_NodeHead *head,
                                  const UA_LocalizedText *value) {
    return UA_Node_insertOrUpdateLocale(&head->description, value);
}

/**** amalgamated original file "/src/server/ua_server.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014-2017 (c) Florian Palm
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015-2016 (c) Chris Iatrou
 *    Copyright 2015 (c) LEvertz
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2016 (c) Julian Grothoff
 *    Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2016 (c) Lorenz Haas
 *    Copyright 2017 (c) frax2222
 *    Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2018 (c) Hilscher Gesellschaft für Systemautomation mbH (Author: Martin Lang)
 *    Copyright 2019 (c) Kalycito Infotech Private Limited
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Jan Hermes)
 *    Copyright 2022 (c) Fraunhofer IOSB (Author: Andreas Ebner)
 */


#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
#endif

#ifdef UA_ENABLE_SUBSCRIPTIONS
#endif

#ifdef UA_ENABLE_NODESET_INJECTOR
#endif

/**********************/
/* Namespace Handling */
/**********************/

/* The NS1 Uri can be changed by the user to some custom string. This method is
 * called to initialize the NS1 Uri if it is not set before to the default
 * Application URI.
 *
 * This is done as soon as the Namespace Array is read or written via node value
 * read / write services, or UA_Server_addNamespace, or UA_Server_getNamespaceByIndex
 * UA_Server_getNamespaceByName or UA_Server_run_startup is called.
 *
 * Therefore one has to set the custom NS1 URI before one of the previously
 * mentioned steps. */

void
setupNs1Uri(UA_Server *server) {
    if(!server->namespaces[1].data) {
        UA_String_copy(&server->config.applicationDescription.applicationUri,
                       &server->namespaces[1]);
    }
}

UA_UInt16 addNamespace(UA_Server *server, const UA_String name) {
    /* ensure that the uri for ns1 is set up from the app description */
    setupNs1Uri(server);

    /* Check if the namespace already exists in the server's namespace array */
    for(size_t i = 0; i < server->namespacesSize; ++i) {
        if(UA_String_equal(&name, &server->namespaces[i]))
            return (UA_UInt16) i;
    }

    /* Make the array bigger */
    UA_String *newNS = (UA_String*)UA_realloc(server->namespaces,
                                              sizeof(UA_String) * (server->namespacesSize + 1));
    UA_CHECK_MEM(newNS, return 0);

    server->namespaces = newNS;

    /* Copy the namespace string */
    UA_StatusCode retval = UA_String_copy(&name, &server->namespaces[server->namespacesSize]);
    UA_CHECK_STATUS(retval, return 0);

    /* Announce the change (otherwise, the array appears unchanged) */
    ++server->namespacesSize;
    return (UA_UInt16)(server->namespacesSize - 1);
}

UA_UInt16 UA_Server_addNamespace(UA_Server *server, const char* name) {
    /* Override const attribute to get string (dirty hack) */
    UA_String nameString;
    nameString.length = strlen(name);
    nameString.data = (UA_Byte*)(uintptr_t)name;
    UA_LOCK(&server->serviceMutex);
    UA_UInt16 retVal = addNamespace(server, nameString);
    UA_UNLOCK(&server->serviceMutex);
    return retVal;
}

UA_ServerConfig*
UA_Server_getConfig(UA_Server *server) {
    UA_CHECK_MEM(server, return NULL);
    return &server->config;
}

UA_StatusCode
getNamespaceByName(UA_Server *server, const UA_String namespaceUri,
                   size_t *foundIndex) {
    /* ensure that the uri for ns1 is set up from the app description */
    setupNs1Uri(server);
    UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND;
    for(size_t idx = 0; idx < server->namespacesSize; idx++) {
        if(UA_String_equal(&server->namespaces[idx], &namespaceUri)) {
            (*foundIndex) = idx;
            res = UA_STATUSCODE_GOOD;
            break;
        }
    }
    return res;
}

UA_StatusCode
getNamespaceByIndex(UA_Server *server, const size_t namespaceIndex,
                   UA_String *foundUri) {
    /* ensure that the uri for ns1 is set up from the app description */
    setupNs1Uri(server);
    UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND;
    if(namespaceIndex >= server->namespacesSize)
        return res;
    res = UA_String_copy(&server->namespaces[namespaceIndex], foundUri);
    return res;
}

UA_StatusCode
UA_Server_getNamespaceByName(UA_Server *server, const UA_String namespaceUri,
                             size_t *foundIndex) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = getNamespaceByName(server, namespaceUri, foundIndex);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_Server_getNamespaceByIndex(UA_Server *server, const size_t namespaceIndex,
                              UA_String *foundUri) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = getNamespaceByIndex(server, namespaceIndex, foundUri);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_Server_forEachChildNodeCall(UA_Server *server, UA_NodeId parentNodeId,
                               UA_NodeIteratorCallback callback, void *handle) {
    UA_BrowseDescription bd;
    UA_BrowseDescription_init(&bd);
    bd.nodeId = parentNodeId;
    bd.browseDirection = UA_BROWSEDIRECTION_BOTH;
    bd.resultMask = UA_BROWSERESULTMASK_REFERENCETYPEID | UA_BROWSERESULTMASK_ISFORWARD;

    UA_BrowseResult br = UA_Server_browse(server, 0, &bd);
    UA_StatusCode res = br.statusCode;
    UA_CHECK_STATUS(res, goto cleanup);

    for(size_t i = 0; i < br.referencesSize; i++) {
        if(!UA_ExpandedNodeId_isLocal(&br.references[i].nodeId))
            continue;
        res = callback(br.references[i].nodeId.nodeId, !br.references[i].isForward,
                       br.references[i].referenceTypeId, handle);
        UA_CHECK_STATUS(res, goto cleanup);
    }
cleanup:
    UA_BrowseResult_clear(&br);
    return res;
}

/*********************/
/* Server Components */
/*********************/

enum ZIP_CMP
cmpServerComponent(const UA_UInt64 *a, const UA_UInt64 *b) {
    if(*a == *b)
        return ZIP_CMP_EQ;
    return (*a < *b) ? ZIP_CMP_LESS : ZIP_CMP_MORE;
}

void
addServerComponent(UA_Server *server, UA_ServerComponent *sc,
                   UA_UInt64 *identifier) {
    if(!sc)
        return;

    sc->identifier = ++server->serverComponentIds;
    ZIP_INSERT(UA_ServerComponentTree, &server->serverComponents, sc);

    /* Start the component if the server is started */
    if(server->state == UA_LIFECYCLESTATE_STARTED && sc->start)
        sc->start(server, sc);

    if(identifier)
        *identifier = sc->identifier;
}

static void *
findServerComponent(void *context, UA_ServerComponent *sc) {
    UA_String *name = (UA_String*)context;
    return (UA_String_equal(&sc->name, name)) ? sc : NULL;
}

UA_ServerComponent *
getServerComponentByName(UA_Server *server, UA_String name) {
    return (UA_ServerComponent*)
        ZIP_ITER(UA_ServerComponentTree, &server->serverComponents,
                 findServerComponent, &name);
}

static void *
removeServerComponent(void *application, UA_ServerComponent *sc) {
    UA_assert(sc->state == UA_LIFECYCLESTATE_STOPPED);
    sc->free((UA_Server*)application, sc);
    return NULL;
}

static void *
startServerComponent(void *application, UA_ServerComponent *sc) {
    sc->start((UA_Server*)application, sc);
    return NULL;
}

static void *
stopServerComponent(void *application, UA_ServerComponent *sc) {
    sc->stop((UA_Server*)application, sc);
    return NULL;
}

/* ZIP_ITER returns NULL only if all components are stopped */
static void *
checkServerComponent(void *application, UA_ServerComponent *sc) {
    return (sc->state == UA_LIFECYCLESTATE_STOPPED) ? NULL : (void*)0x01;
}

/********************/
/* Server Lifecycle */
/********************/

/* The server needs to be stopped before it can be deleted */
UA_StatusCode
UA_Server_delete(UA_Server *server) {
    if(server == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    if(server->state != UA_LIFECYCLESTATE_STOPPED) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "The server must be fully stopped before it can be deleted");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_LOCK(&server->serviceMutex);

    session_list_entry *current, *temp;
    LIST_FOREACH_SAFE(current, &server->sessions, pointers, temp) {
        UA_Server_removeSession(server, current, UA_SHUTDOWNREASON_CLOSE);
    }
    UA_Array_delete(server->namespaces, server->namespacesSize, &UA_TYPES[UA_TYPES_STRING]);

#ifdef UA_ENABLE_SUBSCRIPTIONS
    /* Remove subscriptions without a session */
    UA_Subscription *sub, *sub_tmp;
    LIST_FOREACH_SAFE(sub, &server->subscriptions, serverListEntry, sub_tmp) {
        UA_Subscription_delete(server, sub);
    }

#ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS
    UA_ConditionList_delete(server);
#endif

#endif

#ifdef UA_ENABLE_PUBSUB
    UA_PubSubManager_delete(server, &server->pubSubManager);
#endif

#if UA_MULTITHREADING >= 100
    UA_AsyncManager_clear(&server->asyncManager, server);
#endif

    /* Clean up the Admin Session */
    UA_Session_clear(&server->adminSession, server);
#ifdef UA_ENABLE_SUBSCRIPTIONS
    server->adminSubscription = NULL;
    UA_assert(server->monitoredItemsSize == 0);
    UA_assert(server->subscriptionsSize == 0);
#endif

    /* Remove all remaining server components (must be all stopped) */
    ZIP_ITER(UA_ServerComponentTree, &server->serverComponents,
             removeServerComponent, server);

    UA_UNLOCK(&server->serviceMutex); /* The timer has its own mutex */

    /* Clean up the config */
    UA_ServerConfig_clean(&server->config);

#if UA_MULTITHREADING >= 100
    UA_LOCK_DESTROY(&server->serviceMutex);
#endif

    /* Delete the server itself and return */
    UA_free(server);
    return UA_STATUSCODE_GOOD;
}

/* Regular house-keeping tasks. Removing unused and timed-out channels and
 * sessions. */
static void
serverHouseKeeping(UA_Server *server, void *_) {
    UA_LOCK(&server->serviceMutex);
    UA_EventLoop *el = server->config.eventLoop;
    UA_Server_cleanupSessions(server, el->dateTime_nowMonotonic(el));
    UA_UNLOCK(&server->serviceMutex);
}

/********************/
/* Server Lifecycle */
/********************/

static
UA_INLINE
UA_Boolean UA_Server_NodestoreIsConfigured(UA_Server *server) {
    return server->config.nodestore.getNode != NULL;
}

static UA_Server *
UA_Server_init(UA_Server *server) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    UA_CHECK_FATAL(UA_Server_NodestoreIsConfigured(server), goto cleanup,
                   server->config.logging, UA_LOGCATEGORY_SERVER,
                   "No Nodestore configured in the server");

    /* Init start time to zero, the actual start time will be sampled in
     * UA_Server_run_startup() */
    server->startTime = 0;

    /* Set a seed for non-cyptographic randomness */
#ifndef UA_ENABLE_DETERMINISTIC_RNG
    UA_random_seed((UA_UInt64)UA_DateTime_now());
#endif

    UA_LOCK_INIT(&server->serviceMutex);
    UA_LOCK(&server->serviceMutex);

    /* Initialize the adminSession */
    UA_Session_init(&server->adminSession);
    server->adminSession.sessionId.identifierType = UA_NODEIDTYPE_GUID;
    server->adminSession.sessionId.identifier.guid.data1 = 1;
    server->adminSession.validTill = UA_INT64_MAX;
    server->adminSession.sessionName = UA_STRING_ALLOC("Administrator");

#ifdef UA_ENABLE_SUBSCRIPTIONS
    /* Initialize the adminSubscription */
    server->adminSubscription = UA_Subscription_new();
    UA_CHECK_MEM(server->adminSubscription, goto cleanup);
    UA_Session_attachSubscription(&server->adminSession, server->adminSubscription);
#endif

    /* Create Namespaces 0 and 1
     * Ns1 will be filled later with the uri from the app description */
    server->namespaces = (UA_String *)UA_Array_new(2, &UA_TYPES[UA_TYPES_STRING]);
    UA_CHECK_MEM(server->namespaces, goto cleanup);

    server->namespaces[0] = UA_STRING_ALLOC("http://opcfoundation.org/UA/");
    server->namespaces[1] = UA_STRING_NULL;
    server->namespacesSize = 2;

    /* Initialize Session Management */
    LIST_INIT(&server->sessions);
    server->sessionCount = 0;

#if UA_MULTITHREADING >= 100
    UA_AsyncManager_init(&server->asyncManager, server);
#endif

    /* Initialize the binay protocol support */
    addServerComponent(server, UA_BinaryProtocolManager_new(server), NULL);

    /* Initialized discovery */
#ifdef UA_ENABLE_DISCOVERY
    addServerComponent(server, UA_DiscoveryManager_new(server), NULL);
#endif

    /* Initialize namespace 0*/
    res = initNS0(server);
    UA_CHECK_STATUS(res, goto cleanup);

#ifdef UA_ENABLE_NODESET_INJECTOR
    UA_UNLOCK(&server->serviceMutex);
    res = UA_Server_injectNodesets(server);
    UA_LOCK(&server->serviceMutex);
    UA_CHECK_STATUS(res, goto cleanup);
#endif

#ifdef UA_ENABLE_PUBSUB
    /* Initialized PubSubManager */
    UA_PubSubManager_init(server, &server->pubSubManager);

#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    /* Build PubSub information model */
    initPubSubNS0(server);
#endif

#ifdef UA_ENABLE_PUBSUB_MONITORING
    /* setup default PubSub monitoring callbacks */
    res = UA_PubSubManager_setDefaultMonitoringCallbacks(&server->config.pubSubConfig.monitoringInterface);
    UA_CHECK_STATUS(res, goto cleanup);
#endif /* UA_ENABLE_PUBSUB_MONITORING */
#endif /* UA_ENABLE_PUBSUB */

    UA_UNLOCK(&server->serviceMutex);
    return server;

 cleanup:
    UA_UNLOCK(&server->serviceMutex);
    UA_Server_delete(server);
    return NULL;
}

UA_Server *
UA_Server_newWithConfig(UA_ServerConfig *config) {
    UA_CHECK_MEM(config, return NULL);

    UA_CHECK_LOG(config->eventLoop != NULL, return NULL, ERROR,
                 config->logging, UA_LOGCATEGORY_SERVER, "No EventLoop configured");

    UA_Server *server = (UA_Server *)UA_calloc(1, sizeof(UA_Server));
    UA_CHECK_MEM(server, UA_ServerConfig_clean(config); return NULL);

    server->config = *config;

    /* If not defined, set logging to what the server has */
    if(!server->config.secureChannelPKI.logging)
        server->config.secureChannelPKI.logging = server->config.logging;
    if(!server->config.sessionPKI.logging)
        server->config.sessionPKI.logging = server->config.logging;

    /* Reset the old config */
    memset(config, 0, sizeof(UA_ServerConfig));
    return UA_Server_init(server);
}

/* Returns if the server should be shut down immediately */
static UA_Boolean
setServerShutdown(UA_Server *server) {
    if(server->endTime != 0)
        return false;
    if(server->config.shutdownDelay == 0)
        return true;

    UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                   "Shutting down the server with a delay of %i ms",
                   (int)server->config.shutdownDelay);

    UA_EventLoop *el = server->config.eventLoop;
    server->endTime = el->dateTime_now(el) +
        (UA_DateTime)(server->config.shutdownDelay * UA_DATETIME_MSEC);

    return false;
}

/*******************/
/* Timed Callbacks */
/*******************/

UA_StatusCode
UA_Server_addTimedCallback(UA_Server *server, UA_ServerCallback callback,
                           void *data, UA_DateTime date, UA_UInt64 *callbackId) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode retval = server->config.eventLoop->
        addTimedCallback(server->config.eventLoop, (UA_Callback)callback,
                         server, data, date, callbackId);
    UA_UNLOCK(&server->serviceMutex);
    return retval;
}

UA_StatusCode
addRepeatedCallback(UA_Server *server, UA_ServerCallback callback,
                    void *data, UA_Double interval_ms, UA_UInt64 *callbackId) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    return server->config.eventLoop->
        addCyclicCallback(server->config.eventLoop, (UA_Callback) callback,
                          server, data, interval_ms, NULL,
                          UA_TIMER_HANDLE_CYCLEMISS_WITH_CURRENTTIME, callbackId);
}

UA_StatusCode
UA_Server_addRepeatedCallback(UA_Server *server, UA_ServerCallback callback,
                              void *data, UA_Double interval_ms,
                              UA_UInt64 *callbackId) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = addRepeatedCallback(server, callback, data, interval_ms, callbackId);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId,
                               UA_Double interval_ms) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    return server->config.eventLoop->
        modifyCyclicCallback(server->config.eventLoop, callbackId, interval_ms,
                             NULL, UA_TIMER_HANDLE_CYCLEMISS_WITH_CURRENTTIME);
}

UA_StatusCode
UA_Server_changeRepeatedCallbackInterval(UA_Server *server, UA_UInt64 callbackId,
                                         UA_Double interval_ms) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode retval =
        changeRepeatedCallbackInterval(server, callbackId, interval_ms);
    UA_UNLOCK(&server->serviceMutex);
    return retval;
}

void
removeCallback(UA_Server *server, UA_UInt64 callbackId) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    UA_EventLoop *el = server->config.eventLoop;
    if(el) {
        el->removeCyclicCallback(el, callbackId);
    }
}

void
UA_Server_removeCallback(UA_Server *server, UA_UInt64 callbackId) {
    UA_LOCK(&server->serviceMutex);
    removeCallback(server, callbackId);
    UA_UNLOCK(&server->serviceMutex);
}

static void
notifySecureChannelsStopped(UA_Server *server, struct UA_ServerComponent *sc,
                            UA_LifecycleState state) {
    if(sc->state == UA_LIFECYCLESTATE_STOPPED &&
       server->state == UA_LIFECYCLESTATE_STARTED) {
        sc->notifyState = NULL; /* remove the callback */
        sc->start(server, sc);
    }
}

UA_StatusCode
UA_Server_updateCertificate(UA_Server *server,
                            const UA_ByteString *oldCertificate,
                            const UA_ByteString *newCertificate,
                            const UA_ByteString *newPrivateKey,
                            UA_Boolean closeSessions,
                            UA_Boolean closeSecureChannels) {
    UA_CHECK(server && oldCertificate && newCertificate && newPrivateKey,
             return UA_STATUSCODE_BADINTERNALERROR);

    if(closeSessions) {
        session_list_entry *current;
        LIST_FOREACH(current, &server->sessions, pointers) {
            UA_Session *session = &current->session;
            if(!session->channel)
                continue;
            if(!UA_ByteString_equal(oldCertificate,
                                    &session->channel->securityPolicy->localCertificate))
                continue;

            UA_LOCK(&server->serviceMutex);
            UA_Server_removeSessionByToken(server, &session->authenticationToken,
                                           UA_SHUTDOWNREASON_CLOSE);
            UA_UNLOCK(&server->serviceMutex);
        }
    }

    /* Gracefully close all SecureChannels. And restart the
     * BinaryProtocolManager once it has fully stopped. */
    if(closeSecureChannels) {
        UA_ServerComponent *binaryProtocolManager =
            getServerComponentByName(server, UA_STRING("binary"));
        if(binaryProtocolManager) {
            binaryProtocolManager->notifyState = notifySecureChannelsStopped;
            binaryProtocolManager->stop(server, binaryProtocolManager);
        }
    }

    size_t i = 0;
    while(i < server->config.endpointsSize) {
        UA_EndpointDescription *ed = &server->config.endpoints[i];
        if(UA_ByteString_equal(&ed->serverCertificate, oldCertificate)) {
            UA_String_clear(&ed->serverCertificate);
            UA_String_copy(newCertificate, &ed->serverCertificate);
            UA_SecurityPolicy *sp = getSecurityPolicyByUri(server,
                            &server->config.endpoints[i].securityPolicyUri);
            UA_CHECK_MEM(sp, return UA_STATUSCODE_BADINTERNALERROR);
            sp->updateCertificateAndPrivateKey(sp, *newCertificate, *newPrivateKey);
        }
        i++;
    }

    return UA_STATUSCODE_GOOD;
}

/***************************/
/* Server lookup functions */
/***************************/

UA_SecurityPolicy *
getSecurityPolicyByUri(const UA_Server *server, const UA_ByteString *securityPolicyUri) {
    for(size_t i = 0; i < server->config.securityPoliciesSize; i++) {
        UA_SecurityPolicy *securityPolicyCandidate = &server->config.securityPolicies[i];
        if(UA_ByteString_equal(securityPolicyUri, &securityPolicyCandidate->policyUri))
            return securityPolicyCandidate;
    }
    return NULL;
}

/* The local ApplicationURI has to match the certificates of the
 * SecurityPolicies */
static UA_StatusCode
verifyServerApplicationURI(const UA_Server *server) {
    const UA_String securityPolicyNoneUri =
        UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None");
    for(size_t i = 0; i < server->config.securityPoliciesSize; i++) {
        UA_SecurityPolicy *sp = &server->config.securityPolicies[i];
        if(UA_String_equal(&sp->policyUri, &securityPolicyNoneUri) &&
           sp->localCertificate.length == 0)
            continue;
        UA_StatusCode retval = UA_CertificateUtils_verifyApplicationURI(server->config.allowAllCertificateUris,
                                                                        &sp->localCertificate,
                                                                        &server->config.applicationDescription.applicationUri);
        UA_CHECK_STATUS_ERROR(retval, return retval, server->config.logging,
                              UA_LOGCATEGORY_SERVER,
                              "The configured ApplicationURI \"%.*s\" does not match the "
                              "ApplicationURI specified in the certificate for the "
                              "SecurityPolicy %.*s", (int)
                              server->config.applicationDescription.applicationUri.length,
                              server->config.applicationDescription.applicationUri.data,
                              (int)sp->policyUri.length, sp->policyUri.data);
    }
    return UA_STATUSCODE_GOOD;
}

UA_ServerStatistics
UA_Server_getStatistics(UA_Server *server) {
    UA_ServerStatistics stat;
    stat.scs = server->secureChannelStatistics;
    UA_ServerDiagnosticsSummaryDataType *sds = &server->serverDiagnosticsSummary;
    stat.ss.currentSessionCount = server->activeSessionCount;
    stat.ss.cumulatedSessionCount = sds->cumulatedSessionCount;
    stat.ss.securityRejectedSessionCount = sds->securityRejectedSessionCount;
    stat.ss.rejectedSessionCount = sds->rejectedSessionCount;
    stat.ss.sessionTimeoutCount = sds->sessionTimeoutCount;
    stat.ss.sessionAbortCount = sds->sessionAbortCount;
    return stat;
}

/********************/
/* Main Server Loop */
/********************/

#define UA_MAXTIMEOUT 200 /* Max timeout in ms between main-loop iterations */

void
setServerLifecycleState(UA_Server *server, UA_LifecycleState state) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    if(server->state == state)
        return;
    server->state = state;
    if(server->config.notifyLifecycleState) {
        UA_UNLOCK(&server->serviceMutex);
        server->config.notifyLifecycleState(server, server->state);
        UA_LOCK(&server->serviceMutex);
    }
}

UA_LifecycleState
UA_Server_getLifecycleState(UA_Server *server) {
    return server->state;
}

/* Start: Spin up the workers and the network layer and sample the server's
 *        start time.
 * Iterate: Process repeated callbacks and events in the network layer. This
 *          part can be driven from an external main-loop in an event-driven
 *          single-threaded architecture.
 * Stop: Stop workers, finish all callbacks, stop the network layer, clean up */

UA_StatusCode
UA_Server_run_startup(UA_Server *server) {
    if(server == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }
    UA_ServerConfig *config = &server->config;

#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
    /* Prominently warn user that fuzzing build is enabled. This will tamper
     * with authentication tokens and other important variables E.g. if fuzzing
     * is enabled, and two clients are connected, subscriptions do not work
     * properly, since the tokens will be overridden to allow easier fuzzing. */
    UA_LOG_FATAL(server->config.logging, UA_LOGCATEGORY_SERVER,
                 "Server was built with unsafe fuzzing mode. "
                 "This should only be used for specific fuzzing builds.");
#endif

    if(server->state != UA_LIFECYCLESTATE_STOPPED) {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SERVER,
                       "The server has already been started");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Check if UserIdentityTokens are defined */
    bool hasUserIdentityTokens = false;
    for(size_t i = 0; i < config->endpointsSize; i++) {
        if(config->endpoints[i].userIdentityTokensSize > 0) {
            hasUserIdentityTokens = true;
            break;
        }
    }
    if(config->accessControl.userTokenPoliciesSize == 0 && hasUserIdentityTokens == false) {
        UA_LOG_ERROR(config->logging, UA_LOGCATEGORY_SERVER,
                     "The server has no userIdentificationPolicies defined.");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Start the EventLoop if not already started */
    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    UA_EventLoop *el = config->eventLoop;
    UA_CHECK_MEM_ERROR(el, return UA_STATUSCODE_BADINTERNALERROR,
                       config->logging, UA_LOGCATEGORY_SERVER,
                       "An EventLoop must be configured");

    if(el->state != UA_EVENTLOOPSTATE_STARTED) {
        retVal = el->start(el);
        UA_CHECK_STATUS(retVal, return retVal); /* Errors are logged internally */
    }

    /* Take the server lock */
    UA_LOCK(&server->serviceMutex);

    /* Does the ApplicationURI match the local certificates? */
    retVal = verifyServerApplicationURI(server);
    UA_CHECK_STATUS(retVal, UA_UNLOCK(&server->serviceMutex); return retVal);

#if UA_MULTITHREADING >= 100
    /* Add regulare callback for async operation processing */
    UA_AsyncManager_start(&server->asyncManager, server);
#endif

    /* Are there enough SecureChannels possible for the max number of sessions? */
    if(config->maxSecureChannels != 0 &&
       (config->maxSessions == 0 || config->maxSessions >= config->maxSecureChannels)) {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SERVER,
                       "Maximum SecureChannels count not enough for the "
                       "maximum Sessions count");
    }

    /* Add a regular callback for housekeeping tasks. With a 1s interval. */
    retVal = addRepeatedCallback(server, serverHouseKeeping,
                                 NULL, 1000.0, &server->houseKeepingCallbackId);
    UA_CHECK_STATUS_ERROR(retVal, UA_UNLOCK(&server->serviceMutex); return retVal,
                          config->logging, UA_LOGCATEGORY_SERVER,
                          "Could not create the server housekeeping task");

    /* Ensure that the uri for ns1 is set up from the app description */
    setupNs1Uri(server);

    /* At least one endpoint has to be configured */
    if(config->endpointsSize == 0) {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SERVER,
                       "There has to be at least one endpoint.");
    }

    /* Update Endpoint description */
    for(size_t i = 0; i < config->endpointsSize; ++i) {
        UA_ApplicationDescription_clear(&config->endpoints[i].server);
        UA_ApplicationDescription_copy(&config->applicationDescription,
                                       &config->endpoints[i].server);
    }

    /* Write ServerArray with same ApplicationUri value as NamespaceArray */
    UA_Variant var;
    UA_Variant_init(&var);
    UA_Variant_setArray(&var, &config->applicationDescription.applicationUri,
                        1, &UA_TYPES[UA_TYPES_STRING]);
    UA_NodeId serverArray = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERARRAY);
    writeValueAttribute(server, serverArray, &var);

    /* Sample the start time and set it to the Server object */
    server->startTime = el->dateTime_now(el);
    UA_Variant_init(&var);
    UA_Variant_setScalar(&var, &server->startTime, &UA_TYPES[UA_TYPES_DATETIME]);
    UA_NodeId startTime =
        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STARTTIME);
    writeValueAttribute(server, startTime, &var);

    /* Start all ServerComponents */
    ZIP_ITER(UA_ServerComponentTree, &server->serverComponents,
             startServerComponent, server);

    /* Set the server to STARTED. From here on, only use
     * UA_Server_run_shutdown(server) to stop the server. */
    setServerLifecycleState(server, UA_LIFECYCLESTATE_STARTED);

    UA_UNLOCK(&server->serviceMutex);
    return UA_STATUSCODE_GOOD;
}

UA_UInt16
UA_Server_run_iterate(UA_Server *server, UA_Boolean waitInternal) {
    /* Make sure an EventLoop is configured */
    UA_EventLoop *el = server->config.eventLoop;
    if(!el)
        return 0;

    /* Process timed and network events in the EventLoop */
    UA_UInt32 timeout = (waitInternal) ? UA_MAXTIMEOUT : 0;
    el->run(el, timeout);

    /* Return the time until the next scheduled callback */
    UA_DateTime now = el->dateTime_nowMonotonic(el);
    UA_DateTime nextTimeout = (el->nextCyclicTime(el) - now) / UA_DATETIME_MSEC;
    if(nextTimeout > UA_UINT16_MAX)
        nextTimeout = UA_UINT16_MAX;
    return (UA_UInt16)nextTimeout;
}

static UA_Boolean
testShutdownCondition(UA_Server *server) {
    /* Was there a wait time until the shutdown configured? */
    if(server->endTime == 0)
        return false;
    UA_EventLoop *el = server->config.eventLoop;
    return (el->dateTime_now(el) > server->endTime);
}

static UA_Boolean
testStoppedCondition(UA_Server *server) {
    /* Check if there are remaining server components that did not fully stop */
    if(ZIP_ITER(UA_ServerComponentTree, &server->serverComponents,
                checkServerComponent, server) != NULL)
        return false;
    return true;
}

UA_StatusCode
UA_Server_run_shutdown(UA_Server *server) {
    if(server == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_LOCK(&server->serviceMutex);

    if(server->state != UA_LIFECYCLESTATE_STARTED) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "The server is not started, cannot be shut down");
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Set to stopping and notify the application */
    setServerLifecycleState(server, UA_LIFECYCLESTATE_STOPPING);

#if UA_MULTITHREADING >= 100
    /* Stop regular callback for async operation processing */
    UA_AsyncManager_stop(&server->asyncManager, server);
#endif

    /* Stop the regular housekeeping tasks */
    if(server->houseKeepingCallbackId != 0) {
        removeCallback(server, server->houseKeepingCallbackId);
        server->houseKeepingCallbackId = 0;
    }

    /* Stop PubSub */
#ifdef UA_ENABLE_PUBSUB
    UA_PubSubManager_shutdown(server, &server->pubSubManager);
#endif

    /* Stop all ServerComponents */
    ZIP_ITER(UA_ServerComponentTree, &server->serverComponents,
             stopServerComponent, server);

    /* Are we already stopped? */
    if(testStoppedCondition(server)) {
        setServerLifecycleState(server, UA_LIFECYCLESTATE_STOPPED);
    }

    /* Only stop the EventLoop if it is coupled to the server lifecycle  */
    if(server->config.externalEventLoop) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_GOOD;
    }

    /* Iterate the EventLoop until the server is stopped */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    UA_EventLoop *el = server->config.eventLoop;
    while(!testStoppedCondition(server) &&
          res == UA_STATUSCODE_GOOD) {
        UA_UNLOCK(&server->serviceMutex);
        res = el->run(el, 100);
        UA_LOCK(&server->serviceMutex);
    }

    /* Stop the EventLoop. Iterate until stopped. */
    el->stop(el);
    while(el->state != UA_EVENTLOOPSTATE_STOPPED &&
          el->state != UA_EVENTLOOPSTATE_FRESH &&
          res == UA_STATUSCODE_GOOD) {
        UA_UNLOCK(&server->serviceMutex);
        res = el->run(el, 100);
        UA_LOCK(&server->serviceMutex);
    }

    /* Set server lifecycle state to stopped if not already the case */
    setServerLifecycleState(server, UA_LIFECYCLESTATE_STOPPED);

    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_Server_run(UA_Server *server, const volatile UA_Boolean *running) {
    UA_StatusCode retval = UA_Server_run_startup(server);
    UA_CHECK_STATUS(retval, return retval);

    while(!testShutdownCondition(server)) {
        UA_Server_run_iterate(server, true);
        if(!*running) {
            if(setServerShutdown(server))
                break;
        }
    }
    return UA_Server_run_shutdown(server);
}


/**** amalgamated original file "/src/server/ua_server_ns0.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2017-2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Thomas Bender
 *    Copyright 2017 (c) Julian Grothoff
 *    Copyright 2017 (c) Henrik Norrman
 *    Copyright 2018 (c) Fabian Arndt, Root-Core
 *    Copyright 2019 (c) Kalycito Infotech Private Limited
 *    Copyright 2021 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati)
 *    Copyright 2023 (c) Fraunhofer IOSB (Author: Andreas Ebner)
 */



static UA_StatusCode
ns0_addNode_raw(UA_Server *server, UA_NodeClass nodeClass,
            UA_UInt32 nodeId, char *name, void *attributes,
            const UA_DataType *attributesType) {
    UA_AddNodesItem item;
    UA_AddNodesItem_init(&item);
    item.nodeClass = nodeClass;
    item.requestedNewNodeId.nodeId = UA_NODEID_NUMERIC(0, nodeId);
    item.browseName = UA_QUALIFIEDNAME(0, name);
    UA_ExtensionObject_setValueNoDelete(&item.nodeAttributes,
                                        attributes, attributesType);
    return addNode_raw(server, &server->adminSession, NULL, &item, NULL);
}

static UA_StatusCode
ns0_addNode_finish(UA_Server *server, UA_UInt32 nodeId,
               UA_UInt32 parentNodeId, UA_UInt32 referenceTypeId) {
    const UA_NodeId sourceId = UA_NODEID_NUMERIC(0, nodeId);
    const UA_NodeId refTypeId = UA_NODEID_NUMERIC(0, referenceTypeId);
    const UA_NodeId targetId = UA_NODEID_NUMERIC(0, parentNodeId);
    UA_StatusCode retval = addRef(server, sourceId, refTypeId, targetId, false);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    return addNode_finish(server, &server->adminSession, &sourceId);
}

static UA_StatusCode
addObjectNode(UA_Server *server, char* name, UA_UInt32 objectid,
              UA_UInt32 parentid, UA_UInt32 referenceid, UA_UInt32 type_id) {
    UA_ObjectAttributes object_attr = UA_ObjectAttributes_default;
    object_attr.displayName = UA_LOCALIZEDTEXT("", name);
    return addNode(server, UA_NODECLASS_OBJECT, UA_NODEID_NUMERIC(0, objectid),
                   UA_NODEID_NUMERIC(0, parentid), UA_NODEID_NUMERIC(0, referenceid),
                   UA_QUALIFIEDNAME(0, name), UA_NODEID_NUMERIC(0, type_id),
                   &object_attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
                   NULL, NULL);
}

static UA_StatusCode
addReferenceTypeNode(UA_Server *server, char* name, char *inverseName, UA_UInt32 referencetypeid,
                     UA_Boolean isabstract, UA_Boolean symmetric, UA_UInt32 parentid) {
    UA_ReferenceTypeAttributes reference_attr = UA_ReferenceTypeAttributes_default;
    reference_attr.displayName = UA_LOCALIZEDTEXT("", name);
    reference_attr.isAbstract = isabstract;
    reference_attr.symmetric = symmetric;
    if(inverseName)
        reference_attr.inverseName = UA_LOCALIZEDTEXT("", inverseName);
    return addNode(server, UA_NODECLASS_REFERENCETYPE, UA_NODEID_NUMERIC(0, referencetypeid),
                   UA_NODEID_NUMERIC(0, parentid), UA_NODEID_NULL, UA_QUALIFIEDNAME(0, name),
                   UA_NODEID_NULL, &reference_attr,
                   &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES], NULL, NULL);
}

/***************************/
/* Bootstrap NS0 hierarchy */
/***************************/

/* Creates the basic nodes which are expected by the nodeset compiler to be
 * already created. This is necessary to reduce the dependencies for the nodeset
 * compiler. */
static UA_StatusCode
createNS0_base(UA_Server *server) {
    /* Bootstrap ReferenceTypes. The order of these is important for the
     * ReferenceTypeIndex. The ReferenceTypeIndex is created with the raw node.
     * The ReferenceTypeSet of subtypes for every ReferenceType is created
     * during the call to AddNode_finish. */
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    UA_ReferenceTypeAttributes references_attr = UA_ReferenceTypeAttributes_default;
    references_attr.displayName = UA_LOCALIZEDTEXT("", "References");
    references_attr.isAbstract = true;
    references_attr.symmetric = true;
    references_attr.inverseName = UA_LOCALIZEDTEXT("", "References");
    ret |= ns0_addNode_raw(server, UA_NODECLASS_REFERENCETYPE, UA_NS0ID_REFERENCES, "References",
                           &references_attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES]);

    UA_ReferenceTypeAttributes hassubtype_attr = UA_ReferenceTypeAttributes_default;
    hassubtype_attr.displayName = UA_LOCALIZEDTEXT("", "HasSubtype");
    hassubtype_attr.isAbstract = false;
    hassubtype_attr.symmetric = false;
    hassubtype_attr.inverseName = UA_LOCALIZEDTEXT("", "SubtypeOf");
    ret |= ns0_addNode_raw(server, UA_NODECLASS_REFERENCETYPE, UA_NS0ID_HASSUBTYPE, "HasSubtype",
                           &hassubtype_attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES]);

    UA_ReferenceTypeAttributes aggregates_attr = UA_ReferenceTypeAttributes_default;
    aggregates_attr.displayName = UA_LOCALIZEDTEXT("", "Aggregates");
    aggregates_attr.isAbstract = true;
    aggregates_attr.symmetric = false;
    aggregates_attr.inverseName = UA_LOCALIZEDTEXT("", "AggregatedBy");
    ret |= ns0_addNode_raw(server, UA_NODECLASS_REFERENCETYPE, UA_NS0ID_AGGREGATES, "Aggregates",
                           &aggregates_attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES]);

    ret |= addReferenceTypeNode(server, "HierarchicalReferences", NULL,
                         UA_NS0ID_HIERARCHICALREFERENCES, true, false, UA_NS0ID_REFERENCES);

    ret |= addReferenceTypeNode(server, "NonHierarchicalReferences", NULL,
                         UA_NS0ID_NONHIERARCHICALREFERENCES, true, true, UA_NS0ID_REFERENCES);

    ret |= addReferenceTypeNode(server, "HasChild", NULL, UA_NS0ID_HASCHILD,
                         true, false, UA_NS0ID_HIERARCHICALREFERENCES);

    ret |= addReferenceTypeNode(server, "Organizes", "OrganizedBy", UA_NS0ID_ORGANIZES,
                         false, false, UA_NS0ID_HIERARCHICALREFERENCES);

    ret |= addReferenceTypeNode(server, "HasEventSource", "EventSourceOf", UA_NS0ID_HASEVENTSOURCE,
                         false, false, UA_NS0ID_HIERARCHICALREFERENCES);

    ret |= addReferenceTypeNode(server, "HasModellingRule", "ModellingRuleOf", UA_NS0ID_HASMODELLINGRULE,
                         false, false, UA_NS0ID_NONHIERARCHICALREFERENCES);

    ret |= addReferenceTypeNode(server, "HasEncoding", "EncodingOf", UA_NS0ID_HASENCODING,
                         false, false, UA_NS0ID_NONHIERARCHICALREFERENCES);

    ret |= addReferenceTypeNode(server, "HasDescription", "DescriptionOf", UA_NS0ID_HASDESCRIPTION,
                         false, false, UA_NS0ID_NONHIERARCHICALREFERENCES);

    ret |= addReferenceTypeNode(server, "HasTypeDefinition", "TypeDefinitionOf", UA_NS0ID_HASTYPEDEFINITION,
                         false, false, UA_NS0ID_NONHIERARCHICALREFERENCES);

    ret |= addReferenceTypeNode(server, "GeneratesEvent", "GeneratedBy", UA_NS0ID_GENERATESEVENT,
                         false, false, UA_NS0ID_NONHIERARCHICALREFERENCES);

    /* Complete bootstrap of Aggregates */
    ret |= ns0_addNode_finish(server, UA_NS0ID_AGGREGATES, UA_NS0ID_HASCHILD, UA_NS0ID_HASSUBTYPE);

    /* Complete bootstrap of HasSubtype */
    ret |= ns0_addNode_finish(server, UA_NS0ID_HASSUBTYPE, UA_NS0ID_HASCHILD, UA_NS0ID_HASSUBTYPE);

    ret |= addReferenceTypeNode(server, "HasProperty", "PropertyOf", UA_NS0ID_HASPROPERTY,
                         false, false, UA_NS0ID_AGGREGATES);

    ret |= addReferenceTypeNode(server, "HasComponent", "ComponentOf", UA_NS0ID_HASCOMPONENT,
                         false, false, UA_NS0ID_AGGREGATES);

    ret |= addReferenceTypeNode(server, "HasNotifier", "NotifierOf", UA_NS0ID_HASNOTIFIER,
                         false, false, UA_NS0ID_HASEVENTSOURCE);

    ret |= addReferenceTypeNode(server, "HasOrderedComponent", "OrderedComponentOf",
                         UA_NS0ID_HASORDEREDCOMPONENT, false, false, UA_NS0ID_HASCOMPONENT);

    ret |= addReferenceTypeNode(server, "HasInterface", "InterfaceOf",
                         UA_NS0ID_HASINTERFACE, false, false, UA_NS0ID_NONHIERARCHICALREFERENCES);

    /**************/
    /* Data Types */
    /**************/

    /* Bootstrap BaseDataType */
    UA_DataTypeAttributes basedatatype_attr = UA_DataTypeAttributes_default;
    basedatatype_attr.displayName = UA_LOCALIZEDTEXT("", "BaseDataType");
    basedatatype_attr.isAbstract = true;
    ret |= ns0_addNode_raw(server, UA_NODECLASS_DATATYPE, UA_NS0ID_BASEDATATYPE, "BaseDataType",
                           &basedatatype_attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES]);

    /*****************/
    /* VariableTypes */
    /*****************/

    UA_VariableTypeAttributes basevar_attr = UA_VariableTypeAttributes_default;
    basevar_attr.displayName = UA_LOCALIZEDTEXT("", "BaseVariableType");
    basevar_attr.isAbstract = true;
    basevar_attr.valueRank = UA_VALUERANK_ANY;
    basevar_attr.dataType = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE);
    ret |= ns0_addNode_raw(server, UA_NODECLASS_VARIABLETYPE,
                           UA_NS0ID_BASEVARIABLETYPE, "BaseVariableType",
                           &basevar_attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES]);

    UA_VariableTypeAttributes bdv_attr = UA_VariableTypeAttributes_default;
    bdv_attr.displayName = UA_LOCALIZEDTEXT("", "BaseDataVariableType");
    bdv_attr.dataType = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE);
    bdv_attr.valueRank = UA_VALUERANK_ANY;
    ret |= addNode(server, UA_NODECLASS_VARIABLETYPE,
                   UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
                   UA_NODEID_NUMERIC(0, UA_NS0ID_BASEVARIABLETYPE),
                   UA_NODEID_NULL, UA_QUALIFIEDNAME(0, "BaseDataVariableType"),
                   UA_NODEID_NULL, &bdv_attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],
                   NULL, NULL);

    UA_VariableTypeAttributes prop_attr = UA_VariableTypeAttributes_default;
    prop_attr.displayName = UA_LOCALIZEDTEXT("", "PropertyType");
    prop_attr.dataType = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE);
    prop_attr.valueRank = UA_VALUERANK_ANY;
    ret |= addNode(server, UA_NODECLASS_VARIABLETYPE,
                   UA_NODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE),
                   UA_NODEID_NUMERIC(0, UA_NS0ID_BASEVARIABLETYPE),
                   UA_NODEID_NULL, UA_QUALIFIEDNAME(0, "PropertyType"),
                   UA_NODEID_NULL, &prop_attr,
                   &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES], NULL, NULL);

    /***************/
    /* ObjectTypes */
    /***************/

    UA_ObjectTypeAttributes baseobj_attr = UA_ObjectTypeAttributes_default;
    baseobj_attr.displayName = UA_LOCALIZEDTEXT("", "BaseObjectType");
    ret |= ns0_addNode_raw(server, UA_NODECLASS_OBJECTTYPE,
                           UA_NS0ID_BASEOBJECTTYPE, "BaseObjectType",
                           &baseobj_attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES]);

    UA_ObjectTypeAttributes folder_attr = UA_ObjectTypeAttributes_default;
    folder_attr.displayName = UA_LOCALIZEDTEXT("", "FolderType");
    ret |= addNode(server, UA_NODECLASS_OBJECTTYPE,
                   UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE),
                   UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
                   UA_NODEID_NULL, UA_QUALIFIEDNAME(0, "FolderType"),
                   UA_NODEID_NULL,
                   &folder_attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES], NULL, NULL);

    /******************/
    /* Root and below */
    /******************/

    ret |= addObjectNode(server, "Root", UA_NS0ID_ROOTFOLDER, 0, 0, UA_NS0ID_FOLDERTYPE);

    ret |= addObjectNode(server, "Objects", UA_NS0ID_OBJECTSFOLDER, UA_NS0ID_ROOTFOLDER,
                  UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE);

    ret |= addObjectNode(server, "Types", UA_NS0ID_TYPESFOLDER, UA_NS0ID_ROOTFOLDER,
                  UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE);

    ret |= addObjectNode(server, "ReferenceTypes", UA_NS0ID_REFERENCETYPESFOLDER, UA_NS0ID_TYPESFOLDER,
                  UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE);
    ret |= ns0_addNode_finish(server, UA_NS0ID_REFERENCES,
                              UA_NS0ID_REFERENCETYPESFOLDER, UA_NS0ID_ORGANIZES);

    ret |= addObjectNode(server, "DataTypes", UA_NS0ID_DATATYPESFOLDER, UA_NS0ID_TYPESFOLDER,
                  UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE);
    ret |= ns0_addNode_finish(server, UA_NS0ID_BASEDATATYPE,
                              UA_NS0ID_DATATYPESFOLDER, UA_NS0ID_ORGANIZES);

    ret |= addObjectNode(server, "VariableTypes", UA_NS0ID_VARIABLETYPESFOLDER, UA_NS0ID_TYPESFOLDER,
                  UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE);
    ret |= ns0_addNode_finish(server, UA_NS0ID_BASEVARIABLETYPE,
                              UA_NS0ID_VARIABLETYPESFOLDER, UA_NS0ID_ORGANIZES);

    ret |= addObjectNode(server, "ObjectTypes", UA_NS0ID_OBJECTTYPESFOLDER, UA_NS0ID_TYPESFOLDER,
                  UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE);
    ret |= ns0_addNode_finish(server, UA_NS0ID_BASEOBJECTTYPE,
                              UA_NS0ID_OBJECTTYPESFOLDER, UA_NS0ID_ORGANIZES);

    ret |= addObjectNode(server, "EventTypes", UA_NS0ID_EVENTTYPESFOLDER, UA_NS0ID_TYPESFOLDER,
                  UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE);

    ret |= addObjectNode(server, "Views", UA_NS0ID_VIEWSFOLDER, UA_NS0ID_ROOTFOLDER,
                  UA_NS0ID_ORGANIZES, UA_NS0ID_FOLDERTYPE);

    /* Add BaseEventType */
    UA_ObjectTypeAttributes eventtype_attr = UA_ObjectTypeAttributes_default;
    eventtype_attr.displayName = UA_LOCALIZEDTEXT("", "BaseEventType");
    ret |= addNode(server, UA_NODECLASS_OBJECTTYPE,
                   UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE),
                   UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
                   UA_NODEID_NULL, UA_QUALIFIEDNAME(0, "BaseEventType"),
                   UA_NODEID_NULL,
                   &eventtype_attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES], NULL, NULL);
    ret |= addRef(server,
                  UA_NODEID_NUMERIC(0, UA_NS0ID_EVENTTYPESFOLDER),
                  UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
                  UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE), true);

    if(ret != UA_STATUSCODE_GOOD)
        ret = UA_STATUSCODE_BADINTERNALERROR;

    return ret;
}

/****************/
/* Data Sources */
/****************/

static UA_StatusCode
writeStatus(UA_Server *server, const UA_NodeId *sessionId,
            void *sessionContext, const UA_NodeId *nodeId,
            void *nodeContext, const UA_NumericRange *range,
            const UA_DataValue *value) {
    if(range)
        return UA_STATUSCODE_BADINDEXRANGEINVALID;

    if(nodeId->identifier.numeric != UA_NS0ID_SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Only the local user can write into this variable */
    if(sessionId != &server->adminSession.sessionId)
        return UA_STATUSCODE_BADUSERACCESSDENIED;

    if(!UA_Variant_hasScalarType(&value->value, &UA_TYPES[UA_TYPES_UINT32]))
        return UA_STATUSCODE_BADTYPEMISMATCH;

    UA_EventLoop *el = server->config.eventLoop;
    UA_UInt32 *endTime = (UA_UInt32*)value->value.data;
    server->endTime = el->dateTime_now(el) + (UA_DateTime)(*endTime * UA_DATETIME_SEC);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
readStatus(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
           const UA_NodeId *nodeId, void *nodeContext, UA_Boolean sourceTimestamp,
           const UA_NumericRange *range, UA_DataValue *value) {
    UA_EventLoop *el = server->config.eventLoop;

    if(range) {
        value->hasStatus = true;
        value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
        return UA_STATUSCODE_GOOD;
    }

    if(sourceTimestamp) {
        value->hasSourceTimestamp = true;
        value->sourceTimestamp = el->dateTime_now(el);
    }

    void *data = NULL;

    UA_assert(nodeId->identifierType == UA_NODEIDTYPE_NUMERIC);

    switch(nodeId->identifier.numeric) {
    case UA_NS0ID_SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN: {
        UA_UInt32 *shutdown = UA_UInt32_new();
        if(!shutdown)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        if(server->endTime != 0)
            *shutdown = (UA_UInt32)((server->endTime - el->dateTime_now(el)) / UA_DATETIME_SEC);
        value->value.data = shutdown;
        value->value.type = &UA_TYPES[UA_TYPES_UINT32];
        value->hasValue = true;
        return UA_STATUSCODE_GOOD;
    }

    case UA_NS0ID_SERVER_SERVERSTATUS_STATE: {
        UA_ServerState *state = UA_ServerState_new();
        if(!state)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        if(server->endTime != 0)
            *state = UA_SERVERSTATE_SHUTDOWN;
        value->value.data = state;
        value->value.type = &UA_TYPES[UA_TYPES_SERVERSTATE];
        value->hasValue = true;
        return UA_STATUSCODE_GOOD;
    }

    case UA_NS0ID_SERVER_SERVERSTATUS: {
        UA_ServerStatusDataType *statustype = UA_ServerStatusDataType_new();
        if(!statustype)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        statustype->startTime = server->startTime;
        statustype->currentTime = el->dateTime_now(el);

        statustype->state = UA_SERVERSTATE_RUNNING;
        statustype->secondsTillShutdown = 0;
        if(server->endTime != 0) {
            statustype->state = UA_SERVERSTATE_SHUTDOWN;
            statustype->secondsTillShutdown = (UA_UInt32)
                ((server->endTime - el->dateTime_now(el)) / UA_DATETIME_SEC);
        }

        value->value.data = statustype;
        value->value.type = &UA_TYPES[UA_TYPES_SERVERSTATUSDATATYPE];
        value->hasValue = true;
        return UA_BuildInfo_copy(&server->config.buildInfo, &statustype->buildInfo);
    }

    case UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO:
        value->value.type = &UA_TYPES[UA_TYPES_BUILDINFO];
        data = &server->config.buildInfo;
        break;

    case UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTURI:
        value->value.type = &UA_TYPES[UA_TYPES_STRING];
        data = &server->config.buildInfo.productUri;
        break;

    case UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_MANUFACTURERNAME:
        value->value.type = &UA_TYPES[UA_TYPES_STRING];
        data = &server->config.buildInfo.manufacturerName;
        break;

    case UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTNAME:
        value->value.type = &UA_TYPES[UA_TYPES_STRING];
        data = &server->config.buildInfo.productName;
        break;

    case UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_SOFTWAREVERSION:
        value->value.type = &UA_TYPES[UA_TYPES_STRING];
        data = &server->config.buildInfo.softwareVersion;
        break;

    case UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER:
        value->value.type = &UA_TYPES[UA_TYPES_STRING];
        data = &server->config.buildInfo.buildNumber;
        break;

    case UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDDATE:
        value->value.type = &UA_TYPES[UA_TYPES_DATETIME];
        data = &server->config.buildInfo.buildDate;
        break;

    default:
        value->hasStatus = true;
        value->status = UA_STATUSCODE_BADINTERNALERROR;
        return UA_STATUSCODE_GOOD;
    }

    value->value.data = UA_new(value->value.type);
    if(!value->value.data) {
        value->value.type = NULL;
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    value->hasValue = true;
    return UA_copy(data, value->value.data, value->value.type);
}

#ifdef UA_GENERATED_NAMESPACE_ZERO
static UA_StatusCode
readServiceLevel(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
                 const UA_NodeId *nodeId, void *nodeContext, UA_Boolean includeSourceTimeStamp,
                 const UA_NumericRange *range, UA_DataValue *value) {
    UA_EventLoop *el = server->config.eventLoop;

    if(range) {
        value->hasStatus = true;
        value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
        return UA_STATUSCODE_GOOD;
    }

    value->value.type = &UA_TYPES[UA_TYPES_BYTE];
    value->value.arrayLength = 0;
    UA_Byte *byte = UA_Byte_new();
    if(!byte)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    *byte = 255;
    value->value.data = byte;
    value->value.arrayDimensionsSize = 0;
    value->value.arrayDimensions = NULL;
    value->hasValue = true;
    if(includeSourceTimeStamp) {
        value->hasSourceTimestamp = true;
        value->sourceTimestamp = el->dateTime_now(el);
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
readAuditing(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
             const UA_NodeId *nodeId, void *nodeContext, UA_Boolean includeSourceTimeStamp,
             const UA_NumericRange *range, UA_DataValue *value) {
    UA_EventLoop *el = server->config.eventLoop;

    if(range) {
        value->hasStatus = true;
        value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
        return UA_STATUSCODE_GOOD;
    }

    value->value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
    value->value.arrayLength = 0;
    UA_Boolean *boolean = UA_Boolean_new();
    if(!boolean)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    *boolean = false;
    value->value.data = boolean;
    value->value.arrayDimensionsSize = 0;
    value->value.arrayDimensions = NULL;
    value->hasValue = true;
    if(includeSourceTimeStamp) {
        value->hasSourceTimestamp = true;
        value->sourceTimestamp = el->dateTime_now(el);
    }
    return UA_STATUSCODE_GOOD;
}
#endif

static UA_StatusCode
readNamespaces(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
               const UA_NodeId *nodeid, void *nodeContext, UA_Boolean includeSourceTimeStamp,
               const UA_NumericRange *range,
               UA_DataValue *value) {
    UA_EventLoop *el = server->config.eventLoop;

    /* ensure that the uri for ns1 is set up from the app description */
    setupNs1Uri(server);

    if(range) {
        value->hasStatus = true;
        value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
        return UA_STATUSCODE_GOOD;
    }
    UA_StatusCode retval;
    retval = UA_Variant_setArrayCopy(&value->value, server->namespaces,
                                     server->namespacesSize, &UA_TYPES[UA_TYPES_STRING]);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    value->hasValue = true;
    if(includeSourceTimeStamp) {
        value->hasSourceTimestamp = true;
        value->sourceTimestamp = el->dateTime_now(el);
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
writeNamespaces(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
                const UA_NodeId *nodeid, void *nodeContext, const UA_NumericRange *range,
                const UA_DataValue *value) {
    /* Check the data type */
    if(!value->hasValue ||
       value->value.type != &UA_TYPES[UA_TYPES_STRING])
        return UA_STATUSCODE_BADTYPEMISMATCH;

    /* Check that the variant is not empty */
    if(!value->value.data)
        return UA_STATUSCODE_BADTYPEMISMATCH;

    /* TODO: Writing with a range is not implemented */
    if(range)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_String *newNamespaces = (UA_String*)value->value.data;
    size_t newNamespacesSize = value->value.arrayLength;

    /* Test if we append to the existing namespaces */
    if(newNamespacesSize <= server->namespacesSize)
        return UA_STATUSCODE_BADTYPEMISMATCH;

    /* ensure that the uri for ns1 is set up from the app description */
    setupNs1Uri(server);

    /* Test if the existing namespaces are unchanged */
    for(size_t i = 0; i < server->namespacesSize; ++i) {
        if(!UA_String_equal(&server->namespaces[i], &newNamespaces[i]))
            return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Add namespaces */
    for(size_t i = server->namespacesSize; i < newNamespacesSize; ++i)
        addNamespace(server, newNamespaces[i]);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
readCurrentTime(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
                const UA_NodeId *nodeid, void *nodeContext, UA_Boolean sourceTimeStamp,
                const UA_NumericRange *range, UA_DataValue *value) {
    UA_EventLoop *el = server->config.eventLoop;

    if(range) {
        value->hasStatus = true;
        value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
        return UA_STATUSCODE_GOOD;
    }

    UA_DateTime currentTime = el->dateTime_now(el);
    UA_StatusCode retval = UA_Variant_setScalarCopy(&value->value, &currentTime,
                                                    &UA_TYPES[UA_TYPES_DATETIME]);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    value->hasValue = true;
    if(sourceTimeStamp) {
        value->hasSourceTimestamp = true;
        value->sourceTimestamp = currentTime;
    }
    return UA_STATUSCODE_GOOD;
}

#ifdef UA_GENERATED_NAMESPACE_ZERO
static UA_StatusCode
readOperationLimits(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
                        const UA_NodeId *nodeid, void *nodeContext, UA_Boolean includeSourceTimeStamp,
                        const UA_NumericRange *range,
                        UA_DataValue *value) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(nodeid->identifierType != UA_NODEIDTYPE_NUMERIC)
        return UA_STATUSCODE_BADNOTSUPPORTED;
    switch(nodeid->identifier.numeric) {
        case UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERREAD:
            retval = UA_Variant_setScalarCopy(&value->value, &server->config.maxNodesPerRead, &UA_TYPES[UA_TYPES_UINT32]);
            break;
        case UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERWRITE:
            retval = UA_Variant_setScalarCopy(&value->value, &server->config.maxNodesPerWrite, &UA_TYPES[UA_TYPES_UINT32]);
            break;
        case UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERMETHODCALL:
            retval = UA_Variant_setScalarCopy(&value->value, &server->config.maxNodesPerMethodCall, &UA_TYPES[UA_TYPES_UINT32]);
            break;
        case UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERBROWSE:
            retval = UA_Variant_setScalarCopy(&value->value, &server->config.maxNodesPerBrowse, &UA_TYPES[UA_TYPES_UINT32]);
            break;
        case UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERREGISTERNODES:
            retval = UA_Variant_setScalarCopy(&value->value, &server->config.maxNodesPerRegisterNodes, &UA_TYPES[UA_TYPES_UINT32]);
            break;
        case UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERTRANSLATEBROWSEPATHSTONODEIDS:
            retval = UA_Variant_setScalarCopy(&value->value, &server->config.maxNodesPerTranslateBrowsePathsToNodeIds, &UA_TYPES[UA_TYPES_UINT32]);
            break;
        case UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERNODEMANAGEMENT:
            retval = UA_Variant_setScalarCopy(&value->value, &server->config.maxNodesPerNodeManagement, &UA_TYPES[UA_TYPES_UINT32]);
            break;
        case UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXMONITOREDITEMSPERCALL:
            retval = UA_Variant_setScalarCopy(&value->value, &server->config.maxMonitoredItemsPerCall, &UA_TYPES[UA_TYPES_UINT32]);
            break;
        default:
            retval = UA_STATUSCODE_BADNOTSUPPORTED;
    }
    return retval;
}

static UA_StatusCode
readMinSamplingInterval(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
               const UA_NodeId *nodeid, void *nodeContext, UA_Boolean includeSourceTimeStamp,
               const UA_NumericRange *range, UA_DataValue *value) {
    UA_EventLoop *el = server->config.eventLoop;

    if(range) {
        value->hasStatus = true;
        value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
        return UA_STATUSCODE_GOOD;
    }

    UA_StatusCode retval;
    UA_Duration minInterval;
#ifdef UA_ENABLE_SUBSCRIPTIONS
    minInterval = server->config.samplingIntervalLimits.min;
#else
    minInterval = 0.0;
#endif
    retval = UA_Variant_setScalarCopy(&value->value, &minInterval, &UA_TYPES[UA_TYPES_DURATION]);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    value->hasValue = true;
    if(includeSourceTimeStamp) {
        value->hasSourceTimestamp = true;
        value->sourceTimestamp = el->dateTime_now(el);
    }
    return UA_STATUSCODE_GOOD;
}
#endif

#if defined(UA_GENERATED_NAMESPACE_ZERO) && defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS)
static UA_StatusCode
resendData(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
           const UA_NodeId *methodId, void *methodContext, const UA_NodeId *objectId,
           void *objectContext, size_t inputSize, const UA_Variant *input,
           size_t outputSize, UA_Variant *output) {
    /* Get the input argument */
    if(inputSize != 1 ||
       !UA_Variant_hasScalarType(input, &UA_TYPES[UA_TYPES_UINT32]))
        return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
    UA_UInt32 subscriptionId = *((UA_UInt32*)(input[0].data));

    /* Get the Session */
    UA_LOCK(&server->serviceMutex);
    UA_Session *session = getSessionById(server, sessionId);
    if(!session) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Get the Subscription */
    UA_Subscription *subscription = getSubscriptionById(server, subscriptionId);
    if(!subscription) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
    }

    /* The Subscription is not attached to this Session */
    if(subscription->session != session) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADUSERACCESSDENIED;
    }

    UA_Subscription_resendData(server, subscription);

    UA_UNLOCK(&server->serviceMutex);
    return UA_STATUSCODE_GOOD;
}
static UA_StatusCode
readMonitoredItems(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
                   const UA_NodeId *methodId, void *methodContext, const UA_NodeId *objectId,
                   void *objectContext, size_t inputSize, const UA_Variant *input,
                   size_t outputSize, UA_Variant *output) {
    /* Return two empty arrays by default */
    UA_Variant_setArray(&output[0], UA_Array_new(0, &UA_TYPES[UA_TYPES_UINT32]),
                        0, &UA_TYPES[UA_TYPES_UINT32]);
    UA_Variant_setArray(&output[1], UA_Array_new(0, &UA_TYPES[UA_TYPES_UINT32]),
                        0, &UA_TYPES[UA_TYPES_UINT32]);

    /* Get the Session */
    UA_LOCK(&server->serviceMutex);
    UA_Session *session = getSessionById(server, sessionId);
    if(!session) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    if(inputSize == 0 || !input[0].data) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
    }

    /* Get the Subscription */
    UA_UInt32 subscriptionId = *((UA_UInt32*)(input[0].data));
    UA_Subscription *subscription = getSubscriptionById(server, subscriptionId);
    if(!subscription) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
    }

    /* The Subscription is not attached to this Session */
    if(subscription->session != session) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADUSERACCESSDENIED;
    }

    /* Count the MonitoredItems */
    UA_UInt32 sizeOfOutput = 0;
    UA_MonitoredItem* monitoredItem;
    LIST_FOREACH(monitoredItem, &subscription->monitoredItems, listEntry) {
        ++sizeOfOutput;
    }
    if(sizeOfOutput == 0) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_GOOD;
    }

    /* Allocate the output arrays */
    UA_UInt32 *clientHandles = (UA_UInt32*)
        UA_Array_new(sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]);
    if(!clientHandles) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    UA_UInt32 *serverHandles = (UA_UInt32*)
        UA_Array_new(sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]);
    if(!serverHandles) {
        UA_UNLOCK(&server->serviceMutex);
        UA_free(clientHandles);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    /* Fill the array */
    UA_UInt32 i = 0;
    LIST_FOREACH(monitoredItem, &subscription->monitoredItems, listEntry) {
        clientHandles[i] = monitoredItem->parameters.clientHandle;
        serverHandles[i] = monitoredItem->monitoredItemId;
        ++i;
    }
    UA_Variant_setArray(&output[0], serverHandles, sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]);
    UA_Variant_setArray(&output[1], clientHandles, sizeOfOutput, &UA_TYPES[UA_TYPES_UINT32]);

    UA_UNLOCK(&server->serviceMutex);
    return UA_STATUSCODE_GOOD;
}
#endif /* defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS) */

static UA_StatusCode
writeNs0VariableArray(UA_Server *server, UA_UInt32 id, void *v,
                      size_t length, const UA_DataType *type) {
    UA_Variant var;
    UA_Variant_init(&var);
    UA_Variant_setArray(&var, v, length, type);
    return writeValueAttribute(server, UA_NODEID_NUMERIC(0, id), &var);
}

#ifdef UA_GENERATED_NAMESPACE_ZERO
static UA_StatusCode
writeNs0Variable(UA_Server *server, UA_UInt32 id, void *v, const UA_DataType *type) {
    UA_Variant var;
    UA_Variant_init(&var);
    UA_Variant_setScalar(&var, v, type);
    return writeValueAttribute(server, UA_NODEID_NUMERIC(0, id), &var);
}
#endif

#ifndef UA_GENERATED_NAMESPACE_ZERO
static UA_StatusCode
addVariableNode(UA_Server *server, char* name, UA_UInt32 variableid,
                UA_UInt32 parentid, UA_UInt32 referenceid,
                UA_Int32 valueRank, UA_UInt32 dataType) {
    UA_VariableAttributes attr = UA_VariableAttributes_default;
    attr.displayName = UA_LOCALIZEDTEXT("", name);
    attr.dataType = UA_NODEID_NUMERIC(0, dataType);
    attr.valueRank = valueRank;
    attr.accessLevel = UA_ACCESSLEVELMASK_READ;
    return addNode(server, UA_NODECLASS_VARIABLE, UA_NODEID_NUMERIC(0, variableid),
                   UA_NODEID_NUMERIC(0, parentid), UA_NODEID_NUMERIC(0, referenceid),
                   UA_QUALIFIEDNAME(0, name),
                   UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
                   &attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES], NULL, NULL);
}

/* A minimal server object that is not complete and does not use the mandated
 * references to a server type. To be used on very constrained devices. */
static UA_StatusCode
minimalServerObject(UA_Server *server) {
    /* Server */
    UA_StatusCode retval = addObjectNode(server, "Server", UA_NS0ID_SERVER, UA_NS0ID_OBJECTSFOLDER,
                                         UA_NS0ID_ORGANIZES, UA_NS0ID_BASEOBJECTTYPE);

    /* Use a valuerank of -2 for now. The array is added later on and the valuerank set to 1. */
    retval |= addVariableNode(server, "ServerArray", UA_NS0ID_SERVER_SERVERARRAY,
                              UA_NS0ID_SERVER, UA_NS0ID_HASPROPERTY,
                              UA_VALUERANK_ANY, UA_NS0ID_BASEDATATYPE);

    retval |= addVariableNode(server, "NamespaceArray", UA_NS0ID_SERVER_NAMESPACEARRAY,
                              UA_NS0ID_SERVER, UA_NS0ID_HASPROPERTY,
                              UA_VALUERANK_ANY, UA_NS0ID_BASEDATATYPE);

    retval |= addVariableNode(server, "ServerStatus", UA_NS0ID_SERVER_SERVERSTATUS,
                              UA_NS0ID_SERVER, UA_NS0ID_HASCOMPONENT,
                              UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE);

    retval |= addVariableNode(server, "StartTime", UA_NS0ID_SERVER_SERVERSTATUS_STARTTIME,
                              UA_NS0ID_SERVER_SERVERSTATUS, UA_NS0ID_HASCOMPONENT,
                              UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE);

    retval |= addVariableNode(server, "CurrentTime", UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME,
                              UA_NS0ID_SERVER_SERVERSTATUS, UA_NS0ID_HASCOMPONENT,
                              UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE);

    retval |= addVariableNode(server, "State", UA_NS0ID_SERVER_SERVERSTATUS_STATE,
                              UA_NS0ID_SERVER_SERVERSTATUS, UA_NS0ID_HASCOMPONENT,
                              UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE);

    retval |= addVariableNode(server, "BuildInfo", UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO,
                              UA_NS0ID_SERVER_SERVERSTATUS, UA_NS0ID_HASCOMPONENT,
                              UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE);

    retval |= addVariableNode(server, "ProductUri", UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTURI,
                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT,
                              UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE);

    retval |= addVariableNode(server, "ManufacturerName",
                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_MANUFACTURERNAME,
                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT,
                              UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE);

    retval |= addVariableNode(server, "ProductName",
                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTNAME,
                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT,
                              UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE);

    retval |= addVariableNode(server, "SoftwareVersion",
                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_SOFTWAREVERSION,
                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT,
                              UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE);

    retval |= addVariableNode(server, "BuildNumber",
                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER,
                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT,
                              UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE);

    retval |= addVariableNode(server, "BuildDate",
                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDDATE,
                              UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO, UA_NS0ID_HASCOMPONENT,
                              UA_VALUERANK_SCALAR, UA_NS0ID_BASEDATATYPE);

    return retval;
}

#else

static void
addModellingRules(UA_Server *server) {
    /* Test if the ModellingRules folder was added. (Only for the full ns0.) */
    UA_NodeId mrNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MODELLINGRULES);
    const UA_Node *mrnode = UA_NODESTORE_GET(server, &mrNodeId);
    if(!mrnode)
        return;
    UA_NODESTORE_RELEASE(server, mrnode);

    /* Add ExposesItsArray */
    addRef(server,
           UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MODELLINGRULES),
           UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
           UA_NODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_EXPOSESITSARRAY), true);

    /* Add Mandatory */
    addRef(server,
           UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MODELLINGRULES),
           UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
           UA_NODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY), true);


    /* Add MandatoryPlaceholder */
    addRef(server,
           UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MODELLINGRULES),
           UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
           UA_NODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORYPLACEHOLDER), true);

    /* Add Optional */
    addRef(server,
           UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MODELLINGRULES),
           UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
           UA_NODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_OPTIONAL), true);

    /* Add OptionalPlaceholder */
    addRef(server,
           UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MODELLINGRULES),
           UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
           UA_NODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_OPTIONALPLACEHOLDER), true);
}

#endif

/* Initialize the nodeset 0 by using the generated code of the nodeset compiler.
 * This also initialized the data sources for various variables, such as for
 * example server time. */
UA_StatusCode
initNS0(UA_Server *server) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Initialize base nodes which are always required an cannot be created
     * through the NS compiler */
    server->bootstrapNS0 = true;
    UA_StatusCode retVal = createNS0_base(server);

#ifdef UA_GENERATED_NAMESPACE_ZERO
    UA_UNLOCK(&server->serviceMutex);
    /* Load nodes and references generated from the XML ns0 definition */
    retVal |= namespace0_generated(server);
    UA_LOCK(&server->serviceMutex);
#else
    /* Create a minimal server object */
    retVal |= minimalServerObject(server);
#endif

    server->bootstrapNS0 = false;

    if(retVal != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Initialization of Namespace 0 failed with %s. "
                     "See previous outputs for any error messages.",
                     UA_StatusCode_name(retVal));
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* NamespaceArray */
    UA_DataSource namespaceDataSource = {readNamespaces, writeNamespaces};
    retVal |= setVariableNode_dataSource(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY),
                                         namespaceDataSource);
    retVal |= writeValueRankAttribute(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY), 1);

    /* ServerArray */
    retVal |= writeNs0VariableArray(server, UA_NS0ID_SERVER_SERVERARRAY,
                                    &server->config.applicationDescription.applicationUri,
                                    1, &UA_TYPES[UA_TYPES_STRING]);
    retVal |= writeValueRankAttribute(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERARRAY), 1);

    /* ServerStatus */
    UA_DataSource serverStatus = {readStatus, writeStatus};
    retVal |= setVariableNode_dataSource(server,
                        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS), serverStatus);

    /* StartTime will be sampled in UA_Server_run_startup()*/

    /* CurrentTime */
    UA_DataSource currentTime = {readCurrentTime, NULL};
    UA_NodeId currTime = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
    retVal |= setVariableNode_dataSource(server, currTime, currentTime);
    retVal |= writeMinimumSamplingIntervalAttribute(server, currTime, 100.0);

    /* State */
    retVal |= setVariableNode_dataSource(server,
                 UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE), serverStatus);

    /* BuildInfo */
    retVal |= setVariableNode_dataSource(server,
                 UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO), serverStatus);

    /* BuildInfo - ProductUri */
    retVal |= setVariableNode_dataSource(server,
                 UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTURI),
                                                   serverStatus);

    /* BuildInfo - ManufacturerName */
    retVal |= setVariableNode_dataSource(server,
                 UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_MANUFACTURERNAME),
                                                   serverStatus);

    /* BuildInfo - ProductName */
    retVal |= setVariableNode_dataSource(server,
                 UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_PRODUCTNAME),
                                                   serverStatus);

    /* BuildInfo - SoftwareVersion */
    retVal |= setVariableNode_dataSource(server,
                 UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_SOFTWAREVERSION),
                                                   serverStatus);

    /* BuildInfo - BuildNumber */
    retVal |= setVariableNode_dataSource(server,
                 UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDNUMBER),
                                                   serverStatus);

    /* BuildInfo - BuildDate */
    retVal |= setVariableNode_dataSource(server,
                 UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_BUILDINFO_BUILDDATE),
                                                   serverStatus);

#ifdef UA_GENERATED_NAMESPACE_ZERO

    /* SecondsTillShutdown */
    retVal |= setVariableNode_dataSource(server,
                 UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN),
                                                   serverStatus);

    /* ShutDownReason */
    UA_LocalizedText shutdownReason;
    UA_LocalizedText_init(&shutdownReason);
    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERSTATUS_SHUTDOWNREASON,
                               &shutdownReason, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);

    /* ServiceLevel */
    UA_DataSource serviceLevel = {readServiceLevel, NULL};
    retVal |= setVariableNode_dataSource(server,
                        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVICELEVEL), serviceLevel);

    /* ServerDiagnostics - EnabledFlag */
#ifdef UA_ENABLE_DIAGNOSTICS
    UA_Boolean enabledFlag = true;
#else
    UA_Boolean enabledFlag = false;
#endif
    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_ENABLEDFLAG,
                               &enabledFlag, &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* According to Specification part-5 - pg.no-11(PDF pg.no-29), when the ServerDiagnostics is disabled the client
     * may modify the value of enabledFlag=true in the server. By default, this node have CurrentRead/Write access.
     * In CTT, Subscription_Minimum_1/002.js test will modify the above flag. This will not be a problem when build
     * configuration is set at UA_NAMESPACE_ZERO="REDUCED" as NodeIds will not be present. When UA_NAMESPACE_ZERO="FULL",
     * the test will fail. Hence made the NodeId as read only */
    retVal |= writeAccessLevelAttribute(server,
                       UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_ENABLEDFLAG),
                                        UA_ACCESSLEVELMASK_READ);

    /* Auditing */
    UA_DataSource auditing = {readAuditing, NULL};
    retVal |= setVariableNode_dataSource(server,
                        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_AUDITING), auditing);

    /* Redundancy Support */
    UA_RedundancySupport redundancySupport = UA_REDUNDANCYSUPPORT_NONE;
    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERREDUNDANCY_REDUNDANCYSUPPORT,
                               &redundancySupport, &UA_TYPES[UA_TYPES_REDUNDANCYSUPPORT]);
    /* Remove unused subtypes of ServerRedundancy */
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERREDUNDANCY_CURRENTSERVERID), true);
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERREDUNDANCY_REDUNDANTSERVERARRAY), true);
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERREDUNDANCY_SERVERURIARRAY), true);
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERREDUNDANCY_SERVERNETWORKGROUPS), true);
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_CONFORMANCEUNITS), true);
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_URISVERSION), true);
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_CONFORMANCEUNITS), true);
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXMONITOREDITEMS), true);
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXMONITOREDITEMSPERSUBSCRIPTION), true);
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXMONITOREDITEMSQUEUESIZE), true);
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXSELECTCLAUSEPARAMETERS), true);
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXSESSIONS), true);
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXSUBSCRIPTIONS), true);
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXSUBSCRIPTIONSPERSESSION), true);
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXWHERECLAUSEPARAMETERS), true);

    /* ServerCapabilities - LocaleIdArray */
    UA_LocaleId locale_en = UA_STRING("en");
    retVal |= writeNs0VariableArray(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_LOCALEIDARRAY,
                                    &locale_en, 1, &UA_TYPES[UA_TYPES_LOCALEID]);

    /* ServerCapabilities - MaxBrowseContinuationPoints */
    UA_UInt16 maxBrowseContinuationPoints = UA_MAXCONTINUATIONPOINTS;
    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXBROWSECONTINUATIONPOINTS,
                               &maxBrowseContinuationPoints, &UA_TYPES[UA_TYPES_UINT16]);

    /* ServerProfileArray */
    UA_String profileArray[3];
    UA_UInt16 profileArraySize = 0;
#define ADDPROFILEARRAY(x) profileArray[profileArraySize++] = UA_STRING(x)
    ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/StandardUA2017");
#ifdef UA_ENABLE_NODEMANAGEMENT
    ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/NodeManagement");
#endif
#ifdef UA_ENABLE_METHODCALLS
    ADDPROFILEARRAY("http://opcfoundation.org/UA-Profile/Server/Methods");
#endif
    retVal |= writeNs0VariableArray(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_SERVERPROFILEARRAY,
                                    profileArray, profileArraySize, &UA_TYPES[UA_TYPES_STRING]);

    /* ServerCapabilities - MaxQueryContinuationPoints */
    UA_UInt16 maxQueryContinuationPoints = 0;
    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXQUERYCONTINUATIONPOINTS,
                               &maxQueryContinuationPoints, &UA_TYPES[UA_TYPES_UINT16]);

    /* ServerCapabilities - MaxHistoryContinuationPoints */
    UA_UInt16 maxHistoryContinuationPoints = 0;
    retVal |= writeNs0Variable(server, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXHISTORYCONTINUATIONPOINTS,
                               &maxHistoryContinuationPoints, &UA_TYPES[UA_TYPES_UINT16]);

    /* ServerCapabilities - MinSupportedSampleRate */
    UA_DataSource samplingInterval = {readMinSamplingInterval, NULL};
    retVal |= setVariableNode_dataSource(server,
                 UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MINSUPPORTEDSAMPLERATE),
                                                   samplingInterval);

    /* ServerCapabilities - OperationLimits - MaxNodesPerRead */
    UA_DataSource operationLimitRead = {readOperationLimits, NULL};
    retVal |= setVariableNode_dataSource(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERREAD),
                                        operationLimitRead);

    /* ServerCapabilities - OperationLimits - maxNodesPerWrite */
    retVal |= setVariableNode_dataSource(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERWRITE),
                                        operationLimitRead);

    /* ServerCapabilities - OperationLimits - MaxNodesPerMethodCall */
    retVal |= setVariableNode_dataSource(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERMETHODCALL),
                                        operationLimitRead);

    /* ServerCapabilities - OperationLimits - MaxNodesPerBrowse */
    retVal |= setVariableNode_dataSource(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERBROWSE),
                                        operationLimitRead);

    /* ServerCapabilities - OperationLimits - MaxNodesPerRegisterNodes */
    retVal |= setVariableNode_dataSource(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERREGISTERNODES),
                                        operationLimitRead);

    /* ServerCapabilities - OperationLimits - MaxNodesPerTranslateBrowsePathsToNodeIds */
    retVal |= setVariableNode_dataSource(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERTRANSLATEBROWSEPATHSTONODEIDS),
                                        operationLimitRead);

    /* ServerCapabilities - OperationLimits - MaxNodesPerNodeManagement */
    retVal |= setVariableNode_dataSource(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERNODEMANAGEMENT),
                                        operationLimitRead);

    /* ServerCapabilities - OperationLimits - MaxMonitoredItemsPerCall */
    retVal |= setVariableNode_dataSource(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXMONITOREDITEMSPERCALL),
                                        operationLimitRead);

    /* Remove unused operation limit components */
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERHISTORYREADDATA), true);
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERHISTORYREADEVENTS), true);
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERHISTORYUPDATEDATA), true);
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_OPERATIONLIMITS_MAXNODESPERHISTORYUPDATEEVENTS), true);
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_ROLESET), true);
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXSTRINGLENGTH), true);
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXARRAYLENGTH), true);
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERCAPABILITIES_MAXBYTESTRINGLENGTH), true);

    /* Remove not supported server configurations */
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_ESTIMATEDRETURNTIME), true);
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_LOCALTIME), true);
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_REQUESTSERVERSTATECHANGE), true);
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SETSUBSCRIPTIONDURABLE), true);
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTHTTPSGROUP), true);
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVERCONFIGURATION_CERTIFICATEGROUPS_DEFAULTUSERTOKENGROUP), true);

#ifdef UA_ENABLE_DIAGNOSTICS
    /* ServerDiagnostics - ServerDiagnosticsSummary */
    UA_DataSource serverDiagSummary = {readDiagnostics, NULL};
    retVal |= setVariableNode_dataSource(server,
                        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY), serverDiagSummary);

    /* ServerDiagnostics - ServerDiagnosticsSummary - ServerViewCount */
    retVal |= setVariableNode_dataSource(server,
                        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SERVERVIEWCOUNT), serverDiagSummary);

    /* ServerDiagnostics - ServerDiagnosticsSummary - CurrentSessionCount */
    retVal |= setVariableNode_dataSource(server,
                        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CURRENTSESSIONCOUNT), serverDiagSummary);

    /* ServerDiagnostics - ServerDiagnosticsSummary - CumulatedSessionCount */
    retVal |= setVariableNode_dataSource(server,
                        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CUMULATEDSESSIONCOUNT), serverDiagSummary);

    /* ServerDiagnostics - ServerDiagnosticsSummary - SecurityRejectedSessionCount */
    retVal |= setVariableNode_dataSource(server,
                        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SECURITYREJECTEDSESSIONCOUNT), serverDiagSummary);

    /* ServerDiagnostics - ServerDiagnosticsSummary - RejectedSessionCount */
    retVal |= setVariableNode_dataSource(server,
                        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_REJECTEDSESSIONCOUNT), serverDiagSummary);

    /* ServerDiagnostics - ServerDiagnosticsSummary - SessionTimeoutCount */
    retVal |= setVariableNode_dataSource(server,
                        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SESSIONTIMEOUTCOUNT), serverDiagSummary);

    /* ServerDiagnostics - ServerDiagnosticsSummary - SessionAbortCount */
    retVal |= setVariableNode_dataSource(server,
                        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SESSIONABORTCOUNT), serverDiagSummary);

    /* ServerDiagnostics - ServerDiagnosticsSummary - CurrentSubscriptionCount */
    retVal |= setVariableNode_dataSource(server,
                        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CURRENTSUBSCRIPTIONCOUNT), serverDiagSummary);

    /* ServerDiagnostics - ServerDiagnosticsSummary - CumulatedSubscriptionCount */
    retVal |= setVariableNode_dataSource(server,
                        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CUMULATEDSUBSCRIPTIONCOUNT), serverDiagSummary);

    /* ServerDiagnostics - ServerDiagnosticsSummary - PublishingIntervalCount */
    retVal |= setVariableNode_dataSource(server,
                        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_PUBLISHINGINTERVALCOUNT), serverDiagSummary);

    /* ServerDiagnostics - ServerDiagnosticsSummary - SecurityRejectedRequestsCount */
    retVal |= setVariableNode_dataSource(server,
                        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SECURITYREJECTEDREQUESTSCOUNT), serverDiagSummary);

    /* ServerDiagnostics - ServerDiagnosticsSummary - RejectedRequestsCount */
    retVal |= setVariableNode_dataSource(server,
                        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_REJECTEDREQUESTSCOUNT), serverDiagSummary);

    /* ServerDiagnostics - SubscriptionDiagnosticsArray */
#ifdef UA_ENABLE_SUBSCRIPTIONS
    UA_DataSource serverSubDiagSummary = {readSubscriptionDiagnosticsArray, NULL};
    retVal |= setVariableNode_dataSource(server,
                        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SUBSCRIPTIONDIAGNOSTICSARRAY), serverSubDiagSummary);
#endif

    /* ServerDiagnostics - SessionDiagnosticsSummary - SessionDiagnosticsArray */
    UA_DataSource sessionDiagSummary = {readSessionDiagnosticsArray, NULL};
    retVal |= setVariableNode_dataSource(server,
                        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SESSIONSDIAGNOSTICSSUMMARY_SESSIONDIAGNOSTICSARRAY), sessionDiagSummary);

    /* ServerDiagnostics - SessionDiagnosticsSummary - SessionSecurityDiagnosticsArray */
    UA_DataSource sessionSecDiagSummary = {readSessionSecurityDiagnostics, NULL};
    retVal |= setVariableNode_dataSource(server,
                        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SESSIONSDIAGNOSTICSSUMMARY_SESSIONSECURITYDIAGNOSTICSARRAY), sessionSecDiagSummary);

#else
    /* Removing these NodeIds make Server Object to be non-complaint with UA
     * 1.03 in CTT (Base Inforamtion/Base Info Core Structure/ 001.js) In the
     * 1.04 specification this has been resolved by allowing to remove these
     * static nodes as well */
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SESSIONSDIAGNOSTICSSUMMARY), true);
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY), true);
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SUBSCRIPTIONDIAGNOSTICSARRAY), true);
#endif

    /* The sampling diagnostics array is optional
     * TODO: Add support for this diagnostics */
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SAMPLINGINTERVALDIAGNOSTICSARRAY), true);

#ifndef UA_ENABLE_PUBSUB
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE), true);
#endif

#ifndef UA_ENABLE_HISTORIZING
    deleteNode(server, UA_NODEID_NUMERIC(0, UA_NS0ID_HISTORYSERVERCAPABILITIES), true);
#else
    /* ServerCapabilities - HistoryServerCapabilities - AccessHistoryDataCapability */
    retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_ACCESSHISTORYDATACAPABILITY,
                               &server->config.accessHistoryDataCapability, &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* ServerCapabilities - HistoryServerCapabilities - MaxReturnDataValues */
    retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_MAXRETURNDATAVALUES,
                               &server->config.maxReturnDataValues, &UA_TYPES[UA_TYPES_UINT32]);

    /* ServerCapabilities - HistoryServerCapabilities - AccessHistoryEventsCapability */
    retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_ACCESSHISTORYEVENTSCAPABILITY,
                               &server->config.accessHistoryEventsCapability, &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* ServerCapabilities - HistoryServerCapabilities - MaxReturnEventValues */
    retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_MAXRETURNEVENTVALUES,
                               &server->config.maxReturnEventValues, &UA_TYPES[UA_TYPES_UINT32]);

    /* ServerCapabilities - HistoryServerCapabilities - InsertDataCapability */
    retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_INSERTDATACAPABILITY,
                               &server->config.insertDataCapability, &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* ServerCapabilities - HistoryServerCapabilities - InsertEventCapability */
    retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_INSERTEVENTCAPABILITY,
                               &server->config.insertEventCapability, &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* ServerCapabilities - HistoryServerCapabilities - InsertAnnotationsCapability */
    retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_INSERTANNOTATIONCAPABILITY,
                               &server->config.insertAnnotationsCapability, &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* ServerCapabilities - HistoryServerCapabilities - ReplaceDataCapability */
    retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_REPLACEDATACAPABILITY,
                               &server->config.replaceDataCapability, &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* ServerCapabilities - HistoryServerCapabilities - ReplaceEventCapability */
    retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_REPLACEEVENTCAPABILITY,
                               &server->config.replaceEventCapability, &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* ServerCapabilities - HistoryServerCapabilities - UpdateDataCapability */
    retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_UPDATEDATACAPABILITY,
                               &server->config.updateDataCapability, &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* ServerCapabilities - HistoryServerCapabilities - UpdateEventCapability */
    retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_UPDATEEVENTCAPABILITY,
                               &server->config.updateEventCapability, &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* ServerCapabilities - HistoryServerCapabilities - DeleteRawCapability */
    retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_DELETERAWCAPABILITY,
                               &server->config.deleteRawCapability, &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* ServerCapabilities - HistoryServerCapabilities - DeleteEventCapability */
    retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_DELETEEVENTCAPABILITY,
                               &server->config.deleteEventCapability, &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* ServerCapabilities - HistoryServerCapabilities - DeleteAtTimeDataCapability */
    retVal |= writeNs0Variable(server, UA_NS0ID_HISTORYSERVERCAPABILITIES_DELETEATTIMECAPABILITY,
                               &server->config.deleteAtTimeDataCapability, &UA_TYPES[UA_TYPES_BOOLEAN]);
#endif

#if defined(UA_ENABLE_METHODCALLS) && defined(UA_ENABLE_SUBSCRIPTIONS)
    retVal |= setMethodNode_callback(server,
                                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_GETMONITOREDITEMS),
                                     readMonitoredItems);

    retVal |= setMethodNode_callback(server,
                                     UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_RESENDDATA),
                                     resendData);
#endif

    /* The HasComponent references to the ModellingRules are not part of the
     * Nodeset2.xml. So we add the references manually. */
    addModellingRules(server);

#endif /* UA_GENERATED_NAMESPACE_ZERO */

    if(retVal != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Initialization of Namespace 0 (after bootstrapping) "
                     "failed with %s. See previous outputs for any error messages.",
                     UA_StatusCode_name(retVal));
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return UA_STATUSCODE_GOOD;
}

/**** amalgamated original file "/src/server/ua_server_ns0_diagnostics.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 */


#ifdef UA_ENABLE_DIAGNOSTICS

static UA_Boolean
equalBrowseName(UA_String *bn, char *n) {
    UA_String name = UA_STRING(n);
    return UA_String_equal(bn, &name);
}

#ifdef UA_ENABLE_SUBSCRIPTIONS

/****************************/
/* Subscription Diagnostics */
/****************************/

static void
fillSubscriptionDiagnostics(UA_Subscription *sub,
                            UA_SubscriptionDiagnosticsDataType *diag) {
    UA_NodeId_copy(&sub->session->sessionId, &diag->sessionId); /* ignore status */
    diag->subscriptionId = sub->subscriptionId;
    diag->priority = sub->priority;
    diag->publishingInterval = sub->publishingInterval;
    diag->maxKeepAliveCount = sub->maxKeepAliveCount;
    diag->maxLifetimeCount = sub->lifeTimeCount;
    diag->maxNotificationsPerPublish = sub->notificationsPerPublish;
    diag->publishingEnabled = (sub->state > UA_SUBSCRIPTIONSTATE_ENABLED_NOPUBLISH);
    diag->modifyCount = sub->modifyCount;
    diag->enableCount = sub->enableCount;
    diag->disableCount = sub->disableCount;
    diag->republishRequestCount = sub->republishRequestCount;
    diag->republishMessageRequestCount =
        sub->republishRequestCount; /* Always equal to the previous republishRequestCount */
    diag->republishMessageCount = sub->republishMessageCount;
    diag->transferRequestCount = sub->transferRequestCount;
    diag->transferredToAltClientCount = sub->transferredToAltClientCount;
    diag->transferredToSameClientCount = sub->transferredToSameClientCount;
    diag->publishRequestCount = sub->publishRequestCount;
    diag->dataChangeNotificationsCount = sub->dataChangeNotificationsCount;
    diag->eventNotificationsCount = sub->eventNotificationsCount;
    diag->notificationsCount = sub->notificationsCount;
    diag->latePublishRequestCount = sub->latePublishRequestCount;
    diag->currentKeepAliveCount = sub->currentKeepAliveCount;
    diag->currentLifetimeCount = sub->currentLifetimeCount;
    diag->unacknowledgedMessageCount = (UA_UInt32)sub->retransmissionQueueSize;
    diag->discardedMessageCount = sub->discardedMessageCount;
    diag->monitoredItemCount = sub->monitoredItemsSize;
    diag->monitoringQueueOverflowCount = sub->monitoringQueueOverflowCount;
    diag->nextSequenceNumber = sub->nextSequenceNumber;
    diag->eventQueueOverFlowCount = sub->eventQueueOverFlowCount;

    /* Count the disabled MonitoredItems */
    UA_MonitoredItem *mon;
    LIST_FOREACH(mon, &sub->monitoredItems, listEntry) {
        if(mon->monitoringMode == UA_MONITORINGMODE_DISABLED)
            diag->disabledMonitoredItemCount++;
    }
}

/* The node context points to the subscription */
static UA_StatusCode
readSubscriptionDiagnostics(UA_Server *server,
                            const UA_NodeId *sessionId, void *sessionContext,
                            const UA_NodeId *nodeId, void *nodeContext,
                            UA_Boolean sourceTimestamp,
                            const UA_NumericRange *range, UA_DataValue *value) {
    UA_LOCK_ASSERT(&server->serviceMutex, 0);

    /* Check the Subscription pointer */
    UA_Subscription *sub = (UA_Subscription*)nodeContext;
    if(!sub)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Read the BrowseName */
    UA_QualifiedName bn;
    UA_StatusCode res = UA_Server_readBrowseName(server, *nodeId, &bn);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Set the value */
    UA_SubscriptionDiagnosticsDataType sddt;
    UA_SubscriptionDiagnosticsDataType_init(&sddt);
    fillSubscriptionDiagnostics(sub, &sddt);

    char memberName[128];
    memcpy(memberName, bn.name.data, bn.name.length);
    memberName[bn.name.length] = 0;

    size_t memberOffset;
    const UA_DataType *memberType;
    UA_Boolean isArray;
    UA_Boolean found =
        UA_DataType_getStructMember(&UA_TYPES[UA_TYPES_SUBSCRIPTIONDIAGNOSTICSDATATYPE],
                                    memberName, &memberOffset, &memberType, &isArray);
    if(!found) {
        /* Not the member, but the main subscription diagnostics variable... */
        memberOffset = 0;
        memberType = &UA_TYPES[UA_TYPES_SUBSCRIPTIONDIAGNOSTICSDATATYPE];
    }

    void *content = (void*)(((uintptr_t)&sddt) + memberOffset);
    res = UA_Variant_setScalarCopy(&value->value, content, memberType);
    if(UA_LIKELY(res == UA_STATUSCODE_GOOD))
        value->hasValue = true;

    UA_SubscriptionDiagnosticsDataType_clear(&sddt);
    UA_QualifiedName_clear(&bn);
    return res;
}

/* Return all subscriptions in the server. */
UA_StatusCode
readSubscriptionDiagnosticsArray(UA_Server *server,
                                 const UA_NodeId *sessionId, void *sessionContext,
                                 const UA_NodeId *nodeId, void *nodeContext,
                                 UA_Boolean sourceTimestamp,
                                 const UA_NumericRange *range, UA_DataValue *value) {
    UA_LOCK(&server->serviceMutex);

    /* Get the current session */
    size_t sdSize = 0;
    session_list_entry *sentry;
    LIST_FOREACH(sentry, &server->sessions, pointers) {
        sdSize += sentry->session.subscriptionsSize;
    }

    /* Allocate the output array */
    UA_SubscriptionDiagnosticsDataType *sd = (UA_SubscriptionDiagnosticsDataType*)
        UA_Array_new(sdSize, &UA_TYPES[UA_TYPES_SUBSCRIPTIONDIAGNOSTICSDATATYPE]);
    if(!sd) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    /* Collect the statistics */
    size_t i = 0;
    UA_Subscription *sub;
    LIST_FOREACH(sentry, &server->sessions, pointers) {
        TAILQ_FOREACH(sub, &sentry->session.subscriptions, sessionListEntry) {
            fillSubscriptionDiagnostics(sub, &sd[i]);
            i++;
        }
    }

    /* Set the output */
    value->hasValue = true;
    UA_Variant_setArray(&value->value, sd, sdSize,
                        &UA_TYPES[UA_TYPES_SUBSCRIPTIONDIAGNOSTICSDATATYPE]);

    UA_UNLOCK(&server->serviceMutex);
    return UA_STATUSCODE_GOOD;
}

void
createSubscriptionObject(UA_Server *server, UA_Session *session,
                         UA_Subscription *sub) {
    UA_ExpandedNodeId *children = NULL;
    size_t childrenSize = 0;
    UA_ReferenceTypeSet refTypes;
    UA_NodeId hasComponent = UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT);

    char subIdStr[32];
    itoaUnsigned(sub->subscriptionId, subIdStr, 10);

    /* Find the NodeId of the SubscriptionDiagnosticsArray */
    UA_BrowsePath bp;
    UA_BrowsePath_init(&bp);
    bp.startingNode = sub->session->sessionId;
    UA_RelativePathElement rpe[1];
    memset(rpe, 0, sizeof(UA_RelativePathElement) * 1);
    rpe[0].targetName = UA_QUALIFIEDNAME(0, "SubscriptionDiagnosticsArray");
    bp.relativePath.elements = rpe;
    bp.relativePath.elementsSize = 1;
    UA_BrowsePathResult bpr = translateBrowsePathToNodeIds(server, &bp);
    if(bpr.targetsSize < 1)
        return;

    /* Create an object for the subscription. Instantiates all the mandatory
     * children. */
    UA_VariableAttributes var_attr = UA_VariableAttributes_default;
    var_attr.displayName.text = UA_STRING(subIdStr);
    var_attr.dataType = UA_TYPES[UA_TYPES_SUBSCRIPTIONDIAGNOSTICSDATATYPE].typeId;
    UA_NodeId refId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT);
    UA_QualifiedName browseName = UA_QUALIFIEDNAME(0, subIdStr);
    UA_NodeId typeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SUBSCRIPTIONDIAGNOSTICSTYPE);
    /* Assign a random free NodeId */
    UA_StatusCode res = addNode(server, UA_NODECLASS_VARIABLE, UA_NODEID_NUMERIC(1, 0),
                                bpr.targets[0].targetId.nodeId,
                                refId, browseName, typeId, &var_attr,
                                &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES], NULL,
                                &sub->ns0Id);
    UA_CHECK_STATUS(res, goto cleanup);

    /* Add a second reference from the overall SubscriptionDiagnosticsArray variable */
    const UA_NodeId subDiagArray =
        UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SUBSCRIPTIONDIAGNOSTICSARRAY);
    res = addRefWithSession(server, session,  &subDiagArray, &refId, &sub->ns0Id, true);
    if(res != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Get all children (including the variable itself) and set the contenxt + callback */
    res = referenceTypeIndices(server, &hasComponent, &refTypes, false);
    if(UA_LIKELY(res == UA_STATUSCODE_GOOD)) {
        res = browseRecursive(server, 1, &sub->ns0Id,
                              UA_BROWSEDIRECTION_FORWARD, &refTypes,
                              UA_NODECLASS_VARIABLE, true, &childrenSize, &children);
    }
    if(res != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Add the callback to all variables  */
    UA_DataSource subDiagSource = {readSubscriptionDiagnostics, NULL};
    for(size_t i = 0; i < childrenSize; i++) {
        setVariableNode_dataSource(server, children[i].nodeId, subDiagSource);
        setNodeContext(server, children[i].nodeId, sub);
    }

    UA_Array_delete(children, childrenSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);

 cleanup:
    UA_BrowsePathResult_clear(&bpr);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_SESSION(server->config.logging, session,
                               "Creating the subscription diagnostics object failed "
                               "with StatusCode %s", UA_StatusCode_name(res));
    }
}

/***********************/
/* Session Diagnostics */
/***********************/

static UA_StatusCode
setSessionSubscriptionDiagnostics(UA_Server *server, UA_Session *session,
                                  UA_DataValue *value) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Get the current session */
    size_t sdSize = session->subscriptionsSize;

    /* Allocate the output array */
    UA_SubscriptionDiagnosticsDataType *sd = (UA_SubscriptionDiagnosticsDataType*)
        UA_Array_new(sdSize, &UA_TYPES[UA_TYPES_SUBSCRIPTIONDIAGNOSTICSDATATYPE]);
    if(!sd) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    /* Collect the statistics */
    size_t i = 0;
    UA_Subscription *sub;
    TAILQ_FOREACH(sub, &session->subscriptions, sessionListEntry) {
        fillSubscriptionDiagnostics(sub, &sd[i]);
        i++;
    }

    /* Set the output */
    value->hasValue = true;
    UA_Variant_setArray(&value->value, sd, sdSize,
                        &UA_TYPES[UA_TYPES_SUBSCRIPTIONDIAGNOSTICSDATATYPE]);
    return UA_STATUSCODE_GOOD;
}

#endif /* UA_ENABLE_SUBSCRIPTIONS */

static void
setSessionDiagnostics(UA_Session *session, UA_SessionDiagnosticsDataType *sd) {
    UA_SessionDiagnosticsDataType_copy(&session->diagnostics, sd);
    UA_NodeId_copy(&session->sessionId, &sd->sessionId);
    UA_String_copy(&session->sessionName, &sd->sessionName);
    UA_ApplicationDescription_copy(&session->clientDescription,
                                   &sd->clientDescription);
    sd->maxResponseMessageSize = session->maxResponseMessageSize;
#ifdef UA_ENABLE_SUBSCRIPTIONS
    sd->currentPublishRequestsInQueue = (UA_UInt32)session->responseQueueSize;
#endif
    sd->actualSessionTimeout = session->timeout;

    /* Set LocaleIds */
    UA_StatusCode res =
        UA_Array_copy(session->localeIds, session->localeIdsSize,
                      (void **)&sd->localeIds, &UA_TYPES[UA_TYPES_STRING]);
    if(UA_LIKELY(res == UA_STATUSCODE_GOOD))
        sd->localeIdsSize = session->localeIdsSize;

        /* Set Subscription diagnostics */
#ifdef UA_ENABLE_SUBSCRIPTIONS
    sd->currentSubscriptionsCount = (UA_UInt32)session->subscriptionsSize;

    UA_Subscription *sub;
    TAILQ_FOREACH(sub, &session->subscriptions, sessionListEntry) {
        sd->currentMonitoredItemsCount += (UA_UInt32)sub->monitoredItemsSize;
    }
#endif
}

UA_StatusCode
readSessionDiagnosticsArray(UA_Server *server,
                            const UA_NodeId *sessionId, void *sessionContext,
                            const UA_NodeId *nodeId, void *nodeContext,
                            UA_Boolean sourceTimestamp,
                            const UA_NumericRange *range, UA_DataValue *value) {
    UA_LOCK_ASSERT(&server->serviceMutex, 0);

    /* Allocate the output array */
    UA_SessionDiagnosticsDataType *sd = (UA_SessionDiagnosticsDataType*)
        UA_Array_new(server->sessionCount,
                     &UA_TYPES[UA_TYPES_SESSIONDIAGNOSTICSDATATYPE]);
    if(!sd)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_LOCK(&server->serviceMutex);

    /* Collect the statistics */
    size_t i = 0;
    session_list_entry *session;
    LIST_FOREACH(session, &server->sessions, pointers) {
        setSessionDiagnostics(&session->session, &sd[i]);
        i++;
    }

    /* Set the output */
    value->hasValue = true;
    UA_Variant_setArray(&value->value, sd, server->sessionCount,
                        &UA_TYPES[UA_TYPES_SESSIONDIAGNOSTICSDATATYPE]);

    UA_UNLOCK(&server->serviceMutex);
    return UA_STATUSCODE_GOOD;
}

static void
setSessionSecurityDiagnostics(UA_Session *session,
                              UA_SessionSecurityDiagnosticsDataType *sd) {
    UA_SessionSecurityDiagnosticsDataType_copy(&session->securityDiagnostics, sd);
    UA_NodeId_copy(&session->sessionId, &sd->sessionId);
    UA_String_copy(&session->clientUserIdOfSession, &sd->clientUserIdOfSession);
    UA_SecureChannel *channel = session->channel;
    if(channel) {
        UA_ByteString_copy(&channel->remoteCertificate, &sd->clientCertificate);
        UA_String_copy(&channel->securityPolicy->policyUri, &sd->securityPolicyUri);
        sd->securityMode = channel->securityMode;
        sd->encoding = UA_STRING_ALLOC("UA Binary"); /* The only one atm */
        sd->transportProtocol = UA_STRING_ALLOC("opc.tcp"); /* The only one atm */
    }
}

static UA_StatusCode
readSessionDiagnostics(UA_Server *server,
                       const UA_NodeId *sessionId, void *sessionContext,
                       const UA_NodeId *nodeId, void *nodeContext,
                       UA_Boolean sourceTimestamp,
                       const UA_NumericRange *range, UA_DataValue *value) {
    UA_LOCK(&server->serviceMutex);

    /* Get the Session */
    UA_Session *session = getSessionById(server, sessionId);
    if(!session) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Read the BrowseName */
    UA_QualifiedName bn;
    UA_StatusCode res = readWithReadValue(server, nodeId, UA_ATTRIBUTEID_BROWSENAME, &bn);
    if(res != UA_STATUSCODE_GOOD) {
        UA_UNLOCK(&server->serviceMutex);
        return res;
    }

    union {
        UA_SessionDiagnosticsDataType sddt;
        UA_SessionSecurityDiagnosticsDataType ssddt;
    } data;
    void *content;
    UA_Boolean isArray = false;
    const UA_DataType *type = NULL;
    UA_Boolean securityDiagnostics = false;

    char memberName[128];
    size_t memberOffset;
    UA_Boolean found;

#ifdef UA_ENABLE_SUBSCRIPTIONS
    if(equalBrowseName(&bn.name, "SubscriptionDiagnosticsArray")) {
        res = setSessionSubscriptionDiagnostics(server, session, value);
        goto cleanup;
    }
#endif

    if(equalBrowseName(&bn.name, "SessionDiagnostics")) {
        setSessionDiagnostics(session, &data.sddt);
        content = &data.sddt;
        type = &UA_TYPES[UA_TYPES_SESSIONDIAGNOSTICSDATATYPE];
    } else if(equalBrowseName(&bn.name, "SessionSecurityDiagnostics")) {
        setSessionSecurityDiagnostics(session, &data.ssddt);
        securityDiagnostics = true;
        content = &data.ssddt;
        type = &UA_TYPES[UA_TYPES_SESSIONSECURITYDIAGNOSTICSDATATYPE];
    } else {
        /* Try to find the member in SessionDiagnosticsDataType and
         * SessionSecurityDiagnosticsDataType */
        memcpy(memberName, bn.name.data, bn.name.length);
        memberName[bn.name.length] = 0;
        found = UA_DataType_getStructMember(&UA_TYPES[UA_TYPES_SESSIONDIAGNOSTICSDATATYPE],
                                            memberName, &memberOffset, &type, &isArray);
        if(found) {
            setSessionDiagnostics(session, &data.sddt);
            content = (void*)(((uintptr_t)&data.sddt) + memberOffset);
        } else {
            const UA_DataType *dt = &UA_TYPES[UA_TYPES_SESSIONSECURITYDIAGNOSTICSDATATYPE];
            found = UA_DataType_getStructMember(dt, memberName, &memberOffset,
                                                &type, &isArray);
            if(!found) {
                res = UA_STATUSCODE_BADNOTIMPLEMENTED;
                goto cleanup;
            }
            setSessionSecurityDiagnostics(session, &data.ssddt);
            securityDiagnostics = true;
            content = (void*)(((uintptr_t)&data.ssddt) + memberOffset);
        }
    }

    if(!isArray) {
        res = UA_Variant_setScalarCopy(&value->value, content, type);
    } else {
        size_t len = *(size_t*)content;
        content = *(void**)((uintptr_t)content + sizeof(size_t));
        res = UA_Variant_setArrayCopy(&value->value, content, len, type);
    }
    if(UA_LIKELY(res == UA_STATUSCODE_GOOD))
        value->hasValue = true;

    if(securityDiagnostics)
        UA_SessionSecurityDiagnosticsDataType_clear(&data.ssddt);
    else
        UA_SessionDiagnosticsDataType_clear(&data.sddt);

 cleanup:
    UA_QualifiedName_clear(&bn);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
readSessionSecurityDiagnostics(UA_Server *server,
                               const UA_NodeId *sessionId, void *sessionContext,
                               const UA_NodeId *nodeId, void *nodeContext,
                               UA_Boolean sourceTimestamp,
                               const UA_NumericRange *range, UA_DataValue *value) {
    /* Allocate the output array */
    UA_SessionSecurityDiagnosticsDataType *sd = (UA_SessionSecurityDiagnosticsDataType*)
        UA_Array_new(server->sessionCount,
                     &UA_TYPES[UA_TYPES_SESSIONSECURITYDIAGNOSTICSDATATYPE]);
    if(!sd)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_LOCK(&server->serviceMutex);

    /* Collect the statistics */
    size_t i = 0;
    session_list_entry *session;
    LIST_FOREACH(session, &server->sessions, pointers) {
        setSessionSecurityDiagnostics(&session->session, &sd[i]);
        i++;
    }

    /* Set the output */
    value->hasValue = true;
    UA_Variant_setArray(&value->value, sd, server->sessionCount,
                        &UA_TYPES[UA_TYPES_SESSIONSECURITYDIAGNOSTICSDATATYPE]);

    UA_UNLOCK(&server->serviceMutex);
    return UA_STATUSCODE_GOOD;
}

void
createSessionObject(UA_Server *server, UA_Session *session) {
    UA_ExpandedNodeId *children = NULL;
    size_t childrenSize = 0;
    UA_ReferenceTypeSet refTypes;
    UA_NodeId hasComponent = UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT);

    /* Create an object for the session. Instantiates all the mandatory children. */
    UA_ObjectAttributes object_attr = UA_ObjectAttributes_default;
    object_attr.displayName.text = session->sessionName;
    UA_NodeId parentId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SESSIONSDIAGNOSTICSSUMMARY);
    UA_NodeId refId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT);
    UA_QualifiedName browseName = UA_QUALIFIEDNAME(0, "");
    browseName.name = session->sessionName; /* shallow copy */
    UA_NodeId typeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SESSIONDIAGNOSTICSOBJECTTYPE);
    UA_StatusCode res = addNode(server, UA_NODECLASS_OBJECT, session->sessionId,
                                parentId, refId, browseName, typeId, &object_attr,
                                &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], NULL, NULL);
    if(res != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Recursively browse all children */
    res = referenceTypeIndices(server, &hasComponent, &refTypes, false);
    if(res != UA_STATUSCODE_GOOD)
        goto cleanup;
    res = browseRecursive(server, 1, &session->sessionId,
                          UA_BROWSEDIRECTION_FORWARD, &refTypes,
                          UA_NODECLASS_VARIABLE, false, &childrenSize, &children);
    if(res != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Add the callback to all variables  */
    UA_DataSource sessionDiagSource = {readSessionDiagnostics, NULL};
    for(size_t i = 0; i < childrenSize; i++) {
        setVariableNode_dataSource(server, children[i].nodeId, sessionDiagSource);
    }

 cleanup:
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_SESSION(server->config.logging, session,
                               "Creating the session diagnostics object failed "
                               "with StatusCode %s", UA_StatusCode_name(res));
    }
    UA_Array_delete(children, childrenSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
}

/***************************/
/* Server-Wide Diagnostics */
/***************************/

UA_StatusCode
readDiagnostics(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
                const UA_NodeId *nodeId, void *nodeContext, UA_Boolean sourceTimestamp,
                const UA_NumericRange *range, UA_DataValue *value) {
    if(range) {
        value->hasStatus = true;
        value->status = UA_STATUSCODE_BADINDEXRANGEINVALID;
        return UA_STATUSCODE_GOOD;
    }

    if(sourceTimestamp) {
        UA_EventLoop *el = server->config.eventLoop;
        value->hasSourceTimestamp = true;
        value->sourceTimestamp = el->dateTime_now(el);
    }

    UA_assert(nodeId->identifierType == UA_NODEIDTYPE_NUMERIC);

    void *data = NULL;
    const UA_DataType *type = &UA_TYPES[UA_TYPES_UINT32]; /* Default */

    UA_LOCK(&server->serviceMutex);

    switch(nodeId->identifier.numeric) {
    case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY:
        server->serverDiagnosticsSummary.currentSessionCount =
            server->activeSessionCount;
        data = &server->serverDiagnosticsSummary;
        type = &UA_TYPES[UA_TYPES_SERVERDIAGNOSTICSSUMMARYDATATYPE];
        break;
    case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SERVERVIEWCOUNT:
        data = &server->serverDiagnosticsSummary.serverViewCount;
        break;
    case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CURRENTSESSIONCOUNT:
        data = &server->activeSessionCount;
        break;
    case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CUMULATEDSESSIONCOUNT:
        data = &server->serverDiagnosticsSummary.cumulatedSessionCount;
        break;
    case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SECURITYREJECTEDSESSIONCOUNT:
        data = &server->serverDiagnosticsSummary.securityRejectedSessionCount;
        break;
    case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_REJECTEDSESSIONCOUNT:
        data = &server->serverDiagnosticsSummary.rejectedSessionCount;
        break;
    case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SESSIONTIMEOUTCOUNT:
        data = &server->serverDiagnosticsSummary.sessionTimeoutCount;
        break;
    case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SESSIONABORTCOUNT:
        data = &server->serverDiagnosticsSummary.sessionAbortCount;
        break;
    case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CURRENTSUBSCRIPTIONCOUNT:
        data = &server->serverDiagnosticsSummary.currentSubscriptionCount;
        break;
    case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_CUMULATEDSUBSCRIPTIONCOUNT:
        data = &server->serverDiagnosticsSummary.cumulatedSubscriptionCount;
        break;
    case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_PUBLISHINGINTERVALCOUNT:
        data = &server->serverDiagnosticsSummary.publishingIntervalCount;
        break;
    case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_SECURITYREJECTEDREQUESTSCOUNT:
        data = &server->serverDiagnosticsSummary.securityRejectedRequestsCount;
        break;
    case UA_NS0ID_SERVER_SERVERDIAGNOSTICS_SERVERDIAGNOSTICSSUMMARY_REJECTEDREQUESTSCOUNT:
        data = &server->serverDiagnosticsSummary.rejectedRequestsCount;
        break;
    default:
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_StatusCode res = UA_Variant_setScalarCopy(&value->value, data, type);
    if(res == UA_STATUSCODE_GOOD)
        value->hasValue = true;

    UA_UNLOCK(&server->serviceMutex);
    return res;
}

#endif /* UA_ENABLE_DIAGNOSTICS */

/**** amalgamated original file "/src/server/ua_server_config.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2019 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2019 (c) HMS Industrial Networks AB (Author: Jonas Green)
 */



void
UA_ServerConfig_clean(UA_ServerConfig *config) {
    if(!config)
        return;

    /* Server Description */
    UA_BuildInfo_clear(&config->buildInfo);
    UA_ApplicationDescription_clear(&config->applicationDescription);
#ifdef UA_ENABLE_DISCOVERY_MULTICAST
    UA_MdnsDiscoveryConfiguration_clear(&config->mdnsConfig);
    UA_String_clear(&config->mdnsInterfaceIP);
# if !defined(UA_HAS_GETIFADDR)
    if (config->mdnsIpAddressListSize) {
        UA_free(config->mdnsIpAddressList);
    }
# endif
#endif

    /* Stop and delete the EventLoop */
    UA_EventLoop *el = config->eventLoop;
    if(el && !config->externalEventLoop) {
        if(el->state != UA_EVENTLOOPSTATE_FRESH &&
           el->state != UA_EVENTLOOPSTATE_STOPPED) {
            el->stop(el);
            while(el->state != UA_EVENTLOOPSTATE_STOPPED) {
                el->run(el, 100);
            }
        }
        el->free(el);
        config->eventLoop = NULL;
    }

    /* Networking */
    UA_Array_delete(config->serverUrls, config->serverUrlsSize,
                    &UA_TYPES[UA_TYPES_STRING]);
    config->serverUrls = NULL;
    config->serverUrlsSize = 0;

    /* Security Policies */
    for(size_t i = 0; i < config->securityPoliciesSize; ++i) {
        UA_SecurityPolicy *policy = &config->securityPolicies[i];
        policy->clear(policy);
    }
    UA_free(config->securityPolicies);
    config->securityPolicies = NULL;
    config->securityPoliciesSize = 0;

    for(size_t i = 0; i < config->endpointsSize; ++i)
        UA_EndpointDescription_clear(&config->endpoints[i]);

    UA_free(config->endpoints);
    config->endpoints = NULL;
    config->endpointsSize = 0;

    /* Nodestore */
    if(config->nodestore.context && config->nodestore.clear) {
        config->nodestore.clear(config->nodestore.context);
        config->nodestore.context = NULL;
    }

    /* Certificate Validation */
    if(config->secureChannelPKI.clear)
        config->secureChannelPKI.clear(&config->secureChannelPKI);
    if(config->sessionPKI.clear)
        config->sessionPKI.clear(&config->sessionPKI);

    /* Access Control */
    if(config->accessControl.clear)
        config->accessControl.clear(&config->accessControl);

    /* Historical data */
#ifdef UA_ENABLE_HISTORIZING
    if(config->historyDatabase.clear)
        config->historyDatabase.clear(&config->historyDatabase);
#endif

#ifdef UA_ENABLE_PUBSUB
#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
    if(config->pubSubConfig.securityPolicies != NULL) {
        for(size_t i = 0; i < config->pubSubConfig.securityPoliciesSize; i++) {
            config->pubSubConfig.securityPolicies[i].clear(&config->pubSubConfig.securityPolicies[i]);
        }
        UA_free(config->pubSubConfig.securityPolicies);
        config->pubSubConfig.securityPolicies = NULL;
        config->pubSubConfig.securityPoliciesSize = 0;
    }
#endif
#endif /* UA_ENABLE_PUBSUB */

    /* Logger */
    if(config->logging != NULL && config->logging->clear != NULL)
        config->logging->clear(config->logging);
    config->logging = NULL;

    /* Custom Data Types */
    UA_cleanupDataTypeWithCustom(config->customDataTypes);
    config->customDataTypes = NULL;
}

/**** amalgamated original file "/src/server/ua_server_binary.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014-2016 (c) Sten Grüner
 *    Copyright 2014-2015, 2017 (c) Florian Palm
 *    Copyright 2015-2016 (c) Chris Iatrou
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2016 (c) Joakim L. Gilje
 *    Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2016 (c) TorbenD
 *    Copyright 2017 (c) frax2222
 *    Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2019 (c) Kalycito Infotech Private Limited
 *    Copyright 2023 (c) Hilscher Gesellschaft für Systemautomation mbH (Author: Phuong Nguyen)
 */



#define STARTCHANNELID 1
#define STARTTOKENID 1

#ifdef UA_DEBUG_DUMP_PKGS_FILE
void UA_debug_dumpCompleteChunk(UA_Server *const server, UA_Connection *const connection,
                                UA_ByteString *messageBuffer);
#endif

/************************************/
/* Binary Protocol Server Component */
/************************************/

/* Maximum numbers of sockets to listen on */
#define UA_MAXSERVERCONNECTIONS 16

/* SecureChannel Linked List */
typedef struct channel_entry {
    UA_SecureChannel channel;
    TAILQ_ENTRY(channel_entry) pointers;
} channel_entry;

typedef struct {
    UA_ConnectionState state;
    uintptr_t connectionId;
    UA_ConnectionManager *connectionManager;
} UA_ServerConnection;

/* Reverse connect */
typedef struct reverse_connect_context {
    UA_String hostname;
    UA_UInt16 port;
    UA_UInt64 handle;

    UA_SecureChannelState state;
    UA_Server_ReverseConnectStateCallback stateCallback;
    void *callbackContext;

     /* If this is set to true, the reverse connection is removed/freed when the
      * connection closes. Otherwise we try to reconnect when the connection
      * closes. */
    UA_Boolean destruction;

    UA_ServerConnection currentConnection;
    UA_SecureChannel *channel;
    LIST_ENTRY(reverse_connect_context) next;
} reverse_connect_context;

/* Binary Protocol Manager */
typedef struct {
    UA_ServerComponent sc;
    UA_Server *server;  /* remember the pointer so we don't need an additional
                           context pointer for connections */
    const UA_Logger *logging; /* shortcut */
    UA_UInt64 houseKeepingCallbackId;

    UA_ServerConnection serverConnections[UA_MAXSERVERCONNECTIONS];
    size_t serverConnectionsSize;

    UA_ConnectionConfig tcpConnectionConfig; /* Extracted from the server config
                                              * parameters */

    /* SecureChannels */
    TAILQ_HEAD(, channel_entry) channels;
    UA_UInt32 lastChannelId;
    UA_UInt32 lastTokenId;

    /* Reverse Connections */
    LIST_HEAD(, reverse_connect_context) reverseConnects;
    UA_UInt64 reverseConnectsCheckHandle;
    UA_UInt64 lastReverseConnectHandle;
} UA_BinaryProtocolManager;

void setReverseConnectState(UA_Server *server, reverse_connect_context *context,
                            UA_SecureChannelState newState);
UA_StatusCode attemptReverseConnect(UA_BinaryProtocolManager *bpm,
                                    reverse_connect_context *context);
UA_StatusCode setReverseConnectRetryCallback(UA_BinaryProtocolManager *bpm,
                                             UA_Boolean enabled);

/********************/
/* Helper Functions */
/********************/

UA_UInt32
generateSecureChannelTokenId(UA_Server *server) {
    UA_ServerComponent *sc =
        getServerComponentByName(server, UA_STRING("binary"));
    if(!sc) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Cannot generate a SecureChannel Token Id. "
                     "No BinaryProtocolManager configured.");
        return 0;
    }
    UA_BinaryProtocolManager *bpm = (UA_BinaryProtocolManager*)sc;
    return bpm->lastTokenId++;
}

static void
setBinaryProtocolManagerState(UA_Server *server,
                              UA_BinaryProtocolManager *bpm,
                              UA_LifecycleState state) {
    if(state == bpm->sc.state)
        return;
    bpm->sc.state = state;
    if(bpm->sc.notifyState)
        bpm->sc.notifyState(server, &bpm->sc, state);
}

static void
deleteServerSecureChannel(UA_BinaryProtocolManager *bpm,
                          UA_SecureChannel *channel) {
    /* Clean up the SecureChannel. This is the only place where
     * UA_SecureChannel_clear must be called within the server code-base.
     *
     * First detach all Sessions from the SecureChannel. This also removes
     * outstanding Publish requests whose RequestId is valid only for the
     * SecureChannel. */
    while(channel->sessions)
        UA_Session_detachFromSecureChannel(channel->sessions);
    UA_SecureChannel_clear(channel);

    /* Detach the channel from the server list */
    TAILQ_REMOVE(&bpm->channels, (channel_entry*)channel, pointers);

    /* Update the statistics */
    UA_SecureChannelStatistics *scs = &bpm->server->secureChannelStatistics;
    scs->currentChannelCount--;
    switch(channel->shutdownReason) {
    case UA_SHUTDOWNREASON_CLOSE:
        UA_LOG_INFO_CHANNEL(bpm->logging, channel, "SecureChannel closed");
        break;
    case UA_SHUTDOWNREASON_TIMEOUT:
        UA_LOG_INFO_CHANNEL(bpm->logging, channel, "SecureChannel closed due to timeout");
        scs->channelTimeoutCount++;
        break;
    case UA_SHUTDOWNREASON_PURGE:
        UA_LOG_INFO_CHANNEL(bpm->logging, channel, "SecureChannel was purged");
        scs->channelPurgeCount++;
        break;
    case UA_SHUTDOWNREASON_REJECT:
    case UA_SHUTDOWNREASON_SECURITYREJECT:
        UA_LOG_INFO_CHANNEL(bpm->logging, channel, "SecureChannel was rejected");
        scs->rejectedChannelCount++;
        break;
    case UA_SHUTDOWNREASON_ABORT:
        UA_LOG_INFO_CHANNEL(bpm->logging, channel, "SecureChannel was aborted");
        scs->channelAbortCount++;
        break;
    default:
        UA_assert(false);
        break;
    }

    UA_free(channel);
}

UA_StatusCode
sendServiceFault(UA_Server *server, UA_SecureChannel *channel,
                 UA_UInt32 requestId, UA_UInt32 requestHandle,
                 UA_StatusCode statusCode) {
    UA_EventLoop *el = server->config.eventLoop;

    UA_ServiceFault response;
    UA_ServiceFault_init(&response);
    UA_ResponseHeader *responseHeader = &response.responseHeader;
    responseHeader->requestHandle = requestHandle;
    responseHeader->timestamp = el->dateTime_now(el);
    responseHeader->serviceResult = statusCode;

    UA_LOG_DEBUG(channel->securityPolicy->logger, UA_LOGCATEGORY_SERVER,
                 "Sending response for RequestId %u with ServiceResult %s",
                 (unsigned)requestId, UA_StatusCode_name(statusCode));

    /* Send error message. Message type is MSG and not ERR, since we are on a
     * SecureChannel! */
    return UA_SecureChannel_sendSymmetricMessage(channel, requestId,
                                                 UA_MESSAGETYPE_MSG, &response,
                                                 &UA_TYPES[UA_TYPES_SERVICEFAULT]);
}

/* This is not an ERR message, the connection is not closed afterwards */
static UA_StatusCode
decodeHeaderSendServiceFault(UA_Server *server, UA_SecureChannel *channel,
                             const UA_ByteString *msg, size_t offset,
                             const UA_DataType *responseType, UA_UInt32 requestId,
                             UA_StatusCode error) {
    UA_RequestHeader requestHeader;
    UA_StatusCode retval =
        UA_decodeBinaryInternal(msg, &offset, &requestHeader,
                                &UA_TYPES[UA_TYPES_REQUESTHEADER], NULL);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    retval = sendServiceFault(server, channel, requestId, requestHeader.requestHandle, error);
    UA_RequestHeader_clear(&requestHeader);
    return retval;
}


/*************************/
/* Process Message Types */
/*************************/

/* HEL -> Open up the connection */
static UA_StatusCode
processHEL(UA_Server *server, UA_SecureChannel *channel, const UA_ByteString *msg) {
    UA_ConnectionManager *cm = channel->connectionManager;
    if(!cm || (channel->state != UA_SECURECHANNELSTATE_CONNECTED &&
               channel->state != UA_SECURECHANNELSTATE_RHE_SENT))
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t offset = 0; /* Go to the beginning of the TcpHelloMessage */
    UA_TcpHelloMessage helloMessage;
    UA_StatusCode retval =
        UA_decodeBinaryInternal(msg, &offset, &helloMessage,
                                &UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE], NULL);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Currently not checked */
    UA_String_clear(&helloMessage.endpointUrl);

    /* Parameterize the connection. The TcpHelloMessage casts to a
     * TcpAcknowledgeMessage. */
    retval = UA_SecureChannel_processHELACK(channel,
                                            (UA_TcpAcknowledgeMessage*)&helloMessage);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_INFO_CHANNEL(server->config.logging, channel,
                            "Error during the HEL/ACK handshake");
        return retval;
    }

    /* Get the send buffer from the network layer */
    UA_ByteString ack_msg;
    UA_ByteString_init(&ack_msg);
    retval = cm->allocNetworkBuffer(cm, channel->connectionId,
                                    &ack_msg, channel->config.sendBufferSize);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Build acknowledge response */
    UA_TcpAcknowledgeMessage ackMessage;
    ackMessage.protocolVersion = 0;
    ackMessage.receiveBufferSize = channel->config.recvBufferSize;
    ackMessage.sendBufferSize = channel->config.sendBufferSize;
    ackMessage.maxMessageSize = channel->config.localMaxMessageSize;
    ackMessage.maxChunkCount = channel->config.localMaxChunkCount;

    UA_TcpMessageHeader ackHeader;
    ackHeader.messageTypeAndChunkType = UA_MESSAGETYPE_ACK + UA_CHUNKTYPE_FINAL;
    ackHeader.messageSize = 8 + 20; /* ackHeader + ackMessage */

    /* Encode and send the response */
    UA_Byte *bufPos = ack_msg.data;
    const UA_Byte *bufEnd = &ack_msg.data[ack_msg.length];
    retval |= UA_encodeBinaryInternal(&ackHeader,
                                      &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER],
                                      &bufPos, &bufEnd, NULL, NULL);
    retval |= UA_encodeBinaryInternal(&ackMessage,
                                      &UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE],
                                      &bufPos, &bufEnd, NULL, NULL);
    if(retval != UA_STATUSCODE_GOOD) {
        cm->freeNetworkBuffer(cm, channel->connectionId, &ack_msg);
        return retval;
    }

    ack_msg.length = ackHeader.messageSize;
    retval = cm->sendWithConnection(cm, channel->connectionId, &UA_KEYVALUEMAP_NULL, &ack_msg);
    if(retval == UA_STATUSCODE_GOOD)
        channel->state = UA_SECURECHANNELSTATE_ACK_SENT;
    return retval;
}

/* OPN -> Open up/renew the securechannel */
static UA_StatusCode
processOPN(UA_Server *server, UA_SecureChannel *channel,
           const UA_UInt32 requestId, const UA_ByteString *msg) {
    if(channel->state != UA_SECURECHANNELSTATE_ACK_SENT &&
       channel->state != UA_SECURECHANNELSTATE_OPEN)
        return UA_STATUSCODE_BADINTERNALERROR;
    /* Decode the request */
    UA_NodeId requestType;
    UA_OpenSecureChannelRequest openSecureChannelRequest;
    size_t offset = 0;
    UA_StatusCode retval = UA_NodeId_decodeBinary(msg, &offset, &requestType);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_NodeId_clear(&requestType);
        UA_LOG_WARNING_CHANNEL(server->config.logging, channel,
                               "Could not decode the NodeId. "
                               "Closing the SecureChannel.");
        UA_SecureChannel_shutdown(channel, UA_SHUTDOWNREASON_REJECT);
        return retval;
    }
    retval = UA_decodeBinaryInternal(msg, &offset, &openSecureChannelRequest,
                                     &UA_TYPES[UA_TYPES_OPENSECURECHANNELREQUEST], NULL);

    /* Error occurred */
    const UA_NodeId *opnRequestId =
        &UA_TYPES[UA_TYPES_OPENSECURECHANNELREQUEST].binaryEncodingId;
    if(retval != UA_STATUSCODE_GOOD || !UA_NodeId_equal(&requestType, opnRequestId)) {
        UA_NodeId_clear(&requestType);
        UA_OpenSecureChannelRequest_clear(&openSecureChannelRequest);
        UA_LOG_WARNING_CHANNEL(server->config.logging, channel,
                               "Could not decode the OPN message. "
                               "Closing the SecureChannel.");
        UA_SecureChannel_shutdown(channel, UA_SHUTDOWNREASON_REJECT);
        return retval;
    }
    UA_NodeId_clear(&requestType);

    /* Call the service */
    UA_OpenSecureChannelResponse openScResponse;
    UA_OpenSecureChannelResponse_init(&openScResponse);
    Service_OpenSecureChannel(server, channel, &openSecureChannelRequest, &openScResponse);
    UA_OpenSecureChannelRequest_clear(&openSecureChannelRequest);
    if(openScResponse.responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_CHANNEL(server->config.logging, channel,
                               "Could not open a SecureChannel. "
                               "Closing the connection.");
        UA_SecureChannel_shutdown(channel, UA_SHUTDOWNREASON_REJECT);
        return openScResponse.responseHeader.serviceResult;
    }

    /* Send the response */
    retval = UA_SecureChannel_sendAsymmetricOPNMessage(channel, requestId, &openScResponse,
                                                       &UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE]);
    UA_OpenSecureChannelResponse_clear(&openScResponse);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_CHANNEL(server->config.logging, channel,
                               "Could not send the OPN answer with error code %s",
                               UA_StatusCode_name(retval));
        UA_SecureChannel_shutdown(channel, UA_SHUTDOWNREASON_REJECT);
    }

    return retval;
}

/* The responseHeader must have the requestHandle already set */
UA_StatusCode
sendResponse(UA_Server *server, UA_SecureChannel *channel, UA_UInt32 requestId,
             UA_Response *response, const UA_DataType *responseType) {
    if(!channel)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* If the overall service call failed, answer with a ServiceFault */
    if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
        return sendServiceFault(server, channel, requestId,
                                response->responseHeader.requestHandle,
                                response->responseHeader.serviceResult);

    /* Prepare the ResponseHeader */
    UA_EventLoop *el = server->config.eventLoop;
    response->responseHeader.timestamp = el->dateTime_now(el);

    /* Start the message context */
    UA_MessageContext mc;
    UA_StatusCode retval = UA_MessageContext_begin(&mc, channel, requestId, UA_MESSAGETYPE_MSG);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Assert's required for clang-analyzer */
    UA_assert(mc.buf_pos == &mc.messageBuffer.data[UA_SECURECHANNEL_SYMMETRIC_HEADER_TOTALLENGTH]);
    UA_assert(mc.buf_end <= &mc.messageBuffer.data[mc.messageBuffer.length]);

    /* Encode the response type */
    retval = UA_MessageContext_encode(&mc, &responseType->binaryEncodingId,
                                      &UA_TYPES[UA_TYPES_NODEID]);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Encode the response */
    retval = UA_MessageContext_encode(&mc, response, responseType);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Finish / send out */
    return UA_MessageContext_finish(&mc);
}

/* A Session is "bound" to a SecureChannel if it was created by the
 * SecureChannel or if it was activated on it. A Session can only be bound to
 * one SecureChannel. A Session can only be closed from the SecureChannel to
 * which it is bound.
 *
 * Returns Good if the AuthenticationToken exists nowhere (for CTT). */
UA_StatusCode
getBoundSession(UA_Server *server, const UA_SecureChannel *channel,
                const UA_NodeId *token, UA_Session **session) {
    UA_EventLoop *el = server->config.eventLoop;
    UA_DateTime nowMonotonic = el->dateTime_nowMonotonic(el);
    for(UA_Session *s = channel->sessions; s; s = s->next) {
        if(!UA_NodeId_equal(token, &s->authenticationToken))
            continue;

        /* Has the session timed out? */
        if(s->validTill < nowMonotonic) {
            server->serverDiagnosticsSummary.rejectedSessionCount++;
            return UA_STATUSCODE_BADSESSIONCLOSED;
        }

        /* Return the session */
        *session = s;
        return UA_STATUSCODE_GOOD;
    }

    /* Session exists on another SecureChannel */
#ifdef UA_ENABLE_DIAGNOSTICS
    UA_Session *tmpSession = getSessionByToken(server, token);
    if(tmpSession)
        tmpSession->diagnostics.unauthorizedRequestCount++;
#endif

    /* Update the rejected statistics */
    server->serverDiagnosticsSummary.rejectedSessionCount++;
    return UA_STATUSCODE_BADSESSIONIDINVALID;
}

static UA_StatusCode
processMSG(UA_Server *server, UA_SecureChannel *channel,
           UA_UInt32 requestId, const UA_ByteString *msg) {
    if(channel->state != UA_SECURECHANNELSTATE_OPEN)
        return UA_STATUSCODE_BADINTERNALERROR;
    /* Decode the nodeid */
    size_t offset = 0;
    UA_NodeId requestTypeId;
    UA_StatusCode retval = UA_NodeId_decodeBinary(msg, &offset, &requestTypeId);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    if(requestTypeId.namespaceIndex != 0 ||
       requestTypeId.identifierType != UA_NODEIDTYPE_NUMERIC)
        UA_NodeId_clear(&requestTypeId); /* leads to badserviceunsupported */

    /* Get the service pointers */
    UA_ServiceDescription *sd = getServiceDescription(requestTypeId.identifier.numeric);
    if(!sd) {
        if(requestTypeId.identifier.numeric ==
           UA_NS0ID_CREATESUBSCRIPTIONREQUEST_ENCODING_DEFAULTBINARY) {
            UA_LOG_INFO_CHANNEL(server->config.logging, channel,
                                "Client requested a subscription, "
                                "but those are not enabled in the build");
        } else {
            UA_LOG_INFO_CHANNEL(server->config.logging, channel,
                                "Unknown request with type identifier %" PRIi32,
                                requestTypeId.identifier.numeric);
        }
        return decodeHeaderSendServiceFault(server, channel, msg, offset,
                                            &UA_TYPES[UA_TYPES_SERVICEFAULT],
                                            requestId, UA_STATUSCODE_BADSERVICEUNSUPPORTED);
    }

    /* Decode the request */
    UA_Request request;
    size_t requestPos = offset; /* Store the offset (for sendServiceFault) */
    retval = UA_decodeBinaryInternal(msg, &offset, &request,
                                     sd->requestType, server->config.customDataTypes);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_DEBUG_CHANNEL(server->config.logging, channel,
                             "Could not decode the request with StatusCode %s",
                             UA_StatusCode_name(retval));
        return decodeHeaderSendServiceFault(server, channel, msg, requestPos,
                                            sd->responseType, requestId, retval);
    }

    /* Initialize the response */
    UA_Response response;
    UA_init(&response, sd->responseType);
    response.responseHeader.requestHandle = request.requestHeader.requestHandle;

    /* Process the request */
    UA_LOCK(&server->serviceMutex);
    UA_Boolean async =
        UA_Server_processRequest(server, channel, requestId, sd, &request, &response);
    UA_UNLOCK(&server->serviceMutex);

    /* Send response if not async */
    if(UA_LIKELY(!async)) {
        retval = sendResponse(server, channel, requestId, &response, sd->responseType);
    }

    /* Clean up */
    UA_clear(&request, sd->requestType);
    UA_clear(&response, sd->responseType);
    return retval;
}

/* Takes decoded messages starting at the nodeid of the content type. */
static UA_StatusCode
processSecureChannelMessage(void *application, UA_SecureChannel *channel,
                            UA_MessageType messagetype, UA_UInt32 requestId,
                            UA_ByteString *message) {
    UA_Server *server = (UA_Server*)application;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    switch(messagetype) {
    case UA_MESSAGETYPE_HEL:
        UA_LOG_TRACE_CHANNEL(server->config.logging, channel, "Process a HEL message");
        retval = processHEL(server, channel, message);
        break;
    case UA_MESSAGETYPE_OPN:
        UA_LOG_TRACE_CHANNEL(server->config.logging, channel, "Process an OPN message");
        retval = processOPN(server, channel, requestId, message);
        break;
    case UA_MESSAGETYPE_MSG:
        UA_LOG_TRACE_CHANNEL(server->config.logging, channel, "Process a MSG");
        retval = processMSG(server, channel, requestId, message);
        break;
    case UA_MESSAGETYPE_CLO:
        UA_LOG_TRACE_CHANNEL(server->config.logging, channel, "Process a CLO");
        Service_CloseSecureChannel(server, channel); /* Regular close */
        break;
    default:
        UA_LOG_TRACE_CHANNEL(server->config.logging, channel, "Invalid message type");
        retval = UA_STATUSCODE_BADTCPMESSAGETYPEINVALID;
        break;
    }
    if(retval != UA_STATUSCODE_GOOD) {
        if(!UA_SecureChannel_isConnected(channel)) {
            UA_LOG_INFO_CHANNEL(server->config.logging, channel,
                                "Processing the message failed. Channel already closed "
                                "with StatusCode %s. ", UA_StatusCode_name(retval));
            return retval;
        }

        UA_LOG_INFO_CHANNEL(server->config.logging, channel,
                            "Processing the message failed with StatusCode %s. "
                            "Closing the channel.", UA_StatusCode_name(retval));
        UA_TcpErrorMessage errMsg;
        UA_TcpErrorMessage_init(&errMsg);
        errMsg.error = retval;
        UA_SecureChannel_sendError(channel, &errMsg);
        UA_ShutdownReason reason;
        switch(retval) {
        case UA_STATUSCODE_BADSECURITYMODEREJECTED:
        case UA_STATUSCODE_BADSECURITYCHECKSFAILED:
        case UA_STATUSCODE_BADSECURECHANNELIDINVALID:
        case UA_STATUSCODE_BADSECURECHANNELTOKENUNKNOWN:
        case UA_STATUSCODE_BADSECURITYPOLICYREJECTED:
        case UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED:
            reason = UA_SHUTDOWNREASON_SECURITYREJECT;
            break;
        default:
            reason = UA_SHUTDOWNREASON_CLOSE;
            break;
        }
        UA_SecureChannel_shutdown(channel, reason);
    }

    return retval;
}

/* remove the first channel that has no session attached */
static UA_Boolean
purgeFirstChannelWithoutSession(UA_BinaryProtocolManager *bpm) {
    channel_entry *entry;
    TAILQ_FOREACH(entry, &bpm->channels, pointers) {
        if(entry->channel.sessions)
            continue;
        UA_LOG_INFO_CHANNEL(bpm->logging, &entry->channel,
                            "Channel was purged since maxSecureChannels was "
                            "reached and channel had no session attached");
        UA_SecureChannel_shutdown(&entry->channel, UA_SHUTDOWNREASON_PURGE);
        return true;
    }
    return false;
}

static UA_StatusCode
configServerSecureChannel(void *application, UA_SecureChannel *channel,
                          const UA_AsymmetricAlgorithmSecurityHeader *asymHeader) {
    /* Iterate over available endpoints and choose the correct one */
    UA_SecurityPolicy *securityPolicy = NULL;
    UA_Server *const server = (UA_Server *const) application;
    for(size_t i = 0; i < server->config.securityPoliciesSize; ++i) {
        UA_SecurityPolicy *policy = &server->config.securityPolicies[i];
        if(!UA_ByteString_equal(&asymHeader->securityPolicyUri, &policy->policyUri))
            continue;

        UA_StatusCode res = policy->asymmetricModule.
            compareCertificateThumbprint(policy, &asymHeader->receiverCertificateThumbprint);
        if(res != UA_STATUSCODE_GOOD)
            continue;

        /* We found the correct policy (except for security mode). The endpoint
         * needs to be selected by the client / server to match the security
         * mode in the endpoint for the session. */
        securityPolicy = policy;
        break;
    }

    if(!securityPolicy)
        return UA_STATUSCODE_BADSECURITYPOLICYREJECTED;

    /* If the sender provides a chain of certificates then we shall extract the
     * ApplicationInstanceCertificate. and ignore the extra bytes. See also: OPC
     * UA Part 6, V1.04, 6.7.2.3 Security Header, Table 42 - Asymmetric
     * algorithm Security header */
    UA_ByteString appInstCert = getLeafCertificate(asymHeader->senderCertificate);

    /* Create the channel context and parse the sender (remote) certificate used
     * for the secureChannel. */
    return UA_SecureChannel_setSecurityPolicy(channel, securityPolicy, &appInstCert);
}

static UA_StatusCode
createServerSecureChannel(UA_BinaryProtocolManager *bpm, UA_ConnectionManager *cm,
                          uintptr_t connectionId, UA_SecureChannel **outChannel) {
    UA_Server *server = bpm->server;
    UA_ServerConfig *config = &server->config;

    /* Check if we have space for another SC, otherwise try to find an SC
     * without a session and purge it */
    UA_SecureChannelStatistics *scs = &server->secureChannelStatistics;
    if(scs->currentChannelCount >= config->maxSecureChannels &&
       !purgeFirstChannelWithoutSession(bpm))
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Allocate memory for the SecureChannel */
    channel_entry *entry = (channel_entry *)UA_calloc(1, sizeof(channel_entry));
    if(!entry)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Set up the initial connection config */
    UA_ConnectionConfig connConfig;
    connConfig.protocolVersion = 0;
    connConfig.recvBufferSize = config->tcpBufSize;
    connConfig.sendBufferSize = config->tcpBufSize;
    connConfig.localMaxMessageSize = config->tcpMaxMsgSize;
    connConfig.remoteMaxMessageSize = config->tcpMaxMsgSize;
    connConfig.localMaxChunkCount = config->tcpMaxChunks;
    connConfig.remoteMaxChunkCount = config->tcpMaxChunks;

    if(connConfig.recvBufferSize == 0)
        connConfig.recvBufferSize = 1 << 16; /* 64kB */
    if(connConfig.sendBufferSize == 0)
        connConfig.sendBufferSize = 1 << 16; /* 64kB */

    /* Set up the new SecureChannel */
    UA_SecureChannel_init(&entry->channel);
    entry->channel.config = connConfig;
    entry->channel.certificateVerification = &config->secureChannelPKI;
    entry->channel.processOPNHeader = configServerSecureChannel;
    entry->channel.connectionManager = cm;
    entry->channel.connectionId = connectionId;

    /* Set the SecureChannel identifier already here. So we get the right
     * identifier for logging right away. The rest of the SecurityToken is set
     * in UA_SecureChannelManager_open. Set the ChannelId also in the
     * alternative security token, we don't touch this value during the token
     * rollover. */
    entry->channel.securityToken.channelId = bpm->lastChannelId++;

    /* Set an initial timeout before the negotiation handshake. So the channel
     * is caught if the client is unresponsive.
     *
     * TODO: Make this a configuration option */
    UA_EventLoop *el = server->config.eventLoop;
    entry->channel.securityToken.createdAt = el->dateTime_nowMonotonic(el);
    entry->channel.securityToken.revisedLifetime = 10000; /* 10s should be enough */

    /* Add to the server's list */
    TAILQ_INSERT_TAIL(&bpm->channels, entry, pointers);

    /* Update the statistics */
    server->secureChannelStatistics.currentChannelCount++;
    server->secureChannelStatistics.cumulatedChannelCount++;

    *outChannel = &entry->channel;
    return UA_STATUSCODE_GOOD;
}

/* Callback of a TCP socket (server socket or an active connection) */
void
serverNetworkCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
                      void *application, void **connectionContext,
                      UA_ConnectionState state,
                      const UA_KeyValueMap *params,
                      UA_ByteString msg) {
    UA_BinaryProtocolManager *bpm = (UA_BinaryProtocolManager*)application;

    /* A server socket that is not yet registered in the server. Register it and
     * set the connection context to the pointer in the
     * bpm->serverConnections list. New connections on that server socket
     * inherit the context (and on the first callback we set the context of
     * client-connections to a SecureChannel). */
    if(*connectionContext == NULL) {
        /* The socket is closing without being previously registered -> ignore */
        if(state == UA_CONNECTIONSTATE_CLOSED ||
           state == UA_CONNECTIONSTATE_CLOSING)
            return;

        /* Cannot register */
        if(bpm->serverConnectionsSize >= UA_MAXSERVERCONNECTIONS) {
            UA_LOG_WARNING(bpm->logging, UA_LOGCATEGORY_SERVER,
                           "Cannot register server socket - too many already open");
            cm->closeConnection(cm, connectionId);
            return;
        }

        /* Find and use a free connection slot */
        bpm->serverConnectionsSize++;
        UA_ServerConnection *sc = bpm->serverConnections;
        while(sc->connectionId != 0)
            sc++;
        sc->state = state;
        sc->connectionId = connectionId;
        sc->connectionManager = cm;
        *connectionContext = (void*)sc; /* Set the context pointer in the connection */
        return;
    }

    UA_ServerConnection *sc = (UA_ServerConnection*)*connectionContext;
    UA_SecureChannel *channel = (UA_SecureChannel*)*connectionContext;
    UA_Boolean serverSocket = (sc >= bpm->serverConnections &&
                               sc < &bpm->serverConnections[UA_MAXSERVERCONNECTIONS]);

    /* The connection is closing. This is the last callback for it. */
    if(state == UA_CONNECTIONSTATE_CLOSING) {
        if(serverSocket) {
            /* Server socket is closed */
            sc->state = UA_CONNECTIONSTATE_CLOSED;
            sc->connectionId = 0;
            bpm->serverConnectionsSize--;
        } else {
            /* A connection attached to a SecureChannel is closing. This is the
             * only place where deleteSecureChannel must be used. */
            deleteServerSecureChannel(bpm, channel);
        }

        /* Set BinaryProtocolManager to STOPPED if it is STOPPING and the last
         * socket just closed */
        if(bpm->sc.state == UA_LIFECYCLESTATE_STOPPING &&
           bpm->serverConnectionsSize == 0 &&
           LIST_EMPTY(&bpm->reverseConnects) &&
           TAILQ_EMPTY(&bpm->channels)) {
           setBinaryProtocolManagerState(bpm->server, bpm,
                                         UA_LIFECYCLESTATE_STOPPED);
        }
        return;
    }

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(serverSocket) {
        /* A new connection is opening. This is the only place where
         * createSecureChannel is used. */
        retval = createServerSecureChannel(bpm, cm, connectionId, &channel);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING(bpm->logging, UA_LOGCATEGORY_SERVER,
                           "TCP %lu\t| Could not accept the connection with status %s",
                           (unsigned long)sc->connectionId, UA_StatusCode_name(retval));
            *connectionContext = NULL;
            cm->closeConnection(cm, connectionId);
            return;
        }

        UA_LOG_INFO_CHANNEL(bpm->logging, channel, "SecureChannel created");

        /* Set the new channel as the new context for the connection */
        *connectionContext = (void*)channel;
        return;
    }

    /* The connection has fully opened */
    if(channel->state < UA_SECURECHANNELSTATE_CONNECTED)
        channel->state = UA_SECURECHANNELSTATE_CONNECTED;

    /* Received a message on a normal connection */
#ifdef UA_DEBUG_DUMP_PKGS
    UA_dump_hex_pkg(message->data, message->length);
#endif
#ifdef UA_DEBUG_DUMP_PKGS_FILE
    UA_debug_dumpCompleteChunk(server, channel->connection, message);
#endif

    UA_EventLoop *el = bpm->server->config.eventLoop;
    UA_DateTime nowMonotonic = el->dateTime_nowMonotonic(el);
    retval = UA_SecureChannel_processBuffer(channel, bpm->server,
                                            processSecureChannelMessage,
                                            &msg, nowMonotonic);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_CHANNEL(bpm->logging, channel,
                               "Processing the message failed with error %s",
                               UA_StatusCode_name(retval));

        /* Send an ERR message and close the connection */
        UA_TcpErrorMessage error;
        error.error = retval;
        error.reason = UA_STRING_NULL;
        UA_SecureChannel_sendError(channel, &error);
        UA_SecureChannel_shutdown(channel, UA_SHUTDOWNREASON_ABORT);
    }
}

static UA_StatusCode
createServerConnection(UA_BinaryProtocolManager *bpm, const UA_String *serverUrl) {
    UA_Server *server = bpm->server;
    UA_ServerConfig *config = &server->config;

    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Extract the protocol, hostname and port from the url */
    UA_String hostname = UA_STRING_NULL;
    UA_String path = UA_STRING_NULL;
    UA_UInt16 port = 4840; /* default */
    UA_StatusCode res = UA_parseEndpointUrl(serverUrl, &hostname, &port, &path);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    UA_String tcpString = UA_STRING("tcp");
    for(UA_EventSource *es = config->eventLoop->eventSources;
        es != NULL; es = es->next) {
        /* Is this a usable connection manager? */
        if(es->eventSourceType != UA_EVENTSOURCETYPE_CONNECTIONMANAGER)
            continue;
        UA_ConnectionManager *cm = (UA_ConnectionManager*)es;
        if(!UA_String_equal(&tcpString, &cm->protocol))
            continue;

        /* Set up the parameters */
        UA_KeyValuePair params[3];
        size_t paramsSize = 2;

        params[0].key = UA_QUALIFIEDNAME(0, "port");
        UA_Variant_setScalar(&params[0].value, &port, &UA_TYPES[UA_TYPES_UINT16]);

        UA_Boolean listen = true;
        params[1].key = UA_QUALIFIEDNAME(0, "listen");
        UA_Variant_setScalar(&params[1].value, &listen, &UA_TYPES[UA_TYPES_BOOLEAN]);

        if(hostname.length > 0) {
            /* The hostname is non-empty */
            params[2].key = UA_QUALIFIEDNAME(0, "address");
            UA_Variant_setArray(&params[2].value, &hostname, 1, &UA_TYPES[UA_TYPES_STRING]);
            paramsSize = 3;
        }

        UA_KeyValueMap paramsMap;
        paramsMap.map = params;
        paramsMap.mapSize = paramsSize;

        /* Open the server connection */
        res = cm->openConnection(cm, &paramsMap, bpm, NULL, serverNetworkCallback);
        if(res == UA_STATUSCODE_GOOD)
            return res;
    }

    return UA_STATUSCODE_BADINTERNALERROR;
}

/* Remove timed out SecureChannels */
static void
secureChannelHouseKeeping(UA_Server *server, void *context) {
    UA_BinaryProtocolManager *bpm = (UA_BinaryProtocolManager*)context;
    UA_LOCK(&server->serviceMutex);

    UA_EventLoop *el = server->config.eventLoop;
    UA_DateTime nowMonotonic = el->dateTime_nowMonotonic(el);

    channel_entry *entry;
    TAILQ_FOREACH(entry, &bpm->channels, pointers) {
        UA_Boolean timeout = UA_SecureChannel_checkTimeout(&entry->channel, nowMonotonic);
        if(timeout) {
            UA_LOG_INFO_CHANNEL(bpm->logging, &entry->channel, "SecureChannel has timed out");
            UA_SecureChannel_shutdown(&entry->channel, UA_SHUTDOWNREASON_TIMEOUT);
        }
    }
    UA_UNLOCK(&server->serviceMutex);
}

/**********************/
/* Reverse Connection */
/**********************/

#define UA_MINMESSAGESIZE 8192

static UA_StatusCode
sendRHEMessage(UA_Server *server, uintptr_t connectionId,
               UA_ConnectionManager *cm) {
    UA_ServerConfig *config = UA_Server_getConfig(server);

    /* Get a buffer */
    UA_ByteString message;
    UA_StatusCode retval =
        cm->allocNetworkBuffer(cm, connectionId, &message, UA_MINMESSAGESIZE);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Prepare the RHE message and encode at offset 8 */
    UA_TcpReverseHelloMessage reverseHello;
    UA_TcpReverseHelloMessage_init(&reverseHello);
    reverseHello.serverUri = config->applicationDescription.applicationUri;
    if(config->applicationDescription.discoveryUrlsSize)
        reverseHello.endpointUrl = config->applicationDescription.discoveryUrls[0];

    UA_Byte *bufPos = &message.data[8]; /* skip the header */
    const UA_Byte *bufEnd = &message.data[message.length];
    UA_StatusCode result =
        UA_encodeBinaryInternal(&reverseHello,
                                &UA_TRANSPORT[UA_TRANSPORT_TCPREVERSEHELLOMESSAGE],
                                &bufPos, &bufEnd, NULL, NULL);

    if(result != UA_STATUSCODE_GOOD) {
        cm->freeNetworkBuffer(cm, connectionId, &message);
        return result;
    }

    /* Encode the message header at offset 0 */
    UA_TcpMessageHeader messageHeader;
    messageHeader.messageTypeAndChunkType = UA_CHUNKTYPE_FINAL + UA_MESSAGETYPE_RHE;
    messageHeader.messageSize = (UA_UInt32) ((uintptr_t)bufPos - (uintptr_t)message.data);
    bufPos = message.data;
    retval = UA_encodeBinaryInternal(&messageHeader,
                                     &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER],
                                     &bufPos, &bufEnd, NULL, NULL);
    if(retval != UA_STATUSCODE_GOOD) {
        cm->freeNetworkBuffer(cm, connectionId, &message);
        return retval;
    }

    /* Send the RHE message */
    message.length = messageHeader.messageSize;
    return cm->sendWithConnection(cm, connectionId, NULL, &message);
}

static void
retryReverseConnectCallback(UA_Server *server, void *context) {
    UA_LOCK(&server->serviceMutex);

    UA_BinaryProtocolManager *bpm = (UA_BinaryProtocolManager*)context;

    reverse_connect_context *rc = NULL;
    LIST_FOREACH(rc, &bpm->reverseConnects, next) {
        if(rc->currentConnection.connectionId)
            continue;
        UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_SERVER,
                    "Attempt to reverse reconnect to %.*s:%d",
                    (int)rc->hostname.length, rc->hostname.data, rc->port);
        attemptReverseConnect(bpm, rc);
    }

    UA_UNLOCK(&server->serviceMutex);
}

UA_StatusCode
setReverseConnectRetryCallback(UA_BinaryProtocolManager *bpm, UA_Boolean enabled) {
    UA_Server *server = bpm->server;
    UA_ServerConfig *config = &server->config;

    if(enabled && !bpm->reverseConnectsCheckHandle) {
        UA_UInt32 reconnectInterval = config->reverseReconnectInterval ?
            config->reverseReconnectInterval : 15000;
        return addRepeatedCallback(server, retryReverseConnectCallback, bpm,
                                   reconnectInterval, &bpm->reverseConnectsCheckHandle);
    } else if(!enabled && bpm->reverseConnectsCheckHandle) {
        removeCallback(server, bpm->reverseConnectsCheckHandle);
        bpm->reverseConnectsCheckHandle = 0;
    }
    return UA_STATUSCODE_GOOD;
}

void
setReverseConnectState(UA_Server *server, reverse_connect_context *context,
                       UA_SecureChannelState newState) {
    if(context->state == newState)
        return;

    context->state = newState;

    if(context->stateCallback)
        context->stateCallback(server, context->handle, context->state,
                               context->callbackContext);
}

static void
serverReverseConnectCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
                             void *application, void **connectionContext,
                             UA_ConnectionState state, const UA_KeyValueMap *params,
                             UA_ByteString msg);

UA_StatusCode
attemptReverseConnect(UA_BinaryProtocolManager *bpm, reverse_connect_context *context) {
    UA_Server *server = bpm->server;
    UA_ServerConfig *config = &server->config;
    UA_EventLoop *el = config->eventLoop;

    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Find a TCP ConnectionManager */
    UA_String tcpString = UA_STRING_STATIC("tcp");
    for(UA_EventSource *es = el->eventSources; es != NULL; es = es->next) {
        /* Is this a usable connection manager? */
        if(es->eventSourceType != UA_EVENTSOURCETYPE_CONNECTIONMANAGER)
            continue;

        UA_ConnectionManager *cm = (UA_ConnectionManager*)es;
        if(!UA_String_equal(&tcpString, &cm->protocol))
            continue;

        if(es->state != UA_EVENTSOURCESTATE_STARTED)
            continue;

        /* Set up the parameters */
        UA_KeyValuePair params[2];
        params[0].key = UA_QUALIFIEDNAME(0, "address");
        UA_Variant_setScalar(&params[0].value, &context->hostname,
                             &UA_TYPES[UA_TYPES_STRING]);
        params[1].key = UA_QUALIFIEDNAME(0, "port");
        UA_Variant_setScalar(&params[1].value, &context->port,
                             &UA_TYPES[UA_TYPES_UINT16]);
        UA_KeyValueMap kvm = {2, params};

        /* Open the connection */
        UA_StatusCode res = cm->openConnection(cm, &kvm, bpm, context,
                                               serverReverseConnectCallback);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                           "Failed to create connection for reverse connect: %s\n",
                           UA_StatusCode_name(res));
        }
        return res;
    }

    UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                   "No ConnectionManager found for reverse connect");
    return UA_STATUSCODE_BADINTERNALERROR;
}

UA_StatusCode
UA_Server_addReverseConnect(UA_Server *server, UA_String url,
                            UA_Server_ReverseConnectStateCallback stateCallback,
                            void *callbackContext, UA_UInt64 *handle) {
    UA_ServerConfig *config = UA_Server_getConfig(server);
    UA_ServerComponent *sc =
        getServerComponentByName(server, UA_STRING("binary"));
    UA_BinaryProtocolManager *bpm = (UA_BinaryProtocolManager*)sc;
    if(!bpm) {
        UA_LOG_ERROR(config->logging, UA_LOGCATEGORY_SERVER,
                     "No BinaryProtocolManager configured");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Parse the reverse connect URL */
    UA_String hostname = UA_STRING_NULL;
    UA_UInt16 port = 0;
    UA_StatusCode res = UA_parseEndpointUrl(&url, &hostname, &port, NULL);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SERVER,
                       "OPC UA URL is invalid: %.*s",
                       (int)url.length, url.data);
        return res;
    }

    /* Set up the reverse connection */
    reverse_connect_context *newContext = (reverse_connect_context *)
        UA_calloc(1, sizeof(reverse_connect_context));
    if(!newContext)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_String_copy(&hostname, &newContext->hostname);
    newContext->port = port;
    newContext->handle = ++bpm->lastReverseConnectHandle;
    newContext->stateCallback = stateCallback;
    newContext->callbackContext = callbackContext;

    UA_LOCK(&server->serviceMutex);

    /* Register the retry callback */
    setReverseConnectRetryCallback(bpm, true);

    /* Register the new reverse connection */
    LIST_INSERT_HEAD(&bpm->reverseConnects, newContext, next);

    if(handle)
        *handle = newContext->handle;

    /* Attempt to connect right away */
    res = attemptReverseConnect(bpm, newContext);

    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_Server_removeReverseConnect(UA_Server *server, UA_UInt64 handle) {
    UA_StatusCode result = UA_STATUSCODE_BADNOTFOUND;

    UA_LOCK(&server->serviceMutex);

    UA_ServerComponent *sc =
        getServerComponentByName(server, UA_STRING("binary"));
    UA_BinaryProtocolManager *bpm = (UA_BinaryProtocolManager*)sc;
    if(!bpm) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "No BinaryProtocolManager configured");
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    reverse_connect_context *rev, *temp;
    LIST_FOREACH_SAFE(rev, &bpm->reverseConnects, next, temp) {
        if(rev->handle != handle)
            continue;

        LIST_REMOVE(rev, next);

        /* Connected -> disconnect, otherwise free immediately */
        if(rev->currentConnection.connectionId) {
            UA_ConnectionManager *cm = rev->currentConnection.connectionManager;
            rev->destruction = true;
            cm->closeConnection(cm, rev->currentConnection.connectionId);
        } else {
            setReverseConnectState(server, rev, UA_SECURECHANNELSTATE_CLOSED);
            UA_String_clear(&rev->hostname);
            UA_free(rev);
        }
        result = UA_STATUSCODE_GOOD;
        break;
    }

    if(LIST_EMPTY(&bpm->reverseConnects))
        setReverseConnectRetryCallback(bpm, false);

    UA_UNLOCK(&server->serviceMutex);

    return result;
}

void
serverReverseConnectCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
                             void *application, void **connectionContext,
                             UA_ConnectionState state, const UA_KeyValueMap *params,
                             UA_ByteString msg) {
    (void)params;
    UA_BinaryProtocolManager *bpm = (UA_BinaryProtocolManager*)application;
    UA_LOG_DEBUG(bpm->logging, UA_LOGCATEGORY_SERVER,
                 "Activity for reverse connect %lu with state %d",
                 (long unsigned)connectionId, state);

    reverse_connect_context *context = (reverse_connect_context *)*connectionContext;
    context->currentConnection.state = state;

    /* New connection */
    if(context->currentConnection.connectionId == 0) {
        context->currentConnection.connectionId = connectionId;
        context->currentConnection.connectionManager = cm;
        setReverseConnectState(bpm->server, context, UA_SECURECHANNELSTATE_CONNECTING);
        /* Fall through -- e.g. if state == ESTABLISHED already */
    }

    /* The connection is closing. This is the last callback for it. */
    if(state == UA_CONNECTIONSTATE_CLOSING) {
        if(context->channel) {
            deleteServerSecureChannel(bpm, context->channel);
            context->channel = NULL;
        }

        /* Delete the ReverseConnect entry */
        if(context->destruction) {
            setReverseConnectState(bpm->server, context, UA_SECURECHANNELSTATE_CLOSED);
            LIST_REMOVE(context, next);
            UA_String_clear(&context->hostname);
            UA_free(context);

            /* Check if the Binary Protocol Manager is stopped */
            if(bpm->sc.state == UA_LIFECYCLESTATE_STOPPING &&
               bpm->serverConnectionsSize == 0 &&
               LIST_EMPTY(&bpm->reverseConnects) &&
               TAILQ_EMPTY(&bpm->channels)) {
                setBinaryProtocolManagerState(bpm->server, bpm,
                                              UA_LIFECYCLESTATE_STOPPED);
            }
            return;
        }

        /* Reset. Will be picked up in the regular retry callback. */
        context->currentConnection.connectionId = 0;
        setReverseConnectState(bpm->server, context, UA_SECURECHANNELSTATE_CONNECTING);
        return;
    }

    if(state != UA_CONNECTIONSTATE_ESTABLISHED)
        return;

    /* A new connection is opening. This is the only place where
     * createSecureChannel is used. */
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(!context->channel) {
        retval = createServerSecureChannel(bpm, cm, connectionId, &context->channel);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING(bpm->logging, UA_LOGCATEGORY_SERVER,
                           "TCP %lu\t| Could not accept the reverse "
                           "connection with status %s",
                           (unsigned long)context->currentConnection.connectionId,
                           UA_StatusCode_name(retval));
            cm->closeConnection(cm, connectionId);
            return;
        }

        /* Send the RHE message */
        retval = sendRHEMessage(bpm->server, connectionId, cm);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING(bpm->logging, UA_LOGCATEGORY_SERVER,
                           "TCP %lu\t| Could not send the RHE message "
                           "with status %s",
                           (unsigned long)context->currentConnection.connectionId,
                           UA_StatusCode_name(retval));
            cm->closeConnection(cm, connectionId);
            return;
        }

        context->channel->state = UA_SECURECHANNELSTATE_RHE_SENT;
        setReverseConnectState(bpm->server, context, UA_SECURECHANNELSTATE_RHE_SENT);
        return;
    }

    /* The connection is fully opened and we have a SecureChannel.
     * Process the received buffer */
    UA_EventLoop *el = bpm->server->config.eventLoop;
    UA_DateTime nowMonotonic = el->dateTime_nowMonotonic(el);
    retval = UA_SecureChannel_processBuffer(context->channel, bpm->server,
                                            processSecureChannelMessage,
                                            &msg, nowMonotonic);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_CHANNEL(bpm->logging, context->channel,
                               "Processing the message failed with error %s",
                               UA_StatusCode_name(retval));

        /* Processing the buffer failed within the SecureChannel.
         * Send an ERR message and close the connection. */
        UA_TcpErrorMessage error;
        error.error = retval;
        error.reason = UA_STRING_NULL;
        UA_SecureChannel_sendError(context->channel, &error);
        UA_SecureChannel_shutdown(context->channel, UA_SHUTDOWNREASON_ABORT);

        setReverseConnectState(bpm->server, context, UA_SECURECHANNELSTATE_CLOSING);
        return;
    }

    /* Update the state with the current SecureChannel state */
    setReverseConnectState(bpm->server, context, context->channel->state);
}

/***************************/
/* Binary Protocol Manager */
/***************************/

static UA_StatusCode
UA_BinaryProtocolManager_start(UA_Server *server,
                               UA_ServerComponent *sc) {
    UA_BinaryProtocolManager *bpm = (UA_BinaryProtocolManager*)sc;
    UA_ServerConfig *config = &server->config;
    
    UA_StatusCode retVal =
        addRepeatedCallback(server, secureChannelHouseKeeping,
                            bpm, 1000.0, &bpm->houseKeepingCallbackId);
    if(retVal != UA_STATUSCODE_GOOD)
        return retVal;

    /* Open server sockets */
    UA_Boolean haveServerSocket = false;
    if(config->serverUrlsSize == 0) {
        /* Empty hostname -> listen on all devices */
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SERVER,
                       "No Server URL configured. Using \"opc.tcp://:4840\" "
                       "to configure the listen socket.");
        UA_String defaultUrl = UA_STRING("opc.tcp://:4840");
        retVal = createServerConnection(bpm, &defaultUrl);
        if(retVal == UA_STATUSCODE_GOOD)
            haveServerSocket = true;
    } else {
        for(size_t i = 0; i < config->serverUrlsSize; i++) {
            retVal = createServerConnection(bpm, &config->serverUrls[i]);
            if(retVal == UA_STATUSCODE_GOOD)
                haveServerSocket = true;
        }
    }

    if(!haveServerSocket) {
        UA_LOG_ERROR(config->logging, UA_LOGCATEGORY_SERVER,
                     "The server has no server socket");
    }

    /* Update the application description to include the server urls for
     * discovery. Don't add the urls with an empty host (listening on all
     * interfaces) */
    for(size_t i = 0; i < config->serverUrlsSize; i++) {
        UA_String hostname = UA_STRING_NULL;
        UA_String path = UA_STRING_NULL;
        UA_UInt16 port = 0;
        retVal = UA_parseEndpointUrl(&config->serverUrls[i],
                                     &hostname, &port, &path);
        if(retVal != UA_STATUSCODE_GOOD || hostname.length == 0)
            continue;

        /* Check if the ServerUrl is already present in the DiscoveryUrl array.
         * Add if not already there. */
        size_t j = 0;
        for(; j < config->applicationDescription.discoveryUrlsSize; j++) {
            if(UA_String_equal(&config->serverUrls[i],
                               &config->applicationDescription.discoveryUrls[j]))
                break;
        }
        if(j == config->applicationDescription.discoveryUrlsSize) {
            retVal =
                UA_Array_appendCopy((void**)&config->applicationDescription.discoveryUrls,
                                    &config->applicationDescription.discoveryUrlsSize,
                                    &config->serverUrls[i], &UA_TYPES[UA_TYPES_STRING]);
            (void)retVal;
        }
    }

    /* Set the state to started */
    setBinaryProtocolManagerState(bpm->server, bpm,
                                  UA_LIFECYCLESTATE_STARTED);

    return UA_STATUSCODE_GOOD;
}

static void
UA_BinaryProtocolManager_stop(UA_Server *server,
                              UA_ServerComponent *comp) {
    UA_BinaryProtocolManager *bpm = (UA_BinaryProtocolManager*)comp;

    /* Stop the Housekeeping Task */
    removeCallback(server, bpm->houseKeepingCallbackId);
    bpm->houseKeepingCallbackId = 0;

    /* Stop the regular retry callback */
    setReverseConnectRetryCallback(bpm, false);

    /* Close or free all reverse connections */
    reverse_connect_context *rev, *rev_tmp;
    LIST_FOREACH_SAFE(rev, &bpm->reverseConnects, next, rev_tmp) {
        if(rev->currentConnection.connectionId) {
            UA_ConnectionManager *cm = rev->currentConnection.connectionManager;
            rev->destruction = true;
            cm->closeConnection(cm, rev->currentConnection.connectionId);
        } else {
            LIST_REMOVE(rev, next);
            setReverseConnectState(server, rev, UA_SECURECHANNELSTATE_CLOSED);
            UA_String_clear(&rev->hostname);
            UA_free(rev);
        }
    }

    /* Stop all SecureChannels */
    channel_entry *entry;
    TAILQ_FOREACH(entry, &bpm->channels, pointers) {
        UA_SecureChannel_shutdown(&entry->channel, UA_SHUTDOWNREASON_CLOSE);
    }

    /* Stop all server sockets */
    for(size_t i = 0; i < UA_MAXSERVERCONNECTIONS; i++) {
        UA_ServerConnection *sc = &bpm->serverConnections[i];
        UA_ConnectionManager *cm = sc->connectionManager;
        if(sc->connectionId > 0)
            cm->closeConnection(cm, sc->connectionId);
    }

    /* If open sockets remain, set to STOPPING */
    if(bpm->serverConnectionsSize == 0 &&
       LIST_EMPTY(&bpm->reverseConnects) &&
       TAILQ_EMPTY(&bpm->channels)) {
        setBinaryProtocolManagerState(bpm->server, bpm,
                                      UA_LIFECYCLESTATE_STOPPED);
    } else {
        setBinaryProtocolManagerState(bpm->server, bpm,
                                      UA_LIFECYCLESTATE_STOPPING);
    }
}

static UA_StatusCode
UA_BinaryProtocolManager_free(UA_Server *server,
                              UA_ServerComponent *sc) {
    if(sc->state != UA_LIFECYCLESTATE_STOPPED)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_free(sc);
    return UA_STATUSCODE_GOOD;
}

UA_ServerComponent *
UA_BinaryProtocolManager_new(UA_Server *server) {
    UA_BinaryProtocolManager *bpm = (UA_BinaryProtocolManager*)
        UA_calloc(1, sizeof(UA_BinaryProtocolManager));
    if(!bpm)
        return NULL;

    bpm->server = server;
    bpm->logging = server->config.logging;

    /* Initialize SecureChannel */
    TAILQ_INIT(&bpm->channels);

    /* TODO: use an ID that is likely to be unique after a restart */
    bpm->lastChannelId = STARTCHANNELID;
    bpm->lastTokenId = STARTTOKENID;

    bpm->sc.name = UA_STRING("binary");
    bpm->sc.start = UA_BinaryProtocolManager_start;
    bpm->sc.stop = UA_BinaryProtocolManager_stop;
    bpm->sc.free = UA_BinaryProtocolManager_free;
    return &bpm->sc;
}

/**** amalgamated original file "/src/server/ua_server_utils.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2016-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2016 (c) Lorenz Haas
 *    Copyright 2017 (c) frax2222
 *    Copyright 2017 (c) Florian Palm
 *    Copyright 2017-2018 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Julian Grothoff
 */


const UA_DataType *
UA_Server_findDataType(UA_Server *server, const UA_NodeId *typeId) {
    return UA_findDataTypeWithCustom(typeId, server->config.customDataTypes);
}

/********************************/
/* Information Model Operations */
/********************************/

static void *
returnFirstType(void *context, UA_ReferenceTarget *t) {
    UA_Server *server = (UA_Server*)context;
    /* Don't release the node that is returned.
     * Continues to iterate if NULL is returned. */
    return (void*)(uintptr_t)UA_NODESTORE_GETFROMREF(server, t->targetId);
}

const UA_Node *
getNodeType(UA_Server *server, const UA_NodeHead *head) {
    /* The reference to the parent is different for variable and variabletype */
    UA_Byte parentRefIndex;
    UA_Boolean inverse;
    switch(head->nodeClass) {
    case UA_NODECLASS_OBJECT:
        parentRefIndex = UA_REFERENCETYPEINDEX_HASTYPEDEFINITION;
        inverse = false;
        break;
    case UA_NODECLASS_VARIABLE:
        parentRefIndex = UA_REFERENCETYPEINDEX_HASTYPEDEFINITION;
        inverse = false;
        break;
    case UA_NODECLASS_OBJECTTYPE:
    case UA_NODECLASS_VARIABLETYPE:
    case UA_NODECLASS_REFERENCETYPE:
    case UA_NODECLASS_DATATYPE:
        parentRefIndex = UA_REFERENCETYPEINDEX_HASSUBTYPE;
        inverse = true;
        break;
    default:
        return NULL;
    }

    /* Return the first matching candidate */
    for(size_t i = 0; i < head->referencesSize; ++i) {
        UA_NodeReferenceKind *rk = &head->references[i];
        if(rk->isInverse != inverse)
            continue;
        if(rk->referenceTypeIndex != parentRefIndex)
            continue;
        const UA_Node *type = (const UA_Node*)
            UA_NodeReferenceKind_iterate(rk, returnFirstType, server);
        if(type)
            return type;
    }

    return NULL;
}

UA_Boolean
UA_Node_hasSubTypeOrInstances(const UA_NodeHead *head) {
    for(size_t i = 0; i < head->referencesSize; ++i) {
        if(head->references[i].isInverse == false &&
           head->references[i].referenceTypeIndex == UA_REFERENCETYPEINDEX_HASSUBTYPE)
            return true;
        if(head->references[i].isInverse == true &&
           head->references[i].referenceTypeIndex == UA_REFERENCETYPEINDEX_HASTYPEDEFINITION)
            return true;
    }
    return false;
}

UA_StatusCode
getParentTypeAndInterfaceHierarchy(UA_Server *server, const UA_NodeId *typeNode,
                                   UA_NodeId **typeHierarchy, size_t *typeHierarchySize) {
    UA_ReferenceTypeSet reftypes_subtype =
        UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASSUBTYPE);
    UA_ExpandedNodeId *subTypes = NULL;
    size_t subTypesSize = 0;
    UA_StatusCode retval = browseRecursive(server, 1, typeNode,
                                           UA_BROWSEDIRECTION_INVERSE,
                                           &reftypes_subtype, UA_NODECLASS_UNSPECIFIED,
                                           false, &subTypesSize, &subTypes);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    UA_assert(subTypesSize < 1000);

    UA_ReferenceTypeSet reftypes_interface =
        UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASINTERFACE);
    UA_ExpandedNodeId *interfaces = NULL;
    size_t interfacesSize = 0;
    retval = browseRecursive(server, 1, typeNode, UA_BROWSEDIRECTION_FORWARD,
                             &reftypes_interface, UA_NODECLASS_UNSPECIFIED,
                             false, &interfacesSize, &interfaces);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_Array_delete(subTypes, subTypesSize, &UA_TYPES[UA_TYPES_NODEID]);
        return retval;
    }

    UA_assert(interfacesSize < 1000);

    UA_NodeId *hierarchy = (UA_NodeId*)
        UA_malloc(sizeof(UA_NodeId) * (1 + subTypesSize + interfacesSize));
    if(!hierarchy) {
        UA_Array_delete(subTypes, subTypesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
        UA_Array_delete(interfaces, interfacesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    retval = UA_NodeId_copy(typeNode, hierarchy);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free(hierarchy);
        UA_Array_delete(subTypes, subTypesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
        UA_Array_delete(interfaces, interfacesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    for(size_t i = 0; i < subTypesSize; i++) {
        hierarchy[i+1] = subTypes[i].nodeId;
        UA_NodeId_init(&subTypes[i].nodeId);
    }
    for(size_t i = 0; i < interfacesSize; i++) {
        hierarchy[i+1+subTypesSize] = interfaces[i].nodeId;
        UA_NodeId_init(&interfaces[i].nodeId);
    }

    *typeHierarchy = hierarchy;
    *typeHierarchySize = subTypesSize + interfacesSize + 1;

    UA_assert(*typeHierarchySize < 1000);

    UA_Array_delete(subTypes, subTypesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
    UA_Array_delete(interfaces, interfacesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
getAllInterfaceChildNodeIds(UA_Server *server, const UA_NodeId *objectNode,
                            const UA_NodeId *objectTypeNode,
                            UA_NodeId **interfaceChildNodes,
                            size_t *interfaceChildNodesSize) {
    if(interfaceChildNodesSize == NULL || interfaceChildNodes == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    *interfaceChildNodesSize = 0;
    *interfaceChildNodes = NULL;

    UA_ExpandedNodeId *hasInterfaceCandidates = NULL;
    size_t hasInterfaceCandidatesSize = 0;
    UA_ReferenceTypeSet reftypes_subtype =
        UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASSUBTYPE);

    UA_StatusCode retval =
        browseRecursive(server, 1, objectTypeNode, UA_BROWSEDIRECTION_INVERSE,
                        &reftypes_subtype, UA_NODECLASS_OBJECTTYPE,
                        true, &hasInterfaceCandidatesSize,
                        &hasInterfaceCandidates);

    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* The interface could also have been added manually before calling UA_Server_addNode_finish
     * This can be handled by adding the object node as a start node for the HasInterface lookup */
    UA_ExpandedNodeId *resizedHasInterfaceCandidates = (UA_ExpandedNodeId*)
        UA_realloc(hasInterfaceCandidates,
                   (hasInterfaceCandidatesSize + 1) * sizeof(UA_ExpandedNodeId));

    if(!resizedHasInterfaceCandidates) {
        if(hasInterfaceCandidates)
            UA_Array_delete(hasInterfaceCandidates, hasInterfaceCandidatesSize,
                            &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    hasInterfaceCandidates = resizedHasInterfaceCandidates;
    hasInterfaceCandidatesSize += 1;
    UA_ExpandedNodeId_init(&hasInterfaceCandidates[hasInterfaceCandidatesSize - 1]);

    UA_ExpandedNodeId_init(&hasInterfaceCandidates[hasInterfaceCandidatesSize - 1]);
    UA_NodeId_copy(objectNode, &hasInterfaceCandidates[hasInterfaceCandidatesSize - 1].nodeId);

    size_t outputIndex = 0;

    for(size_t i = 0; i < hasInterfaceCandidatesSize; ++i) {
        UA_ReferenceTypeSet reftypes_interface =
            UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASINTERFACE);
        UA_ExpandedNodeId *interfaceChildren = NULL;
        size_t interfacesChildrenSize = 0;
        retval = browseRecursive(server, 1, &hasInterfaceCandidates[i].nodeId,
                                 UA_BROWSEDIRECTION_FORWARD,
                                 &reftypes_interface, UA_NODECLASS_OBJECTTYPE,
                                 false, &interfacesChildrenSize, &interfaceChildren);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_Array_delete(hasInterfaceCandidates, hasInterfaceCandidatesSize,
                            &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
            if(*interfaceChildNodesSize) {
                UA_Array_delete(*interfaceChildNodes, *interfaceChildNodesSize,
                                &UA_TYPES[UA_TYPES_NODEID]);
                *interfaceChildNodesSize = 0;
            }
            return retval;
        }

        UA_assert(interfacesChildrenSize < 1000);

        if(interfacesChildrenSize == 0) {
            continue;
        }

        if(!*interfaceChildNodes) {
            *interfaceChildNodes = (UA_NodeId*)
                UA_calloc(interfacesChildrenSize, sizeof(UA_NodeId));
            *interfaceChildNodesSize = interfacesChildrenSize;

            if(!*interfaceChildNodes) {
                UA_Array_delete(interfaceChildren, interfacesChildrenSize,
                                &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
                UA_Array_delete(hasInterfaceCandidates, hasInterfaceCandidatesSize,
                                &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
                return UA_STATUSCODE_BADOUTOFMEMORY;
            }
        } else {
            UA_NodeId *resizedInterfaceChildNodes = (UA_NodeId*)
                UA_realloc(*interfaceChildNodes,
                           ((*interfaceChildNodesSize + interfacesChildrenSize) * sizeof(UA_NodeId)));

            if(!resizedInterfaceChildNodes) {
                UA_Array_delete(hasInterfaceCandidates, hasInterfaceCandidatesSize,
                                &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
                UA_Array_delete(interfaceChildren, interfacesChildrenSize,
                                &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
                return UA_STATUSCODE_BADOUTOFMEMORY;
            }

            const size_t oldSize = *interfaceChildNodesSize;
            *interfaceChildNodesSize += interfacesChildrenSize;
            *interfaceChildNodes = resizedInterfaceChildNodes;

            for(size_t j = oldSize; j < *interfaceChildNodesSize; ++j)
                UA_NodeId_init(&(*interfaceChildNodes)[j]);
        }

        for(size_t j = 0; j < interfacesChildrenSize; j++) {
            (*interfaceChildNodes)[outputIndex++] = interfaceChildren[j].nodeId;
        }

        UA_assert(*interfaceChildNodesSize < 1000);
        UA_Array_delete(interfaceChildren, interfacesChildrenSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
    }

    UA_Array_delete(hasInterfaceCandidates, hasInterfaceCandidatesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);

    return UA_STATUSCODE_GOOD;
}

/* For mulithreading: make a copy of the node, edit and replace.
 * For singlethreading: edit the original */
UA_StatusCode
UA_Server_editNode(UA_Server *server, UA_Session *session,
                   const UA_NodeId *nodeId, UA_EditNodeCallback callback,
                   void *data) {
#ifndef UA_ENABLE_IMMUTABLE_NODES
    /* Get the node and process it in-situ */
    const UA_Node *node = UA_NODESTORE_GET(server, nodeId);
    if(!node)
        return UA_STATUSCODE_BADNODEIDUNKNOWN;
    UA_StatusCode retval = callback(server, session, (UA_Node*)(uintptr_t)node, data);
    UA_NODESTORE_RELEASE(server, node);
    return retval;
#else
    UA_StatusCode retval;
    do {
        /* Get an editable copy of the node */
        UA_Node *node;
        retval = UA_NODESTORE_GETCOPY(server, nodeId, &node);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;

        /* Run the operation on the copy */
        retval = callback(server, session, node, data);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_NODESTORE_DELETE(server, node);
            return retval;
        }

        /* Replace the node */
        retval = UA_NODESTORE_REPLACE(server, node);
    } while(retval != UA_STATUSCODE_GOOD);
    return retval;
#endif
}

UA_StatusCode
UA_Server_processServiceOperations(UA_Server *server, UA_Session *session,
                                   UA_ServiceOperation operationCallback,
                                   const void *context, const size_t *requestOperations,
                                   const UA_DataType *requestOperationsType,
                                   size_t *responseOperations,
                                   const UA_DataType *responseOperationsType) {
    size_t ops = *requestOperations;
    if(ops == 0)
        return UA_STATUSCODE_BADNOTHINGTODO;

    /* No padding after size_t */
    void **respPos = (void**)((uintptr_t)responseOperations + sizeof(size_t));
    *respPos = UA_Array_new(ops, responseOperationsType);
    if(!(*respPos))
        return UA_STATUSCODE_BADOUTOFMEMORY;

    *responseOperations = ops;
    uintptr_t respOp = (uintptr_t)*respPos;
    /* No padding after size_t */
    uintptr_t reqOp = *(uintptr_t*)((uintptr_t)requestOperations + sizeof(size_t));
    for(size_t i = 0; i < ops; i++) {
        operationCallback(server, session, context, (void*)reqOp, (void*)respOp);
        reqOp += requestOperationsType->memSize;
        respOp += responseOperationsType->memSize;
    }
    return UA_STATUSCODE_GOOD;
}

/* A few global NodeId definitions */
const UA_NodeId subtypeId = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASSUBTYPE}};
const UA_NodeId hierarchicalReferences = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HIERARCHICALREFERENCES}};

/*********************************/
/* Default attribute definitions */
/*********************************/

const UA_ObjectAttributes UA_ObjectAttributes_default = {
    0,                      /* specifiedAttributes */
    {{0, NULL}, {0, NULL}}, /* displayName */
    {{0, NULL}, {0, NULL}}, /* description */
    0, 0,                   /* writeMask (userWriteMask) */
    0                       /* eventNotifier */
};

const UA_VariableAttributes UA_VariableAttributes_default = {
    0,                           /* specifiedAttributes */
    {{0, NULL}, {0, NULL}},      /* displayName */
    {{0, NULL}, {0, NULL}},      /* description */
    0, 0,                        /* writeMask (userWriteMask) */
    {NULL, UA_VARIANT_DATA,
     0, NULL, 0, NULL},          /* value */
    {0, UA_NODEIDTYPE_NUMERIC,
     {UA_NS0ID_BASEDATATYPE}},   /* dataType */
    UA_VALUERANK_ANY,            /* valueRank */
    0, NULL,                     /* arrayDimensions */
    UA_ACCESSLEVELMASK_READ |    /* accessLevel */
    UA_ACCESSLEVELMASK_STATUSWRITE |
    UA_ACCESSLEVELMASK_TIMESTAMPWRITE,
    0,                           /* userAccessLevel */
    0.0,                         /* minimumSamplingInterval */
    false                        /* historizing */
};

const UA_MethodAttributes UA_MethodAttributes_default = {
    0,                      /* specifiedAttributes */
    {{0, NULL}, {0, NULL}}, /* displayName */
    {{0, NULL}, {0, NULL}}, /* description */
    0, 0,                   /* writeMask (userWriteMask) */
    true, true              /* executable (userExecutable) */
};

const UA_ObjectTypeAttributes UA_ObjectTypeAttributes_default = {
    0,                      /* specifiedAttributes */
    {{0, NULL}, {0, NULL}}, /* displayName */
    {{0, NULL}, {0, NULL}}, /* description */
    0, 0,                   /* writeMask (userWriteMask) */
    false                   /* isAbstract */
};

const UA_VariableTypeAttributes UA_VariableTypeAttributes_default = {
    0,                           /* specifiedAttributes */
    {{0, NULL}, {0, NULL}},      /* displayName */
    {{0, NULL}, {0, NULL}},      /* description */
    0, 0,                        /* writeMask (userWriteMask) */
    {NULL, UA_VARIANT_DATA,
     0, NULL, 0, NULL},          /* value */
    {0, UA_NODEIDTYPE_NUMERIC,
     {UA_NS0ID_BASEDATATYPE}},   /* dataType */
    UA_VALUERANK_ANY,            /* valueRank */
    0, NULL,                     /* arrayDimensions */
    false                        /* isAbstract */
};

const UA_ReferenceTypeAttributes UA_ReferenceTypeAttributes_default = {
    0,                      /* specifiedAttributes */
    {{0, NULL}, {0, NULL}}, /* displayName */
    {{0, NULL}, {0, NULL}}, /* description */
    0, 0,                   /* writeMask (userWriteMask) */
    false,                  /* isAbstract */
    false,                  /* symmetric */
    {{0, NULL}, {0, NULL}}  /* inverseName */
};

const UA_DataTypeAttributes UA_DataTypeAttributes_default = {
    0,                      /* specifiedAttributes */
    {{0, NULL}, {0, NULL}}, /* displayName */
    {{0, NULL}, {0, NULL}}, /* description */
    0, 0,                   /* writeMask (userWriteMask) */
    false                   /* isAbstract */
};

const UA_ViewAttributes UA_ViewAttributes_default = {
    0,                      /* specifiedAttributes */
    {{0, NULL}, {0, NULL}}, /* displayName */
    {{0, NULL}, {0, NULL}}, /* description */
    0, 0,                   /* writeMask (userWriteMask) */
    false,                  /* containsNoLoops */
    0                       /* eventNotifier */
};


/**** amalgamated original file "/src/server/ua_server_async.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2019 (c) Fraunhofer IOSB (Author: Klaus Schick)
 *    Copyright 2019 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 */


#if UA_MULTITHREADING >= 100

static void
UA_AsyncOperation_delete(UA_AsyncOperation *ar) {
    UA_CallMethodRequest_clear(&ar->request);
    UA_CallMethodResult_clear(&ar->response);
    UA_free(ar);
}

static void
UA_AsyncManager_sendAsyncResponse(UA_AsyncManager *am, UA_Server *server,
                                  UA_AsyncResponse *ar) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    UA_LOCK_ASSERT(&am->queueLock, 1);

    /* Get the session */
    UA_Session* session = getSessionById(server, &ar->sessionId);
    if(!session) {
        UA_String sessionId = UA_STRING_NULL;
        UA_NodeId_print(&ar->sessionId, &sessionId);
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Async Service: Session %.*s no longer exists",
                       (int)sessionId.length, sessionId.data);
        UA_String_clear(&sessionId);
        UA_AsyncManager_removeAsyncResponse(&server->asyncManager, ar);
        return;
    }

    /* Check the channel */
    UA_SecureChannel *channel = session->channel;
    if(!channel) {
        UA_LOG_WARNING_SESSION(server->config.logging, session,
                               "Async Service Response cannot be sent. "
                               "No SecureChannel for the session.");
        UA_AsyncManager_removeAsyncResponse(&server->asyncManager, ar);
        return;
    }

    /* Set the request handle */
    UA_ResponseHeader *responseHeader = (UA_ResponseHeader*)
        &ar->response.callResponse.responseHeader;
    responseHeader->requestHandle = ar->requestHandle;

    /* Send the Response */
    UA_StatusCode res =
        sendResponse(server, channel, ar->requestId,
                     (UA_Response*)&ar->response, &UA_TYPES[UA_TYPES_CALLRESPONSE]);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_SESSION(server->config.logging, session,
                               "Async Response for Req# %" PRIu32 " failed "
                               "with StatusCode %s", ar->requestId,
                               UA_StatusCode_name(res));
    }
    UA_AsyncManager_removeAsyncResponse(&server->asyncManager, ar);
}

/* Integrate operation result in the AsyncResponse and send out the response if
 * it is ready. */
static UA_Boolean
integrateOperationResult(UA_AsyncManager *am, UA_Server *server,
                         UA_AsyncOperation *ao) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    UA_LOCK_ASSERT(&am->queueLock, 1);

    /* Grab the open request, so we can continue to construct the response */
    UA_AsyncResponse *ar = ao->parent;

    /* Reduce the number of open results */
    ar->opCountdown -= 1;

    UA_LOG_DEBUG(server->config.logging, UA_LOGCATEGORY_SERVER,
                 "Return result in the server thread with %" PRIu32 " remaining",
                 ar->opCountdown);

    /* Move the UA_CallMethodResult to UA_CallResponse */
    ar->response.callResponse.results[ao->index] = ao->response;
    UA_CallMethodResult_init(&ao->response);

    /* Done with all operations -> send the response */
    UA_Boolean done = (ar->opCountdown == 0);
    if(done)
        UA_AsyncManager_sendAsyncResponse(am, server, ar);
    return done;
}

/* Process all operations in the result queue -> move content over to the
 * AsyncResponse. This is only done by the server thread. Returns the nmber of
 * completed async sesponses. */
static UA_UInt32
processAsyncResults(UA_Server *server) {
    UA_AsyncManager *am = &server->asyncManager;
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    UA_LOCK_ASSERT(&am->queueLock, 0);

    UA_UInt32 count = 0;
    UA_AsyncOperation *ao;
    UA_LOCK(&am->queueLock);
    while((ao = TAILQ_FIRST(&am->resultQueue))) {
        TAILQ_REMOVE(&am->resultQueue, ao, pointers);
        if(integrateOperationResult(am, server, ao))
            count++;
        UA_AsyncOperation_delete(ao);
        /* Pacify clang-analyzer */
        UA_assert(TAILQ_FIRST(&am->resultQueue) != ao);
        am->opsCount--;
    }
    UA_UNLOCK(&am->queueLock);
    return count;
}

/* Check if any operations have timed out */
static void
checkTimeouts(UA_Server *server, void *_) {
    /* Timeouts are not configured */
    if(server->config.asyncOperationTimeout <= 0.0)
        return;

    UA_EventLoop *el = server->config.eventLoop;
    UA_AsyncManager *am = &server->asyncManager;
    const UA_DateTime tNow = el->dateTime_nowMonotonic(el);

    UA_LOCK(&am->queueLock);

    /* Loop over the queue of dispatched ops */
    UA_AsyncOperation *op = NULL, *op_tmp = NULL;
    TAILQ_FOREACH_SAFE(op, &am->dispatchedQueue, pointers, op_tmp) {
        /* The timeout has not passed. Also for all elements following in the queue. */
        if(tNow <= op->parent->timeout)
            break;

        /* Mark as timed out and put it into the result queue */
        op->response.statusCode = UA_STATUSCODE_BADTIMEOUT;
        TAILQ_REMOVE(&am->dispatchedQueue, op, pointers);
        TAILQ_INSERT_TAIL(&am->resultQueue, op, pointers);
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Operation was removed due to a timeout");
    }

    /* Loop over the queue of new ops */
    TAILQ_FOREACH_SAFE(op, &am->newQueue, pointers, op_tmp) {
        /* The timeout has not passed. Also for all elements following in the queue. */
        if(tNow <= op->parent->timeout)
            break;

        /* Mark as timed out and put it into the result queue */
        op->response.statusCode = UA_STATUSCODE_BADTIMEOUT;
        TAILQ_REMOVE(&am->newQueue, op, pointers);
        TAILQ_INSERT_TAIL(&am->resultQueue, op, pointers);
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Operation was removed due to a timeout");
    }

    UA_UNLOCK(&am->queueLock);

    /* Integrate async results and send out complete responses */
    UA_LOCK(&server->serviceMutex);
    processAsyncResults(server);
    UA_UNLOCK(&server->serviceMutex);
}

void
UA_AsyncManager_init(UA_AsyncManager *am, UA_Server *server) {
    memset(am, 0, sizeof(UA_AsyncManager));
    TAILQ_INIT(&am->asyncResponses);
    TAILQ_INIT(&am->newQueue);
    TAILQ_INIT(&am->dispatchedQueue);
    TAILQ_INIT(&am->resultQueue);
    UA_LOCK_INIT(&am->queueLock);
}

void UA_AsyncManager_start(UA_AsyncManager *am, UA_Server *server) {
    /* Add a regular callback for checking timeouts and sending finished
     * responses at a 100ms interval. */
    addRepeatedCallback(server, (UA_ServerCallback)checkTimeouts,
                        NULL, 100.0, &am->checkTimeoutCallbackId);
}

void UA_AsyncManager_stop(UA_AsyncManager *am, UA_Server *server) {
    /* Add a regular callback for checking timeouts and sending finished
     * responses at a 100ms interval. */
    removeCallback(server, am->checkTimeoutCallbackId);
}

void
UA_AsyncManager_clear(UA_AsyncManager *am, UA_Server *server) {
    UA_AsyncOperation *ar, *ar_tmp;

    /* Clean up queues */
    UA_LOCK(&am->queueLock);
    TAILQ_FOREACH_SAFE(ar, &am->newQueue, pointers, ar_tmp) {
        TAILQ_REMOVE(&am->newQueue, ar, pointers);
        UA_AsyncOperation_delete(ar);
    }
    TAILQ_FOREACH_SAFE(ar, &am->dispatchedQueue, pointers, ar_tmp) {
        TAILQ_REMOVE(&am->dispatchedQueue, ar, pointers);
        UA_AsyncOperation_delete(ar);
    }
    TAILQ_FOREACH_SAFE(ar, &am->resultQueue, pointers, ar_tmp) {
        TAILQ_REMOVE(&am->resultQueue, ar, pointers);
        UA_AsyncOperation_delete(ar);
    }
    UA_UNLOCK(&am->queueLock);

    /* Remove responses */
    UA_AsyncResponse *current, *temp;
    TAILQ_FOREACH_SAFE(current, &am->asyncResponses, pointers, temp) {
        UA_AsyncManager_removeAsyncResponse(am, current);
    }

    /* Delete all locks */
    UA_LOCK_DESTROY(&am->queueLock);
}

UA_StatusCode
UA_AsyncManager_createAsyncResponse(UA_AsyncManager *am, UA_Server *server,
                                    const UA_NodeId *sessionId,
                                    const UA_UInt32 requestId, const UA_UInt32 requestHandle,
                                    const UA_AsyncOperationType operationType,
                                    UA_AsyncResponse **outAr) {
    UA_AsyncResponse *newentry = (UA_AsyncResponse*)UA_calloc(1, sizeof(UA_AsyncResponse));
    if(!newentry)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode res = UA_NodeId_copy(sessionId, &newentry->sessionId);
    if(res != UA_STATUSCODE_GOOD) {
        UA_free(newentry);
        return res;
    }

    UA_EventLoop *el = server->config.eventLoop;

    am->asyncResponsesCount += 1;
    newentry->requestId = requestId;
    newentry->requestHandle = requestHandle;
    newentry->timeout = el->dateTime_nowMonotonic(el);
    if(server->config.asyncOperationTimeout > 0.0)
        newentry->timeout += (UA_DateTime)
            (server->config.asyncOperationTimeout * (UA_DateTime)UA_DATETIME_MSEC);
    TAILQ_INSERT_TAIL(&am->asyncResponses, newentry, pointers);

    *outAr = newentry;
    return UA_STATUSCODE_GOOD;
}

/* Remove entry and free all allocated data */
void
UA_AsyncManager_removeAsyncResponse(UA_AsyncManager *am, UA_AsyncResponse *ar) {
    TAILQ_REMOVE(&am->asyncResponses, ar, pointers);
    am->asyncResponsesCount -= 1;
    UA_CallResponse_clear(&ar->response.callResponse);
    UA_NodeId_clear(&ar->sessionId);
    UA_free(ar);
}

/* Enqueue next MethodRequest */
UA_StatusCode
UA_AsyncManager_createAsyncOp(UA_AsyncManager *am, UA_Server *server,
                              UA_AsyncResponse *ar, size_t opIndex,
                              const UA_CallMethodRequest *opRequest) {
    if(server->config.maxAsyncOperationQueueSize != 0 &&
       am->opsCount >= server->config.maxAsyncOperationQueueSize) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "UA_Server_SetNextAsyncMethod: Queue exceeds limit (%d).",
                       (int unsigned)server->config.maxAsyncOperationQueueSize);
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    }

    UA_AsyncOperation *ao = (UA_AsyncOperation*)UA_calloc(1, sizeof(UA_AsyncOperation));
    if(!ao) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "UA_Server_SetNextAsyncMethod: Mem alloc failed.");
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    UA_StatusCode result = UA_CallMethodRequest_copy(opRequest, &ao->request);
    if(result != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "UA_Server_SetAsyncMethodResult: UA_CallMethodRequest_copy failed.");
        UA_free(ao);
        return result;
    }

    UA_CallMethodResult_init(&ao->response);
    ao->index = opIndex;
    ao->parent = ar;

    UA_LOCK(&am->queueLock);
    TAILQ_INSERT_TAIL(&am->newQueue, ao, pointers);
    am->opsCount++;
    ar->opCountdown++;
    UA_UNLOCK(&am->queueLock);

    if(server->config.asyncOperationNotifyCallback)
        server->config.asyncOperationNotifyCallback(server);

    return UA_STATUSCODE_GOOD;
}

/* Get and remove next Method Call Request */
UA_Boolean
UA_Server_getAsyncOperationNonBlocking(UA_Server *server, UA_AsyncOperationType *type,
                                       const UA_AsyncOperationRequest **request,
                                       void **context, UA_DateTime *timeout) {
    UA_AsyncManager *am = &server->asyncManager;

    UA_Boolean bRV = false;
    *type = UA_ASYNCOPERATIONTYPE_INVALID;
    UA_LOCK(&am->queueLock);
    UA_AsyncOperation *ao = TAILQ_FIRST(&am->newQueue);
    if(ao) {
        TAILQ_REMOVE(&am->newQueue, ao, pointers);
        TAILQ_INSERT_TAIL(&am->dispatchedQueue, ao, pointers);
        *type = UA_ASYNCOPERATIONTYPE_CALL;
        *request = (UA_AsyncOperationRequest*)&ao->request;
        *context = (void*)ao;
        if(timeout)
            *timeout = ao->parent->timeout;
        bRV = true;
    }
    UA_UNLOCK(&am->queueLock);

    return bRV;
}

/* Worker submits Method Call Response */
void
UA_Server_setAsyncOperationResult(UA_Server *server,
                                  const UA_AsyncOperationResponse *response,
                                  void *context) {
    UA_AsyncManager *am = &server->asyncManager;

    UA_AsyncOperation *ao = (UA_AsyncOperation*)context;
    if(!ao) {
        /* Something went wrong. Not a good AsyncOp. */
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "UA_Server_SetAsyncMethodResult: Invalid context");
        return;
    }

    UA_LOCK(&am->queueLock);

    /* See if the operation is still in the dispatched queue. Otherwise it has
     * been removed due to a timeout.
     *
     * TODO: Add a tree-structure for the dispatch queue. The linear lookup does
     * not scale. */
    UA_AsyncOperation *op = NULL;
    TAILQ_FOREACH(op, &am->dispatchedQueue, pointers) {
        if(op == ao)
            break;
    }
    if(!op) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "UA_Server_SetAsyncMethodResult: The operation has timed out");
        UA_UNLOCK(&am->queueLock);
        return;
    }

    /* Copy the result into the internal AsyncOperation */
    UA_StatusCode result =
        UA_CallMethodResult_copy(&response->callMethodResult, &ao->response);
    if(result != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "UA_Server_SetAsyncMethodResult: UA_CallMethodResult_copy failed.");
        ao->response.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
    }

    /* Move to the result queue */
    TAILQ_REMOVE(&am->dispatchedQueue, ao, pointers);
    TAILQ_INSERT_TAIL(&am->resultQueue, ao, pointers);

    UA_UNLOCK(&am->queueLock);

    UA_LOG_DEBUG(server->config.logging, UA_LOGCATEGORY_SERVER,
                 "Set the result from the worker thread");
}

/******************/
/* Server Methods */
/******************/

static UA_StatusCode
setMethodNodeAsync(UA_Server *server, UA_Session *session,
                   UA_Node *node, UA_Boolean *isAsync) {
    if(node->head.nodeClass != UA_NODECLASS_METHOD)
        return UA_STATUSCODE_BADNODECLASSINVALID;
    node->methodNode.async = *isAsync;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_setMethodNodeAsync(UA_Server *server, const UA_NodeId id,
                             UA_Boolean isAsync) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res =
        UA_Server_editNode(server, &server->adminSession, &id,
                           (UA_EditNodeCallback)setMethodNodeAsync, &isAsync);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_Server_processServiceOperationsAsync(UA_Server *server, UA_Session *session,
                                        UA_UInt32 requestId, UA_UInt32 requestHandle,
                                        UA_AsyncServiceOperation operationCallback,
                                        const size_t *requestOperations,
                                        const UA_DataType *requestOperationsType,
                                        size_t *responseOperations,
                                        const UA_DataType *responseOperationsType,
                                        UA_AsyncResponse **ar) {
    size_t ops = *requestOperations;
    if(ops == 0)
        return UA_STATUSCODE_BADNOTHINGTODO;

    /* Allocate the response array. No padding after size_t */
    void **respPos = (void**)((uintptr_t)responseOperations + sizeof(size_t));
    *respPos = UA_Array_new(ops, responseOperationsType);
    if(!*respPos)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    *responseOperations = ops;

    /* Finish / dispatch the operations. This may allocate a new AsyncResponse internally */
    uintptr_t respOp = (uintptr_t)*respPos;
    uintptr_t reqOp = *(uintptr_t*)((uintptr_t)requestOperations + sizeof(size_t));
    for(size_t i = 0; i < ops; i++) {
        operationCallback(server, session, requestId, requestHandle,
                          i, (void*)reqOp, (void*)respOp, ar);
        reqOp += requestOperationsType->memSize;
        respOp += responseOperationsType->memSize;
    }

    return UA_STATUSCODE_GOOD;
}

UA_UInt32
UA_AsyncManager_cancel(UA_Server *server, UA_Session *session, UA_UInt32 requestHandle) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    UA_AsyncManager *am = &server->asyncManager;

    UA_LOCK(&am->queueLock);

    /* Loop over the queue of dispatched ops */
    UA_AsyncOperation *op = NULL, *op_tmp = NULL;
    TAILQ_FOREACH_SAFE(op, &am->dispatchedQueue, pointers, op_tmp) {
        if(op->parent->requestHandle != requestHandle ||
           !UA_NodeId_equal(&session->sessionId, &op->parent->sessionId))
            continue;

        /* Set status and put it into the result queue */
        op->response.statusCode = UA_STATUSCODE_BADREQUESTCANCELLEDBYCLIENT;
        TAILQ_REMOVE(&am->dispatchedQueue, op, pointers);
        TAILQ_INSERT_TAIL(&am->resultQueue, op, pointers);

        /* Also set the status of the overall response */
        op->parent->response.callResponse.responseHeader.
            serviceResult = UA_STATUSCODE_BADREQUESTCANCELLEDBYCLIENT;
    }

    /* Idem for waiting ops */
    TAILQ_FOREACH_SAFE(op, &am->newQueue, pointers, op_tmp) {
        if(op->parent->requestHandle != requestHandle ||
           !UA_NodeId_equal(&session->sessionId, &op->parent->sessionId))
            continue;

        /* Mark as timed out and put it into the result queue */
        op->response.statusCode = UA_STATUSCODE_BADREQUESTCANCELLEDBYCLIENT;
        TAILQ_REMOVE(&am->newQueue, op, pointers);
        TAILQ_INSERT_TAIL(&am->resultQueue, op, pointers);

        op->parent->response.callResponse.responseHeader.
            serviceResult = UA_STATUSCODE_BADREQUESTCANCELLEDBYCLIENT;
    }

    UA_UNLOCK(&am->queueLock);

    /* Process messages that have all ops completed */
    return processAsyncResults(server);
}

#endif

/**** amalgamated original file "/src/server/ua_services.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2024 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014-2016 (c) Sten Grüner
 *    Copyright 2014-2015, 2017 (c) Florian Palm
 *    Copyright 2015-2016 (c) Chris Iatrou
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2016 (c) Joakim L. Gilje
 *    Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2016 (c) TorbenD
 *    Copyright 2017 (c) frax2222
 *    Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2019 (c) Kalycito Infotech Private Limited
 *    Copyright 2023 (c) Hilscher Gesellschaft für Systemautomation mbH (Author: Phuong Nguyen)
 */

/* This file contains the service invocation logic that is called from all
 * communication backends */


#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
/* store the authentication token and session ID so we can help fuzzing by
 * setting these values in the next request automatically */
UA_NodeId unsafe_fuzz_authenticationToken = {0, UA_NODEIDTYPE_NUMERIC, {0}};
#endif

/* The counterOffset is the offset of the UA_ServiceCounterDataType for the
 * service in the UA_ SessionDiagnosticsDataType. */
#ifdef UA_ENABLE_DIAGNOSTICS
# define UA_SERVICECOUNTER_OFFSET_NONE(requiresSession) 0, requiresSession
# define UA_SERVICECOUNTER_OFFSET(X, requiresSession) \
    offsetof(UA_SessionDiagnosticsDataType, X), requiresSession
#else
# define UA_SERVICECOUNTER_OFFSET_NONE(requiresSession) requiresSession
# define UA_SERVICECOUNTER_OFFSET(X, requiresSession) requiresSession
#endif

UA_ServiceDescription serviceDescriptions[] = {
    {UA_NS0ID_GETENDPOINTSREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET_NONE(false), (UA_Service)Service_GetEndpoints,
     &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST], &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE]},
    {UA_NS0ID_FINDSERVERSREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET_NONE(false), (UA_Service)Service_FindServers,
     &UA_TYPES[UA_TYPES_FINDSERVERSREQUEST], &UA_TYPES[UA_TYPES_FINDSERVERSRESPONSE]},
#ifdef UA_ENABLE_DISCOVERY
    {UA_NS0ID_REGISTERSERVERREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET_NONE(false), (UA_Service)Service_RegisterServer,
     &UA_TYPES[UA_TYPES_REGISTERSERVERREQUEST], &UA_TYPES[UA_TYPES_REGISTERSERVERRESPONSE]},
    {UA_NS0ID_REGISTERSERVER2REQUEST_ENCODING_DEFAULTBINARY,
    UA_SERVICECOUNTER_OFFSET_NONE(false), (UA_Service)Service_RegisterServer2,
    &UA_TYPES[UA_TYPES_REGISTERSERVER2REQUEST], &UA_TYPES[UA_TYPES_REGISTERSERVER2RESPONSE]},
# ifdef UA_ENABLE_DISCOVERY_MULTICAST
    {UA_NS0ID_FINDSERVERSONNETWORKREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET_NONE(false), (UA_Service)Service_FindServersOnNetwork,
     &UA_TYPES[UA_TYPES_FINDSERVERSONNETWORKREQUEST], &UA_TYPES[UA_TYPES_FINDSERVERSONNETWORKRESPONSE]},
# endif
#endif
    {UA_NS0ID_CREATESESSIONREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET_NONE(false), (UA_Service)Service_CreateSession,
     &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST], &UA_TYPES[UA_TYPES_CREATESESSIONRESPONSE]},
    {UA_NS0ID_ACTIVATESESSIONREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET_NONE(false), (UA_Service)Service_ActivateSession,
     &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST],  &UA_TYPES[UA_TYPES_ACTIVATESESSIONRESPONSE]},
    {UA_NS0ID_CLOSESESSIONREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET_NONE(true), (UA_Service)Service_CloseSession,
     &UA_TYPES[UA_TYPES_CLOSESESSIONREQUEST], &UA_TYPES[UA_TYPES_CLOSESESSIONRESPONSE]},
    {UA_NS0ID_CANCELREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET_NONE(true), (UA_Service)Service_Cancel,
     &UA_TYPES[UA_TYPES_CANCELREQUEST], &UA_TYPES[UA_TYPES_CANCELRESPONSE]},
    {UA_NS0ID_READREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(readCount, true), (UA_Service)Service_Read,
     &UA_TYPES[UA_TYPES_READREQUEST], &UA_TYPES[UA_TYPES_READRESPONSE]},
    {UA_NS0ID_WRITEREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(writeCount, true), (UA_Service)Service_Write,
     &UA_TYPES[UA_TYPES_WRITEREQUEST], &UA_TYPES[UA_TYPES_WRITERESPONSE]},
    {UA_NS0ID_BROWSEREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(browseCount, true), (UA_Service)Service_Browse,
     &UA_TYPES[UA_TYPES_BROWSEREQUEST], &UA_TYPES[UA_TYPES_BROWSERESPONSE]},
    {UA_NS0ID_BROWSENEXTREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(browseNextCount, true), (UA_Service)Service_BrowseNext,
     &UA_TYPES[UA_TYPES_BROWSENEXTREQUEST], &UA_TYPES[UA_TYPES_BROWSENEXTRESPONSE]},
    {UA_NS0ID_REGISTERNODESREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(registerNodesCount, true), (UA_Service)Service_RegisterNodes,
     &UA_TYPES[UA_TYPES_REGISTERNODESREQUEST], &UA_TYPES[UA_TYPES_REGISTERNODESRESPONSE]},
    {UA_NS0ID_UNREGISTERNODESREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(unregisterNodesCount, true), (UA_Service)Service_UnregisterNodes,
     &UA_TYPES[UA_TYPES_UNREGISTERNODESREQUEST], &UA_TYPES[UA_TYPES_UNREGISTERNODESRESPONSE]},
    {UA_NS0ID_TRANSLATEBROWSEPATHSTONODEIDSREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(translateBrowsePathsToNodeIdsCount, true), (UA_Service)Service_TranslateBrowsePathsToNodeIds,
     &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSREQUEST], &UA_TYPES[UA_TYPES_TRANSLATEBROWSEPATHSTONODEIDSRESPONSE]},
#ifdef UA_ENABLE_SUBSCRIPTIONS
    {UA_NS0ID_CREATESUBSCRIPTIONREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(createSubscriptionCount, true), (UA_Service)Service_CreateSubscription,
     &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONREQUEST], &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONRESPONSE]},
    {UA_NS0ID_PUBLISHREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(publishCount, true), NULL,
     &UA_TYPES[UA_TYPES_PUBLISHREQUEST], &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]},
    {UA_NS0ID_REPUBLISHREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(republishCount, true), (UA_Service)Service_Republish,
     &UA_TYPES[UA_TYPES_REPUBLISHREQUEST], &UA_TYPES[UA_TYPES_REPUBLISHRESPONSE]},
    {UA_NS0ID_MODIFYSUBSCRIPTIONREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(modifySubscriptionCount, true), (UA_Service)Service_ModifySubscription,
     &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONREQUEST], &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONRESPONSE]},
    {UA_NS0ID_SETPUBLISHINGMODEREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(setPublishingModeCount, true), (UA_Service)Service_SetPublishingMode,
     &UA_TYPES[UA_TYPES_SETPUBLISHINGMODEREQUEST], &UA_TYPES[UA_TYPES_SETPUBLISHINGMODERESPONSE]},
    {UA_NS0ID_DELETESUBSCRIPTIONSREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(deleteSubscriptionsCount, true), (UA_Service)Service_DeleteSubscriptions,
     &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSREQUEST], &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSRESPONSE]},
    {UA_NS0ID_TRANSFERSUBSCRIPTIONSREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(transferSubscriptionsCount, true), (UA_Service)Service_TransferSubscriptions,
     &UA_TYPES[UA_TYPES_TRANSFERSUBSCRIPTIONSREQUEST], &UA_TYPES[UA_TYPES_TRANSFERSUBSCRIPTIONSRESPONSE]},
    {UA_NS0ID_CREATEMONITOREDITEMSREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(createMonitoredItemsCount, true), (UA_Service)Service_CreateMonitoredItems,
     &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSREQUEST], &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSRESPONSE]},
    {UA_NS0ID_DELETEMONITOREDITEMSREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(deleteMonitoredItemsCount, true), (UA_Service)Service_DeleteMonitoredItems,
     &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSREQUEST], &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSRESPONSE]},
    {UA_NS0ID_MODIFYMONITOREDITEMSREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(modifyMonitoredItemsCount, true), (UA_Service)Service_ModifyMonitoredItems,
     &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSREQUEST], &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSRESPONSE]},
    {UA_NS0ID_SETMONITORINGMODEREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(setMonitoringModeCount, true), (UA_Service)Service_SetMonitoringMode,
     &UA_TYPES[UA_TYPES_SETMONITORINGMODEREQUEST], &UA_TYPES[UA_TYPES_SETMONITORINGMODERESPONSE]},
    {UA_NS0ID_SETTRIGGERINGREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(setTriggeringCount, true), (UA_Service)Service_SetTriggering,
     &UA_TYPES[UA_TYPES_SETTRIGGERINGREQUEST], &UA_TYPES[UA_TYPES_SETTRIGGERINGRESPONSE]},
#endif
#ifdef UA_ENABLE_HISTORIZING
    {UA_NS0ID_HISTORYREADREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(historyReadCount, true), (UA_Service)Service_HistoryRead,
     &UA_TYPES[UA_TYPES_HISTORYREADREQUEST], &UA_TYPES[UA_TYPES_HISTORYREADRESPONSE]},
    {UA_NS0ID_HISTORYUPDATEREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(historyUpdateCount, true), (UA_Service)Service_HistoryUpdate,
     &UA_TYPES[UA_TYPES_HISTORYUPDATEREQUEST], &UA_TYPES[UA_TYPES_HISTORYUPDATERESPONSE]},
#endif
#ifdef UA_ENABLE_METHODCALLS
    {UA_NS0ID_CALLREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(callCount, true), (UA_Service)Service_Call,
     &UA_TYPES[UA_TYPES_CALLREQUEST], &UA_TYPES[UA_TYPES_CALLRESPONSE]},
#endif
#ifdef UA_ENABLE_NODEMANAGEMENT
    {UA_NS0ID_ADDNODESREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(addNodesCount, true), (UA_Service)Service_AddNodes,
     &UA_TYPES[UA_TYPES_ADDNODESREQUEST], &UA_TYPES[UA_TYPES_ADDNODESRESPONSE]},
    {UA_NS0ID_ADDREFERENCESREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(addReferencesCount, true), (UA_Service)Service_AddReferences,
     &UA_TYPES[UA_TYPES_ADDREFERENCESREQUEST], &UA_TYPES[UA_TYPES_ADDREFERENCESRESPONSE]},
    {UA_NS0ID_DELETENODESREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(deleteNodesCount, true), (UA_Service)Service_DeleteNodes,
     &UA_TYPES[UA_TYPES_DELETENODESREQUEST], &UA_TYPES[UA_TYPES_DELETENODESRESPONSE]},
    {UA_NS0ID_DELETEREFERENCESREQUEST_ENCODING_DEFAULTBINARY,
     UA_SERVICECOUNTER_OFFSET(deleteReferencesCount, true), (UA_Service)Service_DeleteReferences,
     &UA_TYPES[UA_TYPES_DELETEREFERENCESREQUEST], &UA_TYPES[UA_TYPES_DELETEREFERENCESRESPONSE]},
#endif
    {0, UA_SERVICECOUNTER_OFFSET_NONE(false), NULL, NULL, NULL}
};

UA_ServiceDescription *
getServiceDescription(UA_UInt32 requestTypeId) {
    for(size_t i = 0; serviceDescriptions[i].requestTypeId > 0; i++) {
        if(serviceDescriptions[i].requestTypeId == requestTypeId)
            return &serviceDescriptions[i];
    }
    return NULL;
}

static const UA_String securityPolicyNone =
    UA_STRING_STATIC("http://opcfoundation.org/UA/SecurityPolicy#None");

static UA_Boolean
processServiceInternal(UA_Server *server, UA_SecureChannel *channel, UA_Session *session,
                       UA_UInt32 requestId, UA_ServiceDescription *sd,
                       const UA_Request *request, UA_Response *response) {
    UA_ResponseHeader *rh = &response->responseHeader;

    /* Check timestamp in the request header */
    if(request->requestHeader.timestamp == 0 &&
       server->config.verifyRequestTimestamp <= UA_RULEHANDLING_WARN) {
        UA_LOG_WARNING_CHANNEL(server->config.logging, channel,
                               "The server sends no timestamp in the request header. "
                               "See the 'verifyRequestTimestamp' setting.");
        if(server->config.verifyRequestTimestamp <= UA_RULEHANDLING_ABORT) {
            rh->serviceResult = UA_STATUSCODE_BADINVALIDTIMESTAMP;
            return false;
        }
    }

    /* If it is an unencrypted (#None) channel, only allow the discovery services */
    if(server->config.securityPolicyNoneDiscoveryOnly &&
       UA_String_equal(&channel->securityPolicy->policyUri, &securityPolicyNone ) &&
       sd->requestType != &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST] &&
       sd->requestType != &UA_TYPES[UA_TYPES_FINDSERVERSREQUEST]
#if defined(UA_ENABLE_DISCOVERY) && defined(UA_ENABLE_DISCOVERY_MULTICAST)
       && sd->requestType != &UA_TYPES[UA_TYPES_FINDSERVERSONNETWORKREQUEST]
#endif
       ) {
        rh->serviceResult = UA_STATUSCODE_BADSECURITYPOLICYREJECTED;
        return false;
    }

    /* Session lifecycle services */
    if(sd->requestType == &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST] ||
       sd->requestType == &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST] ||
       sd->requestType == &UA_TYPES[UA_TYPES_CLOSESESSIONREQUEST]) {
        ((UA_ChannelService)sd->serviceCallback)(server, channel, request, response);
        /* Store the authentication token created during CreateSession to help
         * fuzzing cover more lines */
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
        if(sd->requestType == &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST]) {
            UA_CreateSessionResponse *res = &response->createSessionResponse;
            UA_NodeId_clear(&unsafe_fuzz_authenticationToken);
            UA_NodeId_copy(&res->authenticationToken, &unsafe_fuzz_authenticationToken);
        }
#endif
        return false;
    }

    /* Set an anonymous, inactive session for services that need no session */
    UA_Session anonymousSession;
    if(!session) {
        UA_assert(!sd->sessionRequired);
        UA_Session_init(&anonymousSession);
        anonymousSession.sessionId = UA_NODEID_GUID(0, UA_GUID_NULL);
        anonymousSession.channel = channel;
        session = &anonymousSession;
    }

    /* Trying to use a non-activated session? */
    if(sd->sessionRequired && !session->activated) {
        UA_assert(session != &anonymousSession); /* because sd->sessionRequired */
#ifdef UA_ENABLE_TYPEDESCRIPTION
        UA_LOG_WARNING_SESSION(server->config.logging, session,
                               "%s refused on a non-activated session",
                               sd->requestType->typeName);
#else
        UA_LOG_WARNING_SESSION(server->config.logging, session,
                               "Service %" PRIu32 " refused on a non-activated session",
                               sd->requestType->binaryEncodingId.identifier.numeric);
#endif
        UA_Server_removeSessionByToken(server, &session->authenticationToken,
                                       UA_SHUTDOWNREASON_ABORT);
        rh->serviceResult = UA_STATUSCODE_BADSESSIONNOTACTIVATED;
        return false;
    }

    /* Update the session lifetime */
    UA_EventLoop *el = server->config.eventLoop;
    UA_DateTime nowMonotonic = el->dateTime_nowMonotonic(el);
    UA_DateTime now = el->dateTime_now(el);
    UA_Session_updateLifetime(session, now, nowMonotonic);

    /* The publish request is not answered immediately */
#ifdef UA_ENABLE_SUBSCRIPTIONS
    if(sd->requestType == &UA_TYPES[UA_TYPES_PUBLISHREQUEST]) {
        rh->serviceResult = Service_Publish(server, session, &request->publishRequest, requestId);
        return (rh->serviceResult == UA_STATUSCODE_GOOD);
    }
#endif

    /* An async call request might not be answered immediately */
#if UA_MULTITHREADING >= 100 && defined(UA_ENABLE_METHODCALLS)
    if(sd->requestType == &UA_TYPES[UA_TYPES_CALLREQUEST]) {
        UA_Boolean finished = true;
        Service_CallAsync(server, session, requestId, &request->callRequest,
                          &response->callResponse, &finished);
        return !finished;
    }
#endif

    /* Execute the synchronous service call */
    sd->serviceCallback(server, session, request, response);
    return false;
}

UA_Boolean
UA_Server_processRequest(UA_Server *server, UA_SecureChannel *channel,
                         UA_UInt32 requestId, UA_ServiceDescription *sd,
                         const UA_Request *request, UA_Response *response) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Set the authenticationToken from the create session request to help
     * fuzzing cover more lines */
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
    UA_NodeId *authenticationToken = &request->requestHeader.authenticationToken;
    if(!UA_NodeId_isNull(authenticationToken) &&
       !UA_NodeId_isNull(&unsafe_fuzz_authenticationToken)) {
        UA_NodeId_clear(authenticationToken);
        UA_NodeId_copy(&unsafe_fuzz_authenticationToken, authenticationToken);
    }
#endif

    /* Get the session bound to the SecureChannel (not necessarily activated) */
    UA_Session *session = NULL;
    response->responseHeader.serviceResult =
        getBoundSession(server, channel, &request->requestHeader.authenticationToken, &session);
    if(!session && sd->sessionRequired)
        return false;

    /* The session can be NULL if not required */
    response->responseHeader.serviceResult = UA_STATUSCODE_GOOD;

    /* Process the service */
    UA_Boolean async =
        processServiceInternal(server, channel, session, requestId, sd, request, response);

    /* Update the service statistics */
#ifdef UA_ENABLE_DIAGNOSTICS
    if(session) {
        session->diagnostics.totalRequestCount.totalCount++;
        if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
            session->diagnostics.totalRequestCount.errorCount++;
        if(sd->counterOffset != 0) {
            UA_ServiceCounterDataType *serviceCounter = (UA_ServiceCounterDataType*)
                (((uintptr_t)&session->diagnostics) + sd->counterOffset);
            serviceCounter->totalCount++;
            if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
                serviceCounter->errorCount++;
        }
    }
#endif

    return async;
}

/**** amalgamated original file "/src/server/ua_services_view.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2019 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014-2017 (c) Florian Palm
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015 (c) LEvertz
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015 (c) Ecosmos
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2016 (c) Lorenz Haas
 *    Copyright 2017 (c) pschoppe
 *    Copyright 2017 (c) Julian Grothoff
 *    Copyright 2017 (c) Henrik Norrman
 */


#define UA_MAX_TREE_RECURSE 50 /* How deep up/down the tree do we recurse at most? */

static UA_UInt32
resultMask2AttributesMask(UA_UInt32 resultMask) {
    UA_UInt32 result = 0;
    if(resultMask & UA_BROWSERESULTMASK_NODECLASS)
        result |= UA_NODEATTRIBUTESMASK_NODECLASS;
    if(resultMask & UA_BROWSERESULTMASK_BROWSENAME)
        result |= UA_NODEATTRIBUTESMASK_BROWSENAME;
    if(resultMask & UA_BROWSERESULTMASK_DISPLAYNAME)
        result |= UA_NODEATTRIBUTESMASK_DISPLAYNAME;
    return result;
}

UA_StatusCode
referenceTypeIndices(UA_Server *server, const UA_NodeId *refType,
                     UA_ReferenceTypeSet *indices, UA_Boolean includeSubtypes) {
    if(UA_NodeId_isNull(refType)) {
        *indices = UA_REFERENCETYPESET_ALL;
        return UA_STATUSCODE_GOOD;
    }

    UA_ReferenceTypeSet_init(indices);

    /* Get the node with only the NodeClass attribute. If it is a
     * ReferenceTypeNode, then the indices are always included, as this is an
     * open62541 specific field (not selectable via the attribute id). */
    const UA_Node *refNode =
        UA_NODESTORE_GET_SELECTIVE(server, refType,
                                   UA_NODEATTRIBUTESMASK_NODECLASS,
                                   UA_REFERENCETYPESET_NONE,
                                   UA_BROWSEDIRECTION_INVALID);

    if(!refNode)
        return UA_STATUSCODE_BADREFERENCETYPEIDINVALID;

    if(refNode->head.nodeClass != UA_NODECLASS_REFERENCETYPE) {
        UA_NODESTORE_RELEASE(server, refNode);
        return UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
    }

    if(!includeSubtypes)
        *indices = UA_REFTYPESET(refNode->referenceTypeNode.referenceTypeIndex);
    else
        *indices = refNode->referenceTypeNode.subTypes;

    UA_NODESTORE_RELEASE(server, refNode);
    return UA_STATUSCODE_GOOD;
}

static UA_Boolean
matchClassMask(const UA_Node *node, UA_UInt32 nodeClassMask) {
    if(nodeClassMask != UA_NODECLASS_UNSPECIFIED &&
       (node->head.nodeClass & nodeClassMask) == 0)
        return false;
    return true;
}

/****************/
/* IsNodeInTree */
/****************/

/* Internal method to check if a node is already upwards from a leaf node */

static enum ZIP_CMP
cmpRefTarget(const void *a, const void *b) {
    const UA_ReferenceTarget *aa = (const UA_ReferenceTarget*)a;
    const UA_ReferenceTarget *bb = (const UA_ReferenceTarget*)b;
    return (enum ZIP_CMP)UA_NodePointer_order(aa->targetId, bb->targetId);
}

typedef ZIP_HEAD(UA_ParentRefsTree, UA_ReferenceTargetTreeElem) UA_ParentRefsTree;
ZIP_FUNCTIONS(UA_ParentRefsTree, UA_ReferenceTargetTreeElem, idTreeEntry,
              UA_NodePointer, target, cmpRefTarget)

struct IsNodeInTreeContext {
    UA_Server *server;
    UA_NodePointer nodeToFind;
    UA_ParentRefsTree parents;
    UA_ReferenceTypeSet relevantRefs;
    UA_UInt16 depth;
};

static void *
isNodeInTreeIterateCallback(void *context, UA_ReferenceTarget *t) {
    struct IsNodeInTreeContext *tc =
        (struct IsNodeInTreeContext*)context;

    /* Don't follow remote targets */
    if(!UA_NodePointer_isLocal(t->targetId))
        return NULL;

    /* Found the node? -> return non-NULL */
    if(UA_NodePointer_equal(tc->nodeToFind, t->targetId))
        return (void*)0x01;

    /* Prevent endless loop */
    if(ZIP_FIND(UA_ParentRefsTree, &tc->parents, &t->targetId))
        return NULL;

    /* Prevent pathological recursion depth */
    if(tc->depth >= UA_MAX_TREE_RECURSE)
        return NULL;

    /* Get the node without attributes (if the NodeStore supports it) and only
     * the relevant references in inverse direction */
    const UA_Node *node =
        UA_NODESTORE_GETFROMREF_SELECTIVE(tc->server, t->targetId,
                                          UA_NODEATTRIBUTESMASK_NONE,
                                          tc->relevantRefs,
                                          UA_BROWSEDIRECTION_INVERSE);
    if(!node)
        return NULL;

    /* Add current NodeId to parents tree */
    UA_ReferenceTargetTreeElem stackElem;
    stackElem.target = *t;
    ZIP_INSERT(UA_ParentRefsTree, &tc->parents, &stackElem);

    /* Recurse into appropriate references starting from this tree */
    tc->depth++;
    void *res = NULL;
    for(size_t i = 0; i < node->head.referencesSize && !res; i++) {
        UA_NodeReferenceKind *rk = &node->head.references[i];
        /* Search upwards in the tree */
        if(!rk->isInverse)
            continue;

        /* Consider only the indicated reference types */
        if(!UA_ReferenceTypeSet_contains(&tc->relevantRefs, rk->referenceTypeIndex))
            continue;

        res = UA_NodeReferenceKind_iterate(rk, isNodeInTreeIterateCallback, tc);
    }
    tc->depth--;

    /* Clean up */
    UA_NODESTORE_RELEASE(tc->server, node);
    ZIP_REMOVE(UA_ParentRefsTree, &tc->parents, &stackElem);
    return res;
}

UA_Boolean
isNodeInTree(UA_Server *server, const UA_NodeId *leafNode,
             const UA_NodeId *nodeToFind,
             const UA_ReferenceTypeSet *relevantRefs) {
    struct IsNodeInTreeContext ctx;
    memset(&ctx, 0, sizeof(struct IsNodeInTreeContext));
    ctx.server = server;
    ctx.nodeToFind = UA_NodePointer_fromNodeId(nodeToFind);
    ctx.relevantRefs = *relevantRefs;
    UA_ReferenceTarget tmpTarget;
    memset(&tmpTarget, 0, sizeof(UA_ReferenceTarget));
    tmpTarget.targetId = UA_NodePointer_fromNodeId(leafNode);
    return (isNodeInTreeIterateCallback(&ctx, &tmpTarget) != NULL);
}

UA_Boolean
isNodeInTree_singleRef(UA_Server *server, const UA_NodeId *leafNode,
                       const UA_NodeId *nodeToFind, const UA_Byte relevantRefTypeIndex) {
    UA_ReferenceTypeSet reftypes = UA_REFTYPESET(relevantRefTypeIndex);
    return isNodeInTree(server, leafNode, nodeToFind, &reftypes);
}

static enum ZIP_CMP
cmpTarget(const void *a, const void *b) {
    const RefEntry *aa = (const RefEntry*)a;
    const RefEntry *bb = (const RefEntry*)b;
    if(aa->targetHash < bb->targetHash)
        return ZIP_CMP_LESS;
    if(aa->targetHash > bb->targetHash)
        return ZIP_CMP_MORE;
    return (enum ZIP_CMP)UA_ExpandedNodeId_order(aa->target, bb->target);
}

ZIP_FUNCTIONS(RefHead, RefEntry, zipfields, RefEntry, zipfields, cmpTarget)

UA_StatusCode
RefTree_init(RefTree *rt) {
    rt->size = 0;
    rt->capacity = 0;
    ZIP_INIT(&rt->head);
    size_t space = (sizeof(UA_ExpandedNodeId) + sizeof(RefEntry)) * UA_REFTREE_INITIAL_SIZE;
    rt->targets = (UA_ExpandedNodeId*)UA_malloc(space);
    if(!rt->targets)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    rt->capacity = UA_REFTREE_INITIAL_SIZE;
    return UA_STATUSCODE_GOOD;
}

void
RefTree_clear(RefTree *rt) {
    for(size_t i = 0; i < rt->size; i++)
        UA_ExpandedNodeId_clear(&rt->targets[i]);
    if(rt->targets)
        UA_free(rt->targets);
}

/* Double the capacity of the reftree */
static UA_StatusCode UA_FUNC_ATTR_WARN_UNUSED_RESULT
RefTree_double(RefTree *rt) {
    size_t capacity = rt->capacity * 2;
    UA_assert(capacity > 0);
    size_t space = (sizeof(UA_ExpandedNodeId) + sizeof(RefEntry)) * capacity;
    UA_ExpandedNodeId *newTargets = (UA_ExpandedNodeId*)UA_realloc(rt->targets, space);
    if(!newTargets)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Move the entries to the new location  */
    RefEntry *reArray = (RefEntry*)
        ((uintptr_t)newTargets + (capacity * sizeof(UA_ExpandedNodeId)));
    RefEntry *oldReArray = (RefEntry*)
        ((uintptr_t)newTargets + (rt->capacity * sizeof(UA_ExpandedNodeId)));
    memmove(reArray, oldReArray, rt->size * sizeof(RefEntry));

    /* Reinsert all entries into the tree. The new pointer location has changed
     * their ziptree rank. */
    rt->head.root = NULL;
    for(size_t i = 0; i < rt->size; i++) {
        reArray[i].target = &newTargets[i];
        ZIP_INSERT(RefHead, &rt->head, &reArray[i]);
    }

    rt->capacity = capacity;
    rt->targets = newTargets;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
RefTree_add(RefTree *rt, UA_NodePointer target, UA_Boolean *duplicate) {
    UA_ExpandedNodeId en = UA_NodePointer_toExpandedNodeId(target);

    /* Is the target already in the tree? */
    RefEntry dummy;
    memset(&dummy, 0, sizeof(RefEntry));
    dummy.target = &en;
    dummy.targetHash = UA_ExpandedNodeId_hash(&en);
    if(ZIP_FIND(RefHead, &rt->head, &dummy)) {
        if(duplicate)
            *duplicate = true;
        return UA_STATUSCODE_GOOD;
    }

    UA_StatusCode s = UA_STATUSCODE_GOOD;
    if(rt->capacity <= rt->size) {
        s = RefTree_double(rt);
        if(s != UA_STATUSCODE_GOOD)
            return s;
    }
    s = UA_ExpandedNodeId_copy(&en, &rt->targets[rt->size]);
    if(s != UA_STATUSCODE_GOOD)
        return s;
    RefEntry *re = (RefEntry*)((uintptr_t)rt->targets +
                               (sizeof(UA_ExpandedNodeId) * rt->capacity) +
                               (sizeof(RefEntry) * rt->size));
    re->target = &rt->targets[rt->size];
    re->targetHash = dummy.targetHash;
    ZIP_INSERT(RefHead, &rt->head, re);
    rt->size++;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
RefTree_addNodeId(RefTree *rt, const UA_NodeId *target,
                  UA_Boolean *duplicate) {
    return RefTree_add(rt, UA_NodePointer_fromNodeId(target), duplicate);
}

UA_Boolean
RefTree_contains(RefTree *rt, const UA_ExpandedNodeId *target) {
    RefEntry dummy;
    dummy.target = target;
    dummy.targetHash = UA_ExpandedNodeId_hash(target);
    return !!ZIP_FIND(RefHead, &rt->head, &dummy);
}

UA_Boolean
RefTree_containsNodeId(RefTree *rt, const UA_NodeId *target) {
    UA_ExpandedNodeId en;
    en.nodeId = *target;
    en.namespaceUri = UA_STRING_NULL;
    en.serverIndex = 0;
    return RefTree_contains(rt, &en);
}

/********************/
/* Browse Recursive */
/********************/

struct BrowseRecursiveContext {
    UA_Server *server;
    RefTree *rt;
    UA_UInt16 depth;
    UA_BrowseDirection browseDirection;
    UA_ReferenceTypeSet refTypes;
    UA_UInt32 nodeClassMask;
    UA_StatusCode status;
    UA_Boolean includeStartNodes;
};

static void *
browseRecursiveCallback(void *context, UA_ReferenceTarget *t) {
    struct BrowseRecursiveContext *brc =
        (struct BrowseRecursiveContext*)context;

    /* Have we reached the max recursion depth? */
    if(brc->depth >= UA_MAX_TREE_RECURSE)
        return NULL;

    /* Is this a non-local reference? If yes include it in the returned set. */
    if(!UA_NodePointer_isLocal(t->targetId)) {
        brc->status = RefTree_add(brc->rt, t->targetId, NULL);
        return (brc->status == UA_STATUSCODE_GOOD) ? NULL : (void*)0x01;
    }

    /* We only look at the NodeClass attribute and a subset of the references.
     * Get a node with only these elements if the NodeStore supports that. */
    const UA_Node *node =
        UA_NODESTORE_GETFROMREF_SELECTIVE(brc->server, t->targetId,
                                          UA_NODEATTRIBUTESMASK_NODECLASS,
                                          brc->refTypes, brc->browseDirection);
    if(!node)
        return NULL;

    /* Add the current node if we don't want to skip it as a start node and it
     * matches the nodeClassMask filter Recurse into the children in any
     * case. */
    const UA_NodeHead *head = &node->head;
    if((brc->includeStartNodes || brc->depth > 0)  &&
       matchClassMask(node, brc->nodeClassMask)) {
        UA_Boolean duplicate = false;
        brc->status = RefTree_addNodeId(brc->rt, &head->nodeId, &duplicate);
        if(duplicate || brc->status != UA_STATUSCODE_GOOD)
            goto cleanup;
    }

    /* Recurse */
    brc->depth++;
    void *res = NULL;
    for(size_t i = 0; i < head->referencesSize && !res; i++) {
        UA_NodeReferenceKind *rk = &head->references[i];

        /* Reference in the right direction? */
        if(rk->isInverse && brc->browseDirection == UA_BROWSEDIRECTION_FORWARD)
            continue;
        if(!rk->isInverse && brc->browseDirection == UA_BROWSEDIRECTION_INVERSE)
            continue;

        /* Is the reference part of the hierarchy of references we look for? */
        if(!UA_ReferenceTypeSet_contains(&brc->refTypes, rk->referenceTypeIndex))
            continue;

        res = UA_NodeReferenceKind_iterate(rk, browseRecursiveCallback, brc);
    }
    brc->depth--;

 cleanup:
    UA_NODESTORE_RELEASE(brc->server, node);
    return (brc->status == UA_STATUSCODE_GOOD) ? NULL : (void*)0x01;
}

UA_StatusCode
browseRecursive(UA_Server *server, size_t startNodesSize, const UA_NodeId *startNodes,
                UA_BrowseDirection browseDirection, const UA_ReferenceTypeSet *refTypes,
                UA_UInt32 nodeClassMask, UA_Boolean includeStartNodes,
                size_t *resultsSize, UA_ExpandedNodeId **results) {
    RefTree rt;
    UA_StatusCode retval = RefTree_init(&rt);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    struct BrowseRecursiveContext brc;
    brc.server = server;
    brc.rt = &rt;
    brc.depth = 0;
    brc.refTypes = *refTypes;
    brc.nodeClassMask = nodeClassMask;
    brc.status = UA_STATUSCODE_GOOD;
    brc.includeStartNodes = includeStartNodes;

    for(size_t i = 0; i < startNodesSize && brc.status == UA_STATUSCODE_GOOD; i++) {
        UA_ReferenceTarget target;
        target.targetId = UA_NodePointer_fromNodeId(&startNodes[i]);

        /* Call the inner recursive browse separately for the search direction.
         * Otherwise we might take one step up and another step down in the
         * search tree. */
        if(browseDirection == UA_BROWSEDIRECTION_FORWARD ||
           browseDirection == UA_BROWSEDIRECTION_BOTH) {
            brc.browseDirection = UA_BROWSEDIRECTION_FORWARD;
            browseRecursiveCallback(&brc, &target);
        }

        if(browseDirection == UA_BROWSEDIRECTION_INVERSE ||
           browseDirection == UA_BROWSEDIRECTION_BOTH) {
            brc.browseDirection = UA_BROWSEDIRECTION_INVERSE;
            browseRecursiveCallback(&brc, &target);
        }
    }

    if(rt.size > 0 && brc.status == UA_STATUSCODE_GOOD) {
        *results = rt.targets;
        *resultsSize = rt.size;
    } else {
        RefTree_clear(&rt);
    }
    return brc.status;
}

UA_StatusCode
UA_Server_browseRecursive(UA_Server *server, const UA_BrowseDescription *bd,
                          size_t *resultsSize, UA_ExpandedNodeId **results) {
    UA_LOCK(&server->serviceMutex);

    /* Set the list of relevant reference types */
    UA_ReferenceTypeSet refTypes;
    UA_StatusCode retval = referenceTypeIndices(server, &bd->referenceTypeId,
                                                &refTypes, bd->includeSubtypes);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_UNLOCK(&server->serviceMutex);
        return retval;
    }

    /* Browse */
    retval = browseRecursive(server, 1, &bd->nodeId, bd->browseDirection,
                             &refTypes, bd->nodeClassMask, false, resultsSize, results);

    UA_UNLOCK(&server->serviceMutex);
    return retval;
}

/**********/
/* Browse */
/**********/

typedef struct {
    size_t size;
    size_t capacity;
    UA_ReferenceDescription *descr;
} RefResult;

static UA_StatusCode UA_FUNC_ATTR_WARN_UNUSED_RESULT
RefResult_init(RefResult *rr) {
    memset(rr, 0, sizeof(RefResult));
    rr->descr = (UA_ReferenceDescription*)
        UA_Array_new(UA_REFTREE_INITIAL_SIZE, &UA_TYPES[UA_TYPES_REFERENCEDESCRIPTION]);
    if(!rr->descr)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    rr->capacity = UA_REFTREE_INITIAL_SIZE;
    rr->size = 0;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode UA_FUNC_ATTR_WARN_UNUSED_RESULT
RefResult_double(RefResult *rr) {
    size_t newSize = rr->capacity * 2;
    UA_ReferenceDescription *rd = (UA_ReferenceDescription*)
        UA_realloc(rr->descr, newSize * sizeof(UA_ReferenceDescription));
    if(!rd)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    memset(&rd[rr->size], 0, sizeof(UA_ReferenceDescription) * (newSize - rr->size));
    rr->descr = rd;
    rr->capacity = newSize;
    return UA_STATUSCODE_GOOD;
}

static void
RefResult_clear(RefResult *rr) {
    UA_assert(rr->descr != NULL);
    for(size_t i = 0; i < rr->size; i++)
        UA_ReferenceDescription_clear(&rr->descr[i]);
    UA_free(rr->descr);
}

struct ContinuationPoint {
    ContinuationPoint *next;
    UA_ByteString identifier;

    /* Parameters of the Browse Request */
    UA_BrowseDescription browseDescription;
    UA_UInt32 maxReferences;
    UA_ReferenceTypeSet relevantReferences;

    /* The last reference target that was transmitted to the client. The results
     * list may be incomplete if the last target is removed or references added
     * between the calls to Browse/BrowseNext. */
    UA_NodePointer lastTarget;
    UA_Byte lastRefKindIndex;
    UA_Boolean lastRefInverse;
};

ContinuationPoint *
ContinuationPoint_clear(ContinuationPoint *cp) {
    UA_ByteString_clear(&cp->identifier);
    UA_BrowseDescription_clear(&cp->browseDescription);
    UA_NodePointer_clear(&cp->lastTarget);
    return cp->next;
}

struct BrowseContext {
    /* Context */
    ContinuationPoint *cp;
    UA_Server *server;
    UA_Session *session;
    UA_NodeReferenceKind *rk;
    UA_ReferenceTypeSet resultRefs; /* With additional references for type
                                     * lookups */
    UA_Boolean activeCP; /* true during "forwarding" to the position of the last
                          * reference target */

    /* Results */
    RefResult rr;
    UA_StatusCode status;
    UA_Boolean done;
};

/* Target node on top of the stack */
static UA_StatusCode
addReferenceDescription(struct BrowseContext *bc, UA_NodePointer nodeP,
                        const UA_Node *curr) {
    UA_assert(curr);
    UA_BrowseDescription *bd = &bc->cp->browseDescription;

    /* Ensure capacity is left */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(bc->rr.size >= bc->rr.capacity) {
        res = RefResult_double(&bc->rr);
        if(res != UA_STATUSCODE_GOOD)
           return res;
    }

    UA_ReferenceDescription *descr = &bc->rr.descr[bc->rr.size];

    /* Fields without access to the actual node */
    UA_ExpandedNodeId en = UA_NodePointer_toExpandedNodeId(nodeP);
    res = UA_ExpandedNodeId_copy(&en, &descr->nodeId);
    if(bd->resultMask & UA_BROWSERESULTMASK_REFERENCETYPEID) {
        const UA_NodeId *refTypeId =
            UA_NODESTORE_GETREFERENCETYPEID(bc->server, bc->rk->referenceTypeIndex);
        res |= UA_NodeId_copy(refTypeId, &descr->referenceTypeId);
    }
    if(bd->resultMask & UA_BROWSERESULTMASK_ISFORWARD)
        descr->isForward = !bc->rk->isInverse;

    /* Create fields that require access to the actual node */
    if(bd->resultMask & UA_BROWSERESULTMASK_NODECLASS)
        descr->nodeClass = curr->head.nodeClass;

    if(bd->resultMask & UA_BROWSERESULTMASK_BROWSENAME)
        res |= UA_QualifiedName_copy(&curr->head.browseName,
                                     &descr->browseName);

    if(bd->resultMask & UA_BROWSERESULTMASK_DISPLAYNAME) {
        UA_LocalizedText displayname =
            UA_Session_getNodeDisplayName(bc->session, &curr->head);
        res |= UA_LocalizedText_copy(&displayname, &descr->displayName);
    }

    if(bd->resultMask & UA_BROWSERESULTMASK_TYPEDEFINITION) {
        if(curr->head.nodeClass == UA_NODECLASS_OBJECT ||
           curr->head.nodeClass == UA_NODECLASS_VARIABLE) {
            const UA_Node *type = getNodeType(bc->server, &curr->head);
            if(type) {
                res |= UA_NodeId_copy(&type->head.nodeId,
                                      &descr->typeDefinition.nodeId);
                UA_NODESTORE_RELEASE(bc->server, type);
            }
        }
    }

    /* Clean up and return */
    if(res != UA_STATUSCODE_GOOD) {
        UA_ReferenceDescription_clear(descr);
        return res;
    }
    bc->rr.size++;
    return UA_STATUSCODE_GOOD;
}

static void *
browseReferencTargetCallback(void *context, UA_ReferenceTarget *t) {
    struct BrowseContext *bc = (struct BrowseContext*)context;
    const UA_BrowseDescription *bd = &bc->cp->browseDescription;
    ContinuationPoint *cp = bc->cp;

    /* Remote references are ignored */
    if(!UA_NodePointer_isLocal(t->targetId))
        return NULL;
    
    /* Get the node. Include only the ReferenceTypes we are interested in,
     * including those for figuring out the TypeDefinition (if that was
     * requested). */
    const UA_Node *target =
        UA_NODESTORE_GETFROMREF_SELECTIVE(bc->server, t->targetId,
                                          resultMask2AttributesMask(bd->resultMask),
                                          bc->resultRefs, bd->browseDirection);
    if(!target)
        return NULL;
    
    /* The node class has to match */
    if(!matchClassMask(target, bd->nodeClassMask)) {
        UA_NODESTORE_RELEASE(bc->server, target);
        return NULL;
    }
    
    /* Reached maxrefs. Return the "abort" signal. */
    if(bc->rr.size >= cp->maxReferences) {
        UA_NODESTORE_RELEASE(bc->server, target);
        return (void*)0x01;
    }

    /* Create the reference description */
    bc->status = addReferenceDescription(bc, t->targetId, target);

    /* Release the node */
    UA_NODESTORE_RELEASE(bc->server, target);

    /* Store as last target. The itarget-id is a shallow copy for now. */
    cp->lastTarget = t->targetId;
    cp->lastRefKindIndex = bc->rk->referenceTypeIndex;
    cp->lastRefInverse = bc->rk->isInverse;

    /* Abort if the status is not good. Also doesn't make a deep-copy of
     * cp->lastTarget after returning from here. */
    if(bc->status != UA_STATUSCODE_GOOD) {
        UA_NodePointer_init(&cp->lastTarget);
        return (void*)0x01;
    }
    return NULL;
}

/* Returns whether the node / continuationpoint is done */
static void
browseWithNode(struct BrowseContext *bc, const UA_NodeHead *head ) {
    ContinuationPoint *cp = bc->cp;
    const UA_BrowseDescription *bd = &cp->browseDescription;

    /* Loop over the ReferenceKinds */
    for(size_t i = 0; i < head->referencesSize && bc->status == UA_STATUSCODE_GOOD; ++i) {
        UA_NodeReferenceKind *rk = &head->references[i];

        /* If the continuation point was previously used, skip forward to the
         * last ReferenceType that was transmitted */
        if(bc->activeCP && rk->referenceTypeIndex != cp->lastRefKindIndex)
            continue;
        if(bc->activeCP && rk->isInverse != cp->lastRefInverse)
            continue;

        /* Reference in the right direction? */
        if(rk->isInverse && bd->browseDirection == UA_BROWSEDIRECTION_FORWARD)
            continue;
        if(!rk->isInverse && bd->browseDirection == UA_BROWSEDIRECTION_INVERSE)
            continue;

        /* Is the reference part of the hierarchy of references we look for? */
        if(!UA_ReferenceTypeSet_contains(&cp->relevantReferences, rk->referenceTypeIndex))
            continue;

        /* We have a matching ReferenceKind */

        /* Skip ahead to the target where the last continuation point stopped.
         * This temporarily modifies rk. */
        UA_ReferenceIdTree left = {NULL}, right = {NULL};
        size_t nextTargetIndex = 0;
        if(bc->activeCP) {
            if(rk->hasRefTree) {
                /* Unzip the tree until the continuation point. All NodeIds
                 * larger than the last target are guaranteed to sit on the
                 * right-hand side. */
                UA_ExpandedNodeId lastEn =
                    UA_NodePointer_toExpandedNodeId(cp->lastTarget);
                UA_ReferenceTargetTreeElem key;
                key.target.targetId = cp->lastTarget;
                key.targetIdHash = UA_ExpandedNodeId_hash(&lastEn);
                ZIP_UNZIP(UA_ReferenceIdTree,
                          (UA_ReferenceIdTree*)&rk->targets.tree.idRoot,
                          &key, &left, &right);
                rk->targets.tree.idRoot = right.root;
            } else {
                /* Iterate over the array to find the match */
                for(; nextTargetIndex < rk->targetsSize; nextTargetIndex++) {
                    UA_ReferenceTarget *t = &rk->targets.array[nextTargetIndex];
                    if(UA_NodePointer_equal(cp->lastTarget, t->targetId))
                        break;
                }
                if(nextTargetIndex == rk->targetsSize) {
                    /* Not found - assume that this reference kind is done */
                    bc->activeCP = false;
                    continue;
                }
                nextTargetIndex++; /* From the last index to the next index */
                rk->targets.array = &rk->targets.array[nextTargetIndex];
                rk->targetsSize -= nextTargetIndex;
            }

            /* Clear cp->lastTarget before it gets overwritten in the following
             * browse steps. */
            UA_NodePointer_clear(&cp->lastTarget);
        }

        /* Iterate over all reference targets */
        bc->rk = rk;
        void *res = UA_NodeReferenceKind_iterate(rk, browseReferencTargetCallback, bc);

        /* Undo the "skipping ahead" for the continuation point */
        if(bc->activeCP) {
            if(rk->hasRefTree) {
                rk->targets.tree.idRoot =
                    ZIP_ZIP(UA_ReferenceIdTree, left.root, right.root);
            } else {
                /* rk->targets.array = rk->targets.array[-nextTargetIndex]; */
                rk->targets.array = rk->targets.array - nextTargetIndex;
                rk->targetsSize += nextTargetIndex;
                UA_assert(rk->targetsSize > 0);
            }
            bc->activeCP = false;
        }

        /* The iteration was aborted */
        if(res != NULL) {
            /* Aborted with status code good -> the maximum number of browse
             * results was reached. Make a deep copy of the last target for the
             * continuation point. */
            if(bc->status == UA_STATUSCODE_GOOD)
                bc->status = UA_NodePointer_copy(cp->lastTarget, &cp->lastTarget);
            return;
        }
    }

    /* Reset last-target to prevent clearing it up */
    UA_NodePointer_init(&cp->lastTarget);

    /* Browsing the node is done */
    bc->done = true;
}

/* Results for a single browsedescription. This is the inner loop for both
 * Browse and BrowseNext. The ContinuationPoint contains all the data used.
 * Including the BrowseDescription. Returns whether there are remaining
 * references. */
static void
browse(struct BrowseContext *bc) {
    /* Is the browsedirection valid? */
    struct ContinuationPoint *cp = bc->cp;
    const UA_BrowseDescription *descr = &cp->browseDescription;
    if(descr->browseDirection != UA_BROWSEDIRECTION_BOTH &&
       descr->browseDirection != UA_BROWSEDIRECTION_FORWARD &&
       descr->browseDirection != UA_BROWSEDIRECTION_INVERSE) {
        bc->status = UA_STATUSCODE_BADBROWSEDIRECTIONINVALID;
        return;
    }

    /* Get node with only the selected references and attributes */
    const UA_Node *node =
        UA_NODESTORE_GET_SELECTIVE(bc->server, &descr->nodeId,
                                   resultMask2AttributesMask(descr->resultMask),
                                   bc->resultRefs, descr->browseDirection);
    if(!node) {
        bc->status = UA_STATUSCODE_BADNODEIDUNKNOWN;
        return;
    }

    /* Check AccessControl rights */
    if(bc->session != &bc->server->adminSession) {
        UA_LOCK_ASSERT(&bc->server->serviceMutex, 1);
        UA_UNLOCK(&bc->server->serviceMutex);
        if(!bc->server->config.accessControl.
           allowBrowseNode(bc->server, &bc->server->config.accessControl,
                           &bc->session->sessionId, bc->session->context,
                           &descr->nodeId, node->head.context)) {
            UA_LOCK(&bc->server->serviceMutex);
            UA_NODESTORE_RELEASE(bc->server, node);
            bc->status = UA_STATUSCODE_BADUSERACCESSDENIED;
            return;
        }
        UA_LOCK(&bc->server->serviceMutex);
    }

    /* Browse the node */
    browseWithNode(bc, &node->head);
    UA_NODESTORE_RELEASE(bc->server, node);

    /* Is the reference type valid? This is very infrequent. So we only test
     * this if browsing came up empty. If the node has references of that type,
     * we know the reftype to be good. */
    if(bc->rr.size == 0 && !UA_NodeId_isNull(&descr->referenceTypeId)) {
        const UA_Node *reftype =
            UA_NODESTORE_GET_SELECTIVE(bc->server, &descr->referenceTypeId,
                                       UA_NODEATTRIBUTESMASK_NODECLASS,
                                       UA_REFERENCETYPESET_NONE,
                                       UA_BROWSEDIRECTION_INVALID);
        if(!reftype) {
            bc->status = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
            return;
        }

        UA_Boolean isRef = (reftype->head.nodeClass == UA_NODECLASS_REFERENCETYPE);
        UA_NODESTORE_RELEASE(bc->server, reftype);

        if(!isRef) {
            bc->status = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
            return;
        }
    }
}

/* Start to browse with no previous cp */
void
Operation_Browse(UA_Server *server, UA_Session *session, const UA_UInt32 *maxrefs,
                 const UA_BrowseDescription *descr, UA_BrowseResult *result) {
    /* Stack-allocate a temporary cp */
    ContinuationPoint cp;
    memset(&cp, 0, sizeof(ContinuationPoint));
    cp.maxReferences = *maxrefs;
    cp.browseDescription = *descr; /* Shallow copy. Deep-copy later if we persist the cp. */

    /* How many references can we return at most? */
    if(cp.maxReferences == 0) {
        if(server->config.maxReferencesPerNode != 0) {
            cp.maxReferences = server->config.maxReferencesPerNode;
        } else {
            cp.maxReferences = UA_INT32_MAX;
        }
    } else {
        if(server->config.maxReferencesPerNode != 0 &&
           cp.maxReferences > server->config.maxReferencesPerNode) {
            cp.maxReferences= server->config.maxReferencesPerNode;
        }
    }

    /* Get the list of relevant reference types */
    result->statusCode =
        referenceTypeIndices(server, &descr->referenceTypeId,
                             &cp.relevantReferences, descr->includeSubtypes);
    if(result->statusCode != UA_STATUSCODE_GOOD)
        return;

    /* Prepare the context */
    struct BrowseContext bc;
    bc.cp = &cp;
    bc.server = server;
    bc.session = session;
    bc.status = UA_STATUSCODE_GOOD;
    bc.done = false;
    bc.activeCP = false;
    bc.resultRefs = cp.relevantReferences;
    if(cp.browseDescription.resultMask & UA_BROWSERESULTMASK_TYPEDEFINITION) {
        /* Get the node with additional reference types if we need to lookup the
         * TypeDefinition */
        bc.resultRefs = UA_ReferenceTypeSet_union(bc.resultRefs,
              UA_ReferenceTypeSet_union(UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASTYPEDEFINITION),
                                        UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASSUBTYPE)));
    }
    result->statusCode = RefResult_init(&bc.rr);
    if(result->statusCode != UA_STATUSCODE_GOOD)
        return;

    /* Perform the browse */
    browse(&bc);

    if(bc.status != UA_STATUSCODE_GOOD || bc.rr.size == 0) {
        /* No relevant references, return array of length zero */
        RefResult_clear(&bc.rr);
        result->references = (UA_ReferenceDescription*)UA_EMPTY_ARRAY_SENTINEL;
        result->statusCode = bc.status;
        return;
    }

    /* Move results */
    result->references = bc.rr.descr;
    result->referencesSize = bc.rr.size;

    /* Exit early if done */
    if(bc.done)
        return;

    /* Persist the continuation point */

    ContinuationPoint *cp2 = NULL;
    UA_Guid *ident = NULL;
    UA_StatusCode retval = UA_STATUSCODE_GOOD;

    /* Enough space for the continuation point? */
    if(session->availableContinuationPoints == 0) {
        retval = UA_STATUSCODE_BADNOCONTINUATIONPOINTS;
        goto cleanup;
    }

    /* Allocate and fill the data structure */
    cp2 = (ContinuationPoint*)UA_calloc(1, sizeof(ContinuationPoint));
    if(!cp2) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto cleanup;
    }

    /* The BrowseDescription is only a shallow copy so far */
    retval = UA_BrowseDescription_copy(descr, &cp2->browseDescription);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;
    cp2->maxReferences = cp.maxReferences;
    cp2->relevantReferences = cp.relevantReferences;
    cp2->lastTarget = cp.lastTarget; /* Move the (deep) copy */
    UA_NodePointer_init(&cp.lastTarget); /* No longer clear below (cleanup) */
    cp2->lastRefKindIndex = cp.lastRefKindIndex;
    cp2->lastRefInverse = cp.lastRefInverse;

    /* Create a random bytestring via a Guid */
    ident = UA_Guid_new();
    if(!ident) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto cleanup;
    }
    *ident = UA_Guid_random();
    cp2->identifier.data = (UA_Byte*)ident;
    cp2->identifier.length = sizeof(UA_Guid);

    /* Return the cp identifier */
    retval = UA_ByteString_copy(&cp2->identifier, &result->continuationPoint);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Attach the cp to the session */
    cp2->next = session->continuationPoints;
    session->continuationPoints = cp2;
    --session->availableContinuationPoints;
    return;

 cleanup:
    if(cp2) {
        ContinuationPoint_clear(cp2);
        UA_free(cp2);
    }
    UA_NodePointer_clear(&cp.lastTarget);
    UA_BrowseResult_clear(result);
    result->statusCode = retval;
}

void Service_Browse(UA_Server *server, UA_Session *session,
                    const UA_BrowseRequest *request, UA_BrowseResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session, "Processing BrowseRequest");
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Test the number of operations in the request */
    if(server->config.maxNodesPerBrowse != 0 &&
       request->nodesToBrowseSize > server->config.maxNodesPerBrowse) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return;
    }

    /* No views supported at the moment */
    if(!UA_NodeId_isNull(&request->view.viewId)) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADVIEWIDUNKNOWN;
        return;
    }

    response->responseHeader.serviceResult =
        UA_Server_processServiceOperations(server, session,
                                           (UA_ServiceOperation)Operation_Browse,
                                           &request->requestedMaxReferencesPerNode,
                                           &request->nodesToBrowseSize,
                                           &UA_TYPES[UA_TYPES_BROWSEDESCRIPTION],
                                           &response->resultsSize,
                                           &UA_TYPES[UA_TYPES_BROWSERESULT]);
}

UA_BrowseResult
UA_Server_browse(UA_Server *server, UA_UInt32 maxReferences,
                 const UA_BrowseDescription *bd) {
    UA_BrowseResult result;
    UA_BrowseResult_init(&result);
    UA_LOCK(&server->serviceMutex);
    Operation_Browse(server, &server->adminSession, &maxReferences, bd, &result);
    UA_UNLOCK(&server->serviceMutex);
    return result;
}

static void
Operation_BrowseNext(UA_Server *server, UA_Session *session,
                     const UA_Boolean *releaseContinuationPoints,
                     const UA_ByteString *continuationPoint, UA_BrowseResult *result) {
    /* Find the continuation point */
    ContinuationPoint **prev = &session->continuationPoints;
    ContinuationPoint *cp;
    while((cp = *prev)) {
        if(UA_ByteString_equal(&cp->identifier, continuationPoint))
            break;
        prev = &cp->next;
    }
    if(!cp) {
        result->statusCode = UA_STATUSCODE_BADCONTINUATIONPOINTINVALID;
        return;
    }

    /* Remove the cp */
    if(*releaseContinuationPoints) {
        *prev = ContinuationPoint_clear(cp);
        UA_free(cp);
        ++session->availableContinuationPoints;
        return;
    }

    /* Prepare the context */
    struct BrowseContext bc;
    bc.cp = cp;
    bc.server = server;
    bc.session = session;
    bc.status = UA_STATUSCODE_GOOD;
    bc.done = false;
    bc.activeCP = true;
    bc.resultRefs = cp->relevantReferences;
    if(cp->browseDescription.resultMask & UA_BROWSERESULTMASK_TYPEDEFINITION) {
        /* Get the node with additional reference types if we need to lookup the
         * TypeDefinition */
        bc.resultRefs = UA_ReferenceTypeSet_union(bc.resultRefs,
              UA_ReferenceTypeSet_union(UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASTYPEDEFINITION),
                                        UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASSUBTYPE)));
    }
    result->statusCode = RefResult_init(&bc.rr);
    if(result->statusCode != UA_STATUSCODE_GOOD)
        return;

    /* Continue browsing */
    browse(&bc);

    if(bc.status != UA_STATUSCODE_GOOD || bc.rr.size == 0) {
        /* No relevant references, return array of length zero */
        RefResult_clear(&bc.rr);
        result->references = (UA_ReferenceDescription*)UA_EMPTY_ARRAY_SENTINEL;
        result->statusCode = bc.status;
        goto remove_cp;
    }

    /* Move results */
    result->references = bc.rr.descr;
    result->referencesSize = bc.rr.size;

    if(bc.done)
        goto remove_cp;

    /* Return the cp identifier to signal that there are references left */
    bc.status = UA_ByteString_copy(&cp->identifier, &result->continuationPoint);
    if(bc.status != UA_STATUSCODE_GOOD) {
        UA_BrowseResult_clear(result);
        result->statusCode = bc.status;
    }
    return;

 remove_cp:
    /* Remove the cp */
    *prev = ContinuationPoint_clear(cp);
    UA_free(cp);
    ++session->availableContinuationPoints;
}

void
Service_BrowseNext(UA_Server *server, UA_Session *session,
                   const UA_BrowseNextRequest *request,
                   UA_BrowseNextResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing BrowseNextRequest");
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_Boolean releaseContinuationPoints =
        request->releaseContinuationPoints; /* request is const */
    response->responseHeader.serviceResult =
        UA_Server_processServiceOperations(server, session,
                                           (UA_ServiceOperation)Operation_BrowseNext,
                                           &releaseContinuationPoints,
                                           &request->continuationPointsSize,
                                           &UA_TYPES[UA_TYPES_BYTESTRING],
                                           &response->resultsSize,
                                           &UA_TYPES[UA_TYPES_BROWSERESULT]);
}

UA_BrowseResult
UA_Server_browseNext(UA_Server *server, UA_Boolean releaseContinuationPoint,
                     const UA_ByteString *continuationPoint) {
    UA_BrowseResult result;
    UA_BrowseResult_init(&result);
    UA_LOCK(&server->serviceMutex);
    Operation_BrowseNext(server, &server->adminSession, &releaseContinuationPoint,
                         continuationPoint, &result);
    UA_UNLOCK(&server->serviceMutex);
    return result;
}

/***********************/
/* TranslateBrowsePath */
/***********************/

/* Add all entries for the hash. There are possible duplicates due to hash
 * collisions. The full browsename is checked afterwards. */
static void *
addBrowseHashTarget(void *context, UA_ReferenceTargetTreeElem *elem) {
    RefTree *next = (RefTree*)context;
    return (void*)(uintptr_t)RefTree_add(next, elem->target.targetId, NULL);
}

static UA_StatusCode
walkBrowsePathElement(UA_Server *server, UA_Session *session,
                      const UA_RelativePath *path, const size_t pathIndex,
                      UA_UInt32 nodeClassMask, const UA_QualifiedName *lastBrowseName,
                      UA_BrowsePathResult *result, RefTree *current, RefTree *next) {
    /* For the next level. Note the difference from lastBrowseName */
    const UA_RelativePathElement *elem = &path->elements[pathIndex];
    UA_UInt32 browseNameHash = UA_QualifiedName_hash(&elem->targetName);

    /* Get the relevant ReferenceTypes */
    UA_ReferenceTypeSet refTypes;
    UA_StatusCode res =
        referenceTypeIndices(server, &elem->referenceTypeId,
                             &refTypes, elem->includeSubtypes);
    if(res != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADNOMATCH;

    /* Loop over all Nodes in the current depth level */
    for(size_t i = 0; i < current->size; i++) {
        /* Remote Node. Immediately add to the results with the
         * RemainingPathIndex set. */
        if(!UA_ExpandedNodeId_isLocal(&current->targets[i])) {
            /* Increase the size of the results array */
            UA_BrowsePathTarget *tmpResults = (UA_BrowsePathTarget*)
                UA_realloc(result->targets, sizeof(UA_BrowsePathTarget) *
                           (result->targetsSize + 1));
            if(!tmpResults)
                return UA_STATUSCODE_BADOUTOFMEMORY;
            result->targets = tmpResults;

            /* Copy over the result */
            res = UA_ExpandedNodeId_copy(&current->targets[i],
                                         &result->targets[result->targetsSize].targetId);
            result->targets[result->targetsSize].remainingPathIndex = (UA_UInt32)pathIndex;
            result->targetsSize++;
            if(res != UA_STATUSCODE_GOOD)
                break;
            continue;
        }

        /* Local Node. Add to the tree of results at the next depth. Get only
         * the NodeClass + BrowseName attribute and the selected ReferenceTypes
         * if the nodestore supports that. */
        const UA_Node *node =
            UA_NODESTORE_GET_SELECTIVE(server, &current->targets[i].nodeId,
                                       UA_NODEATTRIBUTESMASK_NODECLASS |
                                       UA_NODEATTRIBUTESMASK_BROWSENAME,
                                       refTypes,
                                       elem->isInverse ? UA_BROWSEDIRECTION_INVERSE :
                                                         UA_BROWSEDIRECTION_FORWARD);
        if(!node)
            continue;

        /* Test whether the node fits the class mask */
        UA_Boolean skip = !matchClassMask(node, nodeClassMask);

        /* Does the BrowseName match for the current node (not the references
         * going out here) */
        skip |= (lastBrowseName &&
                 !UA_QualifiedName_equal(lastBrowseName, &node->head.browseName));

        if(skip) {
            UA_NODESTORE_RELEASE(server, node);
            continue;
        }

        /* Loop over the ReferenceKinds */
        UA_ReferenceTarget targetHashKey;
        targetHashKey.targetNameHash = browseNameHash;
        for(size_t j = 0; j < node->head.referencesSize; j++) {
            UA_NodeReferenceKind *rk = &node->head.references[j];

            /* Does the direction of the reference match? */
            if(rk->isInverse != elem->isInverse)
                continue;

            /* Does the reference type match? */
            if(!UA_ReferenceTypeSet_contains(&refTypes, rk->referenceTypeIndex))
                continue;

            /* Retrieve by BrowseName hash. We might have several nodes where
             * the hash matches. The exact BrowseName will be verified in the
             * next iteration of the outer loop. So we only have to retrieve
             * every node just once. */

            if(rk->hasRefTree) {
                res = (UA_StatusCode)(uintptr_t)
                    ZIP_ITER_KEY(UA_ReferenceNameTree,
                                 (UA_ReferenceNameTree*)&rk->targets.tree.nameRoot,
                                 &targetHashKey, addBrowseHashTarget, next);
                if(res != UA_STATUSCODE_GOOD)
                    break;
            } else {
                /* The array entries don't have a BrowseName hash. Add all of
                 * them at this level to be checked with a full string
                 * comparison. */
                for(size_t k = 0; k < rk->targetsSize; k++) {
                    if(rk->targets.array[k].targetNameHash != browseNameHash)
                        continue;
                    res = RefTree_add(next, rk->targets.array[k].targetId, NULL);
                    if(res != UA_STATUSCODE_GOOD)
                        break;
                }
                if(res != UA_STATUSCODE_GOOD)
                    break;
            }
        }

        UA_NODESTORE_RELEASE(server, node);
    }
    return res;
}

static void
Operation_TranslateBrowsePathToNodeIds(UA_Server *server, UA_Session *session,
                                       const UA_UInt32 *nodeClassMask,
                                       const UA_BrowsePath *path,
                                       UA_BrowsePathResult *result) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    if(path->relativePath.elementsSize == 0) {
        result->statusCode = UA_STATUSCODE_BADNOTHINGTODO;
        return;
    }

    /* RelativePath elements must not have an empty targetName */
    for(size_t i = 0; i < path->relativePath.elementsSize; ++i) {
        if(UA_QualifiedName_isNull(&path->relativePath.elements[i].targetName)) {
            result->statusCode = UA_STATUSCODE_BADBROWSENAMEINVALID;
            return;
        }
    }

    /* Check if the starting node exists */
    const UA_Node *startingNode =
        UA_NODESTORE_GET_SELECTIVE(server, &path->startingNode,
                                   UA_NODEATTRIBUTESMASK_NONE,
                                   UA_REFERENCETYPESET_NONE,
                                   UA_BROWSEDIRECTION_INVALID);
    if(!startingNode) {
        result->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN;
        return;
    }
    UA_NODESTORE_RELEASE(server, startingNode);

    /* Create two RefTrees that are alternated between path elements */
    RefTree rt1;
    RefTree rt2;
    RefTree *current = &rt1;
    RefTree *next = &rt2;
    RefTree *tmp;
    result->statusCode |= RefTree_init(&rt1);
    result->statusCode |= RefTree_init(&rt2);
    UA_BrowsePathTarget *tmpResults = NULL;
    UA_QualifiedName *browseNameFilter = NULL;
    if(result->statusCode != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Copy the starting node into next */
    result->statusCode = RefTree_addNodeId(next, &path->startingNode, NULL);
    if(result->statusCode != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Walk the path elements. Retrieve the nodes only once from the NodeStore.
     * Hence the BrowseName is checked with one element "delay". */
    for(size_t i = 0; i < path->relativePath.elementsSize; i++) {
        /* Switch the trees */
        tmp = current;
        current = next;
        next = tmp;

        /* Clear up current, keep the capacity */
        for(size_t j = 0; j < next->size; j++)
            UA_ExpandedNodeId_clear(&next->targets[j]);
        next->size = 0;
        ZIP_INIT(&next->head);

        /* Do this check after next->size has been set to zero */
        if(current->size == 0)
            break;

        /* Walk element for all NodeIds in the "current" tree.
         * Puts new results in the "next" tree. */
        result->statusCode =
            walkBrowsePathElement(server, session, &path->relativePath, i,
                                  *nodeClassMask, browseNameFilter, result, current, next);
        if(result->statusCode != UA_STATUSCODE_GOOD)
            goto cleanup;

        browseNameFilter = &path->relativePath.elements[i].targetName;
    }

    /* Allocate space for the results array */
    tmpResults = (UA_BrowsePathTarget*)
        UA_realloc(result->targets, sizeof(UA_BrowsePathTarget) *
                   (result->targetsSize + next->size));
    if(!tmpResults && next->size > 0) {
        result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
        goto cleanup;
    }
    result->targets = tmpResults;

    for(size_t k = 0; k < next->size; k++) {
        /* Check the BrowseName. It has been filtered only via its hash so far.
         * Get only the BrowseName attribute if the nodestore supports that. */
        const UA_Node *node =
            UA_NODESTORE_GET_SELECTIVE(server, &next->targets[k].nodeId,
                                       UA_NODEATTRIBUTESMASK_BROWSENAME,
                                       UA_REFERENCETYPESET_NONE,
                                       UA_BROWSEDIRECTION_INVALID);
        if(!node)
            continue;
        UA_Boolean match = UA_QualifiedName_equal(browseNameFilter, &node->head.browseName);
        UA_NODESTORE_RELEASE(server, node);
        if(!match)
            continue;

        /* Move to the target to the results array */
        result->targets[result->targetsSize].targetId = next->targets[k];
        result->targets[result->targetsSize].remainingPathIndex = UA_UINT32_MAX;
        UA_ExpandedNodeId_init(&next->targets[k]);
        result->targetsSize++;
    }

    /* No results => BadNoMatch status code */
    if(result->targetsSize == 0 && result->statusCode == UA_STATUSCODE_GOOD)
        result->statusCode = UA_STATUSCODE_BADNOMATCH;

    /* Clean up the temporary arrays and the targets */
 cleanup:
    RefTree_clear(&rt1);
    RefTree_clear(&rt2);
    if(result->statusCode != UA_STATUSCODE_GOOD) {
        for(size_t i = 0; i < result->targetsSize; ++i)
            UA_BrowsePathTarget_clear(&result->targets[i]);
        if(result->targets)
            UA_free(result->targets);
        result->targets = NULL;
        result->targetsSize = 0;
    }
}

UA_BrowsePathResult
translateBrowsePathToNodeIds(UA_Server *server,
                                       const UA_BrowsePath *browsePath) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    UA_BrowsePathResult result;
    UA_BrowsePathResult_init(&result);
    UA_UInt32 nodeClassMask = 0; /* All node classes */
    Operation_TranslateBrowsePathToNodeIds(server, &server->adminSession, &nodeClassMask,
                                           browsePath, &result);
    return result;
}

UA_BrowsePathResult
UA_Server_translateBrowsePathToNodeIds(UA_Server *server,
                                       const UA_BrowsePath *browsePath) {
    UA_LOCK(&server->serviceMutex);
    UA_BrowsePathResult result = translateBrowsePathToNodeIds(server, browsePath);
    UA_UNLOCK(&server->serviceMutex);
    return result;
}

void
Service_TranslateBrowsePathsToNodeIds(UA_Server *server, UA_Session *session,
                                      const UA_TranslateBrowsePathsToNodeIdsRequest *request,
                                      UA_TranslateBrowsePathsToNodeIdsResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing TranslateBrowsePathsToNodeIdsRequest");
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Test the number of operations in the request */
    if(server->config.maxNodesPerTranslateBrowsePathsToNodeIds != 0 &&
       request->browsePathsSize > server->config.maxNodesPerTranslateBrowsePathsToNodeIds) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return;
    }

    UA_UInt32 nodeClassMask = 0; /* All node classes */
    response->responseHeader.serviceResult =
        UA_Server_processServiceOperations(server, session,
                                           (UA_ServiceOperation)Operation_TranslateBrowsePathToNodeIds,
                                           &nodeClassMask,
                                           &request->browsePathsSize, &UA_TYPES[UA_TYPES_BROWSEPATH],
                                           &response->resultsSize, &UA_TYPES[UA_TYPES_BROWSEPATHRESULT]);
}

UA_BrowsePathResult
browseSimplifiedBrowsePath(UA_Server *server, const UA_NodeId origin,
                           size_t browsePathSize, const UA_QualifiedName *browsePath) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_BrowsePathResult bpr;
    UA_BrowsePathResult_init(&bpr);
    if(browsePathSize > UA_MAX_TREE_RECURSE) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Simplified Browse Path too long");
        bpr.statusCode = UA_STATUSCODE_BADINTERNALERROR;
        return bpr;
    }

    /* Construct the BrowsePath */
    UA_BrowsePath bp;
    UA_BrowsePath_init(&bp);
    bp.startingNode = origin;

    UA_RelativePathElement rpe[UA_MAX_TREE_RECURSE];
    memset(rpe, 0, sizeof(UA_RelativePathElement) * browsePathSize);
    for(size_t j = 0; j < browsePathSize; j++) {
        rpe[j].referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES);
        rpe[j].includeSubtypes = true;
        rpe[j].targetName = browsePath[j];
    }
    bp.relativePath.elements = rpe;
    bp.relativePath.elementsSize = browsePathSize;

    /* Browse */
    UA_UInt32 nodeClassMask = UA_NODECLASS_OBJECT | UA_NODECLASS_VARIABLE | UA_NODECLASS_OBJECTTYPE;

    Operation_TranslateBrowsePathToNodeIds(server, &server->adminSession, &nodeClassMask, &bp, &bpr);
    return bpr;
}

UA_BrowsePathResult
UA_Server_browseSimplifiedBrowsePath(UA_Server *server, const UA_NodeId origin,
                           size_t browsePathSize, const UA_QualifiedName *browsePath) {
    UA_LOCK(&server->serviceMutex);
    UA_BrowsePathResult bpr = browseSimplifiedBrowsePath(server, origin, browsePathSize, browsePath);
    UA_UNLOCK(&server->serviceMutex);
    return bpr;
}

/************/
/* Register */
/************/

void Service_RegisterNodes(UA_Server *server, UA_Session *session,
                           const UA_RegisterNodesRequest *request,
                           UA_RegisterNodesResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing RegisterNodesRequest");
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    //TODO: hang the nodeids to the session if really needed
    if(request->nodesToRegisterSize == 0) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
        return;
    }

    /* Test the number of operations in the request */
    if(server->config.maxNodesPerRegisterNodes != 0 &&
       request->nodesToRegisterSize > server->config.maxNodesPerRegisterNodes) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return;
    }

    response->responseHeader.serviceResult =
        UA_Array_copy(request->nodesToRegister, request->nodesToRegisterSize,
                      (void**)&response->registeredNodeIds, &UA_TYPES[UA_TYPES_NODEID]);
    if(response->responseHeader.serviceResult == UA_STATUSCODE_GOOD)
        response->registeredNodeIdsSize = request->nodesToRegisterSize;
}

void Service_UnregisterNodes(UA_Server *server, UA_Session *session,
                             const UA_UnregisterNodesRequest *request,
                             UA_UnregisterNodesResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing UnRegisterNodesRequest");
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    //TODO: remove the nodeids from the session if really needed
    if(request->nodesToUnregisterSize == 0)
        response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;

    /* Test the number of operations in the request */
    if(server->config.maxNodesPerRegisterNodes != 0 &&
       request->nodesToUnregisterSize > server->config.maxNodesPerRegisterNodes) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return;
    }
}

/**** amalgamated original file "/src/server/ua_services_method.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015-2017 (c) Florian Palm
 *    Copyright 2015-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015 (c) Oleksiy Vasylyev
 *    Copyright 2016 (c) LEvertz
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Julian Grothoff
 *    Copyright 2020 (c) Hilscher Gesellschaft für Systemautomation mbH (Author: Martin Lang)
 */


#ifdef UA_ENABLE_METHODCALLS /* conditional compilation */

#define UA_MAX_METHOD_ARGUMENTS 64

struct GetArgumentsNodeContext {
    UA_Server *server;
    UA_String withBrowseName;
};

static void *
getArgumentsNodeCallback(void *context, UA_ReferenceTarget *t) {
    struct GetArgumentsNodeContext *ctx = (struct GetArgumentsNodeContext*)context;
    const UA_Node *refTarget =
        UA_NODESTORE_GETFROMREF_SELECTIVE(ctx->server, t->targetId,
                                          UA_NODEATTRIBUTESMASK_NODECLASS |
                                          UA_NODEATTRIBUTESMASK_VALUE,
                                          UA_REFERENCETYPESET_NONE,
                                          UA_BROWSEDIRECTION_INVALID);
    if(!refTarget)
        return NULL;
    if(refTarget->head.nodeClass == UA_NODECLASS_VARIABLE &&
       refTarget->head.browseName.namespaceIndex == 0 &&
       UA_String_equal(&ctx->withBrowseName, &refTarget->head.browseName.name)) {
        return (void*)(uintptr_t)&refTarget->variableNode;
    }
    UA_NODESTORE_RELEASE(ctx->server, refTarget);
    return NULL;
}

static const UA_VariableNode *
getArgumentsVariableNode(UA_Server *server, const UA_NodeHead *head,
                         UA_String withBrowseName) {
    for(size_t i = 0; i < head->referencesSize; ++i) {
        UA_NodeReferenceKind *rk = &head->references[i];
        if(rk->isInverse)
            continue;
        if(rk->referenceTypeIndex != UA_REFERENCETYPEINDEX_HASPROPERTY)
            continue;
        struct GetArgumentsNodeContext ctx;
        ctx.server = server;
        ctx.withBrowseName = withBrowseName;
        return (const UA_VariableNode*)
            UA_NodeReferenceKind_iterate(rk, getArgumentsNodeCallback, &ctx);
    }
    return NULL;
}

/* inputArgumentResults has the length request->inputArgumentsSize */
static UA_StatusCode
checkAdjustArguments(UA_Server *server, UA_Session *session,
                     const UA_VariableNode *argRequirements, size_t argsSize,
                     UA_Variant *args, UA_StatusCode *inputArgumentResults) {
    /* Verify that we have a Variant containing UA_Argument (scalar or array) in
     * the "InputArguments" node */
    if(argRequirements->valueSource != UA_VALUESOURCE_DATA)
        return UA_STATUSCODE_BADINTERNALERROR;
    if(!argRequirements->value.data.value.hasValue)
        return UA_STATUSCODE_BADINTERNALERROR;
    if(argRequirements->value.data.value.value.type != &UA_TYPES[UA_TYPES_ARGUMENT])
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Verify the number of arguments. A scalar argument value is interpreted as
     * an array of length 1. */
    size_t argReqsSize = argRequirements->value.data.value.value.arrayLength;
    if(UA_Variant_isScalar(&argRequirements->value.data.value.value))
        argReqsSize = 1;
    if(argReqsSize > argsSize)
        return UA_STATUSCODE_BADARGUMENTSMISSING;
    if(argReqsSize < argsSize)
        return UA_STATUSCODE_BADTOOMANYARGUMENTS;

    /* Type-check every argument against the definition */
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    UA_Argument *argReqs = (UA_Argument*)argRequirements->value.data.value.value.data;
    const char *reason;
    for(size_t i = 0; i < argReqsSize; ++i) {
        /* Incompatible value. Try to correct the type if possible. */
        adjustValueType(server, &args[i], &argReqs[i].dataType);

        /* Check */
        if(!compatibleValue(server, session, &argReqs[i].dataType, argReqs[i].valueRank,
                            argReqs[i].arrayDimensionsSize, argReqs[i].arrayDimensions,
                            &args[i], NULL, &reason)) {
            inputArgumentResults[i] = UA_STATUSCODE_BADTYPEMISMATCH;
            retval = UA_STATUSCODE_BADINVALIDARGUMENT;
        }
    }
    return retval;
}

static const UA_NodeId hasComponentNodeId = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASCOMPONENT}};
static const UA_NodeId organizedByNodeId = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_ORGANIZES}};
static const UA_String namespaceDiModel = UA_STRING_STATIC("http://opcfoundation.org/UA/DI/");
static const UA_NodeId hasTypeDefinitionNodeId = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASTYPEDEFINITION}};
// ns=0 will be replace dynamically. DI-Spec. 1.01: <UAObjectType NodeId="ns=1;i=1005" BrowseName="1:FunctionalGroupType">
static UA_NodeId functionGroupNodeId = {0, UA_NODEIDTYPE_NUMERIC, {1005}};

static UA_Boolean
checkMethodReference(const UA_NodeHead *h, UA_ReferenceTypeSet refs,
                     const UA_ExpandedNodeId *methodId) {
    for(size_t i = 0; i < h->referencesSize; i++) {
        const UA_NodeReferenceKind *rk = &h->references[i];
        if(rk->isInverse)
            continue;
        if(!UA_ReferenceTypeSet_contains(&refs, rk->referenceTypeIndex))
            continue;
        if(UA_NodeReferenceKind_findTarget(rk, methodId))
            return true;
    }
    return false;
}

static void *
iterateFunctionGroupSearch(void *context, UA_ReferenceTarget *t) {
    UA_Server *server = (UA_Server*)context;
    if(!UA_NodePointer_isLocal(t->targetId))
        return NULL;

    UA_NodeId tmpId = UA_NodePointer_toNodeId(t->targetId);
    if(isNodeInTree_singleRef(server, &tmpId, &functionGroupNodeId,
                               UA_REFERENCETYPEINDEX_HASSUBTYPE))
        return (void*)0x01;
    return NULL;
}

static UA_StatusCode
checkFunctionalGroupMethodReference(UA_Server *server, const UA_NodeHead *h,
                                    const UA_ExpandedNodeId *methodId,
                                    UA_Boolean *found) {
    /* Check whether the DI namespace is available */
    size_t foundNamespace = 0;
    UA_StatusCode res = getNamespaceByName(server, namespaceDiModel, &foundNamespace);
    UA_CHECK_STATUS(res, return UA_STATUSCODE_BADMETHODINVALID);
    functionGroupNodeId.namespaceIndex = (UA_UInt16)foundNamespace;

    UA_ReferenceTypeSet hasTypeDefinitionRefs;
    res = referenceTypeIndices(server, &hasTypeDefinitionNodeId,
                               &hasTypeDefinitionRefs, true);
    UA_CHECK_STATUS(res, return res);

    /* Search for a HasTypeDefinition (or sub-) reference to the FunctionGroupType */
    UA_Boolean isFunctionGroup = false;
    for(size_t i = 0; i < h->referencesSize && !isFunctionGroup; ++i) {
        UA_NodeReferenceKind *rk = &h->references[i];
        if(rk->isInverse)
            continue;

        /* Are these HasTypeDefinition references */
        if(!UA_ReferenceTypeSet_contains(&hasTypeDefinitionRefs, rk->referenceTypeIndex))
            continue;

        /* Reference points to FunctionGroupType (or sub-type) from the DI
         * model? */
        isFunctionGroup =
            (UA_NodeReferenceKind_iterate(rk, iterateFunctionGroupSearch,
                                          server) != NULL);
        if(isFunctionGroup)
            break;
    }
    if(!isFunctionGroup)
        return UA_STATUSCODE_GOOD;

    /* Search for the called method with reference Organize (or sub-type) from
     * the parent object */
    UA_ReferenceTypeSet organizesRefs;
    res = referenceTypeIndices(server, &organizedByNodeId, &organizesRefs, true);
    UA_CHECK_STATUS(res, return res);
    for(size_t k = 0; k < h->referencesSize; ++k) {
        const UA_NodeReferenceKind *rk = &h->references[k];
        if(rk->isInverse)
            continue;
        if(!UA_ReferenceTypeSet_contains(&organizesRefs, rk->referenceTypeIndex))
            continue;
        if(UA_NodeReferenceKind_findTarget(rk, methodId)) {
            *found = true;
            break;
        }
    }
    return UA_STATUSCODE_GOOD;
}

static void
callWithMethodAndObject(UA_Server *server, UA_Session *session,
                        const UA_CallMethodRequest *request, UA_CallMethodResult *result,
                        const UA_MethodNode *method, const UA_ObjectNode *object) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Verify the object's NodeClass */
    if(object->head.nodeClass != UA_NODECLASS_OBJECT &&
       object->head.nodeClass != UA_NODECLASS_OBJECTTYPE) {
        result->statusCode = UA_STATUSCODE_BADNODECLASSINVALID;
        return;
    }

    /* Verify the method's NodeClass */
    if(method->head.nodeClass != UA_NODECLASS_METHOD) {
        result->statusCode = UA_STATUSCODE_BADNODECLASSINVALID;
        return;
    }

    /* Is there a method to execute? */
    if(!method->method) {
        result->statusCode = UA_STATUSCODE_BADINTERNALERROR;
        return;
    }

    /* Verify method/object relations. Object must have a hasComponent or a
     * subtype of hasComponent reference to the method node. Therefore, check
     * every reference between the parent object and the method node if there is
     * a hasComponent (or subtype) reference */
    UA_ExpandedNodeId methodId = UA_EXPANDEDNODEID_NODEID(request->methodId);
    UA_ReferenceTypeSet hasComponentRefs;
    result->statusCode = referenceTypeIndices(server, &hasComponentNodeId,
                                              &hasComponentRefs, true);
    UA_CHECK_STATUS(result->statusCode, return);
    UA_Boolean found = checkMethodReference(&object->head, hasComponentRefs, &methodId);

    if(!found) {
        /* If the object doesn't have a hasComponent reference to the method node,
         * check its objectType (and its supertypes). Invoked method can be a component
         * of objectType and be invoked on this objectType's instance (or on a instance
         * of one of its subtypes). */
        const UA_Node *objectType = getNodeType(server, &object->head);
        if(objectType) {
            found = checkMethodReference(&objectType->head, hasComponentRefs, &methodId);
            UA_NODESTORE_RELEASE(server, objectType);
        }
    }

    if(!found) {
        /* The following ParentObject evaluation is a workaround only to fulfill
         * the OPC UA Spec. Part 100 - Devices requirements regarding functional
         * groups. Compare OPC UA Spec. Part 100 - Devices, Release 1.02
         *    - 5.4 FunctionalGroupType
         *    - B.1 Functional Group Usages
         * A functional group is a sub-type of the FolderType and is used to
         * organize the Parameters and Methods from the complete set (named
         * ParameterSet and MethodSet) in (Functional) groups for instance
         * Configuration or Identification. The same Property, Parameter or
         * Method can be referenced from more than one FunctionalGroup. */
        result->statusCode =
            checkFunctionalGroupMethodReference(server, &object->head, &methodId, &found);
        if(!found && result->statusCode == UA_STATUSCODE_GOOD)
            result->statusCode = UA_STATUSCODE_BADMETHODINVALID;
        UA_CHECK_STATUS(result->statusCode, return);
    }

    /* Verify access rights */
    UA_Boolean executable = method->executable;
    if(session != &server->adminSession) {
        UA_UNLOCK(&server->serviceMutex);
        executable = executable && server->config.accessControl.
            getUserExecutableOnObject(server, &server->config.accessControl,
                                      &session->sessionId, session->context,
                                      &request->methodId, method->head.context,
                                      &request->objectId, object->head.context);
        UA_LOCK(&server->serviceMutex);
    }

    if(!executable) {
        result->statusCode = UA_STATUSCODE_BADNOTEXECUTABLE;
        return;
    }

    /* The input arguments are const and not changed. We move the input
     * arguments to a secondary array that is mutable. This is used for small
     * adjustments on the type level during the type checking. But it has to be
     * ensured that the original array can still by _clear'ed after the methods
     * call. */
    if(request->inputArgumentsSize > UA_MAX_METHOD_ARGUMENTS) {
        result->statusCode = UA_STATUSCODE_BADTOOMANYARGUMENTS;
        return;
    }
    UA_Variant mutableInputArgs[UA_MAX_METHOD_ARGUMENTS];
    memcpy(mutableInputArgs, request->inputArguments,
           sizeof(UA_Variant) * request->inputArgumentsSize);

    /* Allocate the inputArgumentResults array */
    result->inputArgumentResults = (UA_StatusCode*)
        UA_Array_new(request->inputArgumentsSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
    if(!result->inputArgumentResults) {
        result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
        return;
    }
    result->inputArgumentResultsSize = request->inputArgumentsSize;

    /* Type-check the input arguments */
    const UA_VariableNode *inputArguments =
        getArgumentsVariableNode(server, &method->head, UA_STRING("InputArguments"));
    if(inputArguments) {
        result->statusCode =
            checkAdjustArguments(server, session, inputArguments, request->inputArgumentsSize,
                                 mutableInputArgs, result->inputArgumentResults);
        UA_NODESTORE_RELEASE(server, (const UA_Node*)inputArguments);
    } else {
        if(request->inputArgumentsSize > 0) {
            result->statusCode = UA_STATUSCODE_BADTOOMANYARGUMENTS;
            return;
        }
    }

    /* Return inputArgumentResults only for BADINVALIDARGUMENT */
    if(result->statusCode != UA_STATUSCODE_BADINVALIDARGUMENT) {
        UA_Array_delete(result->inputArgumentResults, result->inputArgumentResultsSize,
                        &UA_TYPES[UA_TYPES_STATUSCODE]);
        result->inputArgumentResults = NULL;
        result->inputArgumentResultsSize = 0;
    }

    /* Error during type-checking? */
    if(result->statusCode != UA_STATUSCODE_GOOD)
        return;

    /* Get the output arguments node */
    const UA_VariableNode *outputArguments =
        getArgumentsVariableNode(server, &method->head, UA_STRING("OutputArguments"));

    /* Allocate the output arguments array */
    size_t outputArgsSize = 0;
    if(outputArguments)
        outputArgsSize = outputArguments->value.data.value.value.arrayLength;
    result->outputArguments = (UA_Variant*)
        UA_Array_new(outputArgsSize, &UA_TYPES[UA_TYPES_VARIANT]);
    if(!result->outputArguments) {
        result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
        return;
    }
    result->outputArgumentsSize = outputArgsSize;

    /* Release the output arguments node */
    UA_NODESTORE_RELEASE(server, (const UA_Node*)outputArguments);

    /* Call the method */
    UA_UNLOCK(&server->serviceMutex);
    result->statusCode = method->method(server, &session->sessionId, session->context,
                                        &method->head.nodeId, method->head.context,
                                        &object->head.nodeId, object->head.context,
                                        request->inputArgumentsSize, mutableInputArgs,
                                        result->outputArgumentsSize, result->outputArguments);
    UA_LOCK(&server->serviceMutex);
    /* TODO: Verify Output matches the argument definition */
}

#if UA_MULTITHREADING >= 100

static void
Operation_CallMethodAsync(UA_Server *server, UA_Session *session, UA_UInt32 requestId,
                          UA_UInt32 requestHandle, size_t opIndex,
                          UA_CallMethodRequest *opRequest, UA_CallMethodResult *opResult,
                          UA_AsyncResponse **ar) {
    /* Get the method node. We only need the nodeClass and executable attribute.
     * Take all forward hasProperty references to get the input/output argument
     * definition variables. */
    const UA_Node *method =
        UA_NODESTORE_GET_SELECTIVE(server, &opRequest->methodId,
                                   UA_NODEATTRIBUTESMASK_NODECLASS |
                                   UA_NODEATTRIBUTESMASK_EXECUTABLE,
                                   UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASPROPERTY),
                                   UA_BROWSEDIRECTION_FORWARD);
    if(!method) {
        opResult->statusCode = UA_STATUSCODE_BADMETHODINVALID;
        return;
    }

    /* Get the object node. We only need the NodeClass attribute. But take all
     * references for now.
     *
     * TODO: Which references do we need actually? */
    const UA_Node *object =
        UA_NODESTORE_GET_SELECTIVE(server, &opRequest->objectId,
                                   UA_NODEATTRIBUTESMASK_NODECLASS,
                                   UA_REFERENCETYPESET_ALL,
                                   UA_BROWSEDIRECTION_BOTH);
    if(!object) {
        opResult->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN;
        UA_NODESTORE_RELEASE(server, method);
        return;
    }

    /* Synchronous execution */
    if(!method->methodNode.async) {
        callWithMethodAndObject(server, session, opRequest, opResult,
                                &method->methodNode, &object->objectNode);
        goto cleanup;
    }

    /* <-- Async method call --> */

    /* No AsyncResponse allocated so far */
    if(!*ar) {
        opResult->statusCode =
            UA_AsyncManager_createAsyncResponse(&server->asyncManager, server,
                            &session->sessionId, requestId, requestHandle,
                            UA_ASYNCOPERATIONTYPE_CALL, ar);
        if(opResult->statusCode != UA_STATUSCODE_GOOD)
            goto cleanup;
    }

    /* Create the Async Request to be taken by workers */
    opResult->statusCode =
        UA_AsyncManager_createAsyncOp(&server->asyncManager,
                                      server, *ar, opIndex, opRequest);

 cleanup:
    /* Release the method and object node */
    UA_NODESTORE_RELEASE(server, method);
    UA_NODESTORE_RELEASE(server, object);
}

void
Service_CallAsync(UA_Server *server, UA_Session *session, UA_UInt32 requestId,
                  const UA_CallRequest *request, UA_CallResponse *response,
                  UA_Boolean *finished) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session, "Processing CallRequestAsync");
    if(server->config.maxNodesPerMethodCall != 0 &&
        request->methodsToCallSize > server->config.maxNodesPerMethodCall) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return;
    }

    UA_AsyncResponse *ar = NULL;
    response->responseHeader.serviceResult =
        UA_Server_processServiceOperationsAsync(server, session, requestId,
                  request->requestHeader.requestHandle,
                  (UA_AsyncServiceOperation)Operation_CallMethodAsync,
                  &request->methodsToCallSize, &UA_TYPES[UA_TYPES_CALLMETHODREQUEST],
                  &response->resultsSize, &UA_TYPES[UA_TYPES_CALLMETHODRESULT], &ar);

    if(ar) {
        if(ar->opCountdown > 0) {
            /* Move all results to the AsyncResponse. The async operation
             * results will be overwritten when the workers return results. */
            ar->response.callResponse = *response;
            UA_CallResponse_init(response);
            *finished = false;
        } else {
            /* If there is a new AsyncResponse, ensure it has at least one
             * pending operation */
            UA_AsyncManager_removeAsyncResponse(&server->asyncManager, ar);
        }
    }
}
#endif

static void
Operation_CallMethod(UA_Server *server, UA_Session *session, void *context,
                     const UA_CallMethodRequest *request, UA_CallMethodResult *result) {
    /* Get the method node. We only need the nodeClass and executable attribute.
     * Take all forward hasProperty references to get the input/output argument
     * definition variables. */
    const UA_Node *method =
        UA_NODESTORE_GET_SELECTIVE(server, &request->methodId,
                                   UA_NODEATTRIBUTESMASK_NODECLASS |
                                   UA_NODEATTRIBUTESMASK_EXECUTABLE,
                                   UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASPROPERTY),
                                   UA_BROWSEDIRECTION_FORWARD);
    if(!method) {
        result->statusCode = UA_STATUSCODE_BADMETHODINVALID;
        return;
    }

    /* Get the object node. We only need the NodeClass attribute. But take all
     * references for now.
     *
     * TODO: Which references do we need actually? */
    const UA_Node *object =
        UA_NODESTORE_GET_SELECTIVE(server, &request->objectId,
                                   UA_NODEATTRIBUTESMASK_NODECLASS,
                                   UA_REFERENCETYPESET_ALL,
                                   UA_BROWSEDIRECTION_BOTH);
    if(!object) {
        result->statusCode = UA_STATUSCODE_BADNODEIDUNKNOWN;
        UA_NODESTORE_RELEASE(server, method);
        return;
    }

    /* Continue with method and object as context */
    callWithMethodAndObject(server, session, request, result,
                            &method->methodNode, &object->objectNode);

    /* Release the method and object node */
    UA_NODESTORE_RELEASE(server, method);
    UA_NODESTORE_RELEASE(server, object);
}

void Service_Call(UA_Server *server, UA_Session *session,
                  const UA_CallRequest *request, UA_CallResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session, "Processing CallRequest");
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    if(server->config.maxNodesPerMethodCall != 0 &&
       request->methodsToCallSize > server->config.maxNodesPerMethodCall) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return;
    }

    response->responseHeader.serviceResult =
        UA_Server_processServiceOperations(server, session,
                  (UA_ServiceOperation)Operation_CallMethod, NULL,
                  &request->methodsToCallSize, &UA_TYPES[UA_TYPES_CALLMETHODREQUEST],
                  &response->resultsSize, &UA_TYPES[UA_TYPES_CALLMETHODRESULT]);
}

UA_CallMethodResult
UA_Server_call(UA_Server *server, const UA_CallMethodRequest *request) {
    UA_CallMethodResult result;
    UA_CallMethodResult_init(&result);
    UA_LOCK(&server->serviceMutex);
    Operation_CallMethod(server, &server->adminSession, NULL, request, &result);
    UA_UNLOCK(&server->serviceMutex);
    return result;
}

#endif /* UA_ENABLE_METHODCALLS */

/**** amalgamated original file "/src/server/ua_services_session.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014-2017 (c) Florian Palm
 *    Copyright 2014-2016 (c) Sten Grüner
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015 (c) Oleksiy Vasylyev
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017-2018 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2019 (c) Kalycito Infotech Private Limited
 *    Copyright 2018-2020 (c) HMS Industrial Networks AB (Author: Jonas Green)
 */


/* Delayed callback to free the session memory */
static void
removeSessionCallback(UA_Server *server, session_list_entry *entry) {
    UA_LOCK(&server->serviceMutex);
    UA_Session_clear(&entry->session, server);
    UA_UNLOCK(&server->serviceMutex);
    UA_free(entry);
}

void
UA_Server_removeSession(UA_Server *server, session_list_entry *sentry,
                        UA_ShutdownReason shutdownReason) {
    UA_Session *session = &sentry->session;

    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Remove the Subscriptions */
#ifdef UA_ENABLE_SUBSCRIPTIONS
    UA_Subscription *sub, *tempsub;
    TAILQ_FOREACH_SAFE(sub, &session->subscriptions, sessionListEntry, tempsub) {
        UA_Subscription_delete(server, sub);
    }

    UA_PublishResponseEntry *entry;
    while((entry = UA_Session_dequeuePublishReq(session))) {
        UA_PublishResponse_clear(&entry->response);
        UA_free(entry);
    }
#endif

    /* Callback into userland access control */
    if(server->config.accessControl.closeSession) {
        UA_UNLOCK(&server->serviceMutex);
        server->config.accessControl.
            closeSession(server, &server->config.accessControl,
                         &session->sessionId, session->context);
        UA_LOCK(&server->serviceMutex);
    }

    /* Detach the Session from the SecureChannel */
    UA_Session_detachFromSecureChannel(session);

    /* Deactivate the session */
    if(sentry->session.activated) {
        sentry->session.activated = false;
        server->activeSessionCount--;
    }

    /* Detach the session from the session manager and make the capacity
     * available */
    LIST_REMOVE(sentry, pointers);
    server->sessionCount--;

    switch(shutdownReason) {
    case UA_SHUTDOWNREASON_CLOSE:
    case UA_SHUTDOWNREASON_PURGE:
        break;
    case UA_SHUTDOWNREASON_TIMEOUT:
        server->serverDiagnosticsSummary.sessionTimeoutCount++;
        break;
    case UA_SHUTDOWNREASON_REJECT:
        server->serverDiagnosticsSummary.rejectedSessionCount++;
        break;
    case UA_SHUTDOWNREASON_SECURITYREJECT:
        server->serverDiagnosticsSummary.securityRejectedSessionCount++;
        break;
    case UA_SHUTDOWNREASON_ABORT:
        server->serverDiagnosticsSummary.sessionAbortCount++;
        break;
    default:
        UA_assert(false);
        break;
    }

    /* Add a delayed callback to remove the session when the currently
     * scheduled jobs have completed */
    sentry->cleanupCallback.callback = (UA_Callback)removeSessionCallback;
    sentry->cleanupCallback.application = server;
    sentry->cleanupCallback.context = sentry;
    UA_EventLoop *el = server->config.eventLoop;
    el->addDelayedCallback(el, &sentry->cleanupCallback);
}

UA_StatusCode
UA_Server_removeSessionByToken(UA_Server *server, const UA_NodeId *token,
                               UA_ShutdownReason shutdownReason) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    session_list_entry *entry;
    LIST_FOREACH(entry, &server->sessions, pointers) {
        if(UA_NodeId_equal(&entry->session.authenticationToken, token)) {
            UA_Server_removeSession(server, entry, shutdownReason);
            return UA_STATUSCODE_GOOD;
        }
    }
    return UA_STATUSCODE_BADSESSIONIDINVALID;
}

void
UA_Server_cleanupSessions(UA_Server *server, UA_DateTime nowMonotonic) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    session_list_entry *sentry, *temp;
    LIST_FOREACH_SAFE(sentry, &server->sessions, pointers, temp) {
        /* Session has timed out? */
        if(sentry->session.validTill >= nowMonotonic)
            continue;
        UA_LOG_INFO_SESSION(server->config.logging, &sentry->session,
                            "Session has timed out");
        UA_Server_removeSession(server, sentry, UA_SHUTDOWNREASON_TIMEOUT);
    }
}

/************/
/* Services */
/************/

UA_Session *
getSessionByToken(UA_Server *server, const UA_NodeId *token) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    session_list_entry *current = NULL;
    LIST_FOREACH(current, &server->sessions, pointers) {
        /* Token does not match */
        if(!UA_NodeId_equal(&current->session.authenticationToken, token))
            continue;

        /* Session has timed out */
        UA_EventLoop *el = server->config.eventLoop;
        UA_DateTime now = el->dateTime_nowMonotonic(el);
        if(now > current->session.validTill) {
            UA_LOG_INFO_SESSION(server->config.logging, &current->session,
                                "Client tries to use a session that has timed out");
            return NULL;
        }

        return &current->session;
    }

    return NULL;
}

UA_Session *
getSessionById(UA_Server *server, const UA_NodeId *sessionId) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    session_list_entry *current = NULL;
    LIST_FOREACH(current, &server->sessions, pointers) {
        /* Token does not match */
        if(!UA_NodeId_equal(&current->session.sessionId, sessionId))
            continue;

        /* Session has timed out */
        UA_EventLoop *el = server->config.eventLoop;
        UA_DateTime now = el->dateTime_nowMonotonic(el);
        if(now > current->session.validTill) {
            UA_LOG_INFO_SESSION(server->config.logging, &current->session,
                                "Client tries to use a session that has timed out");
            return NULL;
        }

        return &current->session;
    }

    if(UA_NodeId_equal(sessionId, &server->adminSession.sessionId))
        return &server->adminSession;

    return NULL;
}

static UA_StatusCode
signCreateSessionResponse(UA_Server *server, UA_SecureChannel *channel,
                          const UA_CreateSessionRequest *request,
                          UA_CreateSessionResponse *response) {
    if(channel->securityMode != UA_MESSAGESECURITYMODE_SIGN &&
       channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
        return UA_STATUSCODE_GOOD;

    const UA_SecurityPolicy *securityPolicy = channel->securityPolicy;
    UA_SignatureData *signatureData = &response->serverSignature;

    /* Prepare the signature */
    const UA_SecurityPolicySignatureAlgorithm *signAlg =
        &securityPolicy->asymmetricModule.cryptoModule.signatureAlgorithm;
    size_t signatureSize = signAlg->getLocalSignatureSize(channel->channelContext);
    UA_StatusCode retval = UA_String_copy(&signAlg->uri, &signatureData->algorithm);
    retval |= UA_ByteString_allocBuffer(&signatureData->signature, signatureSize);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Allocate a temp buffer */
    size_t dataToSignSize =
        request->clientCertificate.length + request->clientNonce.length;
    UA_ByteString dataToSign;
    retval = UA_ByteString_allocBuffer(&dataToSign, dataToSignSize);
    if(retval != UA_STATUSCODE_GOOD)
        return retval; /* signatureData->signature is cleaned up with the response */

    /* Sign the signature */
    memcpy(dataToSign.data, request->clientCertificate.data,
           request->clientCertificate.length);
    memcpy(dataToSign.data + request->clientCertificate.length,
           request->clientNonce.data, request->clientNonce.length);
    retval = securityPolicy->asymmetricModule.cryptoModule.signatureAlgorithm.
        sign(channel->channelContext, &dataToSign, &signatureData->signature);

    /* Clean up */
    UA_ByteString_clear(&dataToSign);
    return retval;
}

/* Creates and adds a session. But it is not yet attached to a secure channel. */
UA_StatusCode
UA_Server_createSession(UA_Server *server, UA_SecureChannel *channel,
                        const UA_CreateSessionRequest *request, UA_Session **session) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    if(server->sessionCount >= server->config.maxSessions) {
        UA_LOG_WARNING_CHANNEL(server->config.logging, channel,
                               "Could not create a Session - Server limits reached");
        return UA_STATUSCODE_BADTOOMANYSESSIONS;
    }

    session_list_entry *newentry = (session_list_entry*)
        UA_malloc(sizeof(session_list_entry));
    if(!newentry)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Initialize the Session */
    UA_Session_init(&newentry->session);
    newentry->session.sessionId = UA_NODEID_GUID(1, UA_Guid_random());
    newentry->session.authenticationToken = UA_NODEID_GUID(1, UA_Guid_random());

    newentry->session.timeout = server->config.maxSessionTimeout;
    if(request->requestedSessionTimeout <= server->config.maxSessionTimeout &&
       request->requestedSessionTimeout > 0)
        newentry->session.timeout = request->requestedSessionTimeout;

    /* Attach the session to the channel. But don't activate for now. */
    if(channel)
        UA_Session_attachToSecureChannel(&newentry->session, channel);

    UA_EventLoop *el = server->config.eventLoop;
    UA_DateTime now = el->dateTime_now(el);
    UA_DateTime nowMonotonic = el->dateTime_nowMonotonic(el);
    UA_Session_updateLifetime(&newentry->session, now, nowMonotonic);

    /* Add to the server */
    LIST_INSERT_HEAD(&server->sessions, newentry, pointers);
    server->sessionCount++;

    *session = &newentry->session;
    return UA_STATUSCODE_GOOD;
}

void
Service_CreateSession(UA_Server *server, UA_SecureChannel *channel,
                      const UA_CreateSessionRequest *request,
                      UA_CreateSessionResponse *response) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    UA_LOG_DEBUG_CHANNEL(server->config.logging, channel, "Trying to create session");

    if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
       channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
        /* Compare the clientCertificate with the remoteCertificate of the channel.
         * Both the clientCertificate of this request and the remoteCertificate
         * of the channel may contain a partial or a complete certificate chain.
         * The compareCertificate function of the channelModule will compare the
         * first certificate of each chain. The end certificate shall be located
         * first in the chain according to the OPC UA specification Part 6 (1.04),
         * chapter 6.2.3.*/
        UA_StatusCode retval = channel->securityPolicy->channelModule.
            compareCertificate(channel->channelContext, &request->clientCertificate);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING_CHANNEL(server->config.logging, channel,
                                   "The client certificate did not validate");
            response->responseHeader.serviceResult = UA_STATUSCODE_BADCERTIFICATEINVALID;
            return;
        }
    }

    UA_assert(channel->securityToken.channelId != 0);

    if(!UA_ByteString_equal(&channel->securityPolicy->policyUri,
                            &UA_SECURITY_POLICY_NONE_URI) &&
       request->clientNonce.length < 32) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADNONCEINVALID;
        return;
    }

    if(request->clientCertificate.length > 0) {
        response->responseHeader.serviceResult =
            UA_CertificateUtils_verifyApplicationURI(server->config.allowAllCertificateUris,
                                                     &request->clientCertificate,
                                                     &request->clientDescription.applicationUri);
        if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING_CHANNEL(server->config.logging, channel,
                                   "The client's ApplicationURI did not match the certificate");
            server->serverDiagnosticsSummary.securityRejectedSessionCount++;
            server->serverDiagnosticsSummary.rejectedSessionCount++;
            return;
        }
    }

    /* Create the Session */
    UA_Session *newSession = NULL;
    response->responseHeader.serviceResult =
        UA_Server_createSession(server, channel, request, &newSession);
    if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_CHANNEL(server->config.logging, channel,
                               "Processing CreateSessionRequest failed");
        server->serverDiagnosticsSummary.rejectedSessionCount++;
        return;
    }

    /* If the session name is empty, use the generated SessionId */
    response->responseHeader.serviceResult |=
        UA_String_copy(&request->sessionName, &newSession->sessionName);
    if(newSession->sessionName.length == 0)
        response->responseHeader.serviceResult |=
            UA_NodeId_print(&newSession->sessionId, &newSession->sessionName);

    response->responseHeader.serviceResult |= UA_Session_generateNonce(newSession);
    newSession->maxResponseMessageSize = request->maxResponseMessageSize;
    newSession->maxRequestMessageSize = channel->config.localMaxMessageSize;
    response->responseHeader.serviceResult |=
        UA_ApplicationDescription_copy(&request->clientDescription,
                                       &newSession->clientDescription);

#ifdef UA_ENABLE_DIAGNOSTICS
    response->responseHeader.serviceResult |=
        UA_String_copy(&request->serverUri, &newSession->diagnostics.serverUri);
    response->responseHeader.serviceResult |=
        UA_String_copy(&request->endpointUrl, &newSession->diagnostics.endpointUrl);
#endif

    /* Prepare the response */
    response->sessionId = newSession->sessionId;
    response->revisedSessionTimeout = (UA_Double)newSession->timeout;
    response->authenticationToken = newSession->authenticationToken;
    response->responseHeader.serviceResult |=
        UA_ByteString_copy(&newSession->serverNonce, &response->serverNonce);

    /* Copy the server's endpointdescriptions into the response */
    response->responseHeader.serviceResult =
        setCurrentEndPointsArray(server, request->endpointUrl, NULL, 0,
                                 &response->serverEndpoints,
                                 &response->serverEndpointsSize);
    if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
        UA_Server_removeSessionByToken(server, &newSession->authenticationToken,
                                       UA_SHUTDOWNREASON_REJECT);
        return;
    }

    /* Return the server certificate from the SecurityPolicy of the current
     * channel. Or, if the channel is unencrypted, return the standard policy
     * used for usertoken encryption. */
    const UA_SecurityPolicy *sp = channel->securityPolicy;
    if(UA_String_equal(&UA_SECURITY_POLICY_NONE_URI, &sp->policyUri) ||
       sp->localCertificate.length == 0)
        sp = getDefaultEncryptedSecurityPolicy(server);
    if(sp)
        response->responseHeader.serviceResult |=
            UA_ByteString_copy(&sp->localCertificate, &response->serverCertificate);

    /* Sign the signature */
    response->responseHeader.serviceResult |=
       signCreateSessionResponse(server, channel, request, response);

    /* Failure -> remove the session */
    if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
        UA_Server_removeSessionByToken(server, &newSession->authenticationToken,
                                       UA_SHUTDOWNREASON_REJECT);
        return;
    }

#ifdef UA_ENABLE_DIAGNOSTICS
    UA_EventLoop *el = server->config.eventLoop;
    newSession->diagnostics.clientConnectionTime = el->dateTime_now(el);
    newSession->diagnostics.clientLastContactTime =
        newSession->diagnostics.clientConnectionTime;

    /* Create the object in the information model */
    createSessionObject(server, newSession);
#endif

    UA_LOG_INFO_SESSION(server->config.logging, newSession, "Session created");
}

static UA_StatusCode
checkCertificateSignature(const UA_Server *server, const UA_SecurityPolicy *securityPolicy,
                          void *channelContext, const UA_ByteString *serverNonce,
                          const UA_SignatureData *signature,
                          const bool isUserTokenSignature) {
    /* Check for zero signature length */
    if(signature->signature.length == 0) {
        if(isUserTokenSignature)
            return UA_STATUSCODE_BADUSERSIGNATUREINVALID;
        return UA_STATUSCODE_BADAPPLICATIONSIGNATUREINVALID;
    }

    if(!securityPolicy)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Server certificate */
    const UA_ByteString *localCertificate = &securityPolicy->localCertificate;
    /* Data to verify is calculated by appending the serverNonce to the local certificate */
    UA_ByteString dataToVerify;
    size_t dataToVerifySize = localCertificate->length + serverNonce->length;
    UA_StatusCode retval = UA_ByteString_allocBuffer(&dataToVerify, dataToVerifySize);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    memcpy(dataToVerify.data, localCertificate->data, localCertificate->length);
    memcpy(dataToVerify.data + localCertificate->length,
           serverNonce->data, serverNonce->length);
    retval = securityPolicy->asymmetricModule.cryptoModule.signatureAlgorithm.
        verify(channelContext, &dataToVerify, &signature->signature);
    UA_ByteString_clear(&dataToVerify);
    if(retval != UA_STATUSCODE_GOOD) {
        if(isUserTokenSignature)
            retval = UA_STATUSCODE_BADUSERSIGNATUREINVALID;
        else
            retval = UA_STATUSCODE_BADAPPLICATIONSIGNATUREINVALID;
    }
    return retval;
}

static void
selectEndpointAndTokenPolicy(UA_Server *server, UA_SecureChannel *channel,
                             const UA_ExtensionObject *identityToken,
                             const UA_EndpointDescription **ed,
                             const UA_UserTokenPolicy **utp,
                             const UA_SecurityPolicy **tokenSp) {
    for(size_t i = 0; i < server->config.endpointsSize; ++i) {
        const UA_EndpointDescription *desc = &server->config.endpoints[i];

        /* Match the Security Mode */
        if(desc->securityMode != channel->securityMode)
            continue;

        /* Match the SecurityPolicy of the endpoint with the current channel */
        if(!UA_String_equal(&desc->securityPolicyUri, &channel->securityPolicy->policyUri))
            continue;

        /* If no UserTokenPolicies are configured in the endpoint, then use
         * those of the AccessControl plugin. */
        size_t identPoliciesSize = desc->userIdentityTokensSize;
        const UA_UserTokenPolicy *identPolicies = desc->userIdentityTokens;
        if(identPoliciesSize == 0) {
            identPoliciesSize = server->config.accessControl.userTokenPoliciesSize;
            identPolicies = server->config.accessControl.userTokenPolicies;
        }

        /* Match the UserTokenType */
        const UA_DataType *tokenDataType = identityToken->content.decoded.type;
        for(size_t j = 0; j < identPoliciesSize ; j++) {
            const UA_UserTokenPolicy *pol = &identPolicies[j];

            if(!UA_String_equal(&desc->securityPolicyUri, &pol->securityPolicyUri))
                continue;

            /* Part 4, Section 5.6.3.2, Table 17: A NULL or empty
             * UserIdentityToken should be treated as Anonymous */
            if(identityToken->encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY &&
               pol->tokenType == UA_USERTOKENTYPE_ANONYMOUS) {
                *ed = desc;
                *utp = pol;
                return;
            }

            /* Expect decoded content if not anonymous */
            if(!tokenDataType)
                continue;

            if(pol->tokenType == UA_USERTOKENTYPE_ANONYMOUS) {
                if(tokenDataType != &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN])
                    continue;
            } else if(pol->tokenType == UA_USERTOKENTYPE_USERNAME) {
                if(tokenDataType != &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN])
                    continue;
            } else if(pol->tokenType == UA_USERTOKENTYPE_CERTIFICATE) {
                if(tokenDataType != &UA_TYPES[UA_TYPES_X509IDENTITYTOKEN])
                    continue;
            } else if(pol->tokenType == UA_USERTOKENTYPE_ISSUEDTOKEN) {
                if(tokenDataType != &UA_TYPES[UA_TYPES_ISSUEDIDENTITYTOKEN])
                    continue;
            } else {
                continue;
            }

            /* All valid token data types start with a string policyId */
            UA_AnonymousIdentityToken *token = (UA_AnonymousIdentityToken*)
                identityToken->content.decoded.data;

            /* In setCurrentEndPointsArray we prepend the policyId with the
             * security mode to make it unique. Remove that here. */
            if(pol->policyId.length > token->policyId.length)
                continue;
            UA_String tmpId = token->policyId;
            tmpId.length = pol->policyId.length;
            if(!UA_String_equal(&tmpId, &pol->policyId))
                continue;

            /* Match found */
            *ed = desc;
            *utp = pol;

            /* Set the SecurityPolicy used to encrypt the token. If the
             * userTokenPolicy doesn't specify a security policy the security
             * policy of the secure channel is used. */
            *tokenSp = channel->securityPolicy;
            if(pol->securityPolicyUri.length > 0)
                *tokenSp = getSecurityPolicyByUri(server, &pol->securityPolicyUri);

            /* If the server does not allow unencrypted passwords, select the
             * default encrypted policy for the UserTokenPolicy */
#ifdef UA_ENABLE_ENCRYPTION
            if(!*tokenSp ||
               (!server->config.allowNonePolicyPassword &&
                ((*tokenSp)->localCertificate.length == 0 ||
                 UA_String_equal(&UA_SECURITY_POLICY_NONE_URI, &(*tokenSp)->policyUri))))
                *tokenSp = getDefaultEncryptedSecurityPolicy(server);
#endif

            /* Found SecurityPolicy and UserTokenPoliy. Stop here. */
            return;
        }
    }
}

static UA_StatusCode
decryptUserNamePW(UA_Server *server, UA_Session *session,
                  const UA_SecurityPolicy *sp,
                  UA_UserNameIdentityToken *userToken) {
    /* If SecurityPolicy is None there shall be no EncryptionAlgorithm  */
    if(UA_String_equal(&sp->policyUri, &UA_SECURITY_POLICY_NONE_URI)) {
        if(userToken->encryptionAlgorithm.length > 0)
            return UA_STATUSCODE_BADIDENTITYTOKENINVALID;

        UA_LOG_WARNING_SESSION(server->config.logging, session, "ActivateSession: "
                               "Received an unencrypted username/passwort. "
                               "Is the server misconfigured to allow that?");
        return UA_STATUSCODE_GOOD;
    }

    /* Test if the correct encryption algorithm is used */
    if(!UA_String_equal(&userToken->encryptionAlgorithm,
                        &sp->asymmetricModule.cryptoModule.encryptionAlgorithm.uri))
        return UA_STATUSCODE_BADIDENTITYTOKENINVALID;

    /* Encrypted password -- Create a temporary channel context.
     * TODO: We should not need a ChannelContext at all for asymmetric
     * decryption where the remote certificate is not used. */
    void *tempChannelContext = NULL;
    UA_UNLOCK(&server->serviceMutex);
    UA_StatusCode res =
        sp->channelModule.newContext(sp, &sp->localCertificate, &tempChannelContext);
    UA_LOCK(&server->serviceMutex);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_SESSION(server->config.logging, session,
                               "ActivateSession: Failed to create a "
                               "context for the SecurityPolicy %.*s",
                               (int)sp->policyUri.length,
                               sp->policyUri.data);
        return res;
    }

    UA_UInt32 secretLen = 0;
    UA_ByteString secret, tokenNonce;
    size_t tokenpos = 0;
    size_t offset = 0;
    UA_ByteString *sn = &session->serverNonce;
    const UA_SecurityPolicyEncryptionAlgorithm *asymEnc =
        &sp->asymmetricModule.cryptoModule.encryptionAlgorithm;

    res = UA_STATUSCODE_BADIDENTITYTOKENINVALID;

    /* Decrypt the secret */
    if(UA_ByteString_copy(&userToken->password, &secret) != UA_STATUSCODE_GOOD ||
       asymEnc->decrypt(tempChannelContext, &secret) != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* The secret starts with a UInt32 length for the content */
    if(UA_UInt32_decodeBinary(&secret, &offset,
                              &secretLen) != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* The decrypted data must be large enough to include the Encrypted Token
     * Secret Format and the length field must indicate enough data to include
     * the server nonce. */
    if(secret.length < sizeof(UA_UInt32) + sn->length ||
       secret.length < sizeof(UA_UInt32) + secretLen ||
       secretLen < sn->length)
        goto cleanup;

    /* If the Encrypted Token Secret contains padding, the padding must be
     * zeroes according to the 1.04.1 specification errata, chapter 3. */
    for(size_t i = sizeof(UA_UInt32) + secretLen; i < secret.length; i++) {
        if(secret.data[i] != 0)
            goto cleanup;
    }

    /* The server nonce must match according to the 1.04.1 specification errata,
     * chapter 3. */
    tokenpos = sizeof(UA_UInt32) + secretLen - sn->length;
    tokenNonce.length = sn->length;
    tokenNonce.data = &secret.data[tokenpos];
    if(!UA_ByteString_equal(sn, &tokenNonce))
        goto cleanup;

    /* The password was decrypted successfully. Replace usertoken with the
     * decrypted password. The encryptionAlgorithm and policyId fields are left
     * in the UserToken as an indication for the AccessControl plugin that
     * evaluates the decrypted content. */
    memcpy(userToken->password.data,
           &secret.data[sizeof(UA_UInt32)], secretLen - sn->length);
    userToken->password.length = secretLen - sn->length;
    res = UA_STATUSCODE_GOOD;

 cleanup:
    UA_ByteString_clear(&secret);

    /* Remove the temporary channel context */
    UA_UNLOCK(&server->serviceMutex);
    sp->channelModule.deleteContext(tempChannelContext);
    UA_LOCK(&server->serviceMutex);

    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_SESSION(server->config.logging, session,
                               "ActivateSession: Failed to decrypt the "
                               "password with the StatusCode %s",
                               UA_StatusCode_name(res));
    }
    return res;
}

static UA_StatusCode
checkActivateSessionX509(UA_Server *server, UA_Session *session,
                         const UA_SecurityPolicy *sp, UA_X509IdentityToken* token,
                         const UA_SignatureData *tokenSignature) {
    /* The SecurityPolicy must be None */
    if(UA_String_equal(&sp->policyUri, &UA_SECURITY_POLICY_NONE_URI))
        return UA_STATUSCODE_BADIDENTITYTOKENINVALID;

    /* We need a channel context with the user certificate in order to reuse
     * the signature checking code. */
    void *tempChannelContext;
    UA_UNLOCK(&server->serviceMutex);
    UA_StatusCode res = sp->channelModule.
        newContext(sp, &token->certificateData, &tempChannelContext);
    UA_LOCK(&server->serviceMutex);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_SESSION(server->config.logging, session,
                               "ActivateSession: Failed to create a context "
                               "for the SecurityPolicy %.*s",
                               (int)sp->policyUri.length,
                               sp->policyUri.data);
        return res;
    }

    /* Check the user token signature */
    res = checkCertificateSignature(server, sp, tempChannelContext,
                                    &session->serverNonce, tokenSignature, true);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_SESSION(server->config.logging, session,
                               "ActivateSession: User token signature check "
                               "failed with StatusCode %s", UA_StatusCode_name(res));
    }

    /* Delete the temporary channel context */
    UA_UNLOCK(&server->serviceMutex);
    sp->channelModule.deleteContext(tempChannelContext);
    UA_LOCK(&server->serviceMutex);
    return res;
}

/* TODO: Check all of the following: The Server shall verify that the
 * Certificate the Client used to create the new SecureChannel is the same as
 * the Certificate used to create the original SecureChannel. In addition, the
 * Server shall verify that the Client supplied a UserIdentityToken that is
 * identical to the token currently associated with the Session. Once the Server
 * accepts the new SecureChannel it shall reject requests sent via the old
 * SecureChannel. */

void
Service_ActivateSession(UA_Server *server, UA_SecureChannel *channel,
                        const UA_ActivateSessionRequest *req,
                        UA_ActivateSessionResponse *resp) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    const UA_EndpointDescription *ed = NULL;
    const UA_UserTokenPolicy *utp = NULL;
    const UA_SecurityPolicy *tokenSp = NULL;
    UA_String *tmpLocaleIds;

    /* Get the session */
    UA_Session *session = getSessionByToken(server, &req->requestHeader.authenticationToken);
    if(!session) {
        UA_LOG_WARNING_CHANNEL(server->config.logging, channel,
                               "ActivateSession: Session not found");
        resp->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
        goto rejected;
    }

    /* Part 4, §5.6.3: When the ActivateSession Service is called for the
     * first time then the Server shall reject the request if the
     * SecureChannel is not same as the one associated with the
     * CreateSession request. Subsequent calls to ActivateSession may be
     * associated with different SecureChannels. */
    if(!session->activated && session->channel != channel) {
        UA_LOG_WARNING_CHANNEL(server->config.logging, channel,
                               "ActivateSession: The Session has to be initially activated "
                               "on the SecureChannel that created it");
        resp->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
        goto rejected;
    }

    /* Has the session timed out? */
    UA_EventLoop *el = server->config.eventLoop;
    UA_DateTime nowMonotonic = el->dateTime_nowMonotonic(el);
    if(session->validTill < nowMonotonic) {
        UA_LOG_WARNING_SESSION(server->config.logging, session,
                               "ActivateSession: The Session has timed out");
        resp->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
        goto rejected;
    }

    /* Check the client signature */
    if(channel->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
       channel->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
        resp->responseHeader.serviceResult =
            checkCertificateSignature(server, channel->securityPolicy,
                                      channel->channelContext,
                                      &session->serverNonce,
                                      &req->clientSignature, false);
        if(resp->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING_SESSION(server->config.logging, session,
                                   "ActivateSession: Client signature check failed "
                                   "with StatusCode %s",
                                   UA_StatusCode_name(resp->responseHeader.serviceResult));
            goto securityRejected;
        }
    }

    /* Find the matching Endpoint with UserTokenPolicy.
     * Also sets the SecurityPolicy used to encrypt the token. */
    selectEndpointAndTokenPolicy(server, channel, &req->userIdentityToken,
                                 &ed, &utp, &tokenSp);
    if(!ed || !tokenSp) {
        resp->responseHeader.serviceResult = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
        goto rejected;
    }

    if(utp->tokenType == UA_USERTOKENTYPE_USERNAME) {
        /* If it is a UserNameIdentityToken, the password may be encrypted */
       UA_UserNameIdentityToken *userToken = (UA_UserNameIdentityToken *)
           req->userIdentityToken.content.decoded.data;
       resp->responseHeader.serviceResult =
           decryptUserNamePW(server, session, tokenSp, userToken);
       if(resp->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
           goto securityRejected;
    } else if(utp->tokenType == UA_USERTOKENTYPE_CERTIFICATE) {
        /* If it is a X509IdentityToken, check the userTokenSignature. Note this
         * only validates that the user has the corresponding private key for
         * the given user cetificate. Checking whether the user certificate is
         * trusted has to be implemented in the access control plugin. The
         * entire token is forwarded in the call to ActivateSession. */
        UA_X509IdentityToken* token = (UA_X509IdentityToken*)
            req->userIdentityToken.content.decoded.data;
       resp->responseHeader.serviceResult =
           checkActivateSessionX509(server, session, tokenSp,
                                    token, &req->userTokenSignature);
       if(resp->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
           goto securityRejected;
    }

    /* Callback into userland access control */
    UA_UNLOCK(&server->serviceMutex);
    resp->responseHeader.serviceResult = server->config.accessControl.
        activateSession(server, &server->config.accessControl, ed,
                        &channel->remoteCertificate, &session->sessionId,
                        &req->userIdentityToken, &session->context);
    UA_LOCK(&server->serviceMutex);
    if(resp->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_SESSION(server->config.logging, session,
                               "ActivateSession: The AccessControl "
                               "plugin denied the activation with the StatusCode %s",
                               UA_StatusCode_name(resp->responseHeader.serviceResult));
        goto securityRejected;
    }

    /* Attach the session to the currently used channel if the session isn't
     * attached to a channel or if the session is activated on a different
     * channel than it is attached to. */
    if(!session->channel || session->channel != channel) {
        /* Attach the new SecureChannel, the old channel will be detached if present */
        UA_Session_attachToSecureChannel(session, channel);
        UA_LOG_INFO_SESSION(server->config.logging, session,
                            "ActivateSession: Session attached to new channel");
    }

    /* Generate a new session nonce for the next time ActivateSession is called */
    resp->responseHeader.serviceResult = UA_Session_generateNonce(session);
    resp->responseHeader.serviceResult |=
        UA_ByteString_copy(&session->serverNonce, &resp->serverNonce);
    if(resp->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
        UA_Session_detachFromSecureChannel(session);
        UA_LOG_WARNING_SESSION(server->config.logging, session,
                               "ActivateSession: Could not generate the server nonce");
        goto rejected;
    }

    /* Set the Locale */
    if(req->localeIdsSize > 0) {
        /* Part 4, §5.6.3.2: This parameter only needs to be specified during
         * the first call to ActivateSession during a single application
         * Session. If it is not specified the Server shall keep using the
         * current localeIds for the Session. */
        resp->responseHeader.serviceResult |=
            UA_Array_copy(req->localeIds, req->localeIdsSize,
                          (void**)&tmpLocaleIds, &UA_TYPES[UA_TYPES_STRING]);
        if(resp->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
            UA_Session_detachFromSecureChannel(session);
            UA_LOG_WARNING_SESSION(server->config.logging, session,
                                   "ActivateSession: Could not store the Session LocaleIds");
            goto rejected;
        }
        UA_Array_delete(session->localeIds, session->localeIdsSize,
                        &UA_TYPES[UA_TYPES_STRING]);
        session->localeIds = tmpLocaleIds;
        session->localeIdsSize = req->localeIdsSize;
    }

    /* Update the Session lifetime */
    nowMonotonic = el->dateTime_nowMonotonic(el);
    UA_DateTime now = el->dateTime_now(el);
    UA_Session_updateLifetime(session, now, nowMonotonic);

    /* Activate the session */
    if(!session->activated) {
        session->activated = true;
        server->activeSessionCount++;
        server->serverDiagnosticsSummary.cumulatedSessionCount++;
    }

    /* Store the ClientUserId. tokenType can be NULL for the anonymous user. */
    UA_String_clear(&session->clientUserIdOfSession);
    const UA_DataType *tokenType = req->userIdentityToken.content.decoded.type;
    if(tokenType == &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]) {
        const UA_UserNameIdentityToken *userToken = (UA_UserNameIdentityToken*)
            req->userIdentityToken.content.decoded.data;
        UA_String_copy(&userToken->userName, &session->clientUserIdOfSession);
    } else if(tokenType == &UA_TYPES[UA_TYPES_X509IDENTITYTOKEN]) {
        UA_X509IdentityToken* userCertToken = (UA_X509IdentityToken*)
            req->userIdentityToken.content.decoded.data;
        UA_CertificateUtils_getSubjectName(&session->clientUserIdOfSession,
                                           &userCertToken->certificateData);
    } else {
        /* TODO: Handle issued token */
    }

#ifdef UA_ENABLE_DIAGNOSTICS
    /* Add the ClientUserId to the diagnostics history */
    UA_SessionSecurityDiagnosticsDataType *ssd = &session->securityDiagnostics;
    UA_StatusCode res =
        UA_Array_appendCopy((void**)&ssd->clientUserIdHistory,
                            &ssd->clientUserIdHistorySize,
                            &ssd->clientUserIdOfSession,
                            &UA_TYPES[UA_TYPES_STRING]);
    (void)res;

    /* Store the auth mechanism */
    UA_String_clear(&ssd->authenticationMechanism);
    switch(utp->tokenType) {
    case UA_USERTOKENTYPE_ANONYMOUS:
        ssd->authenticationMechanism = UA_STRING_ALLOC("Anonymous"); break;
    case UA_USERTOKENTYPE_USERNAME:
        ssd->authenticationMechanism = UA_STRING_ALLOC("UserName"); break;
    case UA_USERTOKENTYPE_CERTIFICATE:
        ssd->authenticationMechanism = UA_STRING_ALLOC("Certificate"); break;
    case UA_USERTOKENTYPE_ISSUEDTOKEN:
        ssd->authenticationMechanism = UA_STRING_ALLOC("IssuedToken"); break;
    default: break;
    }
#endif

    /* Log the user for which the Session was activated */
    UA_LOG_INFO_SESSION(server->config.logging, session,
                        "ActivateSession: Session activated with ClientUserId \"%.*s\"",
                        (int)session->clientUserIdOfSession.length,
                        session->clientUserIdOfSession.data);
    return;

securityRejected:
    server->serverDiagnosticsSummary.securityRejectedSessionCount++;
rejected:
    server->serverDiagnosticsSummary.rejectedSessionCount++;
}

void
Service_CloseSession(UA_Server *server, UA_SecureChannel *channel,
                     const UA_CloseSessionRequest *request,
                     UA_CloseSessionResponse *response) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Part 4, 5.6.4: When the CloseSession Service is called before the Session
     * is successfully activated, the Server shall reject the request if the
     * SecureChannel is not the same as the one associated with the
     * CreateSession request.
     *
     * A non-activated Session is already bound to the SecureChannel that
     * created the Session. */
    UA_Session *session = NULL;
    response->responseHeader.serviceResult =
        getBoundSession(server, channel, &request->requestHeader.authenticationToken, &session);
    if(!session && response->responseHeader.serviceResult == UA_STATUSCODE_GOOD)
        response->responseHeader.serviceResult = UA_STATUSCODE_BADSESSIONIDINVALID;
    if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_CHANNEL(server->config.logging, channel,
                               "CloseSession: No Session activated to the SecureChannel");
        return;
    }

    UA_assert(session); /* Assured by the previous section */
    UA_LOG_INFO_SESSION(server->config.logging, session, "Closing the Session");

#ifdef UA_ENABLE_SUBSCRIPTIONS
    /* If Subscriptions are not deleted, detach them from the Session */
    if(!request->deleteSubscriptions) {
        UA_Subscription *sub, *sub_tmp;
        TAILQ_FOREACH_SAFE(sub, &session->subscriptions, sessionListEntry, sub_tmp) {
            UA_LOG_INFO_SUBSCRIPTION(server->config.logging, sub,
                                     "Detaching the Subscription from the Session");
            UA_Session_detachSubscription(server, session, sub, true);
        }
    }
#endif

    /* Remove the sesison */
    response->responseHeader.serviceResult =
        UA_Server_removeSessionByToken(server, &session->authenticationToken,
                                       UA_SHUTDOWNREASON_CLOSE);
}

void Service_Cancel(UA_Server *server, UA_Session *session,
                    const UA_CancelRequest *request, UA_CancelResponse *response) {
    /* If multithreading is disabled, then there are no async services. If all
     * services are answered "right away", then there are no services that can
     * be cancelled. */
#if UA_MULTITHREADING >= 100
    response->cancelCount = UA_AsyncManager_cancel(server, session, request->requestHandle);
#endif

    /* Publish requests for Subscriptions are stored separately */
#ifdef UA_ENABLE_SUBSCRIPTIONS
    UA_PublishResponseEntry *pre, *pre_tmp;
    UA_PublishResponseEntry *prev = NULL;
    SIMPLEQ_FOREACH_SAFE(pre, &session->responseQueue, listEntry, pre_tmp) {
        /* Skip entry and set as the previous entry that is kept in the list */
        if(pre->response.responseHeader.requestHandle != request->requestHandle) {
            prev = pre;
            continue;
        }

        /* Dequeue */
        if(prev)
            SIMPLEQ_REMOVE_AFTER(&session->responseQueue, prev, listEntry);
        else
            SIMPLEQ_REMOVE_HEAD(&session->responseQueue, listEntry);
        session->responseQueueSize--;

        /* Send response and clean up */
        response->responseHeader.serviceResult = UA_STATUSCODE_BADREQUESTCANCELLEDBYCLIENT;
        sendResponse(server, session->channel, pre->requestId, (UA_Response *)response,
                     &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]);
        UA_PublishResponse_clear(&pre->response);
        UA_free(pre);

        /* Increase the CancelCount */
        response->cancelCount++;
    }
#endif
}

/**** amalgamated original file "/src/server/ua_services_attribute.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2014-2017 (c) Florian Palm
 *    Copyright 2015 (c) Christian Fimmers
 *    Copyright 2015-2016 (c) Chris Iatrou
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2015 (c) wuyangtang
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2016 (c) Lorenz Haas
 *    Copyright 2017 (c) frax2222
 *    Copyright 2017 (c) Thomas Bender
 *    Copyright 2017 (c) Julian Grothoff
 *    Copyright 2017-2020 (c) HMS Industrial Networks AB (Author: Jonas Green)
 *    Copyright 2017 (c) Henrik Norrman
 *    Copyright 2020 (c) Christian von Arnim, ISW University of Stuttgart  (for VDW and umati)
 */


#ifdef UA_ENABLE_HISTORIZING
#endif

static const UA_NodeAttributesMask attr2mask[28] = {
    UA_NODEATTRIBUTESMASK_NODEID,
    UA_NODEATTRIBUTESMASK_NODECLASS,
    UA_NODEATTRIBUTESMASK_BROWSENAME,
    UA_NODEATTRIBUTESMASK_DISPLAYNAME,
    UA_NODEATTRIBUTESMASK_DESCRIPTION,
    UA_NODEATTRIBUTESMASK_WRITEMASK,
    UA_NODEATTRIBUTESMASK_USERWRITEMASK,
    UA_NODEATTRIBUTESMASK_ISABSTRACT,
    UA_NODEATTRIBUTESMASK_SYMMETRIC,
    UA_NODEATTRIBUTESMASK_INVERSENAME,
    UA_NODEATTRIBUTESMASK_CONTAINSNOLOOPS,
    UA_NODEATTRIBUTESMASK_EVENTNOTIFIER,
    UA_NODEATTRIBUTESMASK_VALUE,
    UA_NODEATTRIBUTESMASK_DATATYPE,
    UA_NODEATTRIBUTESMASK_VALUERANK,
    UA_NODEATTRIBUTESMASK_ARRAYDIMENSIONS,
    UA_NODEATTRIBUTESMASK_ACCESSLEVEL,
    UA_NODEATTRIBUTESMASK_USERACCESSLEVEL,
    UA_NODEATTRIBUTESMASK_MINIMUMSAMPLINGINTERVAL,
    UA_NODEATTRIBUTESMASK_HISTORIZING,
    UA_NODEATTRIBUTESMASK_EXECUTABLE,
    UA_NODEATTRIBUTESMASK_USEREXECUTABLE,
    UA_NODEATTRIBUTESMASK_DATATYPEDEFINITION,
    UA_NODEATTRIBUTESMASK_ROLEPERMISSIONS,
    UA_NODEATTRIBUTESMASK_ROLEPERMISSIONS,
    UA_NODEATTRIBUTESMASK_ACCESSRESTRICTIONS,
    UA_NODEATTRIBUTESMASK_ACCESSLEVEL
};

static UA_UInt32
attributeId2AttributeMask(UA_AttributeId id) {
    if(UA_UNLIKELY(id > UA_ATTRIBUTEID_ACCESSLEVELEX))
        return UA_NODEATTRIBUTESMASK_NONE;
    return attr2mask[id];
}

/******************/
/* Access Control */
/******************/

/* Session for read operations can be NULL. For example for a MonitoredItem
 * where the underlying Subscription was detached during CloseSession. */

static UA_UInt32
getUserWriteMask(UA_Server *server, const UA_Session *session,
                 const UA_NodeHead *head) {
    if(session == &server->adminSession)
        return 0xFFFFFFFF; /* the local admin user has all rights */
    UA_UInt32 mask = head->writeMask;
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    UA_UNLOCK(&server->serviceMutex);
    mask &= server->config.accessControl.
        getUserRightsMask(server, &server->config.accessControl,
                          session ? &session->sessionId : NULL,
                          session ? session->context : NULL,
                          &head->nodeId, head->context);
    UA_LOCK(&server->serviceMutex);
    return mask;
}

static UA_Byte
getAccessLevel(UA_Server *server, const UA_Session *session,
               const UA_VariableNode *node) {
    if(session == &server->adminSession)
        return 0xFF; /* the local admin user has all rights */
    return node->accessLevel;
}

static UA_Byte
getUserAccessLevel(UA_Server *server, const UA_Session *session,
                   const UA_VariableNode *node) {
    if(session == &server->adminSession)
        return 0xFF; /* the local admin user has all rights */
    UA_Byte retval = node->accessLevel;
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    UA_UNLOCK(&server->serviceMutex);
    retval &= server->config.accessControl.
        getUserAccessLevel(server, &server->config.accessControl,
                           session ? &session->sessionId : NULL,
                           session ? session->context : NULL,
                           &node->head.nodeId, node->head.context);
    UA_LOCK(&server->serviceMutex);
    return retval;
}

static UA_Boolean
getUserExecutable(UA_Server *server, const UA_Session *session,
                  const UA_MethodNode *node) {
    if(session == &server->adminSession)
        return true; /* the local admin user has all rights */
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    UA_UNLOCK(&server->serviceMutex);
    UA_Boolean userExecutable = node->executable;
    userExecutable &=
        server->config.accessControl.
        getUserExecutable(server, &server->config.accessControl,
                          session ? &session->sessionId : NULL,
                          session ? session->context : NULL,
                          &node->head.nodeId, node->head.context);
    UA_LOCK(&server->serviceMutex);
    return userExecutable;
}

/****************/
/* Read Service */
/****************/

static UA_StatusCode
readIsAbstractAttribute(const UA_Node *node, UA_Variant *v) {
    const UA_Boolean *isAbstract;
    switch(node->head.nodeClass) {
    case UA_NODECLASS_REFERENCETYPE:
        isAbstract = &node->referenceTypeNode.isAbstract;
        break;
    case UA_NODECLASS_OBJECTTYPE:
        isAbstract = &node->objectTypeNode.isAbstract;
        break;
    case UA_NODECLASS_VARIABLETYPE:
        isAbstract = &node->variableTypeNode.isAbstract;
        break;
    case UA_NODECLASS_DATATYPE:
        isAbstract = &node->dataTypeNode.isAbstract;
        break;
    default:
        return UA_STATUSCODE_BADATTRIBUTEIDINVALID;
    }

    return UA_Variant_setScalarCopy(v, isAbstract, &UA_TYPES[UA_TYPES_BOOLEAN]);
}

static UA_StatusCode
readValueAttributeFromNode(UA_Server *server, UA_Session *session,
                           const UA_VariableNode *vn, UA_DataValue *v,
                           UA_NumericRange *rangeptr) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    /* Update the value by the user callback */
    if(vn->value.data.callback.onRead) {
        UA_UNLOCK(&server->serviceMutex);
        vn->value.data.callback.onRead(server,
                                       session ? &session->sessionId : NULL,
                                       session ? session->context : NULL,
                                       &vn->head.nodeId, vn->head.context, rangeptr,
                                       &vn->value.data.value);
        UA_LOCK(&server->serviceMutex);
        vn = (const UA_VariableNode*)
            UA_NODESTORE_GET_SELECTIVE(server, &vn->head.nodeId,
                                       UA_NODEATTRIBUTESMASK_VALUE,
                                       UA_REFERENCETYPESET_NONE,
                                       UA_BROWSEDIRECTION_INVALID);
        if(!vn)
            return UA_STATUSCODE_BADNODEIDUNKNOWN;
    }

    /* Set the result */
    UA_StatusCode retval;
    if(!rangeptr) {
        retval = UA_DataValue_copy(&vn->value.data.value, v);
    } else {
        *v = vn->value.data.value; /* Copy timestamps */
        UA_Variant_init(&v->value);
        retval = UA_Variant_copyRange(&vn->value.data.value.value, &v->value, *rangeptr);
    }

    /* Clean up */
    if(vn->value.data.callback.onRead)
        UA_NODESTORE_RELEASE(server, (const UA_Node *)vn);
    return retval;
}

static UA_StatusCode
readValueAttributeFromDataSource(UA_Server *server, UA_Session *session,
                                 const UA_VariableNode *vn, UA_DataValue *v,
                                 UA_TimestampsToReturn timestamps,
                                 UA_NumericRange *rangeptr) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    if(!vn->value.dataSource.read)
        return UA_STATUSCODE_BADINTERNALERROR;
    UA_Boolean sourceTimeStamp = (timestamps == UA_TIMESTAMPSTORETURN_SOURCE ||
                                  timestamps == UA_TIMESTAMPSTORETURN_BOTH);
    UA_DataValue v2;
    UA_DataValue_init(&v2);
    UA_UNLOCK(&server->serviceMutex);
    UA_StatusCode retval = vn->value.dataSource.
        read(server,
             session ? &session->sessionId : NULL,
             session ? session->context : NULL,
             &vn->head.nodeId, vn->head.context,
             sourceTimeStamp, rangeptr, &v2);
    UA_LOCK(&server->serviceMutex);
    if(v2.hasValue && v2.value.storageType == UA_VARIANT_DATA_NODELETE) {
        retval = UA_DataValue_copy(&v2, v);
        UA_DataValue_clear(&v2);
    } else {
        *v = v2;
    }
    return retval;
}

static UA_StatusCode
readValueAttributeComplete(UA_Server *server, UA_Session *session,
                           const UA_VariableNode *vn, UA_TimestampsToReturn timestamps,
                           const UA_String *indexRange, UA_DataValue *v) {
    UA_EventLoop *el = server->config.eventLoop;

    /* Compute the index range */
    UA_NumericRange range;
    UA_NumericRange *rangeptr = NULL;
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(indexRange && indexRange->length > 0) {
        retval = UA_NumericRange_parse(&range, *indexRange);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
        rangeptr = &range;
    }

    switch(vn->valueBackend.backendType) {
        case UA_VALUEBACKENDTYPE_INTERNAL:
            retval = readValueAttributeFromNode(server, session, vn, v, rangeptr);
            //TODO change old structure to value backend
            break;
        case UA_VALUEBACKENDTYPE_DATA_SOURCE_CALLBACK:
            retval = readValueAttributeFromDataSource(server, session, vn, v,
                                                      timestamps, rangeptr);
            //TODO change old structure to value backend
            break;
        case UA_VALUEBACKENDTYPE_EXTERNAL:
            if(!vn->valueBackend.backend.external.callback.notificationRead) {
                retval = UA_STATUSCODE_BADNOTREADABLE;
                break;
            }
            retval = vn->valueBackend.backend.external.callback.
                notificationRead(server,
                                 session ? &session->sessionId : NULL,
                                 session ? session->context : NULL,
                                 &vn->head.nodeId, vn->head.context, rangeptr);
            if(retval != UA_STATUSCODE_GOOD)
                break;

            /* Set the result */
            if(rangeptr)
                retval = UA_DataValue_copyVariantRange(
                    *vn->valueBackend.backend.external.value, v, *rangeptr);
            else
                retval = UA_DataValue_copy(*vn->valueBackend.backend.external.value, v);
            break;
        case UA_VALUEBACKENDTYPE_NONE:
            /* Read the value */
            if(vn->valueSource == UA_VALUESOURCE_DATA)
                retval = readValueAttributeFromNode(server, session, vn, v, rangeptr);
            else
                retval = readValueAttributeFromDataSource(server, session, vn, v,
                                                          timestamps, rangeptr);
            /* end lagacy */
            break;
    }

    /* If not defined return a source timestamp of "now".
     * Static nodes always have the current time as source-time. */
    if(!v->hasSourceTimestamp) {
        v->sourceTimestamp = el->dateTime_now(el);
        v->hasSourceTimestamp = true;
    }

    /* Clean up */
    if(rangeptr)
        UA_free(range.dimensions);
    return retval;
}

UA_StatusCode
readValueAttribute(UA_Server *server, UA_Session *session,
                   const UA_VariableNode *vn, UA_DataValue *v) {
    return readValueAttributeComplete(server, session, vn,
                                      UA_TIMESTAMPSTORETURN_NEITHER, NULL, v);
}

static const UA_String binEncoding = {sizeof("Default Binary")-1, (UA_Byte*)"Default Binary"};
static const UA_String xmlEncoding = {sizeof("Default XML")-1, (UA_Byte*)"Default XML"};
static const UA_String jsonEncoding = {sizeof("Default JSON")-1, (UA_Byte*)"Default JSON"};

#define CHECK_NODECLASS(CLASS)                                  \
    if(!(node->head.nodeClass & (CLASS))) {                     \
        retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;           \
        break;                                                  \
    }

#ifdef UA_ENABLE_TYPEDESCRIPTION
static const UA_DataType *
findDataType(const UA_Node *node, const UA_DataTypeArray *customTypes) {
    for(size_t i = 0; i < UA_TYPES_COUNT; ++i) {
        if(UA_NodeId_equal(&UA_TYPES[i].typeId, &node->head.nodeId)) {
            return &UA_TYPES[i];
        }
    }

    // lookup custom type
    while(customTypes) {
        for(size_t i = 0; i < customTypes->typesSize; ++i) {
            if(UA_NodeId_equal(&customTypes->types[i].typeId, &node->head.nodeId))
                return &customTypes->types[i];
        }
        customTypes = customTypes->next;
    }
    return NULL;
}

static UA_StatusCode
getStructureDefinition(const UA_DataType *type, UA_StructureDefinition *def) {
    UA_StatusCode retval =
        UA_NodeId_copy(&type->binaryEncodingId, &def->defaultEncodingId);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    switch(type->typeKind) {
        case UA_DATATYPEKIND_STRUCTURE:
            def->structureType = UA_STRUCTURETYPE_STRUCTURE;
            def->baseDataType = UA_NODEID_NUMERIC(0, UA_NS0ID_STRUCTURE);
            break;
        case UA_DATATYPEKIND_OPTSTRUCT:
            def->structureType = UA_STRUCTURETYPE_STRUCTUREWITHOPTIONALFIELDS;
            def->baseDataType = UA_NODEID_NUMERIC(0, UA_NS0ID_STRUCTURE);
            break;
        case UA_DATATYPEKIND_UNION:
            def->structureType = UA_STRUCTURETYPE_UNION;
            def->baseDataType = UA_NODEID_NUMERIC(0, UA_NS0ID_UNION);
            break;
        default:
            return UA_STATUSCODE_BADENCODINGERROR;
    }
    def->fieldsSize = type->membersSize;
    def->fields = (UA_StructureField *)
        UA_calloc(def->fieldsSize, sizeof(UA_StructureField));
    if(!def->fields) {
        UA_NodeId_clear(&def->defaultEncodingId);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    for(size_t cnt = 0; cnt < def->fieldsSize; cnt++) {
        const UA_DataTypeMember *m = &type->members[cnt];
        def->fields[cnt].valueRank = (m->isArray) ? UA_VALUERANK_ONE_DIMENSION : UA_VALUERANK_SCALAR;
        def->fields[cnt].arrayDimensions = NULL;
        def->fields[cnt].arrayDimensionsSize = 0;
        def->fields[cnt].name = UA_STRING((char *)(uintptr_t)m->memberName);
        def->fields[cnt].description.locale = UA_STRING_NULL;
        def->fields[cnt].description.text = UA_STRING_NULL;
        def->fields[cnt].dataType = m->memberType->typeId;
        def->fields[cnt].maxStringLength = 0;
        def->fields[cnt].isOptional = m->isOptional;
    }
    return UA_STATUSCODE_GOOD;
}
#endif

/* Returns a datavalue that may point into the node via the
 * UA_VARIANT_DATA_NODELETE tag. Don't access the returned DataValue once the
 * node has been released! */
void
ReadWithNode(const UA_Node *node, UA_Server *server, UA_Session *session,
             UA_TimestampsToReturn timestampsToReturn,
             const UA_ReadValueId *id, UA_DataValue *v) {
    UA_LOG_NODEID_TRACE(&node->head.nodeId,
                        UA_LOG_TRACE_SESSION(server->config.logging, session,
                                             "Read attribute %"PRIi32 " of Node %.*s",
                                             id->attributeId, (int)nodeIdStr.length,
                                             nodeIdStr.data));

    /* Only Binary Encoding is supported */
    if(id->dataEncoding.name.length > 0 &&
       !UA_String_equal(&binEncoding, &id->dataEncoding.name)) {
        if(UA_String_equal(&xmlEncoding, &id->dataEncoding.name) ||
           UA_String_equal(&jsonEncoding, &id->dataEncoding.name))
           v->status = UA_STATUSCODE_BADDATAENCODINGUNSUPPORTED;
        else
           v->status = UA_STATUSCODE_BADDATAENCODINGINVALID;
        v->hasStatus = true;
        return;
    }

    /* Index range for an attribute other than value */
    if(id->indexRange.length > 0 && id->attributeId != UA_ATTRIBUTEID_VALUE) {
        v->hasStatus = true;
        v->status = UA_STATUSCODE_BADINDEXRANGENODATA;
        return;
    }

    /* Read the attribute */
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    switch(id->attributeId) {
    case UA_ATTRIBUTEID_NODEID:
        retval = UA_Variant_setScalarCopy(&v->value, &node->head.nodeId,
                                          &UA_TYPES[UA_TYPES_NODEID]);
        break;
    case UA_ATTRIBUTEID_NODECLASS:
        retval = UA_Variant_setScalarCopy(&v->value, &node->head.nodeClass,
                                          &UA_TYPES[UA_TYPES_NODECLASS]);
        break;
    case UA_ATTRIBUTEID_BROWSENAME:
        retval = UA_Variant_setScalarCopy(&v->value, &node->head.browseName,
                                          &UA_TYPES[UA_TYPES_QUALIFIEDNAME]);
        break;
    case UA_ATTRIBUTEID_DISPLAYNAME: {
        UA_LocalizedText lt = UA_Session_getNodeDisplayName(session, &node->head);
        retval = UA_Variant_setScalarCopy(&v->value, &lt,
                                          &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
        break;
    }
    case UA_ATTRIBUTEID_DESCRIPTION: {
        UA_LocalizedText lt = UA_Session_getNodeDescription(session, &node->head);
        retval = UA_Variant_setScalarCopy(&v->value, &lt,
                                          &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
        break;
    }
    case UA_ATTRIBUTEID_WRITEMASK:
        retval = UA_Variant_setScalarCopy(&v->value, &node->head.writeMask,
                                          &UA_TYPES[UA_TYPES_UINT32]);
        break;
    case UA_ATTRIBUTEID_USERWRITEMASK: {
        UA_UInt32 userWriteMask = getUserWriteMask(server, session, &node->head);
        retval = UA_Variant_setScalarCopy(&v->value, &userWriteMask,
                                          &UA_TYPES[UA_TYPES_UINT32]);
        break; }
    case UA_ATTRIBUTEID_ISABSTRACT:
        retval = readIsAbstractAttribute(node, &v->value);
        break;
    case UA_ATTRIBUTEID_SYMMETRIC:
        CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
        retval = UA_Variant_setScalarCopy(&v->value, &node->referenceTypeNode.symmetric,
                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
        break;
    case UA_ATTRIBUTEID_INVERSENAME:
        CHECK_NODECLASS(UA_NODECLASS_REFERENCETYPE);
        if(node->referenceTypeNode.symmetric) {
            /* Symmetric reference types don't have an inverse name */
            retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
            break;
        }
        retval = UA_Variant_setScalarCopy(&v->value, &node->referenceTypeNode.inverseName,
                                          &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
        break;
    case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
        CHECK_NODECLASS(UA_NODECLASS_VIEW);
        retval = UA_Variant_setScalarCopy(&v->value, &node->viewNode.containsNoLoops,
                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
        break;
    case UA_ATTRIBUTEID_EVENTNOTIFIER:
        CHECK_NODECLASS(UA_NODECLASS_VIEW | UA_NODECLASS_OBJECT);
        if(node->head.nodeClass == UA_NODECLASS_VIEW) {
            retval = UA_Variant_setScalarCopy(&v->value, &node->viewNode.eventNotifier,
                                              &UA_TYPES[UA_TYPES_BYTE]);
        } else {
            retval = UA_Variant_setScalarCopy(&v->value, &node->objectNode.eventNotifier,
                                              &UA_TYPES[UA_TYPES_BYTE]);
        }
        break;
    case UA_ATTRIBUTEID_VALUE: {
        CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
        /* VariableTypes don't have the AccessLevel concept. Always allow
         * reading the value. */
        if(node->head.nodeClass == UA_NODECLASS_VARIABLE) {
            /* The access to a value variable is granted via the AccessLevel
             * and UserAccessLevel attributes */
            UA_Byte accessLevel = getAccessLevel(server, session, &node->variableNode);
            if(!(accessLevel & (UA_ACCESSLEVELMASK_READ))) {
                retval = UA_STATUSCODE_BADNOTREADABLE;
                break;
            }
            accessLevel = getUserAccessLevel(server, session, &node->variableNode);
            if(!(accessLevel & (UA_ACCESSLEVELMASK_READ))) {
                retval = UA_STATUSCODE_BADUSERACCESSDENIED;
                break;
            }
        }
        retval = readValueAttributeComplete(server, session, &node->variableNode,
                                            timestampsToReturn, &id->indexRange, v);
        break;
    }
    case UA_ATTRIBUTEID_DATATYPE:
        CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
        retval = UA_Variant_setScalarCopy(&v->value, &node->variableTypeNode.dataType,
                                          &UA_TYPES[UA_TYPES_NODEID]);
        break;
    case UA_ATTRIBUTEID_VALUERANK:
        CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
        retval = UA_Variant_setScalarCopy(&v->value, &node->variableTypeNode.valueRank,
                                          &UA_TYPES[UA_TYPES_INT32]);
        break;
    case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
        CHECK_NODECLASS(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
        retval = UA_Variant_setArrayCopy(&v->value, node->variableTypeNode.arrayDimensions,
                                         node->variableTypeNode.arrayDimensionsSize,
                                         &UA_TYPES[UA_TYPES_UINT32]);
        break;
    case UA_ATTRIBUTEID_ACCESSLEVEL:
        CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
        retval = UA_Variant_setScalarCopy(&v->value, &node->variableNode.accessLevel,
                                          &UA_TYPES[UA_TYPES_BYTE]);
        break;
    case UA_ATTRIBUTEID_ACCESSLEVELEX:
        CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
        /* The normal AccessLevelEx contains the lowest 8 bits from the normal AccessLevel.
         * In our case, all other bits are zero. */
        const UA_Byte accessLevel = *((const UA_Byte*)(&node->variableNode.accessLevel));
        UA_UInt32 accessLevelEx = accessLevel & 0xFF;
        retval = UA_Variant_setScalarCopy(&v->value, &accessLevelEx,
                                          &UA_TYPES[UA_TYPES_UINT32]);

        break;
    case UA_ATTRIBUTEID_USERACCESSLEVEL: {
        CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
        UA_Byte userAccessLevel = getUserAccessLevel(server, session, &node->variableNode);
        retval = UA_Variant_setScalarCopy(&v->value, &userAccessLevel,
                                          &UA_TYPES[UA_TYPES_BYTE]);
        break; }
    case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL:
        CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
        retval = UA_Variant_setScalarCopy(&v->value,
                                          &node->variableNode.minimumSamplingInterval,
                                          &UA_TYPES[UA_TYPES_DOUBLE]);
        break;
    case UA_ATTRIBUTEID_HISTORIZING:
        CHECK_NODECLASS(UA_NODECLASS_VARIABLE);
        retval = UA_Variant_setScalarCopy(&v->value, &node->variableNode.historizing,
                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
        break;
    case UA_ATTRIBUTEID_EXECUTABLE:
        CHECK_NODECLASS(UA_NODECLASS_METHOD);
        retval = UA_Variant_setScalarCopy(&v->value, &node->methodNode.executable,
                          &UA_TYPES[UA_TYPES_BOOLEAN]);
        break;
    case UA_ATTRIBUTEID_USEREXECUTABLE: {
        CHECK_NODECLASS(UA_NODECLASS_METHOD);
        UA_Boolean userExecutable =
            getUserExecutable(server, session, &node->methodNode);
        retval = UA_Variant_setScalarCopy(&v->value, &userExecutable,
                                          &UA_TYPES[UA_TYPES_BOOLEAN]);
        break; }
    case UA_ATTRIBUTEID_DATATYPEDEFINITION: {
        CHECK_NODECLASS(UA_NODECLASS_DATATYPE);

#ifdef UA_ENABLE_TYPEDESCRIPTION
        const UA_DataType *type =
            findDataType(node, server->config.customDataTypes);
        if(!type) {
            retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
            break;
        }

        if(UA_DATATYPEKIND_STRUCTURE == type->typeKind ||
           UA_DATATYPEKIND_OPTSTRUCT == type->typeKind ||
           UA_DATATYPEKIND_UNION == type->typeKind) {
            UA_StructureDefinition def;
            retval = getStructureDefinition(type, &def);
            if(UA_STATUSCODE_GOOD!=retval)
                break;
            retval = UA_Variant_setScalarCopy(&v->value, &def,
                                              &UA_TYPES[UA_TYPES_STRUCTUREDEFINITION]);
            UA_free(def.fields);
            break;
        }
#endif
        retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
        break; }

    case UA_ATTRIBUTEID_ROLEPERMISSIONS:
    case UA_ATTRIBUTEID_USERROLEPERMISSIONS:
    case UA_ATTRIBUTEID_ACCESSRESTRICTIONS:
        /* TODO: Add support for the attributes from the 1.04 spec */
        retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
        break;

    default:
        retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
    }

    /* Reading has failed? */
    if(retval == UA_STATUSCODE_GOOD) {
        v->hasValue = true;
    } else {
        v->hasStatus = true;
        v->status = retval;
    }

    /* Always use the current time as the server-timestamp */
    if(timestampsToReturn == UA_TIMESTAMPSTORETURN_SERVER ||
       timestampsToReturn == UA_TIMESTAMPSTORETURN_BOTH) {
        UA_EventLoop *el = server->config.eventLoop;
        v->serverTimestamp = el->dateTime_now(el);
        v->hasServerTimestamp = true;
        v->hasServerPicoseconds = false;
    } else {
        v->hasServerTimestamp = false;
        v->hasServerPicoseconds = false;
    }

    /* Don't "invent" source timestamps. But remove them when not required. */
    if(timestampsToReturn == UA_TIMESTAMPSTORETURN_SERVER ||
       timestampsToReturn == UA_TIMESTAMPSTORETURN_NEITHER) {
        v->hasSourceTimestamp = false;
        v->hasSourcePicoseconds = false;
    }
}

void
Operation_Read(UA_Server *server, UA_Session *session, UA_TimestampsToReturn *ttr,
               const UA_ReadValueId *rvi, UA_DataValue *dv) {
    /* Get the node (with only the selected attribute if the NodeStore supports that) */
    const UA_Node *node =
        UA_NODESTORE_GET_SELECTIVE(server, &rvi->nodeId,
                                   attributeId2AttributeMask((UA_AttributeId)rvi->attributeId),
                                   UA_REFERENCETYPESET_NONE,
                                   UA_BROWSEDIRECTION_INVALID);
    if(!node) {
        dv->hasStatus = true;
        dv->status = UA_STATUSCODE_BADNODEIDUNKNOWN;
        return;
    }

    /* Perform the read operation */
    ReadWithNode(node, server, session, *ttr, rvi, dv);
    UA_NODESTORE_RELEASE(server, node);
}

void
Service_Read(UA_Server *server, UA_Session *session,
             const UA_ReadRequest *request, UA_ReadResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session, "Processing ReadRequest");
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Check if the timestampstoreturn is valid */
    if(request->timestampsToReturn > UA_TIMESTAMPSTORETURN_NEITHER) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTIMESTAMPSTORETURNINVALID;
        return;
    }

    /* Check if maxAge is valid */
    if(request->maxAge < 0) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADMAXAGEINVALID;
        return;
    }

    /* Check if there are too many operations */
    if(server->config.maxNodesPerRead != 0 &&
       request->nodesToReadSize > server->config.maxNodesPerRead) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return;
    }

    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    response->responseHeader.serviceResult =
        UA_Server_processServiceOperations(server, session,
                                           (UA_ServiceOperation)Operation_Read,
                                           &request->timestampsToReturn,
                                           &request->nodesToReadSize,
                                           &UA_TYPES[UA_TYPES_READVALUEID],
                                           &response->resultsSize,
                                           &UA_TYPES[UA_TYPES_DATAVALUE]);
}

UA_DataValue
readWithSession(UA_Server *server, UA_Session *session,
                const UA_ReadValueId *item,
                UA_TimestampsToReturn timestampsToReturn) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_DataValue dv;
    UA_DataValue_init(&dv);
    Operation_Read(server, session, &timestampsToReturn, item, &dv);
    return dv;
}

UA_StatusCode
readWithReadValue(UA_Server *server, const UA_NodeId *nodeId,
                  const UA_AttributeId attributeId, void *v) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Call the read service */
    UA_ReadValueId item;
    UA_ReadValueId_init(&item);
    item.nodeId = *nodeId;
    item.attributeId = attributeId;
    UA_DataValue dv = readWithSession(server, &server->adminSession,
                                      &item, UA_TIMESTAMPSTORETURN_NEITHER);

    /* Check the return value */
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(dv.hasStatus)
        retval = dv.status;
    else if(!dv.hasValue)
        retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
    if(retval != UA_STATUSCODE_GOOD) {
        UA_DataValue_clear(&dv);
        return retval;
    }

    if(attributeId == UA_ATTRIBUTEID_VALUE ||
       attributeId == UA_ATTRIBUTEID_ARRAYDIMENSIONS) {
        /* Return the entire variant */
        memcpy(v, &dv.value, sizeof(UA_Variant));
    } else {
        /* Return the variant content only */
        memcpy(v, dv.value.data, dv.value.type->memSize);
        UA_free(dv.value.data);
    }
    return retval;
}

/* Exposes the Read service to local users */
UA_DataValue
UA_Server_read(UA_Server *server, const UA_ReadValueId *item,
               UA_TimestampsToReturn timestamps) {
    UA_LOCK(&server->serviceMutex);
    UA_DataValue dv = readWithSession(server, &server->adminSession, item, timestamps);
    UA_UNLOCK(&server->serviceMutex);
    return dv;
}

/* Used in inline functions exposing the Read service with more syntactic sugar
 * for individual attributes */
UA_StatusCode
__UA_Server_read(UA_Server *server, const UA_NodeId *nodeId,
                 const UA_AttributeId attributeId, void *v) {
   UA_LOCK(&server->serviceMutex);
   UA_StatusCode retval = readWithReadValue(server, nodeId, attributeId, v);
   UA_UNLOCK(&server->serviceMutex);
   return retval;
}

UA_StatusCode
readObjectProperty(UA_Server *server, const UA_NodeId objectId,
                   const UA_QualifiedName propertyName,
                   UA_Variant *value) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Create a BrowsePath to get the target NodeId */
    UA_RelativePathElement rpe;
    UA_RelativePathElement_init(&rpe);
    rpe.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
    rpe.isInverse = false;
    rpe.includeSubtypes = false;
    rpe.targetName = propertyName;

    UA_BrowsePath bp;
    UA_BrowsePath_init(&bp);
    bp.startingNode = objectId;
    bp.relativePath.elementsSize = 1;
    bp.relativePath.elements = &rpe;

    UA_StatusCode retval;
    UA_BrowsePathResult bpr = translateBrowsePathToNodeIds(server, &bp);
    if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
        retval = bpr.statusCode;
        UA_BrowsePathResult_clear(&bpr);
        return retval;
    }

    /* Use the first result from the BrowsePath */
    retval = readWithReadValue(server, &bpr.targets[0].targetId.nodeId,
                               UA_ATTRIBUTEID_VALUE, value);

    UA_BrowsePathResult_clear(&bpr);
    return retval;
}


UA_StatusCode
UA_Server_readObjectProperty(UA_Server *server, const UA_NodeId objectId,
                             const UA_QualifiedName propertyName,
                             UA_Variant *value) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode retval = readObjectProperty(server, objectId, propertyName, value);
    UA_UNLOCK(&server->serviceMutex);
    return retval;
}

/*****************/
/* Type Checking */
/*****************/

static UA_DataTypeKind
typeEquivalence(const UA_DataType *t) {
    UA_DataTypeKind k = (UA_DataTypeKind)t->typeKind;
    if(k == UA_DATATYPEKIND_ENUM)
        return UA_DATATYPEKIND_INT32;
    return k;
}

UA_Boolean
compatibleValueDataType(UA_Server *server, const UA_DataType *dataType,
                        const UA_NodeId *constraintDataType) {
    if(compatibleDataTypes(server, &dataType->typeId, constraintDataType))
        return true;

    /* For actual values, the constraint DataType may be a subtype of the
     * DataType of the value -- subtyping in the wrong direction. E.g. UtcTime
     * is a subtype of DateTime. But we allow it to be encoded as a DateTime
     * value when transferred over the wire.
     *
     * We do not allow "subtyping in the "wrong direction" if the received type
     * is abstract. For example, ExtensionObjects (== "Structure" in the type
     * hierarchy) is an abstract type. But ExtensionObject could still be
     * transported over the network. */
    UA_Boolean abstract = false;
    UA_StatusCode res = readWithReadValue(server, &dataType->typeId,
                                          UA_ATTRIBUTEID_ISABSTRACT, &abstract);
    if(res != UA_STATUSCODE_GOOD || abstract)
        return false;

    if(isNodeInTree_singleRef(server, constraintDataType, &dataType->typeId,
                              UA_REFERENCETYPEINDEX_HASSUBTYPE))
        return true;

    return false;
}

UA_Boolean
compatibleDataTypes(UA_Server *server, const UA_NodeId *dataType,
                    const UA_NodeId *constraintDataType) {
    /* Do not allow empty datatypes */
    if(UA_NodeId_isNull(dataType))
       return false;

    /* No constraint or Variant / BaseDataType which allows any content */
    if(UA_NodeId_isNull(constraintDataType) ||
       UA_NodeId_equal(constraintDataType, &UA_TYPES[UA_TYPES_VARIANT].typeId))
        return true;

    /* Same datatypes */
    if(UA_NodeId_equal(dataType, constraintDataType))
        return true;

    /* Is the DataType a subtype of the constraint type? */
    if(isNodeInTree_singleRef(server, dataType, constraintDataType,
                              UA_REFERENCETYPEINDEX_HASSUBTYPE))
        return true;

    return false;
}

/* Test whether a ValueRank and the given arraydimensions are compatible.
 *
 * 5.6.2 Variable NodeClass: If the maximum is unknown the value shall be 0. The
 * number of elements shall be equal to the value of the ValueRank Attribute.
 * This Attribute shall be null if ValueRank <= 0. */
UA_Boolean
compatibleValueRankArrayDimensions(UA_Server *server, UA_Session *session,
                                   UA_Int32 valueRank, size_t arrayDimensionsSize) {
    /* ValueRank invalid */
    if(valueRank < UA_VALUERANK_SCALAR_OR_ONE_DIMENSION) {
        UA_LOG_INFO_SESSION(server->config.logging, session,
                            "The ValueRank is invalid (< -3)");
        return false;
    }

    /* case -3, UA_VALUERANK_SCALAR_OR_ONE_DIMENSION: the value can be a scalar
     *   or a one dimensional array
     * case -2, UA_VALUERANK_ANY: the value can be a scalar or an array with any
     *   number of dimensions
     * case -1, UA_VALUERANK_SCALAR: the value is a scalar
     * case 0, UA_VALUERANK_ONE_OR_MORE_DIMENSIONS: the value is an array with
     *   one or more dimensions */
    if(valueRank <= UA_VALUERANK_ONE_OR_MORE_DIMENSIONS) {
        if(arrayDimensionsSize > 0) {
            UA_LOG_INFO_SESSION(server->config.logging, session,
                                "No ArrayDimensions can be defined for a ValueRank <= 0");
            return false;
        }
        return true;
    }

    /* case >= 1, UA_VALUERANK_ONE_DIMENSION: the value is an array with the
       specified number of dimensions */
    if(arrayDimensionsSize != (size_t)valueRank) {
        UA_LOG_INFO_SESSION(server->config.logging, session,
                            "The number of ArrayDimensions is not equal to "
                            "the (positive) ValueRank");
        return false;
    }
    return true;
}

UA_Boolean
compatibleValueRanks(UA_Int32 valueRank, UA_Int32 constraintValueRank) {
    /* Check if the valuerank of the variabletype allows the change. */
    switch(constraintValueRank) {
    case UA_VALUERANK_SCALAR_OR_ONE_DIMENSION: /* the value can be a scalar or a
                                                  one dimensional array */
        if(valueRank != UA_VALUERANK_SCALAR && valueRank != UA_VALUERANK_ONE_DIMENSION)
            return false;
        break;
    case UA_VALUERANK_ANY: /* the value can be a scalar or an array with any
                              number of dimensions */
        break;
    case UA_VALUERANK_SCALAR: /* the value is a scalar */
        if(valueRank != UA_VALUERANK_SCALAR)
            return false;
        break;
    case UA_VALUERANK_ONE_OR_MORE_DIMENSIONS: /* the value is an array with one
                                                 or more dimensions */
        if(valueRank < (UA_Int32) UA_VALUERANK_ONE_OR_MORE_DIMENSIONS)
            return false;
        break;
    default: /* >= 1: the value is an array with the specified number of
                 dimensions */
        if(valueRank != constraintValueRank)
            return false;
        break;
    }
    return true;
}

/* Check if the ValueRank allows for the value dimension. This is more
 * permissive than checking for the ArrayDimensions attribute. Because the value
 * can have dimensions if the ValueRank < 0 */
static UA_Boolean
compatibleValueRankValue(UA_Int32 valueRank, const UA_Variant *value) {
    /* Invalid ValueRank */
    if(valueRank < UA_VALUERANK_SCALAR_OR_ONE_DIMENSION)
        return false;

    /* Empty arrays (-1) always match */
    if(!value->data)
        return true;

    size_t arrayDims = value->arrayDimensionsSize;
    if(arrayDims == 0 && !UA_Variant_isScalar(value))
        arrayDims = 1; /* array but no arraydimensions -> implicit array dimension 1 */

    /* We cannot simply use compatibleValueRankArrayDimensions since we can have
     * defined ArrayDimensions for the value if the ValueRank is -2 */
    switch(valueRank) {
    case UA_VALUERANK_SCALAR_OR_ONE_DIMENSION: /* The value can be a scalar or a
                                                  one dimensional array */
        return (arrayDims <= 1);
    case UA_VALUERANK_ANY: /* The value can be a scalar or an array with any
                              number of dimensions */
        return true;
    case UA_VALUERANK_SCALAR: /* The value is a scalar */
        return (arrayDims == 0);
    case UA_VALUERANK_ONE_OR_MORE_DIMENSIONS:
        return (arrayDims >= 1);
    default:
        break;
    }

    UA_assert(valueRank >= UA_VALUERANK_ONE_OR_MORE_DIMENSIONS);

    /* case 0:  the value is an array with one or more dimensions */
    return (arrayDims == (UA_UInt32)valueRank);
}

UA_Boolean
compatibleArrayDimensions(size_t constraintArrayDimensionsSize,
                          const UA_UInt32 *constraintArrayDimensions,
                          size_t testArrayDimensionsSize,
                          const UA_UInt32 *testArrayDimensions) {
    /* No array dimensions defined -> everything is permitted if the value rank fits */
    if(constraintArrayDimensionsSize == 0)
        return true;

    /* Dimension count must match */
    if(testArrayDimensionsSize != constraintArrayDimensionsSize)
        return false;

    /* Dimension lengths must not be larger than the constraint. Zero in the
     * constraint indicates a wildcard. */
    for(size_t i = 0; i < constraintArrayDimensionsSize; ++i) {
        if(constraintArrayDimensions[i] < testArrayDimensions[i] &&
           constraintArrayDimensions[i] != 0)
            return false;
    }
    return true;
}

UA_Boolean
compatibleValueArrayDimensions(const UA_Variant *value, size_t targetArrayDimensionsSize,
                               const UA_UInt32 *targetArrayDimensions) {
    size_t valueArrayDimensionsSize = value->arrayDimensionsSize;
    UA_UInt32 const *valueArrayDimensions = value->arrayDimensions;
    UA_UInt32 tempArrayDimensions;
    if(!valueArrayDimensions && !UA_Variant_isScalar(value)) {
        /* An empty array implicitly has array dimensions [0,0,...] with the
         * correct number of dimensions. So it always matches. */
        if(value->arrayLength == 0)
            return true;

        /* Arrays with content and without array dimensions have one implicit dimension */
        valueArrayDimensionsSize = 1;
        tempArrayDimensions = (UA_UInt32)value->arrayLength;
        valueArrayDimensions = &tempArrayDimensions;
    }
    UA_assert(valueArrayDimensionsSize == 0 || valueArrayDimensions != NULL);
    return compatibleArrayDimensions(targetArrayDimensionsSize, targetArrayDimensions,
                                     valueArrayDimensionsSize, valueArrayDimensions);
}

const char *reason_EmptyType = "Empty value only allowed for BaseDataType";
const char *reason_ValueDataType = "DataType of the value is incompatible";
const char *reason_ValueArrayDimensions = "ArrayDimensions of the value are incompatible";
const char *reason_ValueValueRank = "ValueRank of the value is incompatible";

UA_Boolean
compatibleValue(UA_Server *server, UA_Session *session, const UA_NodeId *targetDataTypeId,
                UA_Int32 targetValueRank, size_t targetArrayDimensionsSize,
                const UA_UInt32 *targetArrayDimensions, const UA_Variant *value,
                const UA_NumericRange *range, const char **reason) {
    /* Empty value */
    if(UA_Variant_isEmpty(value)) {
        /* Empty value is allowed for BaseDataType */
        if(UA_NodeId_equal(targetDataTypeId, &UA_TYPES[UA_TYPES_VARIANT].typeId) ||
           UA_NodeId_equal(targetDataTypeId, &UA_NODEID_NULL))
            return true;

        /* Ignore if that is configured */
        if(server->bootstrapNS0 ||
           server->config.allowEmptyVariables == UA_RULEHANDLING_ACCEPT)
            return true;

        UA_LOG_INFO_SESSION(server->config.logging, session,
                            "Only Variables with data type BaseDataType "
                            "can contain an empty value");

        /* Ignore if that is configured */
        if(server->config.allowEmptyVariables == UA_RULEHANDLING_WARN)
            return true;

        /* Default handling is to abort */
        *reason = reason_EmptyType;
        return false;
    }

    /* Empty array of ExtensionObjects */
    if(UA_Variant_hasArrayType(value, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]) &&
       value->arrayLength == 0) {
        /* There is no way to check type compatibility here. Leave it for the upper layers to
         * decide, if empty array is okay. */
        return true;        
    }

    /* Is the datatype compatible? */
    if(!compatibleValueDataType(server, value->type, targetDataTypeId)) {
        *reason = reason_ValueDataType;
        return false;
    }

    /* Array dimensions are checked later when writing the range */
    if(range)
        return true;

    /* See if the array dimensions match. */
    if(!compatibleValueArrayDimensions(value, targetArrayDimensionsSize,
                                       targetArrayDimensions)) {
        *reason = reason_ValueArrayDimensions;
        return false;
    }

    /* Check if the valuerank allows for the value dimension */
    if(!compatibleValueRankValue(targetValueRank, value)) {
        *reason = reason_ValueValueRank;
        return false;
    }

    return true;
}

/*****************/
/* Write Service */
/*****************/

static void
freeWrapperArray(void *app, void *context) {
    UA_free(context);
}

static void
unwrapEOArray(UA_Server *server, UA_Variant *value) {
    /* Only works on arrays of ExtensionObjects */
    if(!UA_Variant_hasArrayType(value, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]) ||
       value->arrayLength == 0)
        return;

    /* All eo need to be already decoded and have the same wrapped type */
    UA_ExtensionObject *eo = (UA_ExtensionObject*)value->data;
    const UA_DataType *innerType = eo[0].content.decoded.type;
    for(size_t i = 0; i < value->arrayLength; i++) {
        if(eo[i].encoding != UA_EXTENSIONOBJECT_DECODED &&
           eo[i].encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE)
            return;
        if(eo[i].content.decoded.type != innerType)
            return;
    }

    /* Allocate the array for the unwrapped data. Since the adjusted value is
     * not cleaned up (only the original value), this memory is being cleaned up
     * by a delayed callback in the server after the method call has
     * finished. */
    UA_DelayedCallback *dc = (UA_DelayedCallback*)
        UA_malloc(sizeof(UA_DelayedCallback) + (value->arrayLength * innerType->memSize));
    if(!dc)
        return;

    /* Move the content */
    uintptr_t pos = ((uintptr_t)dc) + sizeof(UA_DelayedCallback);
    void *unwrappedArray = (void*)pos;
    for(size_t i = 0; i < value->arrayLength; i++) {
        memcpy((void*)pos, eo[i].content.decoded.data, innerType->memSize);
        pos += innerType->memSize;
    }

    /* Adjust the value */
    value->type = innerType;
    value->data = unwrappedArray;

    /* Add the delayed callback to free the memory of the unwrapped array */
    dc->callback = freeWrapperArray;
    dc->application = NULL;
    dc->context = dc;
    UA_EventLoop *el = server->config.eventLoop;
    el->addDelayedCallback(el, dc);
}

void
adjustValueType(UA_Server *server, UA_Variant *value,
                const UA_NodeId *targetDataTypeId) {
    /* If the value is empty, there is nothing we can do here */
    const UA_DataType *type = value->type;
    if(!type)
        return;

    /* Unwrap ExtensionObject arrays if they all contain the same DataType */
    unwrapEOArray(server, value);

    /* The target type is already achieved. No adjustment needed. */
    if(UA_NodeId_equal(&type->typeId, targetDataTypeId))
        return;

    /* Find the target type */
    const UA_DataType *targetType =
        UA_findDataTypeWithCustom(targetDataTypeId, server->config.customDataTypes);
    if(!targetType)
        return;

    /* A string is written to a byte array. the valuerank and array dimensions
     * are checked later */
    if(targetType == &UA_TYPES[UA_TYPES_BYTE] &&
       type == &UA_TYPES[UA_TYPES_BYTESTRING] &&
       UA_Variant_isScalar(value)) {
        UA_ByteString *str = (UA_ByteString*)value->data;
        value->type = &UA_TYPES[UA_TYPES_BYTE];
        value->arrayLength = str->length;
        value->data = str->data;
        return;
    }

    /* An enum was sent as an int32, or an opaque type as a bytestring. This
     * is detected with the typeKind indicating the "true" datatype. */
    UA_DataTypeKind te1 = typeEquivalence(targetType);
    UA_DataTypeKind te2 = typeEquivalence(type);
    if(te1 == te2 && te1 <= UA_DATATYPEKIND_ENUM) {
        value->type = targetType;
        return;
    }

    /* Add more possible type adjustments here. What are they? */
}

static UA_StatusCode
writeArrayDimensionsAttribute(UA_Server *server, UA_Session *session,
                              UA_VariableNode *node, const UA_VariableTypeNode *type,
                              size_t arrayDimensionsSize, UA_UInt32 *arrayDimensions) {
    UA_assert(node != NULL);
    UA_assert(type != NULL);

    /* If this is a variabletype, there must be no instances or subtypes of it
     * when we do the change */
    if(node->head.nodeClass == UA_NODECLASS_VARIABLETYPE &&
       UA_Node_hasSubTypeOrInstances(&node->head)) {
        UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_SERVER,
                    "Cannot change a variable type with existing instances");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Check that the array dimensions match with the valuerank */
    if(!compatibleValueRankArrayDimensions(server, session, node->valueRank,
                                           arrayDimensionsSize)) {
        UA_LOG_DEBUG(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Cannot write the ArrayDimensions. The ValueRank does not match.");
        return UA_STATUSCODE_BADTYPEMISMATCH;
    }

    /* Check if the array dimensions match with the wildcards in the
     * variabletype (dimension length 0) */
    if(type->arrayDimensions &&
       !compatibleArrayDimensions(type->arrayDimensionsSize, type->arrayDimensions,
                                  arrayDimensionsSize, arrayDimensions)) {
       UA_LOG_DEBUG(server->config.logging, UA_LOGCATEGORY_SERVER,
                    "Array dimensions in the variable type do not match");
       return UA_STATUSCODE_BADTYPEMISMATCH;
    }

    /* Check if the current value is compatible with the array dimensions */
    UA_DataValue value;
    UA_DataValue_init(&value);
    UA_StatusCode retval = readValueAttribute(server, session, node, &value);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    if(value.hasValue) {
        if(!compatibleValueArrayDimensions(&value.value, arrayDimensionsSize,
                                           arrayDimensions))
            retval = UA_STATUSCODE_BADTYPEMISMATCH;
        UA_DataValue_clear(&value);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_DEBUG(server->config.logging, UA_LOGCATEGORY_SERVER,
                         "Array dimensions in the current value do not match");
            return retval;
        }
    }

    /* Ok, apply */
    UA_UInt32 *oldArrayDimensions = node->arrayDimensions;
    size_t oldArrayDimensionsSize = node->arrayDimensionsSize;
    retval = UA_Array_copy(arrayDimensions, arrayDimensionsSize,
                           (void**)&node->arrayDimensions,
                           &UA_TYPES[UA_TYPES_UINT32]);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_Array_delete(oldArrayDimensions, oldArrayDimensionsSize, &UA_TYPES[UA_TYPES_UINT32]);
    node->arrayDimensionsSize = arrayDimensionsSize;
    return UA_STATUSCODE_GOOD;
}

/* Stack layout: ... | node | type */
static UA_StatusCode
writeValueRank(UA_Server *server, UA_Session *session,
               UA_VariableNode *node, const UA_VariableTypeNode *type,
               UA_Int32 valueRank) {
    UA_assert(node != NULL);
    UA_assert(type != NULL);

    UA_Int32 constraintValueRank = type->valueRank;

    /* If this is a variabletype, there must be no instances or subtypes of it
     * when we do the change */
    if(node->head.nodeClass == UA_NODECLASS_VARIABLETYPE &&
       UA_Node_hasSubTypeOrInstances(&node->head))
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Check if the valuerank of the variabletype allows the change. */
    if(!compatibleValueRanks(valueRank, constraintValueRank))
        return UA_STATUSCODE_BADTYPEMISMATCH;

    /* Check if the new valuerank is compatible with the array dimensions. Use
     * the read service to handle data sources. */
    size_t arrayDims = node->arrayDimensionsSize;
    if(arrayDims == 0) {
        /* the value could be an array with no arrayDimensions defined.
           dimensions zero indicate a scalar for compatibleValueRankArrayDimensions. */
        UA_DataValue value;
        UA_DataValue_init(&value);
        UA_StatusCode retval = readValueAttribute(server, session, node, &value);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
        if(!value.hasValue || !value.value.type) {
            /* no value -> apply */
            node->valueRank = valueRank;
            return UA_STATUSCODE_GOOD;
        }
        if(!UA_Variant_isScalar(&value.value))
            arrayDims = 1;
        UA_DataValue_clear(&value);
    }
    if(!compatibleValueRankArrayDimensions(server, session, valueRank, arrayDims))
        return UA_STATUSCODE_BADTYPEMISMATCH;

    /* All good, apply the change */
    node->valueRank = valueRank;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
writeDataTypeAttribute(UA_Server *server, UA_Session *session,
                       UA_VariableNode *node, const UA_VariableTypeNode *type,
                       const UA_NodeId *dataType) {
    UA_assert(node != NULL);
    UA_assert(type != NULL);

    /* If this is a variabletype, there must be no instances or subtypes of it
       when we do the change */
    if(node->head.nodeClass == UA_NODECLASS_VARIABLETYPE &&
       UA_Node_hasSubTypeOrInstances(&node->head))
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Does the new type match the constraints of the variabletype? */
    if(!compatibleDataTypes(server, dataType, &type->dataType))
        return UA_STATUSCODE_BADTYPEMISMATCH;

    /* Check if the current value would match the new type */
    UA_DataValue value;
    UA_DataValue_init(&value);
    UA_StatusCode retval = readValueAttribute(server, session, node, &value);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    if(value.hasValue) {
        const char *reason; /* temp value */
        if(!compatibleValue(server, session, dataType, node->valueRank,
                            node->arrayDimensionsSize, node->arrayDimensions,
                            &value.value, NULL, &reason))
            retval = UA_STATUSCODE_BADTYPEMISMATCH;
        UA_DataValue_clear(&value);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_DEBUG(server->config.logging, UA_LOGCATEGORY_SERVER,
                         "The current value does not match the new data type");
            return retval;
        }
    }

    /* Replace the datatype nodeid */
    UA_NodeId dtCopy = node->dataType;
    retval = UA_NodeId_copy(dataType, &node->dataType);
    if(retval != UA_STATUSCODE_GOOD) {
        node->dataType = dtCopy;
        return retval;
    }
    UA_NodeId_clear(&dtCopy);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
writeValueAttributeWithoutRange(UA_VariableNode *node, const UA_DataValue *value) {
    UA_DataValue new_value;
    UA_StatusCode retval = UA_DataValue_copy(value, &new_value);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_DataValue_clear(&node->value.data.value);
    node->value.data.value = new_value;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
writeValueAttributeWithRange(UA_VariableNode *node, const UA_DataValue *value,
                             const UA_NumericRange *rangeptr) {
    /* Value on both sides? */
    if(value->status != node->value.data.value.status ||
       !value->hasValue || !node->value.data.value.hasValue)
        return UA_STATUSCODE_BADINDEXRANGEINVALID;

    /* Make scalar a one-entry array for range matching */
    UA_Variant editableValue;
    const UA_Variant *v = &value->value;
    if(UA_Variant_isScalar(&value->value)) {
        editableValue = value->value;
        editableValue.arrayLength = 1;
        v = &editableValue;
    }

    /* Check that the type is an exact match and not only "compatible" */
    if(!node->value.data.value.value.type || !v->type ||
       !UA_NodeId_equal(&node->value.data.value.value.type->typeId,
                        &v->type->typeId))
        return UA_STATUSCODE_BADTYPEMISMATCH;

    /* Write the value */
    UA_StatusCode retval =
        UA_Variant_setRangeCopy(&node->value.data.value.value,
                                v->data, v->arrayLength, *rangeptr);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Write the status and timestamps */
    node->value.data.value.hasStatus = value->hasStatus;
    node->value.data.value.status = value->status;
    node->value.data.value.hasSourceTimestamp = value->hasSourceTimestamp;
    node->value.data.value.sourceTimestamp = value->sourceTimestamp;
    node->value.data.value.hasSourcePicoseconds = value->hasSourcePicoseconds;
    node->value.data.value.sourcePicoseconds = value->sourcePicoseconds;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
writeNodeValueAttribute(UA_Server *server, UA_Session *session,
                        UA_VariableNode *node, const UA_DataValue *value,
                        const UA_String *indexRange) {
    UA_assert(node != NULL);
    UA_assert(session != NULL);
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Parse the range */
    UA_NumericRange range;
    range.dimensions = NULL;
    UA_NumericRange *rangeptr = NULL;
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(indexRange && indexRange->length > 0) {
        retval = UA_NumericRange_parse(&range, *indexRange);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
        rangeptr = &range;
    }

    /* Created an editable version. The data is not touched. Only the variant
     * "container". */
    UA_DataValue adjustedValue = *value;

    /* Type checking. May change the type of adjustedValue */
    const char *reason;
    if(value->hasValue && value->value.type) {
        /* Try to correct the type */
        adjustValueType(server, &adjustedValue.value, &node->dataType);

        /* Check the type */
        if(!compatibleValue(server, session, &node->dataType, node->valueRank,
                            node->arrayDimensionsSize, node->arrayDimensions,
                            &adjustedValue.value, rangeptr, &reason)) {
            UA_LOG_NODEID_WARNING(&node->head.nodeId,
            if(session == &server->adminSession) {
                /* If the value is written via the local API, log a warning */
                UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                               "Writing the value of Node %.*s failed with the "
                               "following reason: %s",
                               (int)nodeIdStr.length, nodeIdStr.data, reason);
            } else {
                /* Don't spam the logs if writing from remote failed */
                UA_LOG_DEBUG_SESSION(server->config.logging, session,
                                     "Writing the value of Node %.*s failed with the "
                                     "following reason: %s",
                                     (int)nodeIdStr.length, nodeIdStr.data, reason);
            });
            if(rangeptr && rangeptr->dimensions != NULL)
                UA_free(rangeptr->dimensions);
            return UA_STATUSCODE_BADTYPEMISMATCH;
        }
    }

    /* If no source timestamp is defined create one here.
     * It should be created as close to the source as possible. */
    if(node->head.nodeClass == UA_NODECLASS_VARIABLE && !node->isDynamic) {
        adjustedValue.hasSourceTimestamp = false;
        adjustedValue.hasSourcePicoseconds = false;
    }

    /* Call into the different value storage backends.
     *
     * TODO: Clean up this mess with duplicated possibilities for external
     * callbacks */
    retval = UA_STATUSCODE_BADWRITENOTSUPPORTED; /* default */
    switch(node->valueBackend.backendType) {
    case UA_VALUEBACKENDTYPE_NONE:
        if(node->valueSource == UA_VALUESOURCE_DATA) {
            /* Write into the in-situ DataValue */
            if(!rangeptr)
                retval = writeValueAttributeWithoutRange(node, &adjustedValue);
            else
                retval = writeValueAttributeWithRange(node, &adjustedValue, rangeptr);

            /* Callback after writing */
            if(retval == UA_STATUSCODE_GOOD &&
               node->value.data.callback.onWrite) {
                UA_UNLOCK(&server->serviceMutex);
                node->value.data.callback.
                    onWrite(server, &session->sessionId, session->context,
                            &node->head.nodeId, node->head.context,
                            rangeptr, &adjustedValue);
                UA_LOCK(&server->serviceMutex);
            }
        } else if(node->value.dataSource.write) {
            /* Write via the datasource callback */
            UA_UNLOCK(&server->serviceMutex);
            retval = node->value.dataSource.
                write(server, &session->sessionId, session->context,
                      &node->head.nodeId, node->head.context,
                      rangeptr, &adjustedValue);
            UA_LOCK(&server->serviceMutex);
        }
        break;

    case UA_VALUEBACKENDTYPE_EXTERNAL:
        if(node->valueBackend.backend.external.callback.userWrite) {
            retval = node->valueBackend.backend.external.callback.
                userWrite(server, &session->sessionId, session->context,
                          &node->head.nodeId, node->head.context,
                          rangeptr, &adjustedValue);
        }
        break;

    case UA_VALUEBACKENDTYPE_INTERNAL:
    case UA_VALUEBACKENDTYPE_DATA_SOURCE_CALLBACK:
    default:
        break;
    }

    /* Write into the historical data backend. Not that the historical data
     * backend can be configured to "poll" data like a MonitoredItem also. */
#ifdef UA_ENABLE_HISTORIZING
    if(retval == UA_STATUSCODE_GOOD &&
       node->head.nodeClass == UA_NODECLASS_VARIABLE &&
       server->config.historyDatabase.setValue) {
        UA_UNLOCK(&server->serviceMutex);
        server->config.historyDatabase.
            setValue(server, server->config.historyDatabase.context,
                     &session->sessionId, session->context,
                     &node->head.nodeId, node->historizing, &adjustedValue);
        UA_LOCK(&server->serviceMutex);
    }
#endif

    /* Clean up */
    if(rangeptr && rangeptr->dimensions != NULL)
        UA_free(rangeptr->dimensions);
    return retval;
}

static UA_StatusCode
writeIsAbstract(UA_Node *node, UA_Boolean value) {
    switch(node->head.nodeClass) {
    case UA_NODECLASS_OBJECTTYPE:
        node->objectTypeNode.isAbstract = value;
        break;
    case UA_NODECLASS_REFERENCETYPE:
        node->referenceTypeNode.isAbstract = value;
        break;
    case UA_NODECLASS_VARIABLETYPE:
        node->variableTypeNode.isAbstract = value;
        break;
    case UA_NODECLASS_DATATYPE:
        node->dataTypeNode.isAbstract = value;
        break;
    default:
        return UA_STATUSCODE_BADNODECLASSINVALID;
    }
    return UA_STATUSCODE_GOOD;
}

/*****************/
/* Write Service */
/*****************/

#define CHECK_DATATYPE_SCALAR(EXP_DT)                                   \
    if(!wvalue->value.hasValue ||                                       \
       &UA_TYPES[UA_TYPES_##EXP_DT] != wvalue->value.value.type ||      \
       !UA_Variant_isScalar(&wvalue->value.value)) {                    \
        retval = UA_STATUSCODE_BADTYPEMISMATCH;                         \
        break;                                                          \
    }

#define CHECK_DATATYPE_ARRAY(EXP_DT)                                    \
    if(!wvalue->value.hasValue ||                                       \
       &UA_TYPES[UA_TYPES_##EXP_DT] != wvalue->value.value.type ||      \
       UA_Variant_isScalar(&wvalue->value.value)) {                     \
        retval = UA_STATUSCODE_BADTYPEMISMATCH;                         \
        break;                                                          \
    }

#define CHECK_NODECLASS_WRITE(CLASS)                                    \
    if((node->head.nodeClass & (CLASS)) == 0) {                         \
        retval = UA_STATUSCODE_BADNODECLASSINVALID;                     \
        break;                                                          \
    }

#define CHECK_USERWRITEMASK(mask)                           \
    if(!(userWriteMask & (mask))) {                         \
        retval = UA_STATUSCODE_BADUSERACCESSDENIED;         \
        break;                                              \
    }

#define GET_NODETYPE                                \
    type = (const UA_VariableTypeNode*)             \
        getNodeType(server, &node->head);           \
    if(!type) {                                     \
        retval = UA_STATUSCODE_BADTYPEMISMATCH;     \
        break;                                      \
    }

/* Update a localized text. Don't touch the target if copying fails
 * (maybe due to BadOutOfMemory). */
static UA_StatusCode
updateLocalizedText(const UA_LocalizedText *source, UA_LocalizedText *target) {
    UA_LocalizedText tmp;
    UA_StatusCode retval = UA_LocalizedText_copy(source, &tmp);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_LocalizedText_clear(target);
    *target = tmp;
    return UA_STATUSCODE_GOOD;
}

/* Trigger sampling if a MonitoredItem surveils the attribute with no sampling
 * interval */
#ifdef UA_ENABLE_SUBSCRIPTIONS
static void
triggerImmediateDataChange(UA_Server *server, UA_Session *session,
                           UA_Node *node, const UA_WriteValue *wvalue) {
    UA_MonitoredItem *mon = node->head.monitoredItems;
    for(; mon != NULL; mon = mon->sampling.nodeListNext) {
        if(mon->itemToMonitor.attributeId != wvalue->attributeId)
            continue;
        UA_DataValue value;
        UA_DataValue_init(&value);
        ReadWithNode(node, server, session, mon->timestampsToReturn,
                     &mon->itemToMonitor, &value);
        UA_MonitoredItem_processSampledValue(server, mon, &value);
    }
}
#endif

/* This function implements the main part of the write service and operates on a
   copy of the node (not in single-threaded mode). */
static UA_StatusCode
copyAttributeIntoNode(UA_Server *server, UA_Session *session,
                      UA_Node *node, const UA_WriteValue *wvalue) {
    UA_assert(session != NULL);
    const void *value = wvalue->value.value.data;
    UA_UInt32 userWriteMask = getUserWriteMask(server, session, &node->head);
    UA_StatusCode retval = UA_STATUSCODE_GOOD;

    UA_LOG_NODEID_TRACE(&node->head.nodeId,
                        UA_LOG_TRACE_SESSION(server->config.logging, session,
                                             "Write attribute %"PRIi32 " of Node %.*s",
                                             wvalue->attributeId, (int)nodeIdStr.length,
                                             nodeIdStr.data));

    const UA_VariableTypeNode *type;

    switch(wvalue->attributeId) {
    case UA_ATTRIBUTEID_NODEID:
    case UA_ATTRIBUTEID_NODECLASS:
    case UA_ATTRIBUTEID_USERWRITEMASK:
    case UA_ATTRIBUTEID_USERACCESSLEVEL:
    case UA_ATTRIBUTEID_USEREXECUTABLE:
    case UA_ATTRIBUTEID_BROWSENAME: /* BrowseName is tracked in a binary tree
                                       for fast lookup */
        retval = UA_STATUSCODE_BADWRITENOTSUPPORTED;
        break;
    case UA_ATTRIBUTEID_DISPLAYNAME:
        CHECK_USERWRITEMASK(UA_WRITEMASK_DISPLAYNAME);
        CHECK_DATATYPE_SCALAR(LOCALIZEDTEXT);
        retval = UA_Node_insertOrUpdateDisplayName(&node->head,
                                                   (const UA_LocalizedText *)value);
        break;
    case UA_ATTRIBUTEID_DESCRIPTION:
        CHECK_USERWRITEMASK(UA_WRITEMASK_DESCRIPTION);
        CHECK_DATATYPE_SCALAR(LOCALIZEDTEXT);
        retval = UA_Node_insertOrUpdateDescription(&node->head,
                                                   (const UA_LocalizedText *)value);
        break;
    case UA_ATTRIBUTEID_WRITEMASK:
        CHECK_USERWRITEMASK(UA_WRITEMASK_WRITEMASK);
        CHECK_DATATYPE_SCALAR(UINT32);
        node->head.writeMask = *(const UA_UInt32*)value;
        break;
    case UA_ATTRIBUTEID_ISABSTRACT:
        CHECK_USERWRITEMASK(UA_WRITEMASK_ISABSTRACT);
        CHECK_DATATYPE_SCALAR(BOOLEAN);
        retval = writeIsAbstract(node, *(const UA_Boolean*)value);
        break;
    case UA_ATTRIBUTEID_SYMMETRIC:
        CHECK_NODECLASS_WRITE(UA_NODECLASS_REFERENCETYPE);
        CHECK_USERWRITEMASK(UA_WRITEMASK_SYMMETRIC);
        CHECK_DATATYPE_SCALAR(BOOLEAN);
        node->referenceTypeNode.symmetric = *(const UA_Boolean*)value;
        break;
    case UA_ATTRIBUTEID_INVERSENAME:
        CHECK_NODECLASS_WRITE(UA_NODECLASS_REFERENCETYPE);
        CHECK_USERWRITEMASK(UA_WRITEMASK_INVERSENAME);
        CHECK_DATATYPE_SCALAR(LOCALIZEDTEXT);
        retval = updateLocalizedText((const UA_LocalizedText *)value,
                                     &node->referenceTypeNode.inverseName);
        break;
    case UA_ATTRIBUTEID_CONTAINSNOLOOPS:
        CHECK_NODECLASS_WRITE(UA_NODECLASS_VIEW);
        CHECK_USERWRITEMASK(UA_WRITEMASK_CONTAINSNOLOOPS);
        CHECK_DATATYPE_SCALAR(BOOLEAN);
        node->viewNode.containsNoLoops = *(const UA_Boolean*)value;
        break;
    case UA_ATTRIBUTEID_EVENTNOTIFIER:
        CHECK_NODECLASS_WRITE(UA_NODECLASS_VIEW | UA_NODECLASS_OBJECT);
        CHECK_USERWRITEMASK(UA_WRITEMASK_EVENTNOTIFIER);
        CHECK_DATATYPE_SCALAR(BYTE);
        if(node->head.nodeClass == UA_NODECLASS_VIEW) {
            node->viewNode.eventNotifier = *(const UA_Byte*)value;
        } else {
            node->objectNode.eventNotifier = *(const UA_Byte*)value;
        }
        break;
    case UA_ATTRIBUTEID_VALUE:
        CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
        if(node->head.nodeClass == UA_NODECLASS_VARIABLE) {
            /* The access to a value variable is granted via the AccessLevel
             * and UserAccessLevel attributes */
            UA_Byte accessLevel = getAccessLevel(server, session, &node->variableNode);
            if(!(accessLevel & (UA_ACCESSLEVELMASK_WRITE))) {
                retval = UA_STATUSCODE_BADNOTWRITABLE;
                break;
            }
            accessLevel = getUserAccessLevel(server, session, &node->variableNode);
            if(!(accessLevel & (UA_ACCESSLEVELMASK_WRITE))) {
                retval = UA_STATUSCODE_BADUSERACCESSDENIED;
                break;
            }
        } else { /* UA_NODECLASS_VARIABLETYPE */
            CHECK_USERWRITEMASK(UA_WRITEMASK_VALUEFORVARIABLETYPE);
        }
        retval = writeNodeValueAttribute(server, session, &node->variableNode,
                                         &wvalue->value, &wvalue->indexRange);
        break;
    case UA_ATTRIBUTEID_DATATYPE:
        CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
        CHECK_USERWRITEMASK(UA_WRITEMASK_DATATYPE);
        CHECK_DATATYPE_SCALAR(NODEID);
        GET_NODETYPE;
        retval = writeDataTypeAttribute(server, session, &node->variableNode,
                                        type, (const UA_NodeId*)value);
        UA_NODESTORE_RELEASE(server, (const UA_Node*)type);
        break;
    case UA_ATTRIBUTEID_VALUERANK:
        CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
        CHECK_USERWRITEMASK(UA_WRITEMASK_VALUERANK);
        CHECK_DATATYPE_SCALAR(INT32);
        GET_NODETYPE;
        retval = writeValueRank(server, session, &node->variableNode,
                                type, *(const UA_Int32*)value);
        UA_NODESTORE_RELEASE(server, (const UA_Node*)type);
        break;
    case UA_ATTRIBUTEID_ARRAYDIMENSIONS:
        CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE | UA_NODECLASS_VARIABLETYPE);
        CHECK_USERWRITEMASK(UA_WRITEMASK_ARRRAYDIMENSIONS);
        CHECK_DATATYPE_ARRAY(UINT32);
        GET_NODETYPE;
        retval = writeArrayDimensionsAttribute(server, session, &node->variableNode,
                                               type, wvalue->value.value.arrayLength,
                                               (UA_UInt32 *)wvalue->value.value.data);
        UA_NODESTORE_RELEASE(server, (const UA_Node*)type);
        break;
    case UA_ATTRIBUTEID_ACCESSLEVEL:
        CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE);
        CHECK_USERWRITEMASK(UA_WRITEMASK_ACCESSLEVEL);
        CHECK_DATATYPE_SCALAR(BYTE);
        node->variableNode.accessLevel = *(const UA_Byte*)value;
        break;
    case UA_ATTRIBUTEID_ACCESSLEVELEX:
        CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE);
        CHECK_USERWRITEMASK(UA_WRITEMASK_ACCESSLEVELEX);
        CHECK_DATATYPE_SCALAR(UINT32);
        node->variableNode.accessLevel = (UA_Byte)(*(const UA_UInt32*)value & 0xFF);
        break;
    case UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL:
        CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE);
        CHECK_USERWRITEMASK(UA_WRITEMASK_MINIMUMSAMPLINGINTERVAL);
        CHECK_DATATYPE_SCALAR(DOUBLE);
        node->variableNode.minimumSamplingInterval = *(const UA_Double*)value;
        break;
    case UA_ATTRIBUTEID_HISTORIZING:
        CHECK_NODECLASS_WRITE(UA_NODECLASS_VARIABLE);
        CHECK_USERWRITEMASK(UA_WRITEMASK_HISTORIZING);
        CHECK_DATATYPE_SCALAR(BOOLEAN);
        node->variableNode.historizing = *(const UA_Boolean*)value;
        break;
    case UA_ATTRIBUTEID_EXECUTABLE:
        CHECK_NODECLASS_WRITE(UA_NODECLASS_METHOD);
        CHECK_USERWRITEMASK(UA_WRITEMASK_EXECUTABLE);
        CHECK_DATATYPE_SCALAR(BOOLEAN);
        node->methodNode.executable = *(const UA_Boolean*)value;
        break;
    default:
        retval = UA_STATUSCODE_BADATTRIBUTEIDINVALID;
        break;
    }

    /* Check if writing succeeded */
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_INFO_SESSION(server->config.logging, session,
                            "WriteRequest returned status code %s",
                            UA_StatusCode_name(retval));
        return retval;
    }

    /* Trigger MonitoredItems with no SamplingInterval */
#ifdef UA_ENABLE_SUBSCRIPTIONS
    triggerImmediateDataChange(server, session, node, wvalue);
#endif

    return UA_STATUSCODE_GOOD;
}

void
Operation_Write(UA_Server *server, UA_Session *session, void *context,
                const UA_WriteValue *wv, UA_StatusCode *result) {
    UA_assert(session != NULL);
    *result = UA_Server_editNode(server, session, &wv->nodeId,
                                 (UA_EditNodeCallback)copyAttributeIntoNode,
                                 (void*)(uintptr_t)wv);
}

void
Service_Write(UA_Server *server, UA_Session *session,
              const UA_WriteRequest *request,
              UA_WriteResponse *response) {
    UA_assert(session != NULL);
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing WriteRequest");
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    if(server->config.maxNodesPerWrite != 0 &&
       request->nodesToWriteSize > server->config.maxNodesPerWrite) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return;
    }

    response->responseHeader.serviceResult =
        UA_Server_processServiceOperations(server, session,
                                           (UA_ServiceOperation)Operation_Write, NULL,
                                           &request->nodesToWriteSize,
                                           &UA_TYPES[UA_TYPES_WRITEVALUE],
                                           &response->resultsSize,
                                           &UA_TYPES[UA_TYPES_STATUSCODE]);
}

UA_StatusCode
UA_Server_write(UA_Server *server, const UA_WriteValue *value) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    UA_LOCK(&server->serviceMutex);
    Operation_Write(server, &server->adminSession, NULL, value, &res);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

/* Convenience function to be wrapped into inline functions */
UA_StatusCode
__UA_Server_write(UA_Server *server, const UA_NodeId *nodeId,
                  const UA_AttributeId attributeId,
                  const UA_DataType *attr_type, const void *attr) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = writeAttribute(server, &server->adminSession,
                                       nodeId, attributeId, attr, attr_type);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

/* Internal convenience function */
UA_StatusCode
writeAttribute(UA_Server *server, UA_Session *session,
               const UA_NodeId *nodeId, const UA_AttributeId attributeId,
               const void *attr, const UA_DataType *attr_type) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_WriteValue wvalue;
    UA_WriteValue_init(&wvalue);
    wvalue.nodeId = *nodeId;
    wvalue.attributeId = attributeId;
    wvalue.value.hasValue = true;
    if(attr_type == &UA_TYPES[UA_TYPES_VARIANT]) {
        wvalue.value.value = *(const UA_Variant*)attr;
    } else if(attr_type == &UA_TYPES[UA_TYPES_DATAVALUE]) {
        wvalue.value = *(const UA_DataValue*)attr;
    } else {
        /* hacked cast. the target WriteValue is used as const anyway */
        UA_Variant_setScalar(&wvalue.value.value,
                             (void*)(uintptr_t)attr, attr_type);
    }

    UA_StatusCode res = UA_STATUSCODE_GOOD;
    Operation_Write(server, session, NULL, &wvalue, &res);
    return res;
}

#ifdef UA_ENABLE_HISTORIZING
typedef void
 (*UA_HistoryDatabase_readFunc)(UA_Server *server, void *hdbContext,
                                const UA_NodeId *sessionId, void *sessionContext,
                                const UA_RequestHeader *requestHeader,
                                const void *historyReadDetails,
                                UA_TimestampsToReturn timestampsToReturn,
                                UA_Boolean releaseContinuationPoints,
                                size_t nodesToReadSize,
                                const UA_HistoryReadValueId *nodesToRead,
                                UA_HistoryReadResponse *response,
                                void * const * const historyData);

void
Service_HistoryRead(UA_Server *server, UA_Session *session,
                    const UA_HistoryReadRequest *request,
                    UA_HistoryReadResponse *response) {
    UA_assert(session != NULL);
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    if(server->config.historyDatabase.context == NULL) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTSUPPORTED;
        return;
    }

    if(request->historyReadDetails.encoding != UA_EXTENSIONOBJECT_DECODED) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTSUPPORTED;
        return;
    }

    const UA_DataType *historyDataType = &UA_TYPES[UA_TYPES_HISTORYDATA];
    UA_HistoryDatabase_readFunc readHistory = NULL;
    if(request->historyReadDetails.content.decoded.type ==
       &UA_TYPES[UA_TYPES_READRAWMODIFIEDDETAILS]) {
        UA_ReadRawModifiedDetails *details = (UA_ReadRawModifiedDetails*)
            request->historyReadDetails.content.decoded.data;
        if(!details->isReadModified) {
            readHistory = (UA_HistoryDatabase_readFunc)
                server->config.historyDatabase.readRaw;
        } else {
            historyDataType = &UA_TYPES[UA_TYPES_HISTORYMODIFIEDDATA];
            readHistory = (UA_HistoryDatabase_readFunc)
                server->config.historyDatabase.readModified;
        }
    } else if(request->historyReadDetails.content.decoded.type ==
              &UA_TYPES[UA_TYPES_READEVENTDETAILS]) {
        historyDataType = &UA_TYPES[UA_TYPES_HISTORYEVENT];
        readHistory = (UA_HistoryDatabase_readFunc)
            server->config.historyDatabase.readEvent;
    } else if(request->historyReadDetails.content.decoded.type ==
              &UA_TYPES[UA_TYPES_READPROCESSEDDETAILS]) {
        readHistory = (UA_HistoryDatabase_readFunc)
            server->config.historyDatabase.readProcessed;
    } else if(request->historyReadDetails.content.decoded.type ==
              &UA_TYPES[UA_TYPES_READATTIMEDETAILS]) {
        readHistory = (UA_HistoryDatabase_readFunc)
            server->config.historyDatabase.readAtTime;
    } else {
        /* TODO handle more request->historyReadDetails.content.decoded.type types */
        response->responseHeader.serviceResult = UA_STATUSCODE_BADHISTORYOPERATIONUNSUPPORTED;
        return;
    }

    /* Something to do? */
    if(request->nodesToReadSize == 0) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
        return;
    }

    /* Check if there are too many operations */
    if(server->config.maxNodesPerRead != 0 &&
       request->nodesToReadSize > server->config.maxNodesPerRead) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return;
    }

    /* Allocate a temporary array to forward the result pointers to the
     * backend */
    void **historyData = (void **)
        UA_calloc(request->nodesToReadSize, sizeof(void*));
    if(!historyData) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
        return;
    }

    /* Allocate the results array */
    response->results = (UA_HistoryReadResult*)
        UA_Array_new(request->nodesToReadSize, &UA_TYPES[UA_TYPES_HISTORYREADRESULT]);
    if(!response->results) {
        UA_free(historyData);
        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
        return;
    }
    response->resultsSize = request->nodesToReadSize;

    for(size_t i = 0; i < response->resultsSize; ++i) {
        void * data = UA_new(historyDataType);
        UA_ExtensionObject_setValue(&response->results[i].historyData,
                                    data, historyDataType);
        historyData[i] = data;
    }
    UA_UNLOCK(&server->serviceMutex);
    readHistory(server, server->config.historyDatabase.context,
                &session->sessionId, session->context,
                &request->requestHeader,
                request->historyReadDetails.content.decoded.data,
                request->timestampsToReturn,
                request->releaseContinuationPoints,
                request->nodesToReadSize, request->nodesToRead,
                response, historyData);
    UA_LOCK(&server->serviceMutex);
    UA_free(historyData);
}

void
Service_HistoryUpdate(UA_Server *server, UA_Session *session,
                    const UA_HistoryUpdateRequest *request,
                    UA_HistoryUpdateResponse *response) {
    UA_assert(session != NULL);
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    response->resultsSize = request->historyUpdateDetailsSize;
    response->results = (UA_HistoryUpdateResult*)
        UA_Array_new(response->resultsSize, &UA_TYPES[UA_TYPES_HISTORYUPDATERESULT]);
    if(!response->results) {
        response->resultsSize = 0;
        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
        return;
    }

    for(size_t i = 0; i < request->historyUpdateDetailsSize; ++i) {
        UA_HistoryUpdateResult_init(&response->results[i]);
        if(request->historyUpdateDetails[i].encoding != UA_EXTENSIONOBJECT_DECODED) {
            response->results[i].statusCode = UA_STATUSCODE_BADNOTSUPPORTED;
            continue;
        }

        const UA_DataType *updateDetailsType =
            request->historyUpdateDetails[i].content.decoded.type;
        void *updateDetailsData = request->historyUpdateDetails[i].content.decoded.data;

        if(updateDetailsType == &UA_TYPES[UA_TYPES_UPDATEDATADETAILS]) {
            if(!server->config.historyDatabase.updateData) {
                response->results[i].statusCode = UA_STATUSCODE_BADNOTSUPPORTED;
                continue;
            }
            UA_UNLOCK(&server->serviceMutex);
            server->config.historyDatabase.
                updateData(server, server->config.historyDatabase.context,
                           &session->sessionId, session->context,
                           &request->requestHeader,
                           (UA_UpdateDataDetails*)updateDetailsData,
                           &response->results[i]);
            UA_LOCK(&server->serviceMutex);
            continue;
        }

        if(updateDetailsType == &UA_TYPES[UA_TYPES_DELETERAWMODIFIEDDETAILS]) {
            if(!server->config.historyDatabase.deleteRawModified) {
                response->results[i].statusCode = UA_STATUSCODE_BADNOTSUPPORTED;
                continue;
            }
            UA_UNLOCK(&server->serviceMutex);
            server->config.historyDatabase.
                deleteRawModified(server, server->config.historyDatabase.context,
                                  &session->sessionId, session->context,
                                  &request->requestHeader,
                                  (UA_DeleteRawModifiedDetails*)updateDetailsData,
                                  &response->results[i]);
            UA_LOCK(&server->serviceMutex);
            continue;
        }

        response->results[i].statusCode = UA_STATUSCODE_BADNOTSUPPORTED;
    }
}

#endif

UA_StatusCode
UA_Server_writeObjectProperty(UA_Server *server, const UA_NodeId objectId,
                              const UA_QualifiedName propertyName,
                              const UA_Variant value) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode retVal = writeObjectProperty(server, objectId, propertyName, value);
    UA_UNLOCK(&server->serviceMutex);
    return retVal;
}

UA_StatusCode
writeObjectProperty(UA_Server *server, const UA_NodeId objectId,
                    const UA_QualifiedName propertyName,
                    const UA_Variant value) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    UA_RelativePathElement rpe;
    UA_RelativePathElement_init(&rpe);
    rpe.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
    rpe.isInverse = false;
    rpe.includeSubtypes = false;
    rpe.targetName = propertyName;

    UA_BrowsePath bp;
    UA_BrowsePath_init(&bp);
    bp.startingNode = objectId;
    bp.relativePath.elementsSize = 1;
    bp.relativePath.elements = &rpe;

    UA_StatusCode retval;
    UA_BrowsePathResult bpr = translateBrowsePathToNodeIds(server, &bp);
    if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
        retval = bpr.statusCode;
        UA_BrowsePathResult_clear(&bpr);
        return retval;
    }

    retval = writeValueAttribute(server, bpr.targets[0].targetId.nodeId, &value);

    UA_BrowsePathResult_clear(&bpr);
    return retval;
}

UA_StatusCode
writeObjectProperty_scalar(UA_Server *server, const UA_NodeId objectId,
                                     const UA_QualifiedName propertyName,
                                     const void *value, const UA_DataType *type) {
    UA_Variant var;
    UA_Variant_init(&var);
    UA_Variant_setScalar(&var, (void*)(uintptr_t)value, type);
    return writeObjectProperty(server, objectId, propertyName, var);
}

UA_StatusCode UA_EXPORT
UA_Server_writeObjectProperty_scalar(UA_Server *server, const UA_NodeId objectId,
                                     const UA_QualifiedName propertyName,
                                     const void *value, const UA_DataType *type) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode retval = 
        writeObjectProperty_scalar(server, objectId, propertyName, value, type);
    UA_UNLOCK(&server->serviceMutex);
    return retval;
}

static UA_LocalizedText
getLocalizedForSession(const UA_Session *session,
                       const UA_LocalizedTextListEntry *root) {
    const UA_LocalizedTextListEntry *lt;
    UA_LocalizedText result;
    UA_LocalizedText_init(&result);

    /* No session. Return the first  */
    if(!session)
        goto not_found;

    /* Exact match? */
    for(size_t i = 0; i < session->localeIdsSize; ++i) {
        for(lt = root; lt != NULL; lt = lt->next) {
            if(UA_String_equal(&session->localeIds[i], &lt->localizedText.locale))
                return lt->localizedText;
        }
    }

    /* Partial match, e.g. de-DE instead of de-CH */
    for(size_t i = 0; i < session->localeIdsSize; ++i) {
        if(session->localeIds[i].length < 2 ||
           (session->localeIdsSize > 2 &&
            session->localeIds[i].data[2] != '-'))
            continue;

        UA_String requestedPrefix;
        requestedPrefix.data = session->localeIds[i].data;
        requestedPrefix.length = 2;

        for(lt = root; lt != NULL; lt = lt->next) {
            if(lt->localizedText.locale.length < 2 ||
               (lt->localizedText.locale.length > 2 &&
                lt->localizedText.locale.data[2] != '-'))
                continue;

            UA_String currentPrefix;
            currentPrefix.data = lt->localizedText.locale.data;
            currentPrefix.length = 2;

            if(UA_String_equal(&requestedPrefix, &currentPrefix))
                return lt->localizedText;
        }
    }

    /* Not found. Return the first localized text that was added (last in the
     * linked list). Return an empty result if the list is empty. */
 not_found:
    if(!root)
        return result;
    while(root->next)
        root = root->next;
    return root->localizedText;
}

UA_LocalizedText
UA_Session_getNodeDisplayName(const UA_Session *session,
                              const UA_NodeHead *head) {
    return getLocalizedForSession(session, head->displayName);
}

UA_LocalizedText
UA_Session_getNodeDescription(const UA_Session *session,
                              const UA_NodeHead *head) {
    return getLocalizedForSession(session, head->description);
}

/**** amalgamated original file "/src/server/ua_services_discovery.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014-2016 (c) Sten Grüner
 *    Copyright 2014, 2017 (c) Florian Palm
 *    Copyright 2016 (c) Oleksiy Vasylyev
 *    Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) frax2222
 *    Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
 */


#ifdef UA_ENABLE_DISCOVERY


static UA_StatusCode
setApplicationDescriptionFromRegisteredServer(const UA_FindServersRequest *request,
                                              UA_ApplicationDescription *target,
                                              const UA_RegisteredServer *rs) {
    UA_ApplicationDescription_init(target);
    UA_StatusCode retval =
        UA_String_copy(&rs->serverUri, &target->applicationUri);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    retval = UA_String_copy(&rs->productUri, &target->productUri);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    // if the client requests a specific locale, select the corresponding server name
    if(request->localeIdsSize) {
        UA_Boolean appNameFound = false;
        for(size_t i =0; i<request->localeIdsSize && !appNameFound; i++) {
            for(size_t j =0; j<rs->serverNamesSize; j++) {
                if(UA_String_equal(&request->localeIds[i],
                                   &rs->serverNames[j].locale)) {
                    retval = UA_LocalizedText_copy(&rs->serverNames[j],
                                                   &target->applicationName);
                    if(retval != UA_STATUSCODE_GOOD)
                        return retval;
                    appNameFound = true;
                    break;
                }
            }
        }

        // server does not have the requested local, therefore we can select the
        // most suitable one
        if(!appNameFound && rs->serverNamesSize) {
            retval = UA_LocalizedText_copy(&rs->serverNames[0],
                                           &target->applicationName);
            if(retval != UA_STATUSCODE_GOOD)
                return retval;
        }
    } else if(rs->serverNamesSize) {
        // just take the first name
        retval = UA_LocalizedText_copy(&rs->serverNames[0],
                                       &target->applicationName);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
    }

    target->applicationType = rs->serverType;
    retval = UA_String_copy(&rs->gatewayServerUri, &target->gatewayServerUri);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    // TODO where do we get the discoveryProfileUri for application data?

    target->discoveryUrlsSize = rs->discoveryUrlsSize;
    if(rs->discoveryUrlsSize) {
        size_t duSize = sizeof(UA_String) * rs->discoveryUrlsSize;
        target->discoveryUrls = (UA_String *)UA_malloc(duSize);
        if(!target->discoveryUrls)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        for(size_t i = 0; i < rs->discoveryUrlsSize; i++) {
            retval = UA_String_copy(&rs->discoveryUrls[i],
                                    &target->discoveryUrls[i]);
            if(retval != UA_STATUSCODE_GOOD)
                return retval;
        }
    }

    return retval;
}
#endif

void Service_FindServers(UA_Server *server, UA_Session *session,
                         const UA_FindServersRequest *request,
                         UA_FindServersResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session, "Processing FindServersRequest");
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Return the server itself? */
    UA_Boolean foundSelf = false;
    if(request->serverUrisSize) {
        for(size_t i = 0; i < request->serverUrisSize; i++) {
            if(UA_String_equal(&request->serverUris[i],
                               &server->config.applicationDescription.applicationUri)) {
                foundSelf = true;
                break;
            }
        }
    } else {
        foundSelf = true;
    }

#ifndef UA_ENABLE_DISCOVERY
    if(!foundSelf)
        return;

    response->responseHeader.serviceResult =
        UA_Array_copy(&server->config.applicationDescription, 1,
                      (void**)&response->servers,
                      &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION]);
    if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
        return;

    response->serversSize = 1;
#else
    UA_DiscoveryManager *dm = (UA_DiscoveryManager*)
        getServerComponentByName(server, UA_STRING("discovery"));
    if(!dm) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR;
        return;
    }

    /* Allocate enough memory, including memory for the "self" response */
    size_t maxResults = dm->registeredServersSize + 1;
    response->servers = (UA_ApplicationDescription*)
        UA_Array_new(maxResults, &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION]);
    if(!response->servers) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
        return;
    }

    /* Copy into the response. TODO: Evaluate return codes */
    size_t pos = 0;
    if(foundSelf)
        UA_ApplicationDescription_copy(&server->config.applicationDescription,
                                       &response->servers[pos++]);

    registeredServer *current;
    LIST_FOREACH(current, &dm->registeredServers, pointers) {
        UA_Boolean usable = (request->serverUrisSize == 0);
        if(!usable) {
            /* If client only requested a specific set of servers */
            for(size_t i = 0; i < request->serverUrisSize; i++) {
                if(UA_String_equal(&current->registeredServer.serverUri,
                                   &request->serverUris[i])) {
                    usable = true;
                    break;
                }
            }
        }

        if(usable)
            setApplicationDescriptionFromRegisteredServer(request, &response->servers[pos++],
                                                          &current->registeredServer);
    }

    /* Set the final size */
    if(pos > 0) {
        response->serversSize = pos;
    } else {
        UA_free(response->servers);
        response->servers = NULL;
    }
#endif

    if(request->endpointUrl.length > 0 && response->servers != NULL) {
        for(size_t i = 0; i < response->serversSize; i++) {
            UA_Array_delete(response->servers[i].discoveryUrls,
                            response->servers[i].discoveryUrlsSize,
                            &UA_TYPES[UA_TYPES_STRING]);
            response->servers[i].discoveryUrls = NULL;
            response->servers[i].discoveryUrlsSize = 0;
            response->responseHeader.serviceResult |=
                UA_Array_appendCopy((void**)&response->servers[i].discoveryUrls,
                                    &response->servers[i].discoveryUrlsSize,
                                    &request->endpointUrl, &UA_TYPES[UA_TYPES_STRING]);
        }
    }
}

#if defined(UA_ENABLE_DISCOVERY) && defined(UA_ENABLE_DISCOVERY_MULTICAST)
/* All filter criteria must be fulfilled in the list entry. The comparison is
 * case insensitive. Returns true if the entry matches the filter. */
static UA_Boolean
entryMatchesCapabilityFilter(size_t serverCapabilityFilterSize,
                             UA_String *serverCapabilityFilter,
                             serverOnNetwork *current) {
    /* If the entry has less capabilities defined than the filter, there's no match */
    if(serverCapabilityFilterSize > current->serverOnNetwork.serverCapabilitiesSize)
        return false;
    for(size_t i = 0; i < serverCapabilityFilterSize; i++) {
        UA_Boolean capabilityFound = false;
        for(size_t j = 0; j < current->serverOnNetwork.serverCapabilitiesSize; j++) {
            if(UA_String_equal_ignorecase(&serverCapabilityFilter[i],
                               &current->serverOnNetwork.serverCapabilities[j])) {
                capabilityFound = true;
                break;
            }
        }
        if(!capabilityFound)
            return false;
    }
    return true;
}

void
Service_FindServersOnNetwork(UA_Server *server, UA_Session *session,
                             const UA_FindServersOnNetworkRequest *request,
                             UA_FindServersOnNetworkResponse *response) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_DiscoveryManager *dm = (UA_DiscoveryManager*)
        getServerComponentByName(server, UA_STRING("discovery"));
    if(!dm) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR;
        return;
    }

    if(!server->config.mdnsEnabled) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTIMPLEMENTED;
        return;
    }

    /* Set LastCounterResetTime */
    response->lastCounterResetTime =
        dm->serverOnNetworkRecordIdLastReset;

    /* Compute the max number of records to return */
    UA_UInt32 recordCount = 0;
    if(request->startingRecordId < dm->serverOnNetworkRecordIdCounter)
        recordCount = dm->serverOnNetworkRecordIdCounter - request->startingRecordId;
    if(request->maxRecordsToReturn && recordCount > request->maxRecordsToReturn)
        recordCount = UA_MIN(recordCount, request->maxRecordsToReturn);
    if(recordCount == 0) {
        response->serversSize = 0;
        return;
    }

    /* Iterate over all records and add to filtered list */
    UA_UInt32 filteredCount = 0;
    UA_STACKARRAY(UA_ServerOnNetwork*, filtered, recordCount);
    serverOnNetwork *current;
    LIST_FOREACH(current, &dm->serverOnNetwork, pointers) {
        if(filteredCount >= recordCount)
            break;
        if(current->serverOnNetwork.recordId < request->startingRecordId)
            continue;
        if(!entryMatchesCapabilityFilter(request->serverCapabilityFilterSize,
                               request->serverCapabilityFilter, current))
            continue;
        filtered[filteredCount++] = &current->serverOnNetwork;
    }

    if(filteredCount == 0)
        return;

    /* Allocate the array for the response */
    response->servers = (UA_ServerOnNetwork*)
        UA_malloc(sizeof(UA_ServerOnNetwork)*filteredCount);
    if(!response->servers) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
        return;
    }
    response->serversSize = filteredCount;

    /* Copy the server names */
    for(size_t i = 0; i < filteredCount; i++)
        UA_ServerOnNetwork_copy(filtered[i], &response->servers[filteredCount-i-1]);
}
#endif

static const UA_String UA_SECURITY_POLICY_BASIC256SHA256_URI =
    UA_STRING_STATIC("http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256");

UA_SecurityPolicy *
getDefaultEncryptedSecurityPolicy(UA_Server *server) {
    for(size_t i = 0; i < server->config.securityPoliciesSize; i++) {
        UA_SecurityPolicy *sp = &server->config.securityPolicies[i];
        if(UA_String_equal(&UA_SECURITY_POLICY_BASIC256SHA256_URI, &sp->policyUri))
            return sp;
    }
    for(size_t i = server->config.securityPoliciesSize; i > 0; i--) {
        UA_SecurityPolicy *sp = &server->config.securityPolicies[i-1];
        if(!UA_String_equal(&UA_SECURITY_POLICY_NONE_URI, &sp->policyUri))
            return sp;
    }
    UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_CLIENT,
                   "Could not find a SecurityPolicy with encryption for the "
                   "UserTokenPolicy. Using an unencrypted policy.");
    return server->config.securityPoliciesSize > 0 ?
        &server->config.securityPolicies[0]: NULL;
}

const char *securityModeStrs[4] = {"-invalid", "-none", "-sign", "-sign+encrypt"};

static UA_String
securityPolicyUriPostfix(const UA_String uri) {
    for(size_t i = 0; i < uri.length; i++) {
        if(uri.data[i] != '#')
            continue;
        UA_String postfix = {uri.length - i, &uri.data[i]};
        return postfix;
    }
    return uri;
}

static UA_StatusCode
updateEndpointUserIdentityToken(UA_Server *server, UA_EndpointDescription *ed) {
    /* Don't change the UserIdentityTokens if there are manually configured
     * entries */
    if(ed->userIdentityTokensSize > 0)
        return UA_STATUSCODE_GOOD;

    /* Copy the UserTokenPolicies from the AccessControl plugin, but only the matching ones to the securityPolicyUri.
     * TODO: Different instances of the AccessControl plugin per Endpoint */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    for(size_t i = 0; i < server->config.accessControl.userTokenPoliciesSize; i++) {
        UA_UserTokenPolicy *utp = &server->config.accessControl.userTokenPolicies[i];
        if(UA_String_equal(&ed->securityPolicyUri, &utp->securityPolicyUri)) {
             res = UA_Array_appendCopy((void**)&ed->userIdentityTokens,
                                &ed->userIdentityTokensSize,
                                utp,
                                &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
            if(res != UA_STATUSCODE_GOOD)
                return res;
        }
    }

    for(size_t i = 0; i < ed->userIdentityTokensSize; i++) {
        /* Use the securityPolicy of the SecureChannel. But not if the
         * SecureChannel is unencrypted and there is a non-anonymous token. */
        UA_UserTokenPolicy *utp = &ed->userIdentityTokens[i];
        UA_String_clear(&utp->securityPolicyUri);
        if((!server->config.allowNonePolicyPassword || ed->userIdentityTokens[i].tokenType != UA_USERTOKENTYPE_USERNAME) &&
           UA_String_equal(&ed->securityPolicyUri, &UA_SECURITY_POLICY_NONE_URI) &&
           utp->tokenType != UA_USERTOKENTYPE_ANONYMOUS) {
            UA_SecurityPolicy *encSP = getDefaultEncryptedSecurityPolicy(server);
            if(encSP)
                res |= UA_String_copy(&encSP->policyUri, &utp->securityPolicyUri);
        }

        /* Append the SecurityMode and SecurityPolicy postfix to the PolicyId to
         * make it unique */
        UA_String postfix;
        if(utp->securityPolicyUri.length > 0)
            postfix = securityPolicyUriPostfix(utp->securityPolicyUri);
        else
            postfix = securityPolicyUriPostfix(ed->securityPolicyUri);
        size_t newLen = utp->policyId.length + postfix.length +
            strlen(securityModeStrs[ed->securityMode]);
        UA_Byte *newString = (UA_Byte*)UA_realloc(utp->policyId.data, newLen);
        if(!newString)
            continue;
        size_t pos = utp->policyId.length;
        memcpy(&newString[pos], securityModeStrs[ed->securityMode],
               strlen(securityModeStrs[ed->securityMode]));
        pos += strlen(securityModeStrs[ed->securityMode]);
        memcpy(&newString[pos], postfix.data, postfix.length);
        utp->policyId.data = newString;
        utp->policyId.length = newLen;
    }

    return res;
}

/* Also reused to create the EndpointDescription array in the CreateSessionResponse */
UA_StatusCode
setCurrentEndPointsArray(UA_Server *server, const UA_String endpointUrl,
                         UA_String *profileUris, size_t profileUrisSize,
                         UA_EndpointDescription **arr, size_t *arrSize) {
    /* Clone the endpoint for each discoveryURL? */
    size_t clone_times = 1;
    if(endpointUrl.length == 0)
        clone_times = server->config.applicationDescription.discoveryUrlsSize;

    /* Allocate the array */
    *arr = (UA_EndpointDescription*)
        UA_Array_new(server->config.endpointsSize * clone_times,
                     &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
    if(!*arr)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    size_t pos = 0;
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    for(size_t j = 0; j < server->config.endpointsSize; ++j) {
        /* Test if the supported binary profile shall be returned */
        UA_Boolean usable = (profileUrisSize == 0);
        if(!usable) {
            for(size_t i = 0; i < profileUrisSize; ++i) {
                if(!UA_String_equal(&profileUris[i], &server->config.endpoints[j].transportProfileUri))
                    continue;
                usable = true;
                break;
            }
        }
        if(!usable)
            continue;

        /* Copy into the results */
        for(size_t i = 0; i < clone_times; ++i) {
            /* Copy the endpoint with a current ApplicationDescription */
            UA_EndpointDescription *ed = &(*arr)[pos];
            retval |= UA_EndpointDescription_copy(&server->config.endpoints[j], ed);
            UA_ApplicationDescription_clear(&ed->server);
            retval |= UA_ApplicationDescription_copy(&server->config.applicationDescription,
                                                     &ed->server);

            /* Return the certificate for the SecurityPolicy. If the
             * SecureChannel is unencrypted, select the default encrypted
             * SecurityPolicy. */
            UA_SecurityPolicy *sp = getSecurityPolicyByUri(server, &ed->securityPolicyUri);
            if(!sp || UA_String_equal(&UA_SECURITY_POLICY_NONE_URI, &sp->policyUri))
                sp = getDefaultEncryptedSecurityPolicy(server);
            if(sp) {
                UA_ByteString_clear(&ed->serverCertificate);
                retval |= UA_String_copy(&sp->localCertificate, &ed->serverCertificate);
            }

            /* Set the User Identity Token list fromt the AccessControl plugin */
            retval |= updateEndpointUserIdentityToken(server, ed);

            /* Set the EndpointURL */
            UA_String_clear(&ed->endpointUrl);
            if(endpointUrl.length == 0) {
                retval |= UA_String_copy(&server->config.applicationDescription.
                                         discoveryUrls[i], &ed->endpointUrl);
            } else {
                /* Mirror back the requested EndpointUrl and also add it to the
                 * array of discovery urls */
                retval |= UA_String_copy(&endpointUrl, &ed->endpointUrl);
                retval |= UA_Array_appendCopy((void**)&ed->server.discoveryUrls,
                                              &ed->server.discoveryUrlsSize,
                                              &endpointUrl, &UA_TYPES[UA_TYPES_STRING]);
            }
            if(retval != UA_STATUSCODE_GOOD)
                goto error;

            pos++;
        }
    }

    *arrSize = pos;
    return UA_STATUSCODE_GOOD;

 error:
    UA_Array_delete(*arr, server->config.endpointsSize * clone_times,
                    &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
    *arr = NULL;
    return retval;
}

void
Service_GetEndpoints(UA_Server *server, UA_Session *session,
                     const UA_GetEndpointsRequest *request,
                     UA_GetEndpointsResponse *response) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* If the client expects to see a specific endpointurl, mirror it back. If
     * not, clone the endpoints with the discovery url of all networklayers. */
    if(request->endpointUrl.length > 0) {
        UA_LOG_DEBUG_SESSION(server->config.logging, session,
                             "Processing GetEndpointsRequest with endpointUrl "
                             UA_PRINTF_STRING_FORMAT, UA_PRINTF_STRING_DATA(request->endpointUrl));
    } else {
        UA_LOG_DEBUG_SESSION(server->config.logging, session,
                             "Processing GetEndpointsRequest with an empty endpointUrl");
    }

    response->responseHeader.serviceResult =
        setCurrentEndPointsArray(server, request->endpointUrl,
                                 request->profileUris, request->profileUrisSize,
                                 &response->endpoints, &response->endpointsSize);
}

#ifdef UA_ENABLE_DISCOVERY

static void
process_RegisterServer(UA_Server *server, UA_Session *session,
                       const UA_RequestHeader* requestHeader,
                       const UA_RegisteredServer *requestServer,
                       const size_t requestDiscoveryConfigurationSize,
                       const UA_ExtensionObject *requestDiscoveryConfiguration,
                       UA_ResponseHeader* responseHeader,
                       size_t *responseConfigurationResultsSize,
                       UA_StatusCode **responseConfigurationResults,
                       size_t *responseDiagnosticInfosSize,
                       UA_DiagnosticInfo *responseDiagnosticInfos) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_DiscoveryManager *dm = (UA_DiscoveryManager*)
        getServerComponentByName(server, UA_STRING("discovery"));
    if(!dm)
        return;

    if(server->config.applicationDescription.applicationType != UA_APPLICATIONTYPE_DISCOVERYSERVER) {
        responseHeader->serviceResult = UA_STATUSCODE_BADSERVICEUNSUPPORTED;
        return;
    }

    /* Find the server from the request in the registered list */
    registeredServer *rs = NULL;
    LIST_FOREACH(rs, &dm->registeredServers, pointers) {
        if(UA_String_equal(&rs->registeredServer.serverUri, &requestServer->serverUri))
            break;
    }

    UA_MdnsDiscoveryConfiguration *mdnsConfig = NULL;

    const UA_String* mdnsServerName = NULL;
    if(requestDiscoveryConfigurationSize) {
        *responseConfigurationResults =
            (UA_StatusCode *)UA_Array_new(requestDiscoveryConfigurationSize,
                                          &UA_TYPES[UA_TYPES_STATUSCODE]);
        if(!(*responseConfigurationResults)) {
            responseHeader->serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
            return;
        }
        *responseConfigurationResultsSize = requestDiscoveryConfigurationSize;

        for(size_t i = 0; i < requestDiscoveryConfigurationSize; i++) {
            const UA_ExtensionObject *object = &requestDiscoveryConfiguration[i];
            if(!mdnsConfig && (object->encoding == UA_EXTENSIONOBJECT_DECODED ||
                               object->encoding == UA_EXTENSIONOBJECT_DECODED_NODELETE) &&
               (object->content.decoded.type == &UA_TYPES[UA_TYPES_MDNSDISCOVERYCONFIGURATION])) {
                mdnsConfig = (UA_MdnsDiscoveryConfiguration *)object->content.decoded.data;
                mdnsServerName = &mdnsConfig->mdnsServerName;
                (*responseConfigurationResults)[i] = UA_STATUSCODE_GOOD;
            } else {
                (*responseConfigurationResults)[i] = UA_STATUSCODE_BADNOTSUPPORTED;
            }
        }
    }

    if(!mdnsServerName && requestServer->serverNamesSize)
        mdnsServerName = &requestServer->serverNames[0].text;

    if(!mdnsServerName) {
        responseHeader->serviceResult = UA_STATUSCODE_BADSERVERNAMEMISSING;
        return;
    }

    if(requestServer->discoveryUrlsSize == 0) {
        responseHeader->serviceResult = UA_STATUSCODE_BADDISCOVERYURLMISSING;
        return;
    }

    if(requestServer->semaphoreFilePath.length) {
#ifdef UA_ENABLE_DISCOVERY_SEMAPHORE
        char* filePath = (char*)
            UA_malloc(sizeof(char)*requestServer->semaphoreFilePath.length+1);
        if(!filePath) {
            UA_LOG_ERROR_SESSION(server->config.logging, session,
                                 "Cannot allocate memory for semaphore path. Out of memory.");
            responseHeader->serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
            return;
        }
        memcpy(filePath, requestServer->semaphoreFilePath.data,
               requestServer->semaphoreFilePath.length );
        filePath[requestServer->semaphoreFilePath.length] = '\0';
        if(!UA_fileExists( filePath )) {
            responseHeader->serviceResult = UA_STATUSCODE_BADSEMPAHOREFILEMISSING;
            UA_free(filePath);
            return;
        }
        UA_free(filePath);
#else
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_CLIENT,
                       "Ignoring semaphore file path. open62541 not compiled "
                       "with UA_ENABLE_DISCOVERY_SEMAPHORE=ON");
#endif
    }

#ifdef UA_ENABLE_DISCOVERY_MULTICAST
    if(server->config.mdnsEnabled) {
        for(size_t i = 0; i < requestServer->discoveryUrlsSize; i++) {
            /* create TXT if is online and first index, delete TXT if is offline
             * and last index */
            UA_Boolean updateTxt = (requestServer->isOnline && i==0) ||
                (!requestServer->isOnline && i==requestServer->discoveryUrlsSize);
            UA_Discovery_updateMdnsForDiscoveryUrl(dm, mdnsServerName, mdnsConfig,
                                                   &requestServer->discoveryUrls[i],
                                                   requestServer->isOnline, updateTxt);
        }
    }
#endif

    if(!requestServer->isOnline) {
        // server is shutting down. Remove it from the registered servers list
        if(!rs) {
            // server not found, show warning
            UA_LOG_WARNING_SESSION(server->config.logging, session,
                                   "Could not unregister server %.*s. Not registered.",
                                   (int)requestServer->serverUri.length,
                                   requestServer->serverUri.data);
            responseHeader->serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
            return;
        }

        if(dm->registerServerCallback) {
            UA_UNLOCK(&server->serviceMutex);
            dm->registerServerCallback(requestServer,
                                       dm->registerServerCallbackData);
            UA_LOCK(&server->serviceMutex);
        }

        // server found, remove from list
        LIST_REMOVE(rs, pointers);
        UA_RegisteredServer_clear(&rs->registeredServer);
        UA_free(rs);
        dm->registeredServersSize--;
        responseHeader->serviceResult = UA_STATUSCODE_GOOD;
        return;
    }

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(!rs) {
        // server not yet registered, register it by adding it to the list
        UA_LOG_DEBUG_SESSION(server->config.logging, session,
                             "Registering new server: %.*s",
                             (int)requestServer->serverUri.length,
                             requestServer->serverUri.data);

        rs = (registeredServer*)UA_malloc(sizeof(registeredServer));
        if(!rs) {
            responseHeader->serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
            return;
        }

        LIST_INSERT_HEAD(&dm->registeredServers, rs, pointers);
        dm->registeredServersSize++;
    } else {
        UA_RegisteredServer_clear(&rs->registeredServer);
    }

    // Always call the callback, if it is set. Previously we only called it if
    // it was a new register call. It may be the case that this endpoint
    // registered before, then crashed, restarts and registeres again. In that
    // case the entry is not deleted and the callback would not be called.
    if(dm->registerServerCallback) {
        UA_UNLOCK(&server->serviceMutex);
        dm->registerServerCallback(requestServer,
                                   dm->registerServerCallbackData);
        UA_LOCK(&server->serviceMutex);
    }

    // copy the data from the request into the list
    UA_EventLoop *el = server->config.eventLoop;
    UA_DateTime nowMonotonic = el->dateTime_nowMonotonic(el);
    UA_RegisteredServer_copy(requestServer, &rs->registeredServer);
    rs->lastSeen = nowMonotonic;
    responseHeader->serviceResult = retval;
}

void Service_RegisterServer(UA_Server *server, UA_Session *session,
                            const UA_RegisterServerRequest *request,
                            UA_RegisterServerResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing RegisterServerRequest");
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    process_RegisterServer(server, session, &request->requestHeader, &request->server, 0,
                           NULL, &response->responseHeader, 0, NULL, 0, NULL);
}

void Service_RegisterServer2(UA_Server *server, UA_Session *session,
                            const UA_RegisterServer2Request *request,
                             UA_RegisterServer2Response *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing RegisterServer2Request");
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    process_RegisterServer(server, session, &request->requestHeader, &request->server,
                           request->discoveryConfigurationSize, request->discoveryConfiguration,
                           &response->responseHeader, &response->configurationResultsSize,
                           &response->configurationResults, &response->diagnosticInfosSize,
                           response->diagnosticInfos);
}

#endif /* UA_ENABLE_DISCOVERY */

/**** amalgamated original file "/src/server/ua_services_subscription.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2018, 2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2016-2017 (c) Florian Palm
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2018 (c) Ari Breitkreuz, fortiss GmbH
 *    Copyright 2017 (c) Mattias Bornhager
 *    Copyright 2017 (c) Henrik Norrman
 *    Copyright 2017-2018 (c) Thomas Stalder, Blue Time Concept SA
 *    Copyright 2018 (c) Fabian Arndt, Root-Core
 *    Copyright 2017-2019 (c) HMS Industrial Networks AB (Author: Jonas Green)
 */


#ifdef UA_ENABLE_SUBSCRIPTIONS /* conditional compilation */

static void
setSubscriptionSettings(UA_Server *server, UA_Subscription *subscription,
                        UA_Double requestedPublishingInterval,
                        UA_UInt32 requestedLifetimeCount,
                        UA_UInt32 requestedMaxKeepAliveCount,
                        UA_UInt32 maxNotificationsPerPublish,
                        UA_Byte priority) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* re-parameterize the subscription */
    UA_BOUNDEDVALUE_SETWBOUNDS(server->config.publishingIntervalLimits,
                               requestedPublishingInterval,
                               subscription->publishingInterval);
    /* check for nan*/
    if(requestedPublishingInterval != requestedPublishingInterval)
        subscription->publishingInterval = server->config.publishingIntervalLimits.min;
    UA_BOUNDEDVALUE_SETWBOUNDS(server->config.keepAliveCountLimits,
                               requestedMaxKeepAliveCount, subscription->maxKeepAliveCount);
    UA_BOUNDEDVALUE_SETWBOUNDS(server->config.lifeTimeCountLimits,
                               requestedLifetimeCount, subscription->lifeTimeCount);
    if(subscription->lifeTimeCount < 3 * subscription->maxKeepAliveCount)
        subscription->lifeTimeCount = 3 * subscription->maxKeepAliveCount;
    subscription->notificationsPerPublish = maxNotificationsPerPublish;
    if(maxNotificationsPerPublish == 0 ||
       maxNotificationsPerPublish > server->config.maxNotificationsPerPublish)
        subscription->notificationsPerPublish = server->config.maxNotificationsPerPublish;
    subscription->priority = priority;
}

void
Service_CreateSubscription(UA_Server *server, UA_Session *session,
                           const UA_CreateSubscriptionRequest *request,
                           UA_CreateSubscriptionResponse *response) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Check limits for the number of subscriptions */
    if(((server->config.maxSubscriptions != 0) &&
        (server->subscriptionsSize >= server->config.maxSubscriptions)) ||
       ((server->config.maxSubscriptionsPerSession != 0) &&
        (session->subscriptionsSize >= server->config.maxSubscriptionsPerSession))) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYSUBSCRIPTIONS;
        return;
    }

    /* Create the subscription */
    UA_Subscription *sub = UA_Subscription_new();
    if(!sub) {
        UA_LOG_DEBUG_SESSION(server->config.logging, session,
                             "Processing CreateSubscriptionRequest failed");
        response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
        return;
    }

    /* Set the subscription parameters */
    setSubscriptionSettings(server, sub, request->requestedPublishingInterval,
                            request->requestedLifetimeCount,
                            request->requestedMaxKeepAliveCount,
                            request->maxNotificationsPerPublish, request->priority);
    sub->subscriptionId = ++server->lastSubscriptionId;  /* Assign the SubscriptionId */

    /* Register the subscription in the server */
    LIST_INSERT_HEAD(&server->subscriptions, sub, serverListEntry);
    server->subscriptionsSize++;

    /* Update the server statistics */
    server->serverDiagnosticsSummary.currentSubscriptionCount++;
    server->serverDiagnosticsSummary.cumulatedSubscriptionCount++;

    /* Attach the Subscription to the session */
    UA_Session_attachSubscription(session, sub);

    /* Create representation in the Session object */
#ifdef UA_ENABLE_DIAGNOSTICS
    createSubscriptionObject(server, session, sub);
#endif

    /* Set the subscription state. This also registers the callback.
     * Note that also a disabled subscription publishes keepalives. */
    UA_SubscriptionState sState = (request->publishingEnabled) ?
        UA_SUBSCRIPTIONSTATE_ENABLED : UA_SUBSCRIPTIONSTATE_ENABLED_NOPUBLISH;
    UA_StatusCode res = Subscription_setState(server, sub, sState);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_DEBUG_SESSION(server->config.logging, sub->session,
                             "Subscription %" PRIu32 " | Could not register "
                             "publish callback with error code %s",
                             sub->subscriptionId, UA_StatusCode_name(res));
        response->responseHeader.serviceResult = res;
        UA_Subscription_delete(server, sub);
        return;
    }

    UA_LOG_INFO_SUBSCRIPTION(server->config.logging, sub,
                             "Subscription created (Publishing interval %.2fms, "
                             "max %lu notifications per publish)",
                             sub->publishingInterval,
                             (long unsigned)sub->notificationsPerPublish);

    /* Prepare the response */
    response->subscriptionId = sub->subscriptionId;
    response->revisedPublishingInterval = sub->publishingInterval;
    response->revisedLifetimeCount = sub->lifeTimeCount;
    response->revisedMaxKeepAliveCount = sub->maxKeepAliveCount;
}

void
Service_ModifySubscription(UA_Server *server, UA_Session *session,
                           const UA_ModifySubscriptionRequest *request,
                           UA_ModifySubscriptionResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing ModifySubscriptionRequest");
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_Subscription *sub = UA_Session_getSubscriptionById(session, request->subscriptionId);
    if(!sub) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
        return;
    }

    /* Store the old publishing interval */
    UA_Double oldPublishingInterval = sub->publishingInterval;
    UA_Byte oldPriority = sub->priority;

    /* Change the Subscription settings */
    setSubscriptionSettings(server, sub, request->requestedPublishingInterval,
                            request->requestedLifetimeCount,
                            request->requestedMaxKeepAliveCount,
                            request->maxNotificationsPerPublish, request->priority);

    /* Reset the subscription lifetime */
    Subscription_resetLifetime(sub);

    /* The publish interval has changed */
    if(sub->publishingInterval != oldPublishingInterval) {
        /* Change the repeated callback to the new interval. This cannot fail as
         * memory is reused. */
        if(sub->publishCallbackId > 0)
            changeRepeatedCallbackInterval(server, sub->publishCallbackId,
                                           sub->publishingInterval);

        /* For each MonitoredItem check if it was/shall be attached to the
         * publish interval. This ensures that we have less cyclic callbacks
         * registered and that the notifications are fresh. */
        UA_MonitoredItem *mon;
        LIST_FOREACH(mon, &sub->monitoredItems, listEntry) {
            if(mon->parameters.samplingInterval == sub->publishingInterval ||
               mon->parameters.samplingInterval == oldPublishingInterval) {
                UA_MonitoredItem_unregisterSampling(server, mon);
                UA_MonitoredItem_registerSampling(server, mon);
            }
        }
    }

    /* If the priority has changed, re-enter the subscription to the
     * priority-ordered queue in the session. */
    if(oldPriority != sub->priority) {
        UA_Session_detachSubscription(server, session, sub, false);
        UA_Session_attachSubscription(session, sub);
    }

    /* Set the response */
    response->revisedPublishingInterval = sub->publishingInterval;
    response->revisedLifetimeCount = sub->lifeTimeCount;
    response->revisedMaxKeepAliveCount = sub->maxKeepAliveCount;

    /* Update the diagnostics statistics */
#ifdef UA_ENABLE_DIAGNOSTICS
    sub->modifyCount++;
#endif
}

static void
Operation_SetPublishingMode(UA_Server *server, UA_Session *session,
                            const UA_Boolean *publishingEnabled,
                            const UA_UInt32 *subscriptionId,
                            UA_StatusCode *result) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    UA_Subscription *sub = UA_Session_getSubscriptionById(session, *subscriptionId);
    if(!sub) {
        *result = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
        return;
    }

    /* Enable/disable */
    UA_SubscriptionState sState = (*publishingEnabled) ?
        UA_SUBSCRIPTIONSTATE_ENABLED : UA_SUBSCRIPTIONSTATE_ENABLED_NOPUBLISH;
    *result = Subscription_setState(server, sub, sState);

    /* Reset the lifetime counter */
    Subscription_resetLifetime(sub);
}

void
Service_SetPublishingMode(UA_Server *server, UA_Session *session,
                          const UA_SetPublishingModeRequest *request,
                          UA_SetPublishingModeResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing SetPublishingModeRequest");
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_Boolean publishingEnabled = request->publishingEnabled; /* request is const */
    response->responseHeader.serviceResult =
        UA_Server_processServiceOperations(server, session,
                                           (UA_ServiceOperation)Operation_SetPublishingMode,
                                           &publishingEnabled,
                                           &request->subscriptionIdsSize,
                                           &UA_TYPES[UA_TYPES_UINT32],
                                           &response->resultsSize,
                                           &UA_TYPES[UA_TYPES_STATUSCODE]);
}

UA_StatusCode
Service_Publish(UA_Server *server, UA_Session *session,
                const UA_PublishRequest *request, UA_UInt32 requestId) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing PublishRequest with RequestId %u", requestId);
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Return an error if the session has no subscription */
    if(TAILQ_EMPTY(&session->subscriptions))
        return UA_STATUSCODE_BADNOSUBSCRIPTION;

    /* Handle too many subscriptions to free resources before trying to allocate
     * resources for the new publish request. If the limit has been reached the
     * oldest publish request are returned with an error message. */
    UA_Session_ensurePublishQueueSpace(server, session);

    /* Allocate the response to store it in the retransmission queue */
    UA_PublishResponseEntry *entry = (UA_PublishResponseEntry *)
        UA_malloc(sizeof(UA_PublishResponseEntry));
    if(!entry)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Prepare the response */
    entry->requestId = requestId;
    UA_PublishResponse *response = &entry->response;
    UA_PublishResponse_init(response);
    response->responseHeader.requestHandle = request->requestHeader.requestHandle;

    /* Allocate the results array to acknowledge the acknowledge */
    if(request->subscriptionAcknowledgementsSize > 0) {
        response->results = (UA_StatusCode *)
            UA_Array_new(request->subscriptionAcknowledgementsSize,
                         &UA_TYPES[UA_TYPES_STATUSCODE]);
        if(!response->results) {
            UA_free(entry);
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }
        response->resultsSize = request->subscriptionAcknowledgementsSize;
    }

    /* <--- A good StatusCode is returned from here on ---> */

    /* Delete Acknowledged Subscription Messages */
    for(size_t i = 0; i < request->subscriptionAcknowledgementsSize; ++i) {
        UA_SubscriptionAcknowledgement *ack = &request->subscriptionAcknowledgements[i];
        UA_Subscription *sub = UA_Session_getSubscriptionById(session, ack->subscriptionId);
        if(!sub) {
            response->results[i] = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
            UA_LOG_DEBUG_SESSION(server->config.logging, session,
                                 "Cannot process acknowledgements subscription %u" PRIu32,
                                 ack->subscriptionId);
            continue;
        }
        /* Remove the acked transmission from the retransmission queue */
        response->results[i] =
            UA_Subscription_removeRetransmissionMessage(sub, ack->sequenceNumber);
    }

    /* Set the maxTime if a timeout hint is defined */
    entry->maxTime = UA_INT64_MAX;
    if(request->requestHeader.timeoutHint > 0) {
        UA_EventLoop *el = server->config.eventLoop;
        entry->maxTime = el->dateTime_nowMonotonic(el) +
            (request->requestHeader.timeoutHint * UA_DATETIME_MSEC);
    }

    /* Queue the publish response. It will be dequeued in a repeated publish
     * callback. This can also be triggered right now for a late
     * subscription. */
    UA_Session_queuePublishReq(session, entry, false);
    UA_LOG_DEBUG_SESSION(server->config.logging, session, "Queued a publication message");

    /* If there are late subscriptions, the new publish request is used to
     * answer them immediately. Late subscriptions with higher priority are
     * considered earlier. However, a single subscription that generates many
     * notifications must not "starve" other late subscriptions. Hence we move
     * it to the end of the queue for the subscriptions of that priority. */
    UA_Subscription *late, *late_tmp;
    TAILQ_FOREACH_SAFE(late, &session->subscriptions, sessionListEntry, late_tmp) {
        /* Skip non-late subscriptions */
        if(!late->late)
            continue;

        /* Call publish on the late subscription */
        UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, late,
                                  "Send PublishResponse on a late subscription");
        UA_Subscription_publish(server, late);

        /* Skip re-insert if the subscription was deleted or deactivated during
         * _publish */
        if(late->state >= UA_SUBSCRIPTIONSTATE_ENABLED_NOPUBLISH) {
            /* Find the first element with smaller priority and insert before
             * that. If there is none, insert at the end of the queue. */
            UA_Subscription *after = TAILQ_NEXT(late, sessionListEntry);
            while(after && after->priority >= late->priority)
                after = TAILQ_NEXT(after, sessionListEntry);
            TAILQ_REMOVE(&session->subscriptions, late, sessionListEntry);
            if(after)
                TAILQ_INSERT_BEFORE(after, late, sessionListEntry);
            else
                TAILQ_INSERT_TAIL(&session->subscriptions, late, sessionListEntry);
        }

        /* Responses left in the queue? */
        if(session->responseQueueSize == 0)
            break;
    }

    return UA_STATUSCODE_GOOD;
}

static void
Operation_DeleteSubscription(UA_Server *server, UA_Session *session, void *_,
                             const UA_UInt32 *subscriptionId, UA_StatusCode *result) {
    UA_Subscription *sub = UA_Session_getSubscriptionById(session, *subscriptionId);
    if(!sub) {
        *result = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
        UA_LOG_DEBUG_SESSION(server->config.logging, session,
                             "Deleting Subscription with Id %" PRIu32
                             " failed with error code %s",
                             *subscriptionId, UA_StatusCode_name(*result));
        return;
    }

    UA_Subscription_delete(server, sub);
    *result = UA_STATUSCODE_GOOD;
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Subscription %" PRIu32 " | Subscription deleted",
                         *subscriptionId);
}

void
Service_DeleteSubscriptions(UA_Server *server, UA_Session *session,
                            const UA_DeleteSubscriptionsRequest *request,
                            UA_DeleteSubscriptionsResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing DeleteSubscriptionsRequest");
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    response->responseHeader.serviceResult =
        UA_Server_processServiceOperations(server, session,
                  (UA_ServiceOperation)Operation_DeleteSubscription, NULL,
                  &request->subscriptionIdsSize, &UA_TYPES[UA_TYPES_UINT32],
                  &response->resultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
}

void
Service_Republish(UA_Server *server, UA_Session *session,
                  const UA_RepublishRequest *request,
                  UA_RepublishResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing RepublishRequest");
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Get the subscription */
    UA_Subscription *sub = UA_Session_getSubscriptionById(session, request->subscriptionId);
    if(!sub) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
        return;
    }

    /* Reset the lifetime counter */
    Subscription_resetLifetime(sub);

    /* Update the subscription statistics */
#ifdef UA_ENABLE_DIAGNOSTICS
    sub->republishRequestCount++;
#endif

    /* Find the notification in the retransmission queue  */
    UA_NotificationMessageEntry *entry;
    TAILQ_FOREACH(entry, &sub->retransmissionQueue, listEntry) {
        if(entry->message.sequenceNumber == request->retransmitSequenceNumber)
            break;
    }
    if(!entry) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADMESSAGENOTAVAILABLE;
        return;
    }

    response->responseHeader.serviceResult =
        UA_NotificationMessage_copy(&entry->message, &response->notificationMessage);

    /* Update the subscription statistics for the case where we return a message */
#ifdef UA_ENABLE_DIAGNOSTICS
    sub->republishMessageCount++;
#endif
}

static UA_StatusCode
setTransferredSequenceNumbers(const UA_Subscription *sub, UA_TransferResult *result) {
    /* Allocate memory */
    result->availableSequenceNumbers = (UA_UInt32*)
        UA_Array_new(sub->retransmissionQueueSize, &UA_TYPES[UA_TYPES_UINT32]);
    if(!result->availableSequenceNumbers)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    result->availableSequenceNumbersSize = sub->retransmissionQueueSize;

    /* Copy over the sequence numbers */
    UA_NotificationMessageEntry *entry;
    size_t i = 0;
    TAILQ_FOREACH(entry, &sub->retransmissionQueue, listEntry) {
        result->availableSequenceNumbers[i] = entry->message.sequenceNumber;
        i++;
    }

    UA_assert(i == result->availableSequenceNumbersSize);

    return UA_STATUSCODE_GOOD;
}

static void
Operation_TransferSubscription(UA_Server *server, UA_Session *session,
                               const UA_Boolean *sendInitialValues,
                               const UA_UInt32 *subscriptionId,
                               UA_TransferResult *result) {
    /* Get the subscription. This requires a server-wide lookup instead of the
     * usual session-wide lookup. */
    UA_Subscription *sub = getSubscriptionById(server, *subscriptionId);
    if(!sub) {
        result->statusCode = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
        return;
    }

    /* Update the diagnostics statistics */
#ifdef UA_ENABLE_DIAGNOSTICS
    sub->transferRequestCount++;
#endif

    /* Is this the same session? Return the sequence numbers and do nothing else. */
    UA_Session *oldSession = sub->session;
    if(oldSession == session) {
        result->statusCode = setTransferredSequenceNumbers(sub, result);
#ifdef UA_ENABLE_DIAGNOSTICS
        sub->transferredToSameClientCount++;
#endif
        return;
    }

    /* Check with AccessControl if the transfer is allowed */
    if(server->config.accessControl.allowTransferSubscription) {
        UA_LOCK_ASSERT(&server->serviceMutex, 1);
        UA_UNLOCK(&server->serviceMutex);
        if(!server->config.accessControl.
           allowTransferSubscription(server, &server->config.accessControl,
                                     oldSession ? &oldSession->sessionId : NULL,
                                     oldSession ? oldSession->context : NULL,
                                     &session->sessionId, session->context)) {
            UA_LOCK(&server->serviceMutex);
            result->statusCode = UA_STATUSCODE_BADUSERACCESSDENIED;
            return;
        }
        UA_LOCK(&server->serviceMutex);
    } else {
        result->statusCode = UA_STATUSCODE_BADUSERACCESSDENIED;
        return;
    }

    /* Check limits for the number of subscriptions for this Session */
    if((server->config.maxSubscriptionsPerSession != 0) &&
       (session->subscriptionsSize >= server->config.maxSubscriptionsPerSession)) {
        result->statusCode = UA_STATUSCODE_BADTOOMANYSUBSCRIPTIONS;
        return;
    }

    /* Allocate memory for the new subscription */
    UA_Subscription *newSub = (UA_Subscription*)UA_malloc(sizeof(UA_Subscription));
    if(!newSub) {
        result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
        return;
    }

    /* Set the available sequence numbers */
    result->statusCode = setTransferredSequenceNumbers(sub, result);
    if(result->statusCode != UA_STATUSCODE_GOOD) {
        UA_free(newSub);
        return;
    }

    /* Create an identical copy of the Subscription struct. The original
     * subscription remains in place until a StatusChange notification has been
     * sent. The elements for lists and queues are moved over manually to ensure
     * that all backpointers are set correctly. */
    memcpy(newSub, sub, sizeof(UA_Subscription));

    /* Set to the same state as the original subscription */
    newSub->publishCallbackId = 0;
    result->statusCode = Subscription_setState(server, newSub, sub->state);
    if(result->statusCode != UA_STATUSCODE_GOOD) {
        UA_Array_delete(result->availableSequenceNumbers,
                        sub->retransmissionQueueSize, &UA_TYPES[UA_TYPES_UINT32]);
        result->availableSequenceNumbers = NULL;
        result->availableSequenceNumbersSize = 0;
        UA_free(newSub);
        return;
    }

    /* <-- The point of no return --> */

    /* Move over the MonitoredItems and adjust the backpointers */
    LIST_INIT(&newSub->monitoredItems);
    UA_MonitoredItem *mon, *mon_tmp;
    LIST_FOREACH_SAFE(mon, &sub->monitoredItems, listEntry, mon_tmp) {
        LIST_REMOVE(mon, listEntry);
        mon->subscription = newSub;
        LIST_INSERT_HEAD(&newSub->monitoredItems, mon, listEntry);
    }
    sub->monitoredItemsSize = 0;

    /* Move over the notification queue */
    TAILQ_INIT(&newSub->notificationQueue);
    UA_Notification *nn, *nn_tmp;
    TAILQ_FOREACH_SAFE(nn, &sub->notificationQueue, globalEntry, nn_tmp) {
        TAILQ_REMOVE(&sub->notificationQueue, nn, globalEntry);
        TAILQ_INSERT_TAIL(&newSub->notificationQueue, nn, globalEntry);
    }
    sub->notificationQueueSize = 0;
    sub->dataChangeNotifications = 0;
    sub->eventNotifications = 0;

    TAILQ_INIT(&newSub->retransmissionQueue);
    UA_NotificationMessageEntry *nme, *nme_tmp;
    TAILQ_FOREACH_SAFE(nme, &sub->retransmissionQueue, listEntry, nme_tmp) {
        TAILQ_REMOVE(&sub->retransmissionQueue, nme, listEntry);
        TAILQ_INSERT_TAIL(&newSub->retransmissionQueue, nme, listEntry);
        if(oldSession)
            oldSession->totalRetransmissionQueueSize -= 1;
        sub->retransmissionQueueSize -= 1;
    }
    UA_assert(sub->retransmissionQueueSize == 0);
    sub->retransmissionQueueSize = 0;

    /* Add to the server */
    UA_assert(newSub->subscriptionId == sub->subscriptionId);
    LIST_INSERT_HEAD(&server->subscriptions, newSub, serverListEntry);
    server->subscriptionsSize++;

    /* Attach to the session */
    UA_Session_attachSubscription(session, newSub);

    UA_LOG_INFO_SUBSCRIPTION(server->config.logging, newSub, "Transferred to this Session");

    /* Set StatusChange in the original subscription and force publish. This
     * also removes the Subscription, even if there was no PublishResponse
     * queued to send a StatusChangeNotification. */
    sub->statusChange = UA_STATUSCODE_GOODSUBSCRIPTIONTRANSFERRED;
    UA_Subscription_publish(server, sub);

    /* Re-create notifications with the current values for the new subscription */
    if(*sendInitialValues)
        UA_Subscription_resendData(server, newSub);

    /* Do not update the statistics for the number of Subscriptions here. The
     * fact that we duplicate the subscription and move over the content is just
     * an implementtion detail.
     * server->serverDiagnosticsSummary.currentSubscriptionCount++;
     * server->serverDiagnosticsSummary.cumulatedSubscriptionCount++;
     *
     * Update the diagnostics statistics: */
#ifdef UA_ENABLE_DIAGNOSTICS
    if(oldSession &&
       UA_equal(&oldSession->clientDescription, &session->clientDescription,
                &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION]))
        sub->transferredToSameClientCount++;
    else
        sub->transferredToAltClientCount++;
#endif
}

void Service_TransferSubscriptions(UA_Server *server, UA_Session *session,
                                   const UA_TransferSubscriptionsRequest *request,
                                   UA_TransferSubscriptionsResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing TransferSubscriptionsRequest");
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    response->responseHeader.serviceResult =
        UA_Server_processServiceOperations(server, session,
                  (UA_ServiceOperation)Operation_TransferSubscription,
                  &request->sendInitialValues,
                  &request->subscriptionIdsSize, &UA_TYPES[UA_TYPES_UINT32],
                  &response->resultsSize, &UA_TYPES[UA_TYPES_TRANSFERRESULT]);
}

#endif /* UA_ENABLE_SUBSCRIPTIONS */

/**** amalgamated original file "/src/server/ua_services_monitoreditem.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2016-2017 (c) Florian Palm
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2018 (c) Ari Breitkreuz, fortiss GmbH
 *    Copyright 2017 (c) Mattias Bornhager
 *    Copyright 2017 (c) Henrik Norrman
 *    Copyright 2017-2023 (c) Thomas Stalder, Blue Time Concept SA
 *    Copyright 2018 (c) Fabian Arndt, Root-Core
 *    Copyright 2020 (c) Kalycito Infotech Private Limited
 *    Copyright 2021 (c) Uranik, Berisha
 *    Copyright 2021 (c) Ammar, Morshed
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Andreas Ebner)
 */


#ifdef UA_ENABLE_SUBSCRIPTIONS /* conditional compilation */

#ifdef UA_ENABLE_DA

/* Translate a percentage deadband into an absolute deadband based on the
 * UARange property of the variable */
static UA_StatusCode
setAbsoluteFromPercentageDeadband(UA_Server *server, UA_Session *session,
                                  const UA_MonitoredItem *mon, UA_DataChangeFilter *filter) {
    /* A valid deadband? */
    if(filter->deadbandValue < 0.0 || filter->deadbandValue > 100.0)
        return UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED;

    /* Browse for the percent range */
    UA_QualifiedName qn = UA_QUALIFIEDNAME(0, "EURange");
    UA_BrowsePathResult bpr =
        browseSimplifiedBrowsePath(server, mon->itemToMonitor.nodeId, 1, &qn);
    if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
        UA_BrowsePathResult_clear(&bpr);
        return UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED;
    }

    /* Read the range */
    UA_ReadValueId rvi;
    UA_ReadValueId_init(&rvi);
    rvi.nodeId = bpr.targets->targetId.nodeId;
    rvi.attributeId = UA_ATTRIBUTEID_VALUE;
    UA_DataValue rangeVal = readWithSession(server, session, &rvi,
                                            UA_TIMESTAMPSTORETURN_NEITHER);
    UA_BrowsePathResult_clear(&bpr);
    if(!UA_Variant_isScalar(&rangeVal.value) ||
       rangeVal.value.type != &UA_TYPES[UA_TYPES_RANGE]) {
        UA_DataValue_clear(&rangeVal);
        return UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED;
    }

    /* Compute the abs deadband */
    UA_Range *euRange = (UA_Range*)rangeVal.value.data;
    UA_Double absDeadband = (filter->deadbandValue/100.0) * (euRange->high - euRange->low);

    UA_DataValue_clear(&rangeVal);

    /* EURange invalid or NaN? */
    if(absDeadband < 0.0 || absDeadband != absDeadband) {
        UA_DataValue_clear(&rangeVal);
        return UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED;
    }

    /* Adjust the original filter */
    filter->deadbandType = UA_DEADBANDTYPE_ABSOLUTE;
    filter->deadbandValue = absDeadband;
    return UA_STATUSCODE_GOOD;
}

#endif /* UA_ENABLE_DA */

void
Service_SetTriggering(UA_Server *server, UA_Session *session,
                      const UA_SetTriggeringRequest *request,
                      UA_SetTriggeringResponse *response) {
    /* Nothing to do? */
    if(request->linksToRemoveSize == 0 &&
       request->linksToAddSize == 0) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADNOTHINGTODO;
        return;
    }

    /* Get the Subscription */
    UA_Subscription *sub = UA_Session_getSubscriptionById(session, request->subscriptionId);
    if(!sub) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
        return;
    }

    /* Reset the lifetime counter of the Subscription */
    Subscription_resetLifetime(sub);

    /* Get the MonitoredItem */
    UA_MonitoredItem *mon = UA_Subscription_getMonitoredItem(sub, request->triggeringItemId);
    if(!mon) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
        return;
    }

    /* Allocate the results arrays */
    if(request->linksToRemoveSize > 0) {
        response->removeResults = (UA_StatusCode*)
            UA_Array_new(request->linksToRemoveSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
        if(!response->removeResults) {
            response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
            return;
        }
        response->removeResultsSize = request->linksToRemoveSize;
    }

    if(request->linksToAddSize> 0) {
        response->addResults = (UA_StatusCode*)
            UA_Array_new(request->linksToAddSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
        if(!response->addResults) {
            UA_Array_delete(response->removeResults,
                            request->linksToAddSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
            response->removeResults = NULL;
            response->removeResultsSize = 0;
            response->responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
            return;
        }
        response->addResultsSize = request->linksToAddSize;
    }

    /* Apply the changes */
    for(size_t i = 0; i < request->linksToRemoveSize; i++)
        response->removeResults[i] =
            UA_MonitoredItem_removeLink(sub, mon, request->linksToRemove[i]);

    for(size_t i = 0; i < request->linksToAddSize; i++)
        response->addResults[i] =
            UA_MonitoredItem_addLink(sub, mon, request->linksToAdd[i]);
}

#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
static UA_StatusCode
checkEventFilterParam(UA_Server *server, UA_Session *session,
                      const UA_MonitoredItem *mon,
                      UA_MonitoringParameters *params,
                      UA_ExtensionObject *filterResult) {
    UA_assert(mon->itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER);

    /* Correct data type? */
    if(params->filter.encoding != UA_EXTENSIONOBJECT_DECODED &&
       params->filter.encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE)
        return UA_STATUSCODE_BADEVENTFILTERINVALID;
    if(params->filter.content.decoded.type != &UA_TYPES[UA_TYPES_EVENTFILTER])
        return UA_STATUSCODE_BADEVENTFILTERINVALID;

    UA_EventFilter *eventFilter = (UA_EventFilter *)params->filter.content.decoded.data;

    /* Correct number of elements? */
    if(eventFilter->selectClausesSize == 0 ||
       eventFilter->selectClausesSize > UA_EVENTFILTER_MAXSELECT)
        return UA_STATUSCODE_BADEVENTFILTERINVALID;

    /* Allow empty where clauses --> select every event */
    if(eventFilter->whereClause.elementsSize > UA_EVENTFILTER_MAXELEMENTS)
        return UA_STATUSCODE_BADEVENTFILTERINVALID;

    /* Check where-clause */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    const UA_ContentFilter *cf = &eventFilter->whereClause;
    UA_ContentFilterElementResult whereRes[UA_EVENTFILTER_MAXELEMENTS];
    for(size_t i = 0; i < cf->elementsSize; ++i) {
        UA_ContentFilterElement *ef = &cf->elements[i];
        whereRes[i] = UA_ContentFilterElementValidation(server, i, cf->elementsSize, ef);
        if(whereRes[i].statusCode != UA_STATUSCODE_GOOD && res == UA_STATUSCODE_GOOD)
            res = whereRes[i].statusCode;
    }

    /* Check select clause */
    UA_StatusCode selectRes[UA_EVENTFILTER_MAXSELECT];
    for(size_t i = 0; i < eventFilter->selectClausesSize; i++) {
        const UA_SimpleAttributeOperand *sao = &eventFilter->selectClauses[i];
        selectRes[i] = UA_SimpleAttributeOperandValidation(server, sao);
        if(selectRes[i] != UA_STATUSCODE_GOOD && res == UA_STATUSCODE_GOOD)
            res = selectRes[i];
    }

    /* Filter bad, return details */
    if(res != UA_STATUSCODE_GOOD) {
        UA_EventFilterResult *efr = UA_EventFilterResult_new();
        if(!efr) {
            res = UA_STATUSCODE_BADOUTOFMEMORY;
        } else {
            UA_EventFilterResult tmp_efr;
            UA_EventFilterResult_init(&tmp_efr);
            tmp_efr.selectClauseResultsSize = eventFilter->selectClausesSize;
            tmp_efr.selectClauseResults = selectRes;
            tmp_efr.whereClauseResult.elementResultsSize = cf->elementsSize;
            tmp_efr.whereClauseResult.elementResults = whereRes;
            UA_EventFilterResult_copy(&tmp_efr, efr);
            UA_ExtensionObject_setValue(filterResult, efr,
                                        &UA_TYPES[UA_TYPES_EVENTFILTERRESULT]);
        }
    }

    for(size_t i = 0; i < cf->elementsSize; ++i)
        UA_ContentFilterElementResult_clear(&whereRes[i]);
    return res;
}
#endif

/* Verify and adjust the parameters of a MonitoredItem */
static UA_StatusCode
checkAdjustMonitoredItemParams(UA_Server *server, UA_Session *session,
                               const UA_MonitoredItem *mon,
                               const UA_DataType* valueType,
                               UA_MonitoringParameters *params,
                               UA_ExtensionObject *filterResult) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Check the filter */
    if(mon->itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER) {
        /* Event MonitoredItems need a filter */
#ifndef UA_ENABLE_SUBSCRIPTIONS_EVENTS
        return UA_STATUSCODE_BADNOTSUPPORTED;
#else
        UA_StatusCode res = checkEventFilterParam(server, session, mon,
                                                  params, filterResult);
        if(res != UA_STATUSCODE_GOOD)
            return res;
#endif
    } else {
        /* DataChange MonitoredItem. Can be "no filter" which defaults to
         * triggering on Status and Value. */
        if(params->filter.encoding != UA_EXTENSIONOBJECT_DECODED &&
           params->filter.encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE &&
           params->filter.encoding != UA_EXTENSIONOBJECT_ENCODED_NOBODY)
            return UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED;

        /* If the filter ExtensionObject has a body, then it must be a
         * DataChangeFilter */
        if(params->filter.encoding != UA_EXTENSIONOBJECT_ENCODED_NOBODY &&
           params->filter.content.decoded.type != &UA_TYPES[UA_TYPES_DATACHANGEFILTER])
            return UA_STATUSCODE_BADFILTERNOTALLOWED;

        /* Check the deadband and adjust if necessary. */
        if(params->filter.content.decoded.type == &UA_TYPES[UA_TYPES_DATACHANGEFILTER]) {
            UA_DataChangeFilter *filter = (UA_DataChangeFilter *)
                params->filter.content.decoded.data;
            switch(filter->deadbandType) {
            case UA_DEADBANDTYPE_NONE:
                break;
            case UA_DEADBANDTYPE_ABSOLUTE:
                if(mon->itemToMonitor.attributeId != UA_ATTRIBUTEID_VALUE ||
                   !valueType || !UA_DataType_isNumeric(valueType))
                    return UA_STATUSCODE_BADFILTERNOTALLOWED;
                break;
#ifdef UA_ENABLE_DA
            case UA_DEADBANDTYPE_PERCENT: {
                if(mon->itemToMonitor.attributeId != UA_ATTRIBUTEID_VALUE ||
                   !valueType || !UA_DataType_isNumeric(valueType))
                    return UA_STATUSCODE_BADFILTERNOTALLOWED;
                /* If percentage deadband is supported, look up the range values
                 * and precompute as if it was an absolute deadband. */
                UA_StatusCode res =
                    setAbsoluteFromPercentageDeadband(server, session, mon, filter);
                if(res != UA_STATUSCODE_GOOD)
                    return res;
                break;
            }
#endif
            default:
                return UA_STATUSCODE_BADMONITOREDITEMFILTERUNSUPPORTED;
            }
        }
    }

    /* Read the minimum sampling interval for the variable. The sampling
     * interval of the MonitoredItem must not be less than that. */
    if(mon->itemToMonitor.attributeId == UA_ATTRIBUTEID_VALUE) {
        const UA_Node *node = UA_NODESTORE_GET(server, &mon->itemToMonitor.nodeId);
        if(node) {
            const UA_VariableNode *vn = &node->variableNode;
            if(node->head.nodeClass == UA_NODECLASS_VARIABLE) {
                /* Take into account if the publishing interval is used for sampling */
                UA_Double samplingInterval = params->samplingInterval;
                if(samplingInterval < 0 && mon->subscription)
                    samplingInterval = mon->subscription->publishingInterval;
                /* Adjust if smaller than the allowed minimum for the variable */
                if(samplingInterval < vn->minimumSamplingInterval)
                    params->samplingInterval = vn->minimumSamplingInterval;
            }
            UA_NODESTORE_RELEASE(server, node);
        }
    }
        

    /* A negative number indicates that the sampling interval is the publishing
     * interval of the Subscription. Note that the sampling interval selected
     * here remains also when the Subscription's publish interval is adjusted
     * afterwards. */
    if(mon->subscription && params->samplingInterval < 0.0)
        params->samplingInterval = mon->subscription->publishingInterval;

    /* Adjust non-null sampling interval to lie within the configured limits */
    if(params->samplingInterval != 0.0) {
        UA_BOUNDEDVALUE_SETWBOUNDS(server->config.samplingIntervalLimits,
                                   params->samplingInterval, params->samplingInterval);
        /* Check for NaN */
        if(mon->parameters.samplingInterval != mon->parameters.samplingInterval)
            params->samplingInterval = server->config.samplingIntervalLimits.min;
    }

    /* Adjust the maximum queue size */
#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
    if(mon->itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER) {
        /* 0 => Set to the configured maximum. Otherwise adjust with configured limits */
        if(params->queueSize == 0) {
            params->queueSize = server->config.queueSizeLimits.max;
        } else {
            UA_BOUNDEDVALUE_SETWBOUNDS(server->config.queueSizeLimits,
                                       params->queueSize, params->queueSize);
        }
    } else
#endif
    {
        /* 0 or 1 => queue-size 1. Otherwise adjust with configured limits */
        if(params->queueSize == 0)
            params->queueSize = 1;
        if(params->queueSize != 1)
            UA_BOUNDEDVALUE_SETWBOUNDS(server->config.queueSizeLimits,
                                       params->queueSize, params->queueSize);
    }

    return UA_STATUSCODE_GOOD;
}

static const UA_String
binaryEncoding = {sizeof("Default Binary") - 1, (UA_Byte *)"Default Binary"};

/* Structure to pass additional arguments into the operation */
struct createMonContext {
    UA_Subscription *sub;
    UA_TimestampsToReturn timestampsToReturn;
    UA_LocalMonitoredItem *localMon; /* used if non-null */
};

static void
Operation_CreateMonitoredItem(UA_Server *server, UA_Session *session,
                              struct createMonContext *cmc,
                              const UA_MonitoredItemCreateRequest *request,
                              UA_MonitoredItemCreateResult *result) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Check available capacity */
    if(!cmc->localMon &&
       (((server->config.maxMonitoredItems != 0) &&
         (server->monitoredItemsSize >= server->config.maxMonitoredItems)) ||
        ((server->config.maxMonitoredItemsPerSubscription != 0) &&
         (cmc->sub->monitoredItemsSize >= server->config.maxMonitoredItemsPerSubscription)))) {
        result->statusCode = UA_STATUSCODE_BADTOOMANYMONITOREDITEMS;
        return;
    }

    /* Check if the encoding is supported */
    if(request->itemToMonitor.dataEncoding.name.length > 0 &&
       (!UA_String_equal(&binaryEncoding, &request->itemToMonitor.dataEncoding.name) ||
        request->itemToMonitor.dataEncoding.namespaceIndex != 0)) {
        result->statusCode = UA_STATUSCODE_BADDATAENCODINGUNSUPPORTED;
        return;
    }

    /* Check if the encoding is set for a value */
    if(request->itemToMonitor.attributeId != UA_ATTRIBUTEID_VALUE &&
       request->itemToMonitor.dataEncoding.name.length > 0) {
        result->statusCode = UA_STATUSCODE_BADDATAENCODINGINVALID;
        return;
    }

    /* Make an example read to check the itemToMonitor. The DataSource itself
     * could return a (temporary) error. This should still result in a valid
     * MonitoredItem. Only a few StatusCodes are considered unrecoverable and
     * lead to an abort:
     * - The Node does not exist
     * - The AttributeId does not match the NodeClass
     * - The Session does not have sufficient access rights
     * - The indicated encoding is not supported or not valid */
    UA_DataValue v = readWithSession(server, session, &request->itemToMonitor,
                                     cmc->timestampsToReturn);
    if(v.hasStatus &&
       (v.status == UA_STATUSCODE_BADNODEIDUNKNOWN ||
        v.status == UA_STATUSCODE_BADATTRIBUTEIDINVALID ||
        v.status == UA_STATUSCODE_BADDATAENCODINGUNSUPPORTED ||
        v.status == UA_STATUSCODE_BADDATAENCODINGINVALID ||
        v.status == UA_STATUSCODE_BADINDEXRANGEINVALID
        /* Part 4, 5.12.2 CreateMonitoredItems: When a user adds a monitored
         * item that the user is denied read access to, the add operation for
         * the item shall succeed and the bad status Bad_NotReadable or
         * Bad_UserAccessDenied shall be returned in the Publish response.
         * v.status == UA_STATUSCODE_BADNOTREADABLE
         * v.status == UA_STATUSCODE_BADUSERACCESSDENIED
         *
         * The IndexRange error can change depending on the value.
         * v.status == UA_STATUSCODE_BADINDEXRANGENODATA */
        )) {
        result->statusCode = v.status;
        UA_DataValue_clear(&v);
        return;
    }

    /* Adding an Event MonitoredItem */
#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
    if(request->itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER) {
        /* If the 'SubscribeToEvents' bit of EventNotifier attribute is
         * zero, then the object cannot be subscribed to monitor events */
        if(!v.hasValue || !v.value.data) {
            result->statusCode = UA_STATUSCODE_BADINTERNALERROR;
            UA_DataValue_clear(&v);
            return;
        }
        UA_Byte eventNotifierValue = *((UA_Byte *)v.value.data);
        if((eventNotifierValue & 0x01) != 1) {
            result->statusCode = UA_STATUSCODE_BADNOTSUPPORTED;
            UA_LOG_INFO_SUBSCRIPTION(server->config.logging, cmc->sub,
                                     "Could not create a MonitoredItem as the "
                                     "'SubscribeToEvents' bit of the EventNotifier "
                                     "attribute is not set");
            UA_DataValue_clear(&v);
            return;
        }
    }
#endif

    const UA_DataType *valueType = v.value.type;
    UA_DataValue_clear(&v);

    /* Allocate the MonitoredItem */
    UA_MonitoredItem *newMon = NULL;
    if(cmc->localMon) {
        newMon = &cmc->localMon->monitoredItem;
        cmc->localMon = NULL; /* clean up internally from now on */
    } else {
        newMon = (UA_MonitoredItem*)UA_malloc(sizeof(UA_MonitoredItem));
        if(!newMon) {
            result->statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
            return;
        }
    }

    /* Initialize the MonitoredItem */
    UA_MonitoredItem_init(newMon);
    newMon->subscription = cmc->sub;
    newMon->timestampsToReturn = cmc->timestampsToReturn;
    result->statusCode |= UA_ReadValueId_copy(&request->itemToMonitor,
                                              &newMon->itemToMonitor);
    result->statusCode |= UA_MonitoringParameters_copy(&request->requestedParameters,
                                                       &newMon->parameters);
    result->statusCode |= checkAdjustMonitoredItemParams(server, session, newMon,
                                                         valueType, &newMon->parameters,
                                                         &result->filterResult);
    if(result->statusCode != UA_STATUSCODE_GOOD) {
        UA_LOG_INFO_SUBSCRIPTION(server->config.logging, cmc->sub,
                                 "Could not create a MonitoredItem "
                                 "with StatusCode %s",
                                 UA_StatusCode_name(result->statusCode));
        UA_MonitoredItem_delete(server, newMon);
        return;
    }

    /* Initialize the value status so the first sample always passes the filter */
    newMon->lastValue.hasStatus = true;
    newMon->lastValue.status = ~(UA_StatusCode)0;

    /* Register the Monitoreditem in the server and subscription */
    UA_Server_registerMonitoredItem(server, newMon);

    /* Activate the MonitoredItem */
    result->statusCode = UA_MonitoredItem_setMonitoringMode(server, newMon,
                                                            request->monitoringMode);
    if(result->statusCode != UA_STATUSCODE_GOOD) {
        UA_MonitoredItem_delete(server, newMon);
        return;
    }

    /* Prepare the response */
    result->revisedSamplingInterval = newMon->parameters.samplingInterval;
    result->revisedQueueSize = newMon->parameters.queueSize;
    result->monitoredItemId = newMon->monitoredItemId;

    UA_LOG_INFO_SUBSCRIPTION(server->config.logging, cmc->sub,
                             "MonitoredItem %" PRIi32 " | "
                             "Created the MonitoredItem "
                             "(Sampling Interval: %.2fms, Queue Size: %lu)",
                             newMon->monitoredItemId,
                             newMon->parameters.samplingInterval,
                             (unsigned long)newMon->parameters.queueSize);
}

void
Service_CreateMonitoredItems(UA_Server *server, UA_Session *session,
                             const UA_CreateMonitoredItemsRequest *request,
                             UA_CreateMonitoredItemsResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing CreateMonitoredItemsRequest");
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Check the upper bound for the number of items */
    if(server->config.maxMonitoredItemsPerCall != 0 &&
       request->itemsToCreateSize > server->config.maxMonitoredItemsPerCall) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return;
    }

    /* Check if the timestampstoreturn is valid */
    if(request->timestampsToReturn < UA_TIMESTAMPSTORETURN_SOURCE ||
       request->timestampsToReturn > UA_TIMESTAMPSTORETURN_NEITHER) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTIMESTAMPSTORETURNINVALID;
        return;
    }

    /* Find the subscription */
    UA_Subscription *sub = UA_Session_getSubscriptionById(session, request->subscriptionId);
    if(!sub) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
        return;
    }

    /* Reset the lifetime counter of the Subscription */
    Subscription_resetLifetime(sub);

    /* Call the service */
    struct createMonContext cmc;
    cmc.timestampsToReturn = request->timestampsToReturn;
    cmc.sub = sub;
    cmc.localMon = NULL;

    response->responseHeader.serviceResult =
        UA_Server_processServiceOperations(server, session,
                                           (UA_ServiceOperation)Operation_CreateMonitoredItem,
                                           &cmc, &request->itemsToCreateSize,
                                           &UA_TYPES[UA_TYPES_MONITOREDITEMCREATEREQUEST],
                                           &response->resultsSize,
                                           &UA_TYPES[UA_TYPES_MONITOREDITEMCREATERESULT]);
}

UA_MonitoredItemCreateResult
UA_Server_createDataChangeMonitoredItem(UA_Server *server,
                                        UA_TimestampsToReturn timestampsToReturn,
                                        const UA_MonitoredItemCreateRequest item,
                                        void *monitoredItemContext,
                                        UA_Server_DataChangeNotificationCallback callback) {
    UA_MonitoredItemCreateResult result;
    UA_MonitoredItemCreateResult_init(&result);

    /* Check that we don't use the DataChange callback for events */
    if(item.itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "DataChange-MonitoredItem cannot be created for the "
                     "EventNotifier attribute");
        result.statusCode = UA_STATUSCODE_BADINTERNALERROR;
        return result;
    }

    /* Pre-allocate the local MonitoredItem structure */
    UA_LocalMonitoredItem *localMon = (UA_LocalMonitoredItem*)
        UA_calloc(1, sizeof(UA_LocalMonitoredItem));
    if(!localMon) {
        result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
        return result;
    }
    localMon->context = monitoredItemContext;
    localMon->callback.dataChangeCallback = callback;

    /* Call the service */
    struct createMonContext cmc;
    cmc.sub = server->adminSubscription;
    cmc.localMon = localMon;
    cmc.timestampsToReturn = timestampsToReturn;

    UA_LOCK(&server->serviceMutex);
    Operation_CreateMonitoredItem(server, &server->adminSession, &cmc, &item, &result);
    UA_UNLOCK(&server->serviceMutex);

    /* If this failed, clean up the local MonitoredItem structure */
    if(result.statusCode != UA_STATUSCODE_GOOD && cmc.localMon)
        UA_free(localMon);

    return result;
}

UA_MonitoredItemCreateResult
UA_Server_createEventMonitoredItemEx(UA_Server *server,
                                     const UA_MonitoredItemCreateRequest item,
                                     void *monitoredItemContext,
                                     UA_Server_EventNotificationCallback callback) {
    UA_MonitoredItemCreateResult result;
    UA_MonitoredItemCreateResult_init(&result);

    /* Check that we don't use the DataChange callback for events */
    if(item.itemToMonitor.attributeId != UA_ATTRIBUTEID_EVENTNOTIFIER) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Event-MonitoredItem must monitor the EventNotifier attribute");
        result.statusCode = UA_STATUSCODE_BADINTERNALERROR;
        return result;
    }

    const UA_ExtensionObject *filter = &item.requestedParameters.filter;
    if((filter->encoding != UA_EXTENSIONOBJECT_DECODED &&
        filter->encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) ||
       filter->content.decoded.type != &UA_TYPES[UA_TYPES_EVENTFILTER]) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Filter is not of EventFilter data type");
        result.statusCode = UA_STATUSCODE_BADINTERNALERROR;
        return result;
    }

    UA_EventFilter *ef = (UA_EventFilter*)filter->content.decoded.data;
    if(ef->selectClausesSize == 0) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Event filter must define at least one select clause");
        result.statusCode = UA_STATUSCODE_BADINTERNALERROR;
        return result;
    }

    /* Pre-allocate the local MonitoredItem structure */
    UA_LocalMonitoredItem *localMon = (UA_LocalMonitoredItem*)
        UA_calloc(1, sizeof(UA_LocalMonitoredItem));
    if(!localMon) {
        result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
        return result;
    }
    localMon->context = monitoredItemContext;
    localMon->callback.eventCallback = callback;

    /* Create the string names for the event fields */
    localMon->eventFields.map = (UA_KeyValuePair*)
        UA_calloc(ef->selectClausesSize, sizeof(UA_KeyValuePair));
    if(!localMon->eventFields.map) {
        UA_free(localMon);
        result.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
        return result;
    }
    localMon->eventFields.mapSize = ef->selectClausesSize;

#ifdef UA_ENABLE_PARSING
    for(size_t i = 0; i < ef->selectClausesSize; i++) {
        result.statusCode |=
            UA_SimpleAttributeOperand_print(&ef->selectClauses[i],
                                            &localMon->eventFields.map[i].key.name);
    }
    if(result.statusCode != UA_STATUSCODE_GOOD) {
        UA_KeyValueMap_clear(&localMon->eventFields);
        UA_free(localMon);
        return result;
    }
#endif

    /* Call the service */
    struct createMonContext cmc;
    cmc.sub = server->adminSubscription;
    cmc.localMon = localMon;
    cmc.timestampsToReturn = UA_TIMESTAMPSTORETURN_NEITHER;

    UA_LOCK(&server->serviceMutex);
    Operation_CreateMonitoredItem(server, &server->adminSession, &cmc, &item, &result);
    UA_UNLOCK(&server->serviceMutex);

    /* If the service failed, clean up the local MonitoredItem structure */
    if(result.statusCode != UA_STATUSCODE_GOOD && cmc.localMon) {
        UA_KeyValueMap_clear(&localMon->eventFields);
        UA_free(localMon);
    }
    return result;
}

UA_MonitoredItemCreateResult
UA_Server_createEventMonitoredItem(UA_Server *server, const UA_NodeId nodeId,
                                   const UA_EventFilter filter, void *monitoredItemContext,
                                   UA_Server_EventNotificationCallback callback) {
    UA_MonitoredItemCreateRequest item;
    UA_MonitoredItemCreateRequest_init(&item);
    item.itemToMonitor.nodeId = nodeId;
    item.itemToMonitor.attributeId = UA_ATTRIBUTEID_EVENTNOTIFIER;
    item.monitoringMode = UA_MONITORINGMODE_REPORTING;
    UA_ExtensionObject_setValue(&item.requestedParameters.filter,
                                (void*)(uintptr_t)&filter,
                                &UA_TYPES[UA_TYPES_EVENTFILTER]);
    return UA_Server_createEventMonitoredItemEx(server, item, monitoredItemContext, callback);
}

static void
Operation_ModifyMonitoredItem(UA_Server *server, UA_Session *session, UA_Subscription *sub,
                              const UA_MonitoredItemModifyRequest *request,
                              UA_MonitoredItemModifyResult *result) {
    /* Get the MonitoredItem */
    UA_MonitoredItem *mon = UA_Subscription_getMonitoredItem(sub, request->monitoredItemId);
    if(!mon) {
        result->statusCode = UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
        return;
    }

    /* Make local copy of the settings */
    UA_MonitoringParameters params;
    result->statusCode =
        UA_MonitoringParameters_copy(&request->requestedParameters, &params);
    if(result->statusCode != UA_STATUSCODE_GOOD)
        return;

    /* Read the current value to test if filters are possible.
     * Can return an empty value (v.value.type == NULL). */
    UA_DataValue v = readWithSession(server, session, &mon->itemToMonitor,
                                     mon->timestampsToReturn);

    /* Verify and adjust the new parameters. This still leaves the original
     * MonitoredItem untouched. */
    result->statusCode =
        checkAdjustMonitoredItemParams(server, session, mon, v.value.type,
                                       &params, &result->filterResult);
    UA_DataValue_clear(&v);
    if(result->statusCode != UA_STATUSCODE_GOOD) {
        UA_MonitoringParameters_clear(&params);
        return;
    }

    /* Store the old sampling interval */
    UA_Double oldSamplingInterval = mon->parameters.samplingInterval;

    /* Move over the new settings */
    UA_MonitoringParameters_clear(&mon->parameters);
    mon->parameters = params;

    /* Re-register the callback if necessary */
    if(oldSamplingInterval != mon->parameters.samplingInterval) {
        UA_MonitoredItem_unregisterSampling(server, mon);
        result->statusCode =
            UA_MonitoredItem_setMonitoringMode(server, mon, mon->monitoringMode);
    }

    result->revisedSamplingInterval = mon->parameters.samplingInterval;
    result->revisedQueueSize = mon->parameters.queueSize;

    /* If the sampling interval is negative (the sampling callback is called
     * from within the publishing callback), return the publishing interval of
     * the Subscription. Note that we only use the cyclic callback of the
     * Subscription. So if the Subscription publishing interval is modified,
     * this also impacts this MonitoredItem. */
    if(result->revisedSamplingInterval < 0.0 && mon->subscription)
        result->revisedSamplingInterval = mon->subscription->publishingInterval;

    /* Remove some notifications if the queue is now too small */
    UA_MonitoredItem_ensureQueueSpace(server, mon);

    /* Remove the overflow bits if the queue has now a size of 1 */
    UA_MonitoredItem_removeOverflowInfoBits(mon);

    /* If the sampling interval is negative (the sampling callback is called
     * from within the publishing callback), return the publishing interval of
     * the Subscription. Note that we only use the cyclic callback of the
     * Subscription. So if the Subscription publishing interval is modified,
     * this also impacts this MonitoredItem. */
    if(result->revisedSamplingInterval < 0.0 && mon->subscription)
        result->revisedSamplingInterval = mon->subscription->publishingInterval;

    UA_LOG_INFO_SUBSCRIPTION(server->config.logging, sub,
                             "MonitoredItem %" PRIi32 " | "
                             "Modified the MonitoredItem "
                             "(Sampling Interval: %fms, Queue Size: %lu)",
                             mon->monitoredItemId,
                             mon->parameters.samplingInterval,
                             (unsigned long)mon->queueSize);
}

void
Service_ModifyMonitoredItems(UA_Server *server, UA_Session *session,
                             const UA_ModifyMonitoredItemsRequest *request,
                             UA_ModifyMonitoredItemsResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing ModifyMonitoredItemsRequest");
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    if(server->config.maxMonitoredItemsPerCall != 0 &&
       request->itemsToModifySize > server->config.maxMonitoredItemsPerCall) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return;
    }

    /* Check if the timestampstoreturn is valid */
    if(request->timestampsToReturn > UA_TIMESTAMPSTORETURN_NEITHER) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTIMESTAMPSTORETURNINVALID;
        return;
    }

    /* Get the subscription */
    UA_Subscription *sub = UA_Session_getSubscriptionById(session, request->subscriptionId);
    if(!sub) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
        return;
    }

    /* Reset the lifetime counter of the Subscription */
    Subscription_resetLifetime(sub);

    response->responseHeader.serviceResult =
        UA_Server_processServiceOperations(server, session,
                                           (UA_ServiceOperation)Operation_ModifyMonitoredItem,
                                           sub, &request->itemsToModifySize,
                                           &UA_TYPES[UA_TYPES_MONITOREDITEMMODIFYREQUEST],
                                           &response->resultsSize,
                                           &UA_TYPES[UA_TYPES_MONITOREDITEMMODIFYRESULT]);
}

struct setMonitoringContext {
    UA_Subscription *sub;
    UA_MonitoringMode monitoringMode;
};

static void
Operation_SetMonitoringMode(UA_Server *server, UA_Session *session,
                            struct setMonitoringContext *smc,
                            const UA_UInt32 *monitoredItemId, UA_StatusCode *result) {
    UA_MonitoredItem *mon = UA_Subscription_getMonitoredItem(smc->sub, *monitoredItemId);
    if(!mon) {
        *result = UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
        return;
    }
    *result = UA_MonitoredItem_setMonitoringMode(server, mon, smc->monitoringMode);
}

void
Service_SetMonitoringMode(UA_Server *server, UA_Session *session,
                          const UA_SetMonitoringModeRequest *request,
                          UA_SetMonitoringModeResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session, "Processing SetMonitoringMode");
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Check the max number if items */
    if(server->config.maxMonitoredItemsPerCall != 0 &&
       request->monitoredItemIdsSize > server->config.maxMonitoredItemsPerCall) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return;
    }

    /* Get the subscription */
    UA_Subscription *sub = UA_Session_getSubscriptionById(session, request->subscriptionId);
    if(!sub) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
        return;
    }

    /* Reset the lifetime counter of the Subscription */
    Subscription_resetLifetime(sub);

    /* Call the service */
    struct setMonitoringContext smc;
    smc.sub = sub;
    smc.monitoringMode = request->monitoringMode;

    response->responseHeader.serviceResult =
        UA_Server_processServiceOperations(server, session,
                                           (UA_ServiceOperation)Operation_SetMonitoringMode,
                                           &smc, &request->monitoredItemIdsSize,
                                           &UA_TYPES[UA_TYPES_UINT32],
                                           &response->resultsSize,
                                           &UA_TYPES[UA_TYPES_STATUSCODE]);
}

static void
Operation_DeleteMonitoredItem(UA_Server *server, UA_Session *session, UA_Subscription *sub,
                              const UA_UInt32 *monitoredItemId, UA_StatusCode *result) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    UA_MonitoredItem *mon = UA_Subscription_getMonitoredItem(sub, *monitoredItemId);
    if(!mon) {
        *result = UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
        return;
    }
    UA_MonitoredItem_delete(server, mon);
}

void
Service_DeleteMonitoredItems(UA_Server *server, UA_Session *session,
                             const UA_DeleteMonitoredItemsRequest *request,
                             UA_DeleteMonitoredItemsResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing DeleteMonitoredItemsRequest");
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    if(server->config.maxMonitoredItemsPerCall != 0 &&
       request->monitoredItemIdsSize > server->config.maxMonitoredItemsPerCall) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return;
    }

    /* Get the subscription */
    UA_Subscription *sub = UA_Session_getSubscriptionById(session, request->subscriptionId);
    if(!sub) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
        return;
    }

    /* Reset the lifetime counter of the Subscription */
    Subscription_resetLifetime(sub);

    response->responseHeader.serviceResult =
        UA_Server_processServiceOperations(server, session,
                                           (UA_ServiceOperation)Operation_DeleteMonitoredItem,
                                           sub, &request->monitoredItemIdsSize,
                                           &UA_TYPES[UA_TYPES_UINT32],
                                           &response->resultsSize,
                                           &UA_TYPES[UA_TYPES_STATUSCODE]);
}

UA_StatusCode
UA_Server_deleteMonitoredItem(UA_Server *server, UA_UInt32 monitoredItemId) {
    UA_LOCK(&server->serviceMutex);

    UA_Subscription *sub = server->adminSubscription;
    UA_MonitoredItem *mon;
    LIST_FOREACH(mon, &sub->monitoredItems, listEntry) {
        if(mon->monitoredItemId == monitoredItemId)
            break;
    }

    UA_StatusCode res = UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
    if(mon) {
        UA_MonitoredItem_delete(server, mon);
        res = UA_STATUSCODE_GOOD;
    }

    UA_UNLOCK(&server->serviceMutex);
    return res;
}

#endif /* UA_ENABLE_SUBSCRIPTIONS */

/**** amalgamated original file "/src/server/ua_services_securechannel.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014, 2017 (c) Florian Palm
 *    Copyright 2015 (c) Oleksiy Vasylyev
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2023 (c) Hilscher Gesellschaft für Systemautomation mbH (Author: Phuong Nguyen)
 */


/* This contains the SecureChannel Services to be called after validation and
 * decoding of the message. The main SecureChannel logic is handled in
 * /src/ua_securechannel.* and /src/server/ua_server_binary.c. */

void
Service_OpenSecureChannel(UA_Server *server, UA_SecureChannel *channel,
                          UA_OpenSecureChannelRequest *request,
                          UA_OpenSecureChannelResponse *response) {
    const UA_SecurityPolicy *sp = channel->securityPolicy;

    switch(request->requestType) {
    /* Open the channel */
    case UA_SECURITYTOKENREQUESTTYPE_ISSUE:
        /* We must expect an OPN handshake */
        if(channel->state != UA_SECURECHANNELSTATE_ACK_SENT) {
            UA_LOG_ERROR_CHANNEL(server->config.logging, channel,
                                 "Called open on already open or closed channel");
            response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR;
            goto error;
        }

        /* Set the SecurityMode */
        if(request->securityMode != UA_MESSAGESECURITYMODE_NONE &&
           UA_ByteString_equal(&sp->policyUri, &UA_SECURITY_POLICY_NONE_URI)) {
            response->responseHeader.serviceResult = UA_STATUSCODE_BADSECURITYMODEREJECTED;
            goto error;
        }
        channel->securityMode = request->securityMode;
        break;

    /* Renew the channel */
    case UA_SECURITYTOKENREQUESTTYPE_RENEW:
        /* The channel must be open to be renewed */
        if(channel->state != UA_SECURECHANNELSTATE_OPEN) {
            UA_LOG_ERROR_CHANNEL(server->config.logging, channel,
                                 "Called renew on channel which is not open");
            response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR;
            goto error;
        }

        /* Check whether the nonce was reused */
        if(channel->securityMode != UA_MESSAGESECURITYMODE_NONE &&
           UA_ByteString_equal(&channel->remoteNonce, &request->clientNonce)) {
            UA_LOG_ERROR_CHANNEL(server->config.logging, channel,
                                 "The client reused the last nonce");
            response->responseHeader.serviceResult = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
            goto error;
        }

        break;

    /* Unknown request type */
    default:
        response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR;
        return;
    }

    /* Create a new SecurityToken. It will be switched over when the first
     * message is received. The ChannelId is left unchanged. */
    UA_EventLoop *el = server->config.eventLoop;
    channel->altSecurityToken.channelId = channel->securityToken.channelId;
    channel->altSecurityToken.tokenId = generateSecureChannelTokenId(server);
    channel->altSecurityToken.createdAt = el->dateTime_nowMonotonic(el);
    channel->altSecurityToken.revisedLifetime =
        (request->requestedLifetime > server->config.maxSecurityTokenLifetime) ?
        server->config.maxSecurityTokenLifetime : request->requestedLifetime;
    if(channel->altSecurityToken.revisedLifetime == 0)
        channel->altSecurityToken.revisedLifetime = server->config.maxSecurityTokenLifetime;

    /* Set the nonces. The remote nonce will be "rotated in" when it is first used. */
    UA_ByteString_clear(&channel->remoteNonce);
    channel->remoteNonce = request->clientNonce;
    UA_ByteString_init(&request->clientNonce);

    response->responseHeader.serviceResult = UA_SecureChannel_generateLocalNonce(channel);
    UA_CHECK_STATUS(response->responseHeader.serviceResult, goto error);

    /* Update the channel state */
    channel->renewState = UA_SECURECHANNELRENEWSTATE_NEWTOKEN_SERVER;
    channel->state = UA_SECURECHANNELSTATE_OPEN;

    /* Set the response */
    response->securityToken = channel->altSecurityToken;
    response->securityToken.createdAt = el->dateTime_now(el); /* only for sending */
    response->responseHeader.timestamp = response->securityToken.createdAt;
    response->responseHeader.requestHandle = request->requestHeader.requestHandle;
    response->responseHeader.serviceResult =
        UA_ByteString_copy(&channel->localNonce, &response->serverNonce);
    UA_CHECK_STATUS(response->responseHeader.serviceResult, goto error);

    /* Success */
    if(request->requestType == UA_SECURITYTOKENREQUESTTYPE_ISSUE) {
        UA_LOG_INFO_CHANNEL(server->config.logging, channel,
                            "SecureChannel opened with SecurityPolicy %.*s "
                            "and a revised lifetime of %.2fs",
                            (int)channel->securityPolicy->policyUri.length,
                            channel->securityPolicy->policyUri.data,
                            (UA_Float)response->securityToken.revisedLifetime / 1000);
    } else {
        UA_LOG_INFO_CHANNEL(server->config.logging, channel, "SecureChannel renewed "
                            "with a revised lifetime of %.2fs",
                            (UA_Float)response->securityToken.revisedLifetime / 1000);
    }

    return;

 error:
    if(request->requestType == UA_SECURITYTOKENREQUESTTYPE_ISSUE) {
        UA_LOG_INFO_CHANNEL(server->config.logging, channel,
                            "Opening a SecureChannel failed");
    } else {
        UA_LOG_DEBUG_CHANNEL(server->config.logging, channel,
                             "Renewing SecureChannel failed");
    }
}

/* The server does not send a CloseSecureChannel response */
void
Service_CloseSecureChannel(UA_Server *server, UA_SecureChannel *channel) {
    UA_SecureChannel_shutdown(channel, UA_SHUTDOWNREASON_CLOSE);
}

/**** amalgamated original file "/src/server/ua_services_nodemanagement.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014-2017 (c) Florian Palm
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015-2016 (c) Chris Iatrou
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2017 (c) Julian Grothoff
 *    Copyright 2016 (c) LEvertz
 *    Copyright 2016 (c) Lorenz Haas
 *    Copyright 2017 (c) frax2222
 *    Copyright 2017-2018 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Christian von Arnim
 *    Copyright 2021 (c) Christian von Arnim, ISW University of Stuttgart  (for VDW and umati)
 *    Copyright 2017 (c) Henrik Norrman
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Andreas Ebner)
 */


/*********************/
/* Edit Node Context */
/*********************/

UA_StatusCode
UA_Server_getNodeContext(UA_Server *server, UA_NodeId nodeId,
                         void **nodeContext) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode retval = getNodeContext(server, nodeId, nodeContext);
    UA_UNLOCK(&server->serviceMutex);
    return retval;
}

UA_StatusCode
getNodeContext(UA_Server *server, UA_NodeId nodeId,
               void **nodeContext) {
    const UA_Node *node = UA_NODESTORE_GET(server, &nodeId);
    if(!node)
        return UA_STATUSCODE_BADNODEIDUNKNOWN;
    *nodeContext = node->head.context;
    UA_NODESTORE_RELEASE(server, node);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
setDeconstructedNode(UA_Server *server, UA_Session *session,
                     UA_NodeHead *head, void *context) {
    head->constructed = false;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
setConstructedNodeContext(UA_Server *server, UA_Session *session,
                          UA_NodeHead *head, void *context) {
    head->context = context;
    head->constructed = true;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
editNodeContext(UA_Server *server, UA_Session* session,
                UA_NodeHead *head, void *context) {
    head->context = context;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
setNodeContext(UA_Server *server, UA_NodeId nodeId,
               void *nodeContext) {
    return UA_Server_editNode(server, &server->adminSession, &nodeId,
                              (UA_EditNodeCallback)editNodeContext, nodeContext);
}

UA_StatusCode
UA_Server_setNodeContext(UA_Server *server, UA_NodeId nodeId,
                         void *nodeContext) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode retval = setNodeContext(server, nodeId, nodeContext);
    UA_UNLOCK(&server->serviceMutex);
    return retval;
}

static UA_StatusCode
checkSetIsDynamicVariable(UA_Server *server, UA_Session *session,
                          const UA_NodeId *nodeId);

/**********************/
/* Consistency Checks */
/**********************/

#define UA_PARENT_REFERENCES_COUNT 2

const UA_NodeId parentReferences[UA_PARENT_REFERENCES_COUNT] = {
    {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASSUBTYPE}},
    {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASCOMPONENT}}
};

static void
logAddNode(const UA_Logger *logger, UA_Session *session,
           const UA_NodeId *nodeId, const char *msg) {
    UA_LOG_NODEID_INFO(nodeId,
    UA_LOG_INFO_SESSION(logger, session, "AddNode (%.*s): %s",
                        (int)nodeIdStr.length, nodeIdStr.data, msg));
}

/* Check if the requested parent node exists, has the right node class and is
 * referenced with an allowed (hierarchical) reference type. For "type" nodes,
 * only hasSubType references are allowed. */
static UA_StatusCode
checkParentReference(UA_Server *server, UA_Session *session, const UA_NodeHead *head,
                     const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId) {
    /* Objects do not need a parent (e.g. mandatory/optional modellingrules).
     * Also, there are some variables which do not have parents, e.g.
     * EnumStrings, EnumValues */
    if((head->nodeClass == UA_NODECLASS_OBJECT ||
        head->nodeClass == UA_NODECLASS_VARIABLE) &&
       UA_NodeId_isNull(parentNodeId) && UA_NodeId_isNull(referenceTypeId))
        return UA_STATUSCODE_GOOD;

    /* See if the parent exists */
    const UA_Node *parent = UA_NODESTORE_GET(server, parentNodeId);
    if(!parent) {
        logAddNode(server->config.logging, session, &head->nodeId,
                   "Parent node not found");
        return UA_STATUSCODE_BADPARENTNODEIDINVALID;
    }

    UA_NodeClass parentNodeClass = parent->head.nodeClass;
    UA_NODESTORE_RELEASE(server, parent);

    /* Check the referencetype exists */
    const UA_Node *referenceType = UA_NODESTORE_GET(server, referenceTypeId);
    if(!referenceType) {
        logAddNode(server->config.logging, session, &head->nodeId,
                   "Reference type to the parent not found");
        return UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
    }

    /* Check if the referencetype is a reference type node */
    if(referenceType->head.nodeClass != UA_NODECLASS_REFERENCETYPE) {
        logAddNode(server->config.logging, session, &head->nodeId,
                   "Reference type to the parent is not a ReferenceTypeNode");
        UA_NODESTORE_RELEASE(server, referenceType);
        return UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
    }

    /* Check that the reference type is not abstract */
    UA_Boolean referenceTypeIsAbstract = referenceType->referenceTypeNode.isAbstract;
    UA_NODESTORE_RELEASE(server, referenceType);
    if(referenceTypeIsAbstract == true) {
        logAddNode(server->config.logging, session, &head->nodeId,
                   "Abstract reference type to the parent not allowed");
        return UA_STATUSCODE_BADREFERENCENOTALLOWED;
    }

    /* Check hassubtype relation for type nodes */
    if(head->nodeClass == UA_NODECLASS_DATATYPE ||
       head->nodeClass == UA_NODECLASS_VARIABLETYPE ||
       head->nodeClass == UA_NODECLASS_OBJECTTYPE ||
       head->nodeClass == UA_NODECLASS_REFERENCETYPE) {
        /* Type needs hassubtype reference to the supertype */
        if(referenceType->referenceTypeNode.referenceTypeIndex !=
           UA_REFERENCETYPEINDEX_HASSUBTYPE) {
            logAddNode(server->config.logging, session, &head->nodeId,
                       "Type nodes need to have a HasSubType reference to the parent");
            return UA_STATUSCODE_BADREFERENCENOTALLOWED;
        }
        /* Supertype needs to be of the same node type  */
        if(parentNodeClass != head->nodeClass) {
            logAddNode(server->config.logging, session, &head->nodeId,
                       "Type nodes needs to be of the same node "
                       "type as their parent");
            return UA_STATUSCODE_BADPARENTNODEIDINVALID;
        }
        return UA_STATUSCODE_GOOD;
    }

    /* Test if the referencetype is hierarchical */
    const UA_NodeId hierarchRefs = UA_NODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES);
    if(!isNodeInTree_singleRef(server, referenceTypeId, &hierarchRefs,
                               UA_REFERENCETYPEINDEX_HASSUBTYPE)) {
        logAddNode(server->config.logging, session, &head->nodeId,
                   "Reference type to the parent is not hierarchical");
        return UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
    }

    return UA_STATUSCODE_GOOD;
}

/* Only BaseDataType can have empty values. Generate a default value. */
static UA_StatusCode
setDefaultValue(UA_Server *server, const UA_VariableNode *node) {
    /* Get the DataType */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    const UA_DataType *type = UA_Server_findDataType(server, &node->dataType);
    if(!type) {
        /* No description for the DataType found. It is possible that an
         * abstract DataType is used, e.g. UInteger. Browse to see if there is a
         * non-abstract subtype that can be used for the default value.
         *
         * Look up and downwards in the hierarchy. Some data types (e.g.
         * UtcTime) are derived from a non-abstract data type. This is then used
         * for the actual value, Use the first match. */
        UA_ReferenceTypeSet refs = UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASSUBTYPE);
        UA_ExpandedNodeId *typeCandidates = NULL;
        size_t typeCandidatesSize = 0;
        res = browseRecursive(server, 1, &node->dataType,
                              UA_BROWSEDIRECTION_BOTH, &refs,
                              UA_NODECLASS_DATATYPE, false,
                              &typeCandidatesSize, &typeCandidates);
        if(res != UA_STATUSCODE_GOOD)
            return res;

        for(size_t i = 0; i < typeCandidatesSize; i++) {
            /* Skip BaseDataType (Variant). This is the root of the DataType
             * hierarchy. Variables of BaseDataType can be empty. */
            if(UA_NodeId_equal(&UA_TYPES[UA_TYPES_VARIANT].typeId,
                               &typeCandidates[i].nodeId))
                continue;

            /* Skip ExtensionObject. Even though we can encode the type it is
             * abstract and nodes should not contain them as value. */
            if(UA_NodeId_equal(&UA_TYPES[UA_TYPES_EXTENSIONOBJECT].typeId,
                               &typeCandidates[i].nodeId))
                continue;

            /* Get the type encoding information */
            type = UA_Server_findDataType(server, &typeCandidates[i].nodeId);
            if(type)
                break;
        }

        UA_Array_delete(typeCandidates, typeCandidatesSize,
                        &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
        if(!type)
            return UA_STATUSCODE_BADTYPEMISMATCH;
    }

    /* Set up the value with the default content */
    UA_Variant val;
    UA_Variant_init(&val);
    if(node->valueRank < 0) {
        /* Set a scalar */
        void *data = UA_new(type);
        if(!data)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        UA_Variant_setScalar(&val, data, type);
    } else {
        /* Set an array
         *
         * https://reference.opcfoundation.org/v104/Core/docs/Part3/5.6.2/#Table13
         * specifies ArrayDimensions as follows: This Attribute specifies the
         * maximum supported length of each dimension. If the maximum is unknown
         * the value shall be 0. The number of elements shall be equal to the
         * value of the ValueRank Attribute. This Attribute shall be null if
         * ValueRank <= 0.
         *
         * The (variant) values themselves cannot have ArrayDimensions with a
         * dimension length of zero. We however consider that empty arrays
         * (null-array or length zero) have implicit array dimensions [0,0,...].
         * With the appropriate number of dimensions. So they always match.
         *
         * We automatically create a null array during the node creation when
         * required for the type-checking..
         *
         * Also see the method 'compatibleValueArrayDimensions' where the
         * compatibility of the ArrayDimensions is checked. */
        UA_Variant_setArray(&val, NULL, 0, type);
    }

    /* Write the value */
    res = writeAttribute(server, &server->adminSession, &node->head.nodeId,
                         UA_ATTRIBUTEID_VALUE, &val, &UA_TYPES[UA_TYPES_VARIANT]);

    /* Clean up */
    UA_Variant_clear(&val);
    return res;
}

static UA_StatusCode
typeCheckVariableNode(UA_Server *server, UA_Session *session,
                      const UA_VariableNode *node,
                      const UA_VariableTypeNode *vt) {
    /* Check the datatype against the vt */
    if(!compatibleDataTypes(server, &node->dataType, &vt->dataType)) {
        logAddNode(server->config.logging, session, &node->head.nodeId,
                   "The value of is incompatible with "
                   "the datatype of the VariableType");
        return UA_STATUSCODE_BADTYPEMISMATCH;
    }

    /* Check valueRank against array dimensions */
    if(!compatibleValueRankArrayDimensions(server, session, node->valueRank,
                                           node->arrayDimensionsSize)) {
        logAddNode(server->config.logging, session, &node->head.nodeId,
                   "The value rank of is incompatible with its array dimensions");
        return UA_STATUSCODE_BADTYPEMISMATCH;
    }

    /* Check valueRank against the vt */
    if(!compatibleValueRanks(node->valueRank, vt->valueRank)) {
        logAddNode(server->config.logging, session, &node->head.nodeId,
                   "The value rank is incompatible "
                   "with the value rank of the VariableType");
        return UA_STATUSCODE_BADTYPEMISMATCH;
    }

    /* Check array dimensions against the vt */
    if(!compatibleArrayDimensions(vt->arrayDimensionsSize, vt->arrayDimensions,
                                  node->arrayDimensionsSize, node->arrayDimensions)) {
        logAddNode(server->config.logging, session, &node->head.nodeId,
                   "The array dimensions are incompatible with the "
                   "array dimensions of the VariableType");
        return UA_STATUSCODE_BADTYPEMISMATCH;
    }

    /* Typecheck the value. Less strict for NS0 -- we adjust nodes after loading
     * the generated definitions. */
    if(server->bootstrapNS0)
        return UA_STATUSCODE_GOOD;

    /* The value might come from a datasource, so we perform a
     * regular read. */
    UA_DataValue value;
    UA_DataValue_init(&value);
    UA_StatusCode retval = readValueAttribute(server, session, node, &value);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* We have a value. Write it back to perform checks and adjustments. */
    const char *reason;
    if(node->valueSource == UA_VALUESOURCE_DATA && value.hasValue) {
        if(!compatibleValue(server, session, &node->dataType, node->valueRank,
                            node->arrayDimensionsSize, node->arrayDimensions,
                            &value.value, NULL, &reason)) {
            retval = writeAttribute(server, session, &node->head.nodeId,
                                    UA_ATTRIBUTEID_VALUE, &value.value,
                                    &UA_TYPES[UA_TYPES_VARIANT]);
        }
        UA_DataValue_clear(&value);
        return retval;
    }

    /* Only BaseDataType (Variant) can have empty values */
    if(!value.hasValue &&
       !UA_NodeId_equal(&node->dataType, &UA_TYPES[UA_TYPES_VARIANT].typeId)) {
        /* Warn if that is configured */
        if(server->config.allowEmptyVariables != UA_RULEHANDLING_ACCEPT)
            UA_LOG_NODEID_DEBUG(&node->head.nodeId,
               UA_LOG_DEBUG_SESSION(server->config.logging, session,
                                    "AddNode (%.*s): The value is empty. "
                                    "But this is only allowed for BaseDataType. "
                                    "Create a matching default value.",
                                    (int)nodeIdStr.length, nodeIdStr.data));

        /* Abort if that is configured */
        if(server->config.allowEmptyVariables == UA_RULEHANDLING_ABORT)
            retval = UA_STATUSCODE_BADTYPEMISMATCH;

        /* Try to generate and write a default value */
        if(server->config.allowEmptyVariables == UA_RULEHANDLING_DEFAULT) {
            retval = setDefaultValue(server, node);
            if(retval != UA_STATUSCODE_GOOD) {
                UA_LOG_NODEID_INFO(&node->head.nodeId,
                   UA_LOG_INFO_SESSION(server->config.logging, session,
                                       "AddNode (%.*s): Could not create a default value "
                                       "with StatusCode %s", (int)nodeIdStr.length,
                                       nodeIdStr.data, UA_StatusCode_name(retval)));
            }
        }
        return retval;
    }

    /* Type-check the value */
    if(retval == UA_STATUSCODE_GOOD &&
       !compatibleValue(server, session, &node->dataType, node->valueRank,
                        node->arrayDimensionsSize, node->arrayDimensions,
                        &value.value, NULL, &reason)) {
        UA_LOG_NODEID_INFO(&node->head.nodeId,
           UA_LOG_INFO_SESSION(server->config.logging, session,
                               "AddNode (%.*s): The VariableNode value has "
                               "failed the type check with reason %s. ",
                               (int)nodeIdStr.length, nodeIdStr.data, reason));
        retval = UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_DataValue_clear(&value);
    return retval;
}

/********************/
/* Instantiate Node */
/********************/

static const UA_NodeId baseDataVariableType =
    {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_BASEDATAVARIABLETYPE}};
static const UA_NodeId baseObjectType =
    {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_BASEOBJECTTYPE}};
static const UA_NodeId hasTypeDefinition =
    {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASTYPEDEFINITION}};

/* Use attributes from the variable type wherever required. Reload the node if
 * changes were made. */
static UA_StatusCode
useVariableTypeAttributes(UA_Server *server, UA_Session *session,
                          const UA_VariableNode *node,
                          const UA_VariableTypeNode *vt) {
    /* If no value is set, see if the vt provides one and copy it. This needs to
     * be done before copying the datatype from the vt, as setting the datatype
     * triggers a typecheck. */
    UA_ReadValueId item;
    UA_ReadValueId_init(&item);
    item.nodeId = node->head.nodeId;
    item.attributeId = UA_ATTRIBUTEID_VALUE;
    UA_DataValue dv = readWithSession(server, session, &item,
                                      UA_TIMESTAMPSTORETURN_NEITHER);

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(dv.hasValue && !dv.value.type) {
        UA_DataValue v;
        UA_DataValue_init(&v);
        retval = readValueAttribute(server, session, (const UA_VariableNode*)vt, &v);
        if(retval == UA_STATUSCODE_GOOD && v.hasValue) {
            retval = writeAttribute(server, session, &node->head.nodeId,
                                    UA_ATTRIBUTEID_VALUE, &v.value,
                                    &UA_TYPES[UA_TYPES_VARIANT]);
        }
        UA_DataValue_clear(&v);

        if(retval != UA_STATUSCODE_GOOD) {
            logAddNode(server->config.logging, session, &node->head.nodeId,
                       "The default content of the VariableType could "
                       "not be used. This may happen if the VariableNode "
                       "makes additional restrictions.");
            retval = UA_STATUSCODE_GOOD;
        }
    }
    UA_DataValue_clear(&dv);

    /* If no datatype is given, use the datatype of the vt */
    if(UA_NodeId_isNull(&node->dataType)) {
        logAddNode(server->config.logging, session, &node->head.nodeId,
                   "No datatype given; Copy the datatype attribute "
                   "from the TypeDefinition");
        retval = writeAttribute(server, session, &node->head.nodeId,
                                UA_ATTRIBUTEID_DATATYPE, &vt->dataType,
                                &UA_TYPES[UA_TYPES_NODEID]);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
    }

    /* Use the ArrayDimensions of the vt */
    if(node->arrayDimensionsSize == 0 && vt->arrayDimensionsSize > 0) {
        UA_Variant v;
        UA_Variant_init(&v);
        UA_Variant_setArray(&v, vt->arrayDimensions, vt->arrayDimensionsSize,
                            &UA_TYPES[UA_TYPES_UINT32]);
        retval = writeAttribute(server, session, &node->head.nodeId,
                                UA_ATTRIBUTEID_ARRAYDIMENSIONS, &v,
                                &UA_TYPES[UA_TYPES_VARIANT]);
    }

    return retval;
}

/* Search for an instance of "browseName" in node searchInstance. Used during
 * copyChildNodes to find overwritable/mergable nodes. Does not touch
 * outInstanceNodeId if no child is found. */
static UA_StatusCode
findChildByBrowsename(UA_Server *server, UA_Session *session,
                      const UA_NodeId *searchInstance,
                      const UA_QualifiedName *browseName,
                      UA_NodeId *outInstanceNodeId) {
    UA_BrowseDescription bd;
    UA_BrowseDescription_init(&bd);
    bd.nodeId = *searchInstance;
    bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES);
    bd.includeSubtypes = true;
    bd.browseDirection = UA_BROWSEDIRECTION_FORWARD;
    bd.nodeClassMask = UA_NODECLASS_OBJECT | UA_NODECLASS_VARIABLE | UA_NODECLASS_METHOD;
    bd.resultMask = UA_BROWSERESULTMASK_BROWSENAME;

    UA_BrowseResult br;
    UA_BrowseResult_init(&br);
    UA_UInt32 maxrefs = 0;
    Operation_Browse(server, session, &maxrefs, &bd, &br);
    if(br.statusCode != UA_STATUSCODE_GOOD)
        return br.statusCode;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    for(size_t i = 0; i < br.referencesSize; ++i) {
        UA_ReferenceDescription *rd = &br.references[i];
        if(rd->browseName.namespaceIndex == browseName->namespaceIndex &&
           UA_String_equal(&rd->browseName.name, &browseName->name)) {
            retval = UA_NodeId_copy(&rd->nodeId.nodeId, outInstanceNodeId);
            break;
        }
    }

    UA_BrowseResult_clear(&br);
    return retval;
}

static const UA_ExpandedNodeId mandatoryId =
    {{0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_MODELLINGRULE_MANDATORY}}, {0, NULL}, 0};

static UA_Boolean
isMandatoryChild(UA_Server *server, UA_Session *session,
                 const UA_NodeId *childNodeId) {
    /* Get the child */
    const UA_Node *child = UA_NODESTORE_GET(server, childNodeId);
    if(!child)
        return false;

    /* Look for the reference making the child mandatory */
    UA_Boolean found = false;
    for(size_t i = 0; i < child->head.referencesSize; ++i) {
        UA_NodeReferenceKind *rk = &child->head.references[i];
        if(rk->referenceTypeIndex != UA_REFERENCETYPEINDEX_HASMODELLINGRULE)
            continue;
        if(rk->isInverse)
            continue;

        if(UA_NodeReferenceKind_findTarget(rk, &mandatoryId)) {
            found = true;
            break;
        }
    }

    UA_NODESTORE_RELEASE(server, child);
    return found;
}

static UA_StatusCode
copyAllChildren(UA_Server *server, UA_Session *session,
                const UA_NodeId *source, const UA_NodeId *destination);

static void
Operation_addReference(UA_Server *server, UA_Session *session, void *context,
                       const UA_AddReferencesItem *item, UA_StatusCode *retval);

UA_StatusCode
addRefWithSession(UA_Server *server, UA_Session *session, const UA_NodeId *sourceId,
                  const UA_NodeId *referenceTypeId, const UA_NodeId *targetId,
                  UA_Boolean forward) {
    UA_AddReferencesItem ref_item;
    UA_AddReferencesItem_init(&ref_item);
    ref_item.sourceNodeId = *sourceId;
    ref_item.referenceTypeId = *referenceTypeId;
    ref_item.isForward = forward;
    ref_item.targetNodeId.nodeId = *targetId;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    Operation_addReference(server, session, NULL, &ref_item, &retval);
    return retval;
}

UA_StatusCode
addRef(UA_Server *server, const UA_NodeId sourceId,
       const UA_NodeId referenceTypeId, const UA_NodeId targetId,
       UA_Boolean forward) {
    return addRefWithSession(server, &server->adminSession, &sourceId,
                             &referenceTypeId, &targetId, forward);
}

static UA_StatusCode
addInterfaceChildren(UA_Server *server, UA_Session *session,
                     const UA_NodeId *nodeId, const UA_NodeId *typeId) {
    /* Get the hierarchy of the type and all its supertypes */
    UA_NodeId *hierarchy = NULL;
    size_t hierarchySize = 0;
    UA_StatusCode retval = getAllInterfaceChildNodeIds(server, nodeId, typeId,
                                                       &hierarchy, &hierarchySize);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Copy members of the type and supertypes (and instantiate them) */
    for(size_t i = 0; i < hierarchySize; ++i) {
        retval = copyAllChildren(server, session, &hierarchy[i], nodeId);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_Array_delete(hierarchy, hierarchySize, &UA_TYPES[UA_TYPES_NODEID]);
            return retval;
        }
    }

    for(size_t i = 0; i < hierarchySize; ++i) {
        UA_NodeId refId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASINTERFACE);
        retval = addRef(server, *nodeId, refId, hierarchy[i], true);

        /* Don't add the original HasInterface reference to ObjectType sub nodes */
        if(retval == UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED) {
            retval = UA_STATUSCODE_GOOD;
        } else if(retval != UA_STATUSCODE_GOOD) {
            break;
        }
    }

    UA_Array_delete(hierarchy, hierarchySize, &UA_TYPES[UA_TYPES_NODEID]);
    return retval;
}

static UA_StatusCode
copyChild(UA_Server *server, UA_Session *session,
          const UA_NodeId *destinationNodeId,
          const UA_ReferenceDescription *rd) {
    UA_assert(session);
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Is there an existing child with the browsename? */
    UA_NodeId existingChild = UA_NODEID_NULL;
    UA_StatusCode retval = findChildByBrowsename(server, session, destinationNodeId,
                                                 &rd->browseName, &existingChild);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Have a child with that browseName. Deep-copy missing members. */
    if(!UA_NodeId_isNull(&existingChild)) {
        if(rd->nodeClass == UA_NODECLASS_VARIABLE ||
           rd->nodeClass == UA_NODECLASS_OBJECT)
            retval = copyAllChildren(server, session, &rd->nodeId.nodeId, &existingChild);
        UA_NodeId_clear(&existingChild);
        return retval;
    }

    /* Is the child mandatory? If not, ask callback whether child should be instantiated.
     * If not, skip. */
    if(!isMandatoryChild(server, session, &rd->nodeId.nodeId)) {
        if(!server->config.nodeLifecycle.createOptionalChild)
            return UA_STATUSCODE_GOOD;
        UA_UNLOCK(&server->serviceMutex);
        UA_Boolean createChild = server->config.nodeLifecycle.
            createOptionalChild(server, &session->sessionId, session->context,
                                &rd->nodeId.nodeId, destinationNodeId, &rd->referenceTypeId);
        UA_LOCK(&server->serviceMutex);
        if(!createChild)
            return UA_STATUSCODE_GOOD;
    }

    /* Child is a method -> create a reference */
    if(rd->nodeClass == UA_NODECLASS_METHOD) {
        UA_AddReferencesItem newItem;
        UA_AddReferencesItem_init(&newItem);
        newItem.sourceNodeId = *destinationNodeId;
        newItem.referenceTypeId = rd->referenceTypeId;
        newItem.isForward = true;
        newItem.targetNodeId = rd->nodeId;
        newItem.targetNodeClass = UA_NODECLASS_METHOD;
        Operation_addReference(server, session, NULL, &newItem, &retval);
        return retval;
    }

    /* Child is a variable or object */
    if(rd->nodeClass == UA_NODECLASS_VARIABLE ||
       rd->nodeClass == UA_NODECLASS_OBJECT) {
        /* Make a copy of the node */
        UA_Node *node;
        retval = UA_NODESTORE_GETCOPY(server, &rd->nodeId.nodeId, &node);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;

        /* Remove the context of the copied node */
        node->head.context = NULL;
        node->head.constructed = false;
#ifdef UA_ENABLE_SUBSCRIPTIONS
        node->head.monitoredItems = NULL;
#endif

        /* The value backend is copied by default. But we don't want to keep it
         * here. */
        if(node->head.nodeClass == UA_NODECLASS_VARIABLE ||
           node->head.nodeClass == UA_NODECLASS_VARIABLETYPE) {
            if(node->variableNode.valueSource != UA_VALUESOURCE_DATA)
                memset(&node->variableNode.value, 0, sizeof(node->variableNode.value));
            node->variableNode.valueSource = UA_VALUESOURCE_DATA;
            memset(&node->variableNode.valueBackend, 0, sizeof(UA_ValueBackend));
        }

        /* Reset the NodeId (random numeric id will be assigned in the nodestore) */
        UA_NodeId_clear(&node->head.nodeId);
        node->head.nodeId.namespaceIndex = destinationNodeId->namespaceIndex;

        if(server->config.nodeLifecycle.generateChildNodeId) {
            UA_UNLOCK(&server->serviceMutex);
            retval = server->config.nodeLifecycle.
                generateChildNodeId(server, &session->sessionId, session->context,
                                    &rd->nodeId.nodeId, destinationNodeId,
                                    &rd->referenceTypeId, &node->head.nodeId);
            UA_LOCK(&server->serviceMutex);
            if(retval != UA_STATUSCODE_GOOD) {
                UA_NODESTORE_DELETE(server, node);
                return retval;
            }
        }

        /* Remove references, they are re-created from scratch in addnode_finish */
        /* TODO: Be more clever in removing references that are re-added during
         * addnode_finish. That way, we can call addnode_finish also on children that were
         * manually added by the user during addnode_begin and addnode_finish. */
        /* For now we keep all the modelling rule references and delete all others */
        const UA_NodeId nodeId_typesFolder= UA_NODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER);
        const UA_ReferenceTypeSet reftypes_aggregates =
            UA_REFTYPESET(UA_REFERENCETYPEINDEX_AGGREGATES);
        UA_ReferenceTypeSet reftypes_skipped;
        /* Check if the hasModellingRule-reference is required (configured or node in an
            instance declaration) */
        if(server->config.modellingRulesOnInstances ||
           isNodeInTree(server, destinationNodeId,
                        &nodeId_typesFolder, &reftypes_aggregates)) {
            reftypes_skipped = UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASMODELLINGRULE);
        } else {
            UA_ReferenceTypeSet_init(&reftypes_skipped);
        }
        reftypes_skipped = UA_ReferenceTypeSet_union(reftypes_skipped, UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASINTERFACE));
        UA_Node_deleteReferencesSubset(node, &reftypes_skipped);

        /* Add the node to the nodestore */
        UA_NodeId newNodeId = UA_NODEID_NULL;
        retval = UA_NODESTORE_INSERT(server, node, &newNodeId);
        /* node = NULL; The pointer is no longer valid */
        if(retval != UA_STATUSCODE_GOOD)
            return retval;

        /* Add the node references */
        retval = addNode_addRefs(server, session, &newNodeId, destinationNodeId,
                                 &rd->referenceTypeId, &rd->typeDefinition.nodeId);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_NODESTORE_REMOVE(server, &newNodeId);
            UA_NodeId_clear(&newNodeId);
            return retval;
        }

        if (rd->nodeClass == UA_NODECLASS_VARIABLE) {
            retval = checkSetIsDynamicVariable(server, session, &newNodeId);

            if(retval != UA_STATUSCODE_GOOD) {
                UA_NODESTORE_REMOVE(server, &newNodeId);
                return retval;
            }
        }

        /* For the new child, recursively copy the members of the original. No
         * typechecking is performed here. Assuming that the original is
         * consistent. */
        retval = copyAllChildren(server, session, &rd->nodeId.nodeId, &newNodeId);
        if(retval != UA_STATUSCODE_GOOD) {
            deleteNode(server, newNodeId, true);
            return retval;
        }

        /* Check if its a dynamic variable, add all type and/or interface
         * children and call the constructor */
        retval = addNode_finish(server, session, &newNodeId);
        if(retval != UA_STATUSCODE_GOOD) {
            deleteNode(server, newNodeId, true);
            return retval;
        }

        /* Clean up.  Because it can happen that a string is assigned as ID at
         * generateChildNodeId. */
        UA_NodeId_clear(&newNodeId);
    }

    return retval;
}

/* Copy any children of Node sourceNodeId to another node destinationNodeId. */
static UA_StatusCode
copyAllChildren(UA_Server *server, UA_Session *session,
                const UA_NodeId *source, const UA_NodeId *destination) {
    /* Browse to get all children of the source */
    UA_BrowseDescription bd;
    UA_BrowseDescription_init(&bd);
    bd.nodeId = *source;
    bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES);
    bd.includeSubtypes = true;
    bd.browseDirection = UA_BROWSEDIRECTION_FORWARD;
    bd.nodeClassMask = UA_NODECLASS_OBJECT | UA_NODECLASS_VARIABLE | UA_NODECLASS_METHOD;
    bd.resultMask = UA_BROWSERESULTMASK_REFERENCETYPEID | UA_BROWSERESULTMASK_NODECLASS |
        UA_BROWSERESULTMASK_BROWSENAME | UA_BROWSERESULTMASK_TYPEDEFINITION;

    UA_BrowseResult br;
    UA_BrowseResult_init(&br);
    UA_UInt32 maxrefs = 0;
    Operation_Browse(server, session, &maxrefs, &bd, &br);
    if(br.statusCode != UA_STATUSCODE_GOOD)
        return br.statusCode;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    for(size_t i = 0; i < br.referencesSize; ++i) {
        UA_ReferenceDescription *rd = &br.references[i];
        retval = copyChild(server, session, destination, rd);
        if(retval != UA_STATUSCODE_GOOD)
            break;
    }

    UA_BrowseResult_clear(&br);
    return retval;
}

static UA_StatusCode
addTypeChildren(UA_Server *server, UA_Session *session,
                const UA_NodeId *nodeId, const UA_NodeId *typeId) {
    /* Get the hierarchy of the type and all its supertypes */
    UA_NodeId *hierarchy = NULL;
    size_t hierarchySize = 0;
    UA_StatusCode retval = getParentTypeAndInterfaceHierarchy(server, typeId,
                                                              &hierarchy, &hierarchySize);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_assert(hierarchySize < 1000);

    /* Copy members of the type and supertypes (and instantiate them) */
    for(size_t i = 0; i < hierarchySize; ++i) {
        retval = copyAllChildren(server, session, &hierarchy[i], nodeId);
        if(retval != UA_STATUSCODE_GOOD)
            break;
    }

    UA_Array_delete(hierarchy, hierarchySize, &UA_TYPES[UA_TYPES_NODEID]);
    return retval;
}

/************/
/* Add Node */
/************/

static const UA_NodeId hasSubtype = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASSUBTYPE}};

UA_StatusCode
addNode_addRefs(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId,
                const UA_NodeId *parentNodeId, const UA_NodeId *referenceTypeId,
                const UA_NodeId *typeDefinitionId) {
    /* Get the node */
    const UA_Node *type = NULL;
    const UA_Node *node = UA_NODESTORE_GET(server, nodeId);
    if(!node)
        return UA_STATUSCODE_BADNODEIDUNKNOWN;

    /* Use the typeDefinition as parent for type-nodes */
    const UA_NodeHead *head = &node->head;
    if(head->nodeClass == UA_NODECLASS_VARIABLETYPE ||
       head->nodeClass == UA_NODECLASS_OBJECTTYPE ||
       head->nodeClass == UA_NODECLASS_REFERENCETYPE ||
       head->nodeClass == UA_NODECLASS_DATATYPE) {
        if(UA_NodeId_equal(referenceTypeId, &UA_NODEID_NULL))
            referenceTypeId = &hasSubtype;
        const UA_Node *parentNode = UA_NODESTORE_GET(server, parentNodeId);
        if(parentNode) {
            if(parentNode->head.nodeClass == head->nodeClass)
                typeDefinitionId = parentNodeId;
            UA_NODESTORE_RELEASE(server, parentNode);
        }
    }

    UA_StatusCode retval;
    /* Make sure newly created node does not have itself as parent */
    if(UA_NodeId_equal(nodeId, parentNodeId)) {
        logAddNode(server->config.logging, session, nodeId,
                   "A node cannot have itself as parent");
        retval = UA_STATUSCODE_BADINVALIDARGUMENT;
        goto cleanup;
    }


    /* Check parent reference. Objects may have no parent. */
    retval = checkParentReference(server, session, head, parentNodeId, referenceTypeId);
    if(retval != UA_STATUSCODE_GOOD) {
        logAddNode(server->config.logging, session, nodeId,
                   "The parent reference for is invalid");
        goto cleanup;
    }

    /* Replace empty typeDefinition with the most permissive default */
    if((head->nodeClass == UA_NODECLASS_VARIABLE ||
        head->nodeClass == UA_NODECLASS_OBJECT) &&
       UA_NodeId_isNull(typeDefinitionId)) {
        logAddNode(server->config.logging, session, nodeId,
                   "No TypeDefinition. Use the default "
                   "TypeDefinition for the Variable/Object");
        if(head->nodeClass == UA_NODECLASS_VARIABLE)
            typeDefinitionId = &baseDataVariableType;
        else
            typeDefinitionId = &baseObjectType;
    }

    /* Get the node type. There must be a typedefinition for variables, objects
     * and type-nodes. See the above checks. */
    if(!UA_NodeId_isNull(typeDefinitionId)) {
        /* Get the type node */
        type = UA_NODESTORE_GET(server, typeDefinitionId);
        if(!type) {
            logAddNode(server->config.logging, session, nodeId, "Node type not found");
            retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
            goto cleanup;
        }

        UA_Boolean typeOk = false;
        const UA_NodeHead *typeHead = &type->head;
        switch(head->nodeClass) {
            case UA_NODECLASS_DATATYPE:
                typeOk = typeHead->nodeClass == UA_NODECLASS_DATATYPE;
                break;
            case UA_NODECLASS_METHOD:
                typeOk = typeHead->nodeClass == UA_NODECLASS_METHOD;
                break;
            case UA_NODECLASS_OBJECT:
            case UA_NODECLASS_OBJECTTYPE:
                typeOk = typeHead->nodeClass == UA_NODECLASS_OBJECTTYPE;
                break;
            case UA_NODECLASS_REFERENCETYPE:
                typeOk = typeHead->nodeClass == UA_NODECLASS_REFERENCETYPE;
                break;
            case UA_NODECLASS_VARIABLE:
            case UA_NODECLASS_VARIABLETYPE:
                typeOk = typeHead->nodeClass == UA_NODECLASS_VARIABLETYPE;
                break;
            case UA_NODECLASS_VIEW:
                typeOk = typeHead->nodeClass == UA_NODECLASS_VIEW;
                break;
            default:
                typeOk = false;
        }
        if(!typeOk) {
            logAddNode(server->config.logging, session, nodeId,
                       "Type does not match the NodeClass");
            retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
            goto cleanup;
        }

        /* See if the type has the correct node class. For type-nodes, we know
         * that type has the same nodeClass from checkParentReference. */
        if(head->nodeClass == UA_NODECLASS_VARIABLE &&
           type->variableTypeNode.isAbstract) {
            /* Get subtypes of the parent reference types */
            UA_ReferenceTypeSet refTypes1, refTypes2;
            retval |= referenceTypeIndices(server, &parentReferences[0], &refTypes1, true);
            retval |= referenceTypeIndices(server, &parentReferences[1], &refTypes2, true);
            UA_ReferenceTypeSet refTypes = UA_ReferenceTypeSet_union(refTypes1, refTypes2);
            if(retval != UA_STATUSCODE_GOOD)
                goto cleanup;

            /* Abstract variable is allowed if parent is a children of a
             * base data variable. An abstract variable may be part of an
             * object type which again is below BaseObjectType */
            const UA_NodeId variableTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE);
            const UA_NodeId objectTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE);
            if(!isNodeInTree(server, parentNodeId, &variableTypes, &refTypes) &&
               !isNodeInTree(server, parentNodeId, &objectTypes, &refTypes)) {
                logAddNode(server->config.logging, session, nodeId,
                           "Type of variable node must be a "
                           "VariableType and cannot be abstract");
                retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
                goto cleanup;
            }
        }

        if(head->nodeClass == UA_NODECLASS_OBJECT &&
           type->objectTypeNode.isAbstract) {
            /* Get subtypes of the parent reference types */
            UA_ReferenceTypeSet refTypes1, refTypes2;
            retval |= referenceTypeIndices(server, &parentReferences[0], &refTypes1, true);
            retval |= referenceTypeIndices(server, &parentReferences[1], &refTypes2, true);
            UA_ReferenceTypeSet refTypes = UA_ReferenceTypeSet_union(refTypes1, refTypes2);
            if(retval != UA_STATUSCODE_GOOD)
                goto cleanup;


            /* Object node created of an abstract ObjectType. Only allowed if
             * within BaseObjectType folder or if it's an event (subType of
             * BaseEventType) */
            const UA_NodeId objectTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE);
            UA_Boolean isInBaseObjectType =
                isNodeInTree(server, parentNodeId, &objectTypes, &refTypes);

            const UA_NodeId eventTypes = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE);
            UA_Boolean isInBaseEventType =
                isNodeInTree_singleRef(server, &type->head.nodeId, &eventTypes,
                                       UA_REFERENCETYPEINDEX_HASSUBTYPE);

            if(!isInBaseObjectType &&
               !(isInBaseEventType && UA_NodeId_isNull(parentNodeId))) {
                logAddNode(server->config.logging, session, nodeId,
                           "Type of ObjectNode must be ObjectType and not be abstract");
                retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
                goto cleanup;
            }
        }
    }

    /* Add reference to the parent */
    if(!UA_NodeId_isNull(parentNodeId)) {
        if(UA_NodeId_isNull(referenceTypeId)) {
            logAddNode(server->config.logging, session, nodeId,
                       "Reference to parent cannot be null");
            retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
            goto cleanup;
        }

        retval = addRefWithSession(server, session, &head->nodeId, referenceTypeId,
                                   parentNodeId, false);
        if(retval != UA_STATUSCODE_GOOD) {
            logAddNode(server->config.logging, session, nodeId,
                       "Adding reference to parent failed");
            goto cleanup;
        }
    }

    /* Add a hasTypeDefinition reference */
    if(head->nodeClass == UA_NODECLASS_VARIABLE ||
       head->nodeClass == UA_NODECLASS_OBJECT) {
        UA_assert(type != NULL); /* see above */
        retval = addRefWithSession(server, session, &head->nodeId, &hasTypeDefinition,
                                   &type->head.nodeId, true);
        if(retval != UA_STATUSCODE_GOOD) {
            logAddNode(server->config.logging, session, nodeId,
                       "Adding a reference to the type definition failed");
        }
    }

 cleanup:
    UA_NODESTORE_RELEASE(server, node);
    if(type)
        UA_NODESTORE_RELEASE(server, type);
    return retval;
}

/* Create the node and add it to the nodestore. But don't typecheck and add
 * references so far */
UA_StatusCode
addNode_raw(UA_Server *server, UA_Session *session, void *nodeContext,
            const UA_AddNodesItem *item, UA_NodeId *outNewNodeId) {
    /* Do not check access for server */
    if(session != &server->adminSession && server->config.accessControl.allowAddNode) {
        UA_LOCK_ASSERT(&server->serviceMutex, 1);
        UA_UNLOCK(&server->serviceMutex);
        if(!server->config.accessControl.
           allowAddNode(server, &server->config.accessControl,
                        &session->sessionId, session->context, item)) {
            UA_LOCK(&server->serviceMutex);
            return UA_STATUSCODE_BADUSERACCESSDENIED;
        }
        UA_LOCK(&server->serviceMutex);
    }

    /* Check the namespaceindex */
    if(item->requestedNewNodeId.nodeId.namespaceIndex >= server->namespacesSize) {
        UA_LOG_INFO_SESSION(server->config.logging, session,
                            "AddNode: Namespace invalid");
        return UA_STATUSCODE_BADNODEIDINVALID;
    }

    if(item->nodeAttributes.encoding != UA_EXTENSIONOBJECT_DECODED &&
       item->nodeAttributes.encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) {
        UA_LOG_INFO_SESSION(server->config.logging, session,
                            "AddNode: Node attributes invalid");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Create a node */
    UA_Node *node = UA_NODESTORE_NEW(server, item->nodeClass);
    if(!node) {
        UA_LOG_INFO_SESSION(server->config.logging, session,
                            "AddNode: Node could not create a node "
                            "in the nodestore");
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    UA_NodeId tmpOutId = UA_NODEID_NULL;
    /* Fill the node attributes */
    node->head.context = nodeContext;
    UA_StatusCode retval =
        UA_NodeId_copy(&item->requestedNewNodeId.nodeId, &node->head.nodeId);
    if(retval != UA_STATUSCODE_GOOD)
        goto create_error;

    retval = UA_QualifiedName_copy(&item->browseName, &node->head.browseName);
    if(retval != UA_STATUSCODE_GOOD)
        goto create_error;

    retval = UA_Node_setAttributes(node, item->nodeAttributes.content.decoded.data,
                                   item->nodeAttributes.content.decoded.type);
    if(retval != UA_STATUSCODE_GOOD)
        goto create_error;

    /* Create a current source timestamp for values that don't have any */
    if(node->head.nodeClass == UA_NODECLASS_VARIABLE &&
       !node->variableNode.value.data.value.hasSourceTimestamp) {
        UA_EventLoop *el = server->config.eventLoop;
        node->variableNode.value.data.value.sourceTimestamp = el->dateTime_now(el);
        node->variableNode.value.data.value.hasSourceTimestamp = true;
    }

    /* Add the node to the nodestore */
    if(!outNewNodeId)
        outNewNodeId = &tmpOutId;
    retval = UA_NODESTORE_INSERT(server, node, outNewNodeId);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_INFO_SESSION(server->config.logging, session,
                            "AddNode: Node could not add the new node "
                            "to the nodestore with error code %s",
                            UA_StatusCode_name(retval));
        return retval;
    }

    if(outNewNodeId == &tmpOutId)
        UA_NodeId_clear(&tmpOutId);

    return UA_STATUSCODE_GOOD;

create_error:
    UA_LOG_INFO_SESSION(server->config.logging, session,
                        "AddNode: Node could not create a node "
                        "with error code %s", UA_StatusCode_name(retval));
    UA_NODESTORE_DELETE(server, node);
    return retval;
}

static UA_StatusCode
findDefaultInstanceBrowseNameNode(UA_Server *server, UA_NodeId startingNode,
                                  UA_NodeId *foundId) {
    UA_NodeId_init(foundId);
    UA_RelativePathElement rpe;
    UA_RelativePathElement_init(&rpe);
    rpe.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
    rpe.targetName = UA_QUALIFIEDNAME(0, "DefaultInstanceBrowseName");
    UA_BrowsePath bp;
    UA_BrowsePath_init(&bp);
    bp.startingNode = startingNode;
    bp.relativePath.elementsSize = 1;
    bp.relativePath.elements = &rpe;
    UA_BrowsePathResult bpr = translateBrowsePathToNodeIds(server, &bp);
    UA_StatusCode retval = bpr.statusCode;
    if(retval == UA_STATUSCODE_GOOD && bpr.targetsSize > 0)
        retval = UA_NodeId_copy(&bpr.targets[0].targetId.nodeId, foundId);
    UA_BrowsePathResult_clear(&bpr);
    return retval;
}

/* Check if we got a valid browse name for the new node. For object nodes the
 * BrowseName may only be null if the parent type has a
 * 'DefaultInstanceBrowseName' property. */
static UA_StatusCode
checkSetBrowseName(UA_Server *server, UA_Session *session, UA_AddNodesItem *item) {
    /* If the object node already has a browse name we are done here. */
    if(!UA_QualifiedName_isNull(&item->browseName))
        return UA_STATUSCODE_GOOD;

    /* Nodes other than Objects must have a BrowseName */
    if(item->nodeClass != UA_NODECLASS_OBJECT)
        return UA_STATUSCODE_BADBROWSENAMEINVALID;

    /* At this point we have an object with an empty browse name. Check the type
     * node if it has a DefaultInstanceBrowseName property. */
    UA_NodeId defaultBrowseNameNode;
    UA_StatusCode retval =
        findDefaultInstanceBrowseNameNode(server, item->typeDefinition.nodeId,
                                          &defaultBrowseNameNode);
    if(retval != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADBROWSENAMEINVALID;

    UA_Variant defaultBrowseName;
    retval = readWithReadValue(server, &defaultBrowseNameNode,
                               UA_ATTRIBUTEID_VALUE, &defaultBrowseName);
    UA_NodeId_clear(&defaultBrowseNameNode);
    if(retval != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADBROWSENAMEINVALID;

    if(UA_Variant_hasScalarType(&defaultBrowseName, &UA_TYPES[UA_TYPES_QUALIFIEDNAME])) {
        item->browseName = *(UA_QualifiedName*)defaultBrowseName.data;
        UA_QualifiedName_init((UA_QualifiedName*)defaultBrowseName.data);
    } else {
        retval = UA_STATUSCODE_BADBROWSENAMEINVALID;
    }

    UA_Variant_clear(&defaultBrowseName);
    return retval;
}

/* Prepare the node, then add it to the nodestore */
static UA_StatusCode
Operation_addNode_begin(UA_Server *server, UA_Session *session, void *nodeContext,
                        const UA_AddNodesItem *item, const UA_NodeId *parentNodeId,
                        const UA_NodeId *referenceTypeId, UA_NodeId *outNewNodeId) {
    /* Create a temporary NodeId if none is returned */
    UA_NodeId newId;
    if(!outNewNodeId) {
        UA_NodeId_init(&newId);
        outNewNodeId = &newId;
    }

    /* Set the BrowsenName before adding to the Nodestore. The BrowseName is
     * immutable afterwards. */
    UA_Boolean noBrowseName = UA_QualifiedName_isNull(&item->browseName);
    UA_StatusCode retval =
        checkSetBrowseName(server, session, (UA_AddNodesItem*)(uintptr_t)item);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Create the node and add it to the nodestore */
    retval = addNode_raw(server, session, nodeContext, item, outNewNodeId);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Typecheck and add references to parent and type definition */
    retval = addNode_addRefs(server, session, outNewNodeId, parentNodeId,
                             referenceTypeId, &item->typeDefinition.nodeId);
    if(retval != UA_STATUSCODE_GOOD)
        deleteNode(server, *outNewNodeId, true);

    if(outNewNodeId == &newId)
        UA_NodeId_clear(&newId);

 cleanup:
    if(noBrowseName)
        UA_QualifiedName_clear((UA_QualifiedName*)(uintptr_t)&item->browseName);
    return retval;
}

/* Construct children first */
static UA_StatusCode
recursiveCallConstructors(UA_Server *server, UA_Session *session,
                          const UA_NodeId *nodeId, const UA_Node *type) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Browse the children */
    UA_BrowseDescription bd;
    UA_BrowseDescription_init(&bd);
    bd.nodeId = *nodeId;
    bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES);
    bd.includeSubtypes = true;
    bd.browseDirection = UA_BROWSEDIRECTION_FORWARD;

    UA_BrowseResult br;
    UA_BrowseResult_init(&br);
    UA_UInt32 maxrefs = 0;
    Operation_Browse(server, session, &maxrefs, &bd, &br);
    if(br.statusCode != UA_STATUSCODE_GOOD)
        return br.statusCode;

    /* Call the constructor for every unconstructed child node */
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    for(size_t i = 0; i < br.referencesSize; ++i) {
        UA_ReferenceDescription *rd = &br.references[i];
        if(!UA_ExpandedNodeId_isLocal(&rd->nodeId))
            continue;
        const UA_Node *target = UA_NODESTORE_GET(server, &rd->nodeId.nodeId);
        if(!target)
            continue;
        if(target->head.constructed) {
            UA_NODESTORE_RELEASE(server, target);
            continue;
        }

        const UA_Node *targetType = NULL;
        if(target->head.nodeClass == UA_NODECLASS_VARIABLE ||
           target->head.nodeClass == UA_NODECLASS_OBJECT) {
            targetType = getNodeType(server, &target->head);
            if(!targetType) {
                UA_NODESTORE_RELEASE(server, target);
                retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
                break;
            }
        }

        UA_NODESTORE_RELEASE(server, target);
        retval = recursiveCallConstructors(server, session, &rd->nodeId.nodeId, targetType);

        if(targetType)
            UA_NODESTORE_RELEASE(server, targetType);
        if(retval != UA_STATUSCODE_GOOD)
            break;
    }

    UA_BrowseResult_clear(&br);

    /* If a child could not be constructed or the node is already constructed */
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Get the node context */
    const UA_Node *node = UA_NODESTORE_GET(server, nodeId);
    if(!node)
        return UA_STATUSCODE_BADNODEIDUNKNOWN;
    void *context = node->head.context;
    UA_NODESTORE_RELEASE(server, node);

    /* Call the global constructor */
    if(server->config.nodeLifecycle.constructor) {
        UA_UNLOCK(&server->serviceMutex);
        retval = server->config.nodeLifecycle.
            constructor(server, &session->sessionId,
                        session->context, nodeId, &context);
        UA_LOCK(&server->serviceMutex);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
    }

    /* Call the local (per-type) constructor */
    const UA_NodeTypeLifecycle *lifecycle = NULL;
    if(type && node->head.nodeClass == UA_NODECLASS_OBJECT)
        lifecycle = &type->objectTypeNode.lifecycle;
    else if(type && node->head.nodeClass == UA_NODECLASS_VARIABLE)
        lifecycle = &type->variableTypeNode.lifecycle;
    if(lifecycle && lifecycle->constructor) {
        UA_UNLOCK(&server->serviceMutex);
        retval = lifecycle->constructor(server, &session->sessionId,
                                        session->context, &type->head.nodeId,
                                        type->head.context, nodeId, &context);
        UA_LOCK(&server->serviceMutex);
        if(retval != UA_STATUSCODE_GOOD)
            goto global_destructor;
    }

    /* Set the context *and* mark the node as constructed */
    retval = UA_Server_editNode(server, &server->adminSession, nodeId,
                                (UA_EditNodeCallback)setConstructedNodeContext, context);
    if(retval != UA_STATUSCODE_GOOD)
        goto local_destructor;

    /* All good, return */
    return retval;

    /* Fail. Call the destructors. */
  local_destructor:
    if(lifecycle && lifecycle->destructor) {
        UA_UNLOCK(&server->serviceMutex);
        lifecycle->destructor(server, &session->sessionId, session->context,
                              &type->head.nodeId, type->head.context, nodeId, &context);
        UA_LOCK(&server->serviceMutex);
    }

  global_destructor:
    if(server->config.nodeLifecycle.destructor) {
        UA_UNLOCK(&server->serviceMutex);
        server->config.nodeLifecycle.destructor(server, &session->sessionId,
                                                session->context, nodeId, context);
        UA_LOCK(&server->serviceMutex);
    }
    return retval;
}

/* Add new ReferenceType to the subtypes bitfield */
static UA_StatusCode
addReferenceTypeSubtype(UA_Server *server, UA_Session *session,
                        UA_Node *node, void *context) {
    node->referenceTypeNode.subTypes =
        UA_ReferenceTypeSet_union(node->referenceTypeNode.subTypes,
                                  *(UA_ReferenceTypeSet*)context);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
setReferenceTypeSubtypes(UA_Server *server, const UA_ReferenceTypeNode *node) {
    /* Get the ReferenceTypes upwards in the hierarchy */
    size_t parentsSize = 0;
    UA_ExpandedNodeId *parents = NULL;
    UA_ReferenceTypeSet reftypes_subtype = UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASSUBTYPE);
    UA_StatusCode res =
        browseRecursive(server, 1, &node->head.nodeId, UA_BROWSEDIRECTION_INVERSE,
                        &reftypes_subtype, UA_NODECLASS_UNSPECIFIED,
                        false, &parentsSize, &parents);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Add the ReferenceTypeIndex of this node */
    const UA_ReferenceTypeSet *newRefSet = &node->subTypes;
    for(size_t i = 0; i < parentsSize; i++) {
        UA_Server_editNode(server, &server->adminSession, &parents[i].nodeId,
                           addReferenceTypeSubtype, (void*)(uintptr_t)newRefSet);
    }

    UA_Array_delete(parents, parentsSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
setVariableNodeDynamic(UA_Server *server, UA_Session *session,
                       UA_Node *node, const void *ctx) {
    if(node->head.nodeClass != UA_NODECLASS_VARIABLE)
        return UA_STATUSCODE_BADINTERNALERROR;
    ((UA_VariableNode*)node)->isDynamic = *(const UA_Boolean*)ctx;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
checkSetIsDynamicVariable(UA_Server *server, UA_Session *session,
                          const UA_NodeId *nodeId) {
    /* Get all hierarchical reference types */
    UA_ReferenceTypeSet reftypes_hierarchical;
    UA_ReferenceTypeSet_init(&reftypes_hierarchical);
    UA_NodeId hierarchicalRefs = UA_NODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES);
    UA_StatusCode res =
        referenceTypeIndices(server, &hierarchicalRefs, &reftypes_hierarchical, true);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Is the variable under the server object? */
    UA_NodeId serverNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER);
    if(isNodeInTree(server, nodeId, &serverNodeId, &reftypes_hierarchical))
        return UA_STATUSCODE_GOOD;

    /* Is the variable in the type hierarchy? */
    UA_NodeId typesNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_TYPESFOLDER);
    if(isNodeInTree(server, nodeId, &typesNodeId, &reftypes_hierarchical))
        return UA_STATUSCODE_GOOD;

    /* Is the variable a property of a method node (InputArguments /
     * OutputArguments)? */
    UA_BrowseDescription bd;
    UA_BrowseDescription_init(&bd);
    bd.nodeId = *nodeId;
    bd.browseDirection = UA_BROWSEDIRECTION_INVERSE;
    bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
    bd.includeSubtypes = false;
    bd.nodeClassMask = UA_NODECLASS_METHOD;
    UA_BrowseResult br;
    UA_BrowseResult_init(&br);
    UA_UInt32 maxrefs = 0;
    Operation_Browse(server, session, &maxrefs, &bd, &br);
    UA_Boolean hasParentMethod = (br.referencesSize > 0);
    UA_BrowseResult_clear(&br);
    if(hasParentMethod)
        return UA_STATUSCODE_GOOD;

    /* Set the variable to "dynamic" */
    UA_Boolean isDynamic = true;
    UA_Server_editNode(server, session, nodeId,
                       (UA_EditNodeCallback)setVariableNodeDynamic, &isDynamic);

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_setVariableNodeDynamic(UA_Server *server, const UA_NodeId nodeId,
                                 UA_Boolean isDynamic) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res =
        UA_Server_editNode(server, &server->adminSession, &nodeId,
                           (UA_EditNodeCallback)setVariableNodeDynamic, &isDynamic);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

/* Children, references, type-checking, constructors. */
UA_StatusCode
addNode_finish(UA_Server *server, UA_Session *session, const UA_NodeId *nodeId) {
    /* Get the node */
    const UA_Node *type = NULL;
    const UA_Node *node = UA_NODESTORE_GET(server, nodeId);
    if(!node)
        return UA_STATUSCODE_BADNODEIDUNKNOWN;

    /* Set the ReferenceTypesSet of subtypes in the ReferenceTypeNode */
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(node->head.nodeClass == UA_NODECLASS_REFERENCETYPE) {
        retval = setReferenceTypeSubtypes(server, &node->referenceTypeNode);
        if(retval != UA_STATUSCODE_GOOD)
            goto cleanup;
    }

    /* Check NodeClass for 'hasSubtype'. UA_NODECLASS_VARIABLE not allowed
     * to have subtype */
    if(node->head.nodeClass == UA_NODECLASS_VARIABLE) {
        for(size_t i = 0; i < node->head.referencesSize; i++) {
            if(node->head.references[i].referenceTypeIndex ==
               UA_REFERENCETYPEINDEX_HASSUBTYPE) {
                UA_LOG_NODEID_INFO(&node->head.nodeId,
                UA_LOG_INFO_SESSION(server->config.logging, session,
                                    "AddNode (%.*s): Variable not allowed "
                                    "to have HasSubType reference",
                                    (int)nodeIdStr.length, nodeIdStr.data));
                retval = UA_STATUSCODE_BADREFERENCENOTALLOWED;
                goto cleanup;
            }
        }
    }

    /* Set variables to dynamic (source and server timestamps are meaningful) if
     * they fulfill some conditions. (Do this before replacing the default value
     * in a VariableNode. So that the sourceTimestamp is set in the Write service.) */
    if(node->head.nodeClass == UA_NODECLASS_VARIABLE) {
        retval = checkSetIsDynamicVariable(server, session, nodeId);
        if(retval != UA_STATUSCODE_GOOD)
            goto cleanup;
    }

    /* Get the type node */
    if(node->head.nodeClass == UA_NODECLASS_VARIABLE ||
       node->head.nodeClass == UA_NODECLASS_VARIABLETYPE ||
       node->head.nodeClass == UA_NODECLASS_OBJECT) {
        type = getNodeType(server, &node->head);
        if(!type) {
            if(server->bootstrapNS0)
                goto constructor;
            logAddNode(server->config.logging, session, &node->head.nodeId,
                       "Node type not found");
            retval = UA_STATUSCODE_BADTYPEDEFINITIONINVALID;
            goto cleanup;
        }
    }

    /* Initialize and typecheck the variable */
    if(node->head.nodeClass == UA_NODECLASS_VARIABLE ||
       node->head.nodeClass == UA_NODECLASS_VARIABLETYPE) {
        /* Use attributes from the type. The value and value constraints are the
         * same for the variable and variabletype attribute structs. */
        retval = useVariableTypeAttributes(server, session,
                                           &node->variableNode,
                                           &type->variableTypeNode);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_NODEID_INFO(&node->head.nodeId,
            UA_LOG_INFO_SESSION(server->config.logging, session,
                                "AddNode (%.*s): Using attributes for from "
                                "the variable type failed with error code %s",
                                (int)nodeIdStr.length, nodeIdStr.data,
                                UA_StatusCode_name(retval)));
            goto cleanup;
        }

        /* Get a new pointer to the node. It might have been switched out */
#ifdef UA_ENABLE_IMMUTABLE_NODES
        UA_NODESTORE_RELEASE(server, node);
        node = UA_NODESTORE_GET(server, nodeId);
        if(!node || (node->head.nodeClass != UA_NODECLASS_VARIABLE &&
                     node->head.nodeClass != UA_NODECLASS_VARIABLETYPE)) {
            retval = UA_STATUSCODE_BADINTERNALERROR;
            goto cleanup;
        }
#endif

        /* Check if all attributes hold the constraints of the type now. The initial
         * attributes must type-check. The constructor might change the attributes
         * again. Then, the changes are type-checked by the normal write service. */
        retval = typeCheckVariableNode(server, session, &node->variableNode,
                                       &type->variableTypeNode);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_NODEID_INFO(&node->head.nodeId,
            UA_LOG_INFO_SESSION(server->config.logging, session,
                                "AddNode (%.*s): Type-checking "
                                "failed with error code %s", (int)nodeIdStr.length,
                                nodeIdStr.data, UA_StatusCode_name(retval)));
            goto cleanup;
        }
    }

    /* Add (mandatory) child nodes from the type definition */
    if(node->head.nodeClass == UA_NODECLASS_VARIABLE ||
       node->head.nodeClass == UA_NODECLASS_OBJECT) {
        retval = addTypeChildren(server, session, nodeId, &type->head.nodeId);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_NODEID_INFO(&node->head.nodeId,
            UA_LOG_INFO_SESSION(server->config.logging, session,
                                "AddNode (%.*s): Adding child nodes "
                                "failed with error code %s", (int)nodeIdStr.length,
                                nodeIdStr.data, UA_StatusCode_name(retval)));
            goto cleanup;
        }
    }

    /* Add (mandatory) child nodes from the HasInterface references */
    if(node->head.nodeClass == UA_NODECLASS_OBJECT) {
        retval = addInterfaceChildren(server, session, nodeId, &type->head.nodeId);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_NODEID_INFO(&node->head.nodeId,
            UA_LOG_INFO_SESSION(server->config.logging, session,
                                "AddNode (%.*s): Adding child nodes "
                                "interface failed with error code %s",
                                (int)nodeIdStr.length, nodeIdStr.data,
                                UA_StatusCode_name(retval)));
            goto cleanup;
        }
    }

    /* Call the constructor(s) */
 constructor:
    if(!node->head.constructed)
        retval = recursiveCallConstructors(server, session, nodeId, type);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_NODEID_INFO(&node->head.nodeId,
        UA_LOG_INFO_SESSION(server->config.logging, session,
                            "AddNode (%.*s): Calling the node constructor(s) "
                            "failed with status code %s", (int)nodeIdStr.length,
                            nodeIdStr.data, UA_StatusCode_name(retval)));
    }

 cleanup:
    if(type)
        UA_NODESTORE_RELEASE(server, type);
    if(node)
        UA_NODESTORE_RELEASE(server, node);
    if(retval != UA_STATUSCODE_GOOD)
        deleteNode(server, *nodeId, true);
    return retval;
}

static void
Operation_addNode(UA_Server *server, UA_Session *session, void *nodeContext,
                  const UA_AddNodesItem *item, UA_AddNodesResult *result) {
    result->statusCode =
        Operation_addNode_begin(server, session, nodeContext,
                                item, &item->parentNodeId.nodeId,
                                &item->referenceTypeId, &result->addedNodeId);
    if(result->statusCode != UA_STATUSCODE_GOOD)
        return;

    /* AddNodes_finish */
    result->statusCode = addNode_finish(server, session, &result->addedNodeId);

    /* If finishing failed, the node was deleted */
    if(result->statusCode != UA_STATUSCODE_GOOD)
        UA_NodeId_clear(&result->addedNodeId);
}

void
Service_AddNodes(UA_Server *server, UA_Session *session,
                 const UA_AddNodesRequest *request,
                 UA_AddNodesResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session, "Processing AddNodesRequest");
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    if(server->config.maxNodesPerNodeManagement != 0 &&
       request->nodesToAddSize > server->config.maxNodesPerNodeManagement) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return;
    }

    response->responseHeader.serviceResult =
        UA_Server_processServiceOperations(server, session,
                                           (UA_ServiceOperation)Operation_addNode, NULL,
                                           &request->nodesToAddSize,
                                           &UA_TYPES[UA_TYPES_ADDNODESITEM],
                                           &response->resultsSize,
                                           &UA_TYPES[UA_TYPES_ADDNODESRESULT]);
}

UA_StatusCode
addNode(UA_Server *server, const UA_NodeClass nodeClass, const UA_NodeId requestedNewNodeId,
        const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
        const UA_QualifiedName browseName, const UA_NodeId typeDefinition,
        const void *attr, const UA_DataType *attributeType,
        void *nodeContext, UA_NodeId *outNewNodeId) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Create the AddNodesItem */
    UA_AddNodesItem item;
    UA_AddNodesItem_init(&item);
    item.nodeClass = nodeClass;
    item.requestedNewNodeId.nodeId = requestedNewNodeId;
    item.browseName = browseName;
    item.parentNodeId.nodeId = parentNodeId;
    item.referenceTypeId = referenceTypeId;
    item.typeDefinition.nodeId = typeDefinition;
    UA_ExtensionObject_setValueNoDelete(&item.nodeAttributes,
                                        (void*)(uintptr_t)attr, attributeType);

    /* Call the normal addnodes service */
    UA_AddNodesResult result;
    UA_AddNodesResult_init(&result);
    Operation_addNode(server, &server->adminSession, nodeContext, &item, &result);
    if(outNewNodeId)
        *outNewNodeId = result.addedNodeId;
    else
        UA_NodeId_clear(&result.addedNodeId);
    return result.statusCode;
}

UA_StatusCode
__UA_Server_addNode(UA_Server *server, const UA_NodeClass nodeClass,
                    const UA_NodeId *requestedNewNodeId,
                    const UA_NodeId *parentNodeId,
                    const UA_NodeId *referenceTypeId,
                    const UA_QualifiedName browseName,
                    const UA_NodeId *typeDefinition,
                    const UA_NodeAttributes *attr,
                    const UA_DataType *attributeType,
                    void *nodeContext, UA_NodeId *outNewNodeId) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode reval =
        addNode(server, nodeClass, *requestedNewNodeId, *parentNodeId,
                *referenceTypeId, browseName, *typeDefinition, attr,
                attributeType, nodeContext, outNewNodeId);
    UA_UNLOCK(&server->serviceMutex);
    return reval;
}

UA_StatusCode
addNode_begin(UA_Server *server, const UA_NodeClass nodeClass,
              const UA_NodeId requestedNewNodeId, const UA_NodeId parentNodeId,
              const UA_NodeId referenceTypeId, const UA_QualifiedName browseName,
              const UA_NodeId typeDefinition, const void *attr,
              const UA_DataType *attributeType, void *nodeContext,
              UA_NodeId *outNewNodeId) {
    UA_AddNodesItem item;
    UA_AddNodesItem_init(&item);
    item.nodeClass = nodeClass;
    item.requestedNewNodeId.nodeId = requestedNewNodeId;
    item.browseName = browseName;
    item.typeDefinition.nodeId = typeDefinition;
    UA_ExtensionObject_setValueNoDelete(&item.nodeAttributes,
                                        (void*)(uintptr_t)attr, attributeType);
    return Operation_addNode_begin(server, &server->adminSession, nodeContext, &item,
                                   &parentNodeId, &referenceTypeId, outNewNodeId);
}

UA_StatusCode
UA_Server_addNode_begin(UA_Server *server, const UA_NodeClass nodeClass,
                        const UA_NodeId requestedNewNodeId, const UA_NodeId parentNodeId,
                        const UA_NodeId referenceTypeId, const UA_QualifiedName browseName,
                        const UA_NodeId typeDefinition, const void *attr,
                        const UA_DataType *attributeType, void *nodeContext,
                        UA_NodeId *outNewNodeId) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res =
        addNode_begin(server, nodeClass, requestedNewNodeId, parentNodeId,
                      referenceTypeId, browseName, typeDefinition, attr,
                      attributeType, nodeContext, outNewNodeId);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_Server_addNode_finish(UA_Server *server, const UA_NodeId nodeId) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode retval = addNode_finish(server, &server->adminSession, &nodeId);
    UA_UNLOCK(&server->serviceMutex);
    return retval;
}

/****************/
/* Delete Nodes */
/****************/

static void
Operation_deleteReference(UA_Server *server, UA_Session *session, void *context,
                          const UA_DeleteReferencesItem *item, UA_StatusCode *retval);

struct RemoveIncomingContext {
    UA_Server *server;
    UA_Session *session;
    UA_DeleteReferencesItem *item;
};

static void *
removeIncomingReferencesCallback(void *context, UA_ReferenceTarget *t) {
    struct RemoveIncomingContext *ctx = (struct RemoveIncomingContext *)context;
    if(!UA_NodePointer_isLocal(t->targetId))
        return NULL;
    UA_StatusCode dummy;
    ctx->item->sourceNodeId = UA_NodePointer_toNodeId(t->targetId);
    Operation_deleteReference(ctx->server, ctx->session, NULL, ctx->item, &dummy);
    return NULL;
}

/* Remove references to this node (in the other nodes) */
static void
removeIncomingReferences(UA_Server *server, UA_Session *session,
                         const UA_NodeHead *head) {
    UA_DeleteReferencesItem item;
    UA_DeleteReferencesItem_init(&item);
    item.targetNodeId.nodeId = head->nodeId;
    item.deleteBidirectional = false;

    struct RemoveIncomingContext ctx;
    ctx.server = server;
    ctx.session = session;
    ctx.item = &item;

    for(size_t i = 0; i < head->referencesSize; ++i) {
        UA_NodeReferenceKind *rk = &head->references[i];
        item.isForward = rk->isInverse;
        item.referenceTypeId =
            *UA_NODESTORE_GETREFERENCETYPEID(server, rk->referenceTypeIndex);
        UA_NodeReferenceKind_iterate(rk, removeIncomingReferencesCallback, &ctx);
    }
}

static void *
checkTargetInRefTree(void *context, UA_ReferenceTarget *t) {
    RefTree *refTree = (RefTree*)context;
    if(!UA_NodePointer_isLocal(t->targetId))
        return NULL;
    UA_NodeId tmpId = UA_NodePointer_toNodeId(t->targetId);
    if(!RefTree_containsNodeId(refTree, &tmpId))
        return (void*)0x1;
    return NULL;
}

/* A node is auto-deleted if all its hierarchical parents are being deleted */
static UA_Boolean
hasParentRef(const UA_NodeHead *head, const UA_ReferenceTypeSet *refSet,
             RefTree *refTree) {
    for(size_t i = 0; i < head->referencesSize; i++) {
        UA_NodeReferenceKind *rk = &head->references[i];
        if(!rk->isInverse)
            continue;
        if(!UA_ReferenceTypeSet_contains(refSet, rk->referenceTypeIndex))
            continue;
        if(UA_NodeReferenceKind_iterate(rk, checkTargetInRefTree, refTree) != NULL)
            return true;
    }
    return false;
}

static void
deconstructNodeSet(UA_Server *server, UA_Session *session,
                   UA_ReferenceTypeSet *hierarchRefsSet, RefTree *refTree) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Deconstruct the nodes based on the RefTree entries, parent nodes first */
    for(size_t i = 0; i < refTree->size; i++) {
        const UA_Node *member = UA_NODESTORE_GET(server, &refTree->targets[i].nodeId);
        if(!member)
            continue;

        /* Call the type-level destructor */
        void *context = member->head.context; /* No longer needed after this function */
        if(member->head.nodeClass == UA_NODECLASS_OBJECT ||
           member->head.nodeClass == UA_NODECLASS_VARIABLE) {
            const UA_Node *type = getNodeType(server, &member->head);
            if(type) {
               /* Get the lifecycle */
               const UA_NodeTypeLifecycle *lifecycle;
               if(member->head.nodeClass == UA_NODECLASS_OBJECT)
                  lifecycle = &type->objectTypeNode.lifecycle;
               else
                  lifecycle = &type->variableTypeNode.lifecycle;

               /* Call the destructor */
               if(lifecycle->destructor) {
                  UA_UNLOCK(&server->serviceMutex);
                  lifecycle->destructor(server,
                                        &session->sessionId, session->context,
                                        &type->head.nodeId, type->head.context,
                                        &member->head.nodeId, &context);
                  UA_LOCK(&server->serviceMutex);
               }

               /* Release the type node */
               UA_NODESTORE_RELEASE(server, type);
            }
        }

        /* Call the global destructor */
        if(server->config.nodeLifecycle.destructor) {
            UA_UNLOCK(&server->serviceMutex);
            server->config.nodeLifecycle.destructor(server, &session->sessionId,
                                                    session->context,
                                                    &member->head.nodeId, context);
            UA_LOCK(&server->serviceMutex);
        }

        /* Release the node. Don't access the node context from here on. */
        UA_NODESTORE_RELEASE(server, member);

        /* Set the constructed flag to false */
        UA_Server_editNode(server, &server->adminSession, &refTree->targets[i].nodeId,
                           (UA_EditNodeCallback)setDeconstructedNode, NULL);
    }
}

struct DeleteChildrenContext {
    UA_Server *server;
    const UA_ReferenceTypeSet *hierarchRefsSet;
    RefTree *refTree;
    UA_StatusCode res;
};

static void *
deleteChildrenCallback(void *context, UA_ReferenceTarget *t) {
    struct DeleteChildrenContext *ctx = (struct DeleteChildrenContext*)context;

    /* Get the child */
    const UA_Node *child = UA_NODESTORE_GETFROMREF(ctx->server, t->targetId);
    if(!child)
        return NULL;

    /* Only delete child nodes that have no other parent */
    if(!hasParentRef(&child->head, ctx->hierarchRefsSet, ctx->refTree))
        ctx->res = RefTree_addNodeId(ctx->refTree, &child->head.nodeId, NULL);

    UA_NODESTORE_RELEASE(ctx->server, child);
    return (ctx->res == UA_STATUSCODE_GOOD) ? NULL : (void*)0x01;
}

/* The processNodeLayer function searches all children's of the head node and
 * adds the children node to the RefTree if all incoming references sources are
 * contained in the RefTree (No external references to this node --> node can be
 * deleted) */
static UA_StatusCode
autoDeleteChildren(UA_Server *server, UA_Session *session, RefTree *refTree,
                   const UA_ReferenceTypeSet *hierarchRefsSet, const UA_NodeHead *head){
    struct DeleteChildrenContext ctx;
    ctx.server = server;
    ctx.hierarchRefsSet = hierarchRefsSet;
    ctx.refTree = refTree;
    ctx.res = UA_STATUSCODE_GOOD;

    for(size_t i = 0; i < head->referencesSize; ++i) {
        /* Check if the ReferenceType is hierarchical */
        UA_NodeReferenceKind *rk = &head->references[i];
        if(!UA_ReferenceTypeSet_contains(hierarchRefsSet, rk->referenceTypeIndex))
            continue;

        /* Check if the references are forward (to a child) */
        if(rk->isInverse)
            continue;

        /* Loop over the references */
        UA_NodeReferenceKind_iterate(rk, deleteChildrenCallback, &ctx);
        if(ctx.res != UA_STATUSCODE_GOOD)
            return ctx.res;
    }
    return UA_STATUSCODE_GOOD;
}

/* Build up an ordered set (tree) of all nodes that can be deleted. Step through
 * the ordered set in order to avoid recursion. */
static UA_StatusCode
buildDeleteNodeSet(UA_Server *server, UA_Session *session,
                   const UA_ReferenceTypeSet *hierarchRefsSet,
                   const UA_NodeId *initial, UA_Boolean removeTargetRefs,
                   RefTree *refTree) {
    /* Add the initial node to delete */
    UA_StatusCode res = RefTree_addNodeId(refTree, initial, NULL);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Find out which hierarchical children should also be deleted. We know
     * there are no "external" ExpandedNodeId in the RefTree. */
    size_t pos = 0;
    while(pos < refTree->size) {
        const UA_Node *member = UA_NODESTORE_GET(server, &refTree->targets[pos].nodeId);
        pos++;
        if(!member)
            continue;
        res |= autoDeleteChildren(server, session, refTree, hierarchRefsSet, &member->head);
        UA_NODESTORE_RELEASE(server, member);
    }
    return res;
}

static void
deleteNodeSet(UA_Server *server, UA_Session *session,
              const UA_ReferenceTypeSet *hierarchRefsSet,
              UA_Boolean removeTargetRefs, RefTree *refTree) {
    /* Delete the nodes based on the RefTree entries */
    for(size_t i = refTree->size; i > 0; --i) {
        const UA_Node *member = UA_NODESTORE_GET(server, &refTree->targets[i-1].nodeId);
        if(!member)
            continue;
        UA_NODESTORE_RELEASE(server, member);
        if(removeTargetRefs)
            removeIncomingReferences(server, session, &member->head);
        UA_NODESTORE_REMOVE(server, &member->head.nodeId);
    }
}

static void
deleteNodeOperation(UA_Server *server, UA_Session *session, void *context,
                    const UA_DeleteNodesItem *item, UA_StatusCode *result) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Do not check access for server */
    if(session != &server->adminSession && server->config.accessControl.allowDeleteNode) {
        UA_UNLOCK(&server->serviceMutex);
        if(!server->config.accessControl.
           allowDeleteNode(server, &server->config.accessControl,
                           &session->sessionId, session->context, item)) {
            UA_LOCK(&server->serviceMutex);
            *result = UA_STATUSCODE_BADUSERACCESSDENIED;
            return;
        }
        UA_LOCK(&server->serviceMutex);
    }

    const UA_Node *node = UA_NODESTORE_GET(server, &item->nodeId);
    if(!node) {
        *result = UA_STATUSCODE_BADNODEIDUNKNOWN;
        return;
    }

    if(UA_Node_hasSubTypeOrInstances(&node->head)) {
        UA_LOG_NODEID_INFO(&node->head.nodeId,
        UA_LOG_INFO_SESSION(server->config.logging, session, "DeleteNode (%.*s): "
                            "Cannot delete a type node with active instances or "
                            "subtypes", (int)nodeIdStr.length, nodeIdStr.data));
        UA_NODESTORE_RELEASE(server, node);
        *result = UA_STATUSCODE_BADINTERNALERROR;
        return;
    }

    /* TODO: Check if the information model consistency is violated */
    /* TODO: Check if the node is a mandatory child of a parent */

    /* Relase the node. Don't access the pointer after this! */
    UA_NODESTORE_RELEASE(server, node);

    /* A node can be referenced with hierarchical references from several
     * parents in the information model. (But not in a circular way.) The
     * hierarchical references are checked to see if a node can be deleted.
     * Getting the type hierarchy can fail in case of low RAM. In that case the
     * nodes are always deleted. */
    UA_ReferenceTypeSet hierarchRefsSet;
    UA_NodeId hr = UA_NODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES);
    *result = referenceTypeIndices(server, &hr, &hierarchRefsSet, true);
    if(*result != UA_STATUSCODE_GOOD)
        return;

    /* The list of childs is needed for the deconstructing and deleting phase.
     * Within the processNodeLayer we generate a RefTree based set of childs
     * which can be deleted beside the parent node. */
    RefTree refTree;
    *result = RefTree_init(&refTree);
    if(*result != UA_STATUSCODE_GOOD)
        return;
    *result = buildDeleteNodeSet(server, session, &hierarchRefsSet, &item->nodeId,
                                 item->deleteTargetReferences, &refTree);
    if(*result != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_SESSION(server->config.logging, session,
                               "DeleteNode: Incomplete lookup of nodes. "
                               "Still deleting what we have.");
        /* Continue, so the RefTree is cleaned up. Return the error message
         * anyway. */
    }

    /* Deconstruct, then delete, then clean up the set */
    deconstructNodeSet(server, session, &hierarchRefsSet, &refTree);
    deleteNodeSet(server, session, &hierarchRefsSet,
                  item->deleteTargetReferences, &refTree);
    RefTree_clear(&refTree);
}

void
Service_DeleteNodes(UA_Server *server, UA_Session *session,
                    const UA_DeleteNodesRequest *request,
                    UA_DeleteNodesResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing DeleteNodesRequest");
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    if(server->config.maxNodesPerNodeManagement != 0 &&
       request->nodesToDeleteSize > server->config.maxNodesPerNodeManagement) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return;
    }

    response->responseHeader.serviceResult =
        UA_Server_processServiceOperations(server, session,
                                           (UA_ServiceOperation)deleteNodeOperation,
                                           NULL, &request->nodesToDeleteSize,
                                           &UA_TYPES[UA_TYPES_DELETENODESITEM],
                                           &response->resultsSize,
                                           &UA_TYPES[UA_TYPES_STATUSCODE]);
}

UA_StatusCode
UA_Server_deleteNode(UA_Server *server, const UA_NodeId nodeId,
                     UA_Boolean deleteReferences) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode retval = deleteNode(server, nodeId, deleteReferences);
    UA_UNLOCK(&server->serviceMutex);
    return retval;
}

UA_StatusCode
deleteNode(UA_Server *server, const UA_NodeId nodeId,
                     UA_Boolean deleteReferences) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    UA_DeleteNodesItem item;
    item.deleteTargetReferences = deleteReferences;
    item.nodeId = nodeId;
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    deleteNodeOperation(server, &server->adminSession, NULL, &item, &retval);
    return retval;
}

/******************/
/* Add References */
/******************/

struct AddNodeInfo {
    UA_Byte refTypeIndex;
    UA_Boolean isForward;
    const UA_ExpandedNodeId *targetNodeId;
    UA_UInt32 targetBrowseNameHash;
};

static UA_StatusCode
addOneWayReference(UA_Server *server, UA_Session *session, UA_Node *node,
                   const struct AddNodeInfo *info) {
    return UA_Node_addReference(node, info->refTypeIndex, info->isForward,
                                info->targetNodeId, info->targetBrowseNameHash);
}

static UA_StatusCode
deleteOneWayReference(UA_Server *server, UA_Session *session, UA_Node *node,
                      const UA_DeleteReferencesItem *item) {
    const UA_Node *refType = UA_NODESTORE_GET(server, &item->referenceTypeId);
    if(!refType)
        return UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
    if(refType->head.nodeClass != UA_NODECLASS_REFERENCETYPE) {
        UA_NODESTORE_RELEASE(server, refType);
        return UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
    }
    UA_Byte refTypeIndex = refType->referenceTypeNode.referenceTypeIndex;
    UA_NODESTORE_RELEASE(server, refType);
    return UA_Node_deleteReference(node, refTypeIndex, item->isForward, &item->targetNodeId);
}

static void
Operation_addReference(UA_Server *server, UA_Session *session, void *context,
                       const UA_AddReferencesItem *item, UA_StatusCode *retval) {
    (void)context;
    UA_assert(session);
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Check access rights */
    if(session != &server->adminSession && server->config.accessControl.allowAddReference) {
        UA_UNLOCK(&server->serviceMutex);
        if (!server->config.accessControl.
                allowAddReference(server, &server->config.accessControl,
                                  &session->sessionId, session->context, item)) {
            UA_LOCK(&server->serviceMutex);
            *retval = UA_STATUSCODE_BADUSERACCESSDENIED;
            return;
        }
        UA_LOCK(&server->serviceMutex);
    }

    /* TODO: Currently no expandednodeids are allowed */
    if(item->targetServerUri.length > 0) {
        *retval = UA_STATUSCODE_BADNOTIMPLEMENTED;
        return;
    }

    /* Check the ReferenceType and get the index */
    const UA_Node *refType = UA_NODESTORE_GET(server, &item->referenceTypeId);
    if(!refType) {
        UA_LOG_NODEID_DEBUG(&item->referenceTypeId,
            UA_LOG_DEBUG_SESSION(server->config.logging, session,
                                 "Cannot add reference - ReferenceType %.*s unknown",
                                 (int)nodeIdStr.length, nodeIdStr.data));
        *retval = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
        return;
    }
    if(refType->head.nodeClass != UA_NODECLASS_REFERENCETYPE) {
        UA_LOG_NODEID_DEBUG(&item->referenceTypeId,
            UA_LOG_DEBUG_SESSION(server->config.logging, session,
                                 "Cannot add reference - ReferenceType %.*s with wrong NodeClass",
                                 (int)nodeIdStr.length, nodeIdStr.data));
        UA_NODESTORE_RELEASE(server, refType);
        *retval = UA_STATUSCODE_BADREFERENCETYPEIDINVALID;
        return;
    }
    UA_Byte refTypeIndex = refType->referenceTypeNode.referenceTypeIndex;
    UA_NODESTORE_RELEASE(server, refType);

    /* Get the source and target node BrowseName hash */
    const UA_Node *targetNode = UA_NODESTORE_GET(server, &item->targetNodeId.nodeId);
    if(!targetNode) {
        UA_LOG_NODEID_DEBUG(&item->targetNodeId.nodeId,
            UA_LOG_DEBUG_SESSION(server->config.logging, session,
                                 "Cannot add reference - target %.*s does not exist",
                                 (int)nodeIdStr.length, nodeIdStr.data));
        *retval = UA_STATUSCODE_BADTARGETNODEIDINVALID;
        return;
    }
    UA_UInt32 targetNameHash = UA_QualifiedName_hash(&targetNode->head.browseName);
    UA_NODESTORE_RELEASE(server, targetNode);

    const UA_Node *sourceNode = UA_NODESTORE_GET(server, &item->sourceNodeId);
    if(!sourceNode) {
        *retval = UA_STATUSCODE_BADSOURCENODEIDINVALID;
        return;
    }
    UA_UInt32 sourceNameHash = UA_QualifiedName_hash(&sourceNode->head.browseName);
    UA_NODESTORE_RELEASE(server, sourceNode);

    /* Compute the BrowseName hash and release the target */
    struct AddNodeInfo info;
    info.refTypeIndex = refTypeIndex;
    info.targetNodeId = &item->targetNodeId;
    info.isForward = item->isForward;
    info.targetBrowseNameHash = targetNameHash;

    /* Add the first direction */
    *retval = UA_Server_editNode(server, session, &item->sourceNodeId,
                                 (UA_EditNodeCallback)addOneWayReference, &info);
    UA_Boolean firstExisted = false;
    if(*retval == UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED) {
        *retval = UA_STATUSCODE_GOOD;
        firstExisted = true;
    }
    if(*retval != UA_STATUSCODE_GOOD)
        return;

    /* Add the second direction */
    UA_ExpandedNodeId target2;
    UA_ExpandedNodeId_init(&target2);
    target2.nodeId = item->sourceNodeId;
    info.targetNodeId = &target2;
    info.isForward = !info.isForward;
    info.targetBrowseNameHash = sourceNameHash;
    *retval = UA_Server_editNode(server, session, &item->targetNodeId.nodeId,
                                 (UA_EditNodeCallback)addOneWayReference, &info);

    /* Second direction existed already */
    if(*retval == UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED) {
        /* Calculate common duplicate reference not allowed result and set bad
         * result if BOTH directions already existed */
        if(UA_NodeId_equal(&item->sourceNodeId, &item->targetNodeId.nodeId)) {
            *retval = UA_STATUSCODE_GOOD;
            UA_LOG_INFO_SESSION(server->config.logging, session, "The source node and the target node are identical. The check for duplicate references is skipped.");
        }
        else if(firstExisted) {
            *retval = UA_STATUSCODE_BADDUPLICATEREFERENCENOTALLOWED;
            return;
        }
        *retval = UA_STATUSCODE_GOOD;
    }

    /* Remove first direction if the second direction failed */
    if(*retval != UA_STATUSCODE_GOOD && !firstExisted) {
        UA_DeleteReferencesItem deleteItem;
        deleteItem.sourceNodeId = item->sourceNodeId;
        deleteItem.referenceTypeId = item->referenceTypeId;
        deleteItem.isForward = item->isForward;
        deleteItem.targetNodeId = item->targetNodeId;
        deleteItem.deleteBidirectional = false;
        /* Ignore status code */
        UA_Server_editNode(server, session, &item->sourceNodeId,
                           (UA_EditNodeCallback)deleteOneWayReference, &deleteItem);
    }
}

void
Service_AddReferences(UA_Server *server, UA_Session *session,
                      const UA_AddReferencesRequest *request,
                      UA_AddReferencesResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing AddReferencesRequest");
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    UA_assert(session);

    if(server->config.maxNodesPerNodeManagement != 0 &&
       request->referencesToAddSize > server->config.maxNodesPerNodeManagement) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return;
    }

    response->responseHeader.serviceResult =
        UA_Server_processServiceOperations(server, session,
                                           (UA_ServiceOperation)Operation_addReference,
                                           NULL, &request->referencesToAddSize,
                                           &UA_TYPES[UA_TYPES_ADDREFERENCESITEM],
                                           &response->resultsSize,
                                           &UA_TYPES[UA_TYPES_STATUSCODE]);
}

UA_StatusCode
UA_Server_addReference(UA_Server *server, const UA_NodeId sourceId,
                       const UA_NodeId refTypeId,
                       const UA_ExpandedNodeId targetId,
                       UA_Boolean isForward) {
    UA_AddReferencesItem item;
    UA_AddReferencesItem_init(&item);
    item.sourceNodeId = sourceId;
    item.referenceTypeId = refTypeId;
    item.isForward = isForward;
    item.targetNodeId = targetId;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    UA_LOCK(&server->serviceMutex);
    Operation_addReference(server, &server->adminSession, NULL, &item, &retval);
    UA_UNLOCK(&server->serviceMutex);
    return retval;
}

/*********************/
/* Delete References */
/*********************/

static void
Operation_deleteReference(UA_Server *server, UA_Session *session, void *context,
                          const UA_DeleteReferencesItem *item, UA_StatusCode *retval) {
    /* Do not check access for server */
    if(session != &server->adminSession &&
       server->config.accessControl.allowDeleteReference) {
        UA_LOCK_ASSERT(&server->serviceMutex, 1);
        UA_UNLOCK(&server->serviceMutex);
        if (!server->config.accessControl.
                allowDeleteReference(server, &server->config.accessControl,
                                     &session->sessionId, session->context, item)){
            UA_LOCK(&server->serviceMutex);
            *retval = UA_STATUSCODE_BADUSERACCESSDENIED;
            return;
        }
        UA_LOCK(&server->serviceMutex);
    }

    // TODO: Check consistency constraints, remove the references.
    *retval = UA_Server_editNode(server, session, &item->sourceNodeId,
                                 (UA_EditNodeCallback)deleteOneWayReference,
                                 /* cast away const qualifier because callback
                                  * uses it anyway */
                                 (UA_DeleteReferencesItem *)(uintptr_t)item);
    if(*retval != UA_STATUSCODE_GOOD)
        return;

    if(!item->deleteBidirectional || item->targetNodeId.serverIndex != 0)
        return;

    UA_DeleteReferencesItem secondItem;
    UA_DeleteReferencesItem_init(&secondItem);
    secondItem.isForward = !item->isForward;
    secondItem.sourceNodeId = item->targetNodeId.nodeId;
    secondItem.targetNodeId.nodeId = item->sourceNodeId;
    secondItem.referenceTypeId = item->referenceTypeId;
    *retval = UA_Server_editNode(server, session, &secondItem.sourceNodeId,
                                 (UA_EditNodeCallback)deleteOneWayReference,
                                 &secondItem);
}

void
Service_DeleteReferences(UA_Server *server, UA_Session *session,
                         const UA_DeleteReferencesRequest *request,
                         UA_DeleteReferencesResponse *response) {
    UA_LOG_DEBUG_SESSION(server->config.logging, session,
                         "Processing DeleteReferencesRequest");
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    if(server->config.maxNodesPerNodeManagement != 0 &&
       request->referencesToDeleteSize > server->config.maxNodesPerNodeManagement) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYOPERATIONS;
        return;
    }

    response->responseHeader.serviceResult =
        UA_Server_processServiceOperations(server, session,
                                           (UA_ServiceOperation)Operation_deleteReference,
                                           NULL, &request->referencesToDeleteSize,
                                           &UA_TYPES[UA_TYPES_DELETEREFERENCESITEM],
                                           &response->resultsSize,
                                           &UA_TYPES[UA_TYPES_STATUSCODE]);
}

UA_StatusCode
deleteReference(UA_Server *server, const UA_NodeId sourceNodeId,
                const UA_NodeId referenceTypeId, UA_Boolean isForward,
                const UA_ExpandedNodeId targetNodeId,
                UA_Boolean deleteBidirectional) {
    UA_DeleteReferencesItem item;
    item.sourceNodeId = sourceNodeId;
    item.referenceTypeId = referenceTypeId;
    item.isForward = isForward;
    item.targetNodeId = targetNodeId;
    item.deleteBidirectional = deleteBidirectional;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    Operation_deleteReference(server, &server->adminSession, NULL, &item, &retval);
    return retval;
}

UA_StatusCode
UA_Server_deleteReference(UA_Server *server, const UA_NodeId sourceNodeId,
                          const UA_NodeId referenceTypeId, UA_Boolean isForward,
                          const UA_ExpandedNodeId targetNodeId,
                          UA_Boolean deleteBidirectional) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = deleteReference(server, sourceNodeId, referenceTypeId,
                                        isForward, targetNodeId, deleteBidirectional);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

/**********************/
/* Set Value Callback */
/**********************/

static UA_StatusCode
setValueCallback(UA_Server *server, UA_Session *session,
                 UA_VariableNode *node, const UA_ValueCallback *callback) {
    if(node->head.nodeClass != UA_NODECLASS_VARIABLE)
        return UA_STATUSCODE_BADNODECLASSINVALID;
    node->value.data.callback = *callback;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
setVariableNode_valueCallback(UA_Server *server, const UA_NodeId nodeId,
                              const UA_ValueCallback callback) {
    return UA_Server_editNode(server, &server->adminSession, &nodeId,
                              (UA_EditNodeCallback)setValueCallback,
                              /* cast away const because
                               * callback uses const anyway */
                              (UA_ValueCallback *)(uintptr_t) &callback);
}

UA_StatusCode
UA_Server_setVariableNode_valueCallback(UA_Server *server,
                                        const UA_NodeId nodeId,
                                        const UA_ValueCallback callback) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode retval = UA_Server_editNode(server, &server->adminSession, &nodeId,
                                              (UA_EditNodeCallback)setValueCallback,
                                              /* cast away const because
                                               * callback uses const anyway */
                                              (UA_ValueCallback *)(uintptr_t) &callback);
    UA_UNLOCK(&server->serviceMutex);
    return retval;
}

/***************************************************/
/* Special Handling of Variables with Data Sources */
/***************************************************/

UA_StatusCode
UA_Server_addDataSourceVariableNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
                                    const UA_NodeId parentNodeId,
                                    const UA_NodeId referenceTypeId,
                                    const UA_QualifiedName browseName,
                                    const UA_NodeId typeDefinition,
                                    const UA_VariableAttributes attr,
                                    const UA_DataSource dataSource,
                                    void *nodeContext, UA_NodeId *outNewNodeId) {
    UA_AddNodesItem item;
    UA_AddNodesItem_init(&item);
    item.nodeClass = UA_NODECLASS_VARIABLE;
    item.requestedNewNodeId.nodeId = requestedNewNodeId;
    item.browseName = browseName;
    UA_ExpandedNodeId typeDefinitionId;
    UA_ExpandedNodeId_init(&typeDefinitionId);
    typeDefinitionId.nodeId = typeDefinition;
    item.typeDefinition = typeDefinitionId;
    UA_ExtensionObject_setValueNoDelete(&item.nodeAttributes, (void*)(uintptr_t)&attr,
                                        &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES]);
    UA_NodeId newNodeId;
    if(!outNewNodeId) {
        newNodeId = UA_NODEID_NULL;
        outNewNodeId = &newNodeId;
    }

    UA_LOCK(&server->serviceMutex);
    /* Create the node and add it to the nodestore */
    UA_StatusCode retval = addNode_raw(server, &server->adminSession, nodeContext,
                                       &item, outNewNodeId);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Set the data source */
    retval = setVariableNode_dataSource(server, *outNewNodeId, dataSource);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Typecheck and add references to parent and type definition */
    retval = addNode_addRefs(server, &server->adminSession, outNewNodeId, &parentNodeId,
                             &referenceTypeId, &typeDefinition);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Call the constructors */
    retval = addNode_finish(server, &server->adminSession, outNewNodeId);

 cleanup:
    UA_UNLOCK(&server->serviceMutex);
    if(outNewNodeId == &newNodeId)
        UA_NodeId_clear(&newNodeId);

    return retval;
}

static UA_StatusCode
setDataSource(UA_Server *server, UA_Session *session,
              UA_VariableNode *node, const UA_DataSource *dataSource) {
    if(node->head.nodeClass != UA_NODECLASS_VARIABLE)
        return UA_STATUSCODE_BADNODECLASSINVALID;
    if(node->valueSource == UA_VALUESOURCE_DATA)
        UA_DataValue_clear(&node->value.data.value);
    node->value.dataSource = *dataSource;
    node->valueSource = UA_VALUESOURCE_DATASOURCE;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
setVariableNode_dataSource(UA_Server *server, const UA_NodeId nodeId,
                           const UA_DataSource dataSource) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    return UA_Server_editNode(server, &server->adminSession, &nodeId,
                              (UA_EditNodeCallback)setDataSource,
                              /* casting away const because callback casts it back anyway */
                              (UA_DataSource *) (uintptr_t)&dataSource);
}

UA_StatusCode
UA_Server_setVariableNode_dataSource(UA_Server *server, const UA_NodeId nodeId,
                                     const UA_DataSource dataSource) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode retval = setVariableNode_dataSource(server, nodeId, dataSource);
    UA_UNLOCK(&server->serviceMutex);
    return retval;
}

/******************************/
/* Set External Value Source  */
/******************************/
static UA_StatusCode
setExternalValueSource(UA_Server *server, UA_Session *session,
                 UA_VariableNode *node, const UA_ValueBackend *externalValueSource) {
    if(node->head.nodeClass != UA_NODECLASS_VARIABLE)
        return UA_STATUSCODE_BADNODECLASSINVALID;
    node->valueBackend.backendType = UA_VALUEBACKENDTYPE_EXTERNAL;
    node->valueBackend.backend.external.value =
        externalValueSource->backend.external.value;
    node->valueBackend.backend.external.callback.notificationRead =
        externalValueSource->backend.external.callback.notificationRead;
    node->valueBackend.backend.external.callback.userWrite =
        externalValueSource->backend.external.callback.userWrite;
    return UA_STATUSCODE_GOOD;
}

/****************************/
/* Set Data Source Callback */
/****************************/
static UA_StatusCode
setDataSourceCallback(UA_Server *server, UA_Session *session,
                 UA_VariableNode *node, const UA_DataSource *dataSource) {
    if(node->head.nodeClass != UA_NODECLASS_VARIABLE)
        return UA_STATUSCODE_BADNODECLASSINVALID;
    node->valueBackend.backendType = UA_VALUEBACKENDTYPE_DATA_SOURCE_CALLBACK;
    node->valueBackend.backend.dataSource.read = dataSource->read;
    node->valueBackend.backend.dataSource.write = dataSource->write;
    return UA_STATUSCODE_GOOD;
}

/**********************/
/* Set Value Backend  */
/**********************/

UA_StatusCode
UA_Server_setVariableNode_valueBackend(UA_Server *server, const UA_NodeId nodeId,
                                       const UA_ValueBackend valueBackend){
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    UA_LOCK(&server->serviceMutex);
    switch(valueBackend.backendType){
        case UA_VALUEBACKENDTYPE_NONE:
            UA_UNLOCK(&server->serviceMutex);
            return UA_STATUSCODE_BADCONFIGURATIONERROR;
        case UA_VALUEBACKENDTYPE_DATA_SOURCE_CALLBACK:
            retval = UA_Server_editNode(server, &server->adminSession, &nodeId,
                                        (UA_EditNodeCallback) setDataSourceCallback,
                                        (UA_DataSource *)(uintptr_t) &valueBackend.backend.dataSource);
            break;
        case UA_VALUEBACKENDTYPE_INTERNAL:
            break;
        case UA_VALUEBACKENDTYPE_EXTERNAL:
            retval = UA_Server_editNode(server, &server->adminSession, &nodeId,
                                        (UA_EditNodeCallback) setExternalValueSource,
                /* cast away const because callback uses const anyway */
                                        (UA_ValueCallback *)(uintptr_t) &valueBackend);
            break;
    }


    // UA_StatusCode retval = UA_Server_editNode(server, &server->adminSession, &nodeId,
    // (UA_EditNodeCallback)setValueCallback,
    /* cast away const because callback uses const anyway */
    // (UA_ValueCallback *)(uintptr_t) &callback);


    UA_UNLOCK(&server->serviceMutex);
    return retval;
}


/************************************/
/* Special Handling of Method Nodes */
/************************************/

#ifdef UA_ENABLE_METHODCALLS

static const UA_NodeId hasproperty = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASPROPERTY}};
static const UA_NodeId propertytype = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_PROPERTYTYPE}};

static UA_StatusCode
UA_Server_addMethodNodeEx_finish(UA_Server *server, const UA_NodeId nodeId,
                                 UA_MethodCallback method,
                                 const size_t inputArgumentsSize,
                                 const UA_Argument *inputArguments,
                                 const UA_NodeId inputArgumentsRequestedNewNodeId,
                                 UA_NodeId *inputArgumentsOutNewNodeId,
                                 const size_t outputArgumentsSize,
                                 const UA_Argument *outputArguments,
                                 const UA_NodeId outputArgumentsRequestedNewNodeId,
                                 UA_NodeId *outputArgumentsOutNewNodeId) {
    /* Browse to see which argument nodes exist */
    UA_BrowseDescription bd;
    UA_BrowseDescription_init(&bd);
    bd.nodeId = nodeId;
    bd.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY);
    bd.includeSubtypes = false;
    bd.browseDirection = UA_BROWSEDIRECTION_FORWARD;
    bd.nodeClassMask = UA_NODECLASS_VARIABLE;
    bd.resultMask = UA_BROWSERESULTMASK_BROWSENAME;

    UA_BrowseResult br;
    UA_BrowseResult_init(&br);
    UA_UInt32 maxrefs = 0;
    Operation_Browse(server, &server->adminSession, &maxrefs, &bd, &br);

    UA_StatusCode retval = br.statusCode;
    if(retval != UA_STATUSCODE_GOOD) {
        deleteNode(server, nodeId, true);
        UA_BrowseResult_clear(&br);
        return retval;
    }

    /* Filter out the argument nodes */
    UA_NodeId inputArgsId = UA_NODEID_NULL;
    UA_NodeId outputArgsId = UA_NODEID_NULL;
    const UA_QualifiedName inputArgsName = UA_QUALIFIEDNAME(0, "InputArguments");
    const UA_QualifiedName outputArgsName = UA_QUALIFIEDNAME(0, "OutputArguments");
    for(size_t i = 0; i < br.referencesSize; i++) {
        UA_ReferenceDescription *rd = &br.references[i];
        if(rd->browseName.namespaceIndex == 0 &&
           UA_String_equal(&rd->browseName.name, &inputArgsName.name))
            inputArgsId = rd->nodeId.nodeId;
        else if(rd->browseName.namespaceIndex == 0 &&
                UA_String_equal(&rd->browseName.name, &outputArgsName.name))
            outputArgsId = rd->nodeId.nodeId;
    }

    /* Add the Input Arguments VariableNode */
    if(inputArgumentsSize > 0 && UA_NodeId_isNull(&inputArgsId)) {
        UA_VariableAttributes attr = UA_VariableAttributes_default;
        char *name = "InputArguments";
        attr.displayName = UA_LOCALIZEDTEXT("", name);
        attr.dataType = UA_TYPES[UA_TYPES_ARGUMENT].typeId;
        attr.valueRank = UA_VALUERANK_ONE_DIMENSION;
        UA_UInt32 inputArgsSize32 = (UA_UInt32)inputArgumentsSize;
        attr.arrayDimensions = &inputArgsSize32;
        attr.arrayDimensionsSize = 1;
        UA_Variant_setArray(&attr.value, (void *)(uintptr_t)inputArguments,
                            inputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
        retval = addNode(server, UA_NODECLASS_VARIABLE, inputArgumentsRequestedNewNodeId,
                         nodeId, hasproperty, UA_QUALIFIEDNAME(0, name),
                         propertytype, &attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],
                         NULL, &inputArgsId);
        if(retval != UA_STATUSCODE_GOOD)
            goto error;
    }

    /* Add the Output Arguments VariableNode */
    if(outputArgumentsSize > 0 && UA_NodeId_isNull(&outputArgsId)) {
        UA_VariableAttributes attr = UA_VariableAttributes_default;
        char *name = "OutputArguments";
        attr.displayName = UA_LOCALIZEDTEXT("", name);
        attr.dataType = UA_TYPES[UA_TYPES_ARGUMENT].typeId;
        attr.valueRank = UA_VALUERANK_ONE_DIMENSION;
        UA_UInt32 outputArgsSize32 = (UA_UInt32)outputArgumentsSize;
        attr.arrayDimensions = &outputArgsSize32;
        attr.arrayDimensionsSize = 1;
        UA_Variant_setArray(&attr.value, (void *)(uintptr_t)outputArguments,
                            outputArgumentsSize, &UA_TYPES[UA_TYPES_ARGUMENT]);
        retval = addNode(server, UA_NODECLASS_VARIABLE, outputArgumentsRequestedNewNodeId,
                         nodeId, hasproperty, UA_QUALIFIEDNAME(0, name),
                         propertytype, &attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],
                         NULL, &outputArgsId);
        if(retval != UA_STATUSCODE_GOOD)
            goto error;
    }

    retval = setMethodNode_callback(server, nodeId, method);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    /* Call finish to add the parent reference */
    retval = addNode_finish(server, &server->adminSession, &nodeId);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    if(inputArgumentsOutNewNodeId != NULL) {
        UA_NodeId_copy(&inputArgsId, inputArgumentsOutNewNodeId);
    }
    if(outputArgumentsOutNewNodeId != NULL) {
        UA_NodeId_copy(&outputArgsId, outputArgumentsOutNewNodeId);
    }
    UA_BrowseResult_clear(&br);
    return retval;

error:
    deleteNode(server, nodeId, true);
    deleteNode(server, inputArgsId, true);
    deleteNode(server, outputArgsId, true);
    UA_BrowseResult_clear(&br);
    return retval;
}

UA_StatusCode
UA_Server_addMethodNode_finish(UA_Server *server, const UA_NodeId nodeId,
                               UA_MethodCallback method,
                               size_t inputArgumentsSize,
                               const UA_Argument* inputArguments,
                               size_t outputArgumentsSize,
                               const UA_Argument* outputArguments) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode retval =
        UA_Server_addMethodNodeEx_finish(server, nodeId, method,
                                         inputArgumentsSize, inputArguments,
                                         UA_NODEID_NULL, NULL,
                                         outputArgumentsSize, outputArguments,
                                         UA_NODEID_NULL, NULL);
    UA_UNLOCK(&server->serviceMutex);
    return retval;
}

UA_StatusCode
addMethodNode(UA_Server *server, const UA_NodeId requestedNewNodeId,
              const UA_NodeId parentNodeId, const UA_NodeId referenceTypeId,
              const UA_QualifiedName browseName,
              const UA_MethodAttributes *attr, UA_MethodCallback method,
              size_t inputArgumentsSize, const UA_Argument *inputArguments,
              const UA_NodeId inputArgumentsRequestedNewNodeId,
              UA_NodeId *inputArgumentsOutNewNodeId,
              size_t outputArgumentsSize, const UA_Argument *outputArguments,
              const UA_NodeId outputArgumentsRequestedNewNodeId,
              UA_NodeId *outputArgumentsOutNewNodeId,
              void *nodeContext, UA_NodeId *outNewNodeId) {
    UA_AddNodesItem item;
    UA_AddNodesItem_init(&item);
    item.nodeClass = UA_NODECLASS_METHOD;
    item.requestedNewNodeId.nodeId = requestedNewNodeId;
    item.browseName = browseName;
    UA_ExtensionObject_setValueNoDelete(&item.nodeAttributes, (void*)(uintptr_t)attr,
                                        &UA_TYPES[UA_TYPES_METHODATTRIBUTES]);
    UA_NodeId newId;
    if(!outNewNodeId) {
        UA_NodeId_init(&newId);
        outNewNodeId = &newId;
    }
    UA_StatusCode retval = Operation_addNode_begin(server, &server->adminSession,
                                                   nodeContext, &item, &parentNodeId,
                                                   &referenceTypeId, outNewNodeId);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    retval = UA_Server_addMethodNodeEx_finish(server, *outNewNodeId, method,
                                              inputArgumentsSize, inputArguments,
                                              inputArgumentsRequestedNewNodeId,
                                              inputArgumentsOutNewNodeId,
                                              outputArgumentsSize, outputArguments,
                                              outputArgumentsRequestedNewNodeId,
                                              outputArgumentsOutNewNodeId);
    if(outNewNodeId == &newId)
        UA_NodeId_clear(&newId);
    return retval;
}

UA_StatusCode
UA_Server_addMethodNodeEx(UA_Server *server, const UA_NodeId requestedNewNodeId,
                          const UA_NodeId parentNodeId,
                          const UA_NodeId referenceTypeId,
                          const UA_QualifiedName browseName,
                          const UA_MethodAttributes attr, UA_MethodCallback method,
                          size_t inputArgumentsSize, const UA_Argument *inputArguments,
                          const UA_NodeId inputArgumentsRequestedNewNodeId,
                          UA_NodeId *inputArgumentsOutNewNodeId,
                          size_t outputArgumentsSize, const UA_Argument *outputArguments,
                          const UA_NodeId outputArgumentsRequestedNewNodeId,
                          UA_NodeId *outputArgumentsOutNewNodeId,
                          void *nodeContext, UA_NodeId *outNewNodeId) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = addMethodNode(server, requestedNewNodeId,
                                      parentNodeId, referenceTypeId,
                                      browseName, &attr, method,
                                      inputArgumentsSize, inputArguments,
                                      inputArgumentsRequestedNewNodeId,
                                      inputArgumentsOutNewNodeId,
                                      outputArgumentsSize,
                                      outputArguments,
                                      outputArgumentsRequestedNewNodeId,
                                      outputArgumentsOutNewNodeId,
                                      nodeContext, outNewNodeId);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

static UA_StatusCode
editMethodCallback(UA_Server *server, UA_Session* session,
                   UA_Node *node, UA_MethodCallback methodCallback) {
    if(node->head.nodeClass != UA_NODECLASS_METHOD)
        return UA_STATUSCODE_BADNODECLASSINVALID;
    node->methodNode.method = methodCallback;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
setMethodNode_callback(UA_Server *server,
                       const UA_NodeId methodNodeId,
                       UA_MethodCallback methodCallback) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    return UA_Server_editNode(server, &server->adminSession, &methodNodeId,
                              (UA_EditNodeCallback)editMethodCallback,
                              (void*)(uintptr_t)methodCallback);
}

UA_StatusCode
UA_Server_setMethodNodeCallback(UA_Server *server,
                                const UA_NodeId methodNodeId,
                                UA_MethodCallback methodCallback) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode retVal = setMethodNode_callback(server, methodNodeId, methodCallback);
    UA_UNLOCK(&server->serviceMutex);
    return retVal;
}

UA_StatusCode
UA_Server_getMethodNodeCallback(UA_Server *server,
                                const UA_NodeId methodNodeId,
                                UA_MethodCallback *outMethodCallback) {
    UA_LOCK(&server->serviceMutex);
    const UA_Node *node = UA_NODESTORE_GET(server, &methodNodeId);
    if(!node) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADNODEIDUNKNOWN;
    }

    if(node->head.nodeClass != UA_NODECLASS_METHOD) {
        UA_NODESTORE_RELEASE(server, node);
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADNODECLASSINVALID;
    }

    *outMethodCallback = node->methodNode.method;
    UA_NODESTORE_RELEASE(server, node);
    UA_UNLOCK(&server->serviceMutex);
    return UA_STATUSCODE_GOOD;
}

#endif

/************************/
/* Lifecycle Management */
/************************/

void UA_EXPORT
UA_Server_setAdminSessionContext(UA_Server *server,
                                 void *context) {
    server->adminSession.context = context;
}

static UA_StatusCode
setNodeTypeLifecycleCallback(UA_Server *server, UA_Session *session,
                             UA_Node *node, UA_NodeTypeLifecycle *lifecycle) {
    if(node->head.nodeClass == UA_NODECLASS_OBJECTTYPE) {
        node->objectTypeNode.lifecycle = *lifecycle;
    } else if(node->head.nodeClass == UA_NODECLASS_VARIABLETYPE) {
        node->variableTypeNode.lifecycle = *lifecycle;
    } else {
        return UA_STATUSCODE_BADNODECLASSINVALID;
    }
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
setNodeTypeLifecycle(UA_Server *server, UA_NodeId nodeId,
                     UA_NodeTypeLifecycle lifecycle) {
    return UA_Server_editNode(server, &server->adminSession, &nodeId,
                              (UA_EditNodeCallback)setNodeTypeLifecycleCallback,
                              &lifecycle);
}

UA_StatusCode
UA_Server_setNodeTypeLifecycle(UA_Server *server, UA_NodeId nodeId,
                               UA_NodeTypeLifecycle lifecycle) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode retval = setNodeTypeLifecycle(server, nodeId, lifecycle);
    UA_UNLOCK(&server->serviceMutex);
    return retval;
}

/**** amalgamated original file "/src/pubsub/ua_pubsub_networkmessage.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2017 - 2018 Fraunhofer IOSB (Author: Tino Bischoff)
 * Copyright (c) 2019 Fraunhofer IOSB (Author: Andreas Ebner)
 */



#ifdef UA_ENABLE_PUBSUB /* conditional compilation */

const UA_Byte NM_VERSION_MASK = 15;
const UA_Byte NM_PUBLISHER_ID_ENABLED_MASK = 16;
const UA_Byte NM_GROUP_HEADER_ENABLED_MASK = 32;
const UA_Byte NM_PAYLOAD_HEADER_ENABLED_MASK = 64;
const UA_Byte NM_EXTENDEDFLAGS1_ENABLED_MASK = 128;
const UA_Byte NM_PUBLISHER_ID_MASK = 7;
const UA_Byte NM_DATASET_CLASSID_ENABLED_MASK = 8;
const UA_Byte NM_SECURITY_ENABLED_MASK = 16;
const UA_Byte NM_TIMESTAMP_ENABLED_MASK = 32;
const UA_Byte NM_PICOSECONDS_ENABLED_MASK = 64;
const UA_Byte NM_EXTENDEDFLAGS2_ENABLED_MASK = 128;
const UA_Byte NM_NETWORK_MSG_TYPE_MASK = 28;
const UA_Byte NM_CHUNK_MESSAGE_MASK = 1;
const UA_Byte NM_PROMOTEDFIELDS_ENABLED_MASK = 2;
const UA_Byte GROUP_HEADER_WRITER_GROUPID_ENABLED = 1;
const UA_Byte GROUP_HEADER_GROUP_VERSION_ENABLED = 2;
const UA_Byte GROUP_HEADER_NM_NUMBER_ENABLED = 4;
const UA_Byte GROUP_HEADER_SEQUENCE_NUMBER_ENABLED = 8;
const UA_Byte SECURITY_HEADER_NM_SIGNED = 1;
const UA_Byte SECURITY_HEADER_NM_ENCRYPTED = 2;
const UA_Byte SECURITY_HEADER_SEC_FOOTER_ENABLED = 4;
const UA_Byte SECURITY_HEADER_FORCE_KEY_RESET = 8;
const UA_Byte DS_MESSAGEHEADER_DS_MSG_VALID = 1;
const UA_Byte DS_MESSAGEHEADER_FIELD_ENCODING_MASK = 6;
const UA_Byte DS_MESSAGEHEADER_SEQ_NR_ENABLED_MASK = 8;
const UA_Byte DS_MESSAGEHEADER_STATUS_ENABLED_MASK = 16;
const UA_Byte DS_MESSAGEHEADER_CONFIGMAJORVERSION_ENABLED_MASK = 32;
const UA_Byte DS_MESSAGEHEADER_CONFIGMINORVERSION_ENABLED_MASK = 64;
const UA_Byte DS_MESSAGEHEADER_FLAGS2_ENABLED_MASK = 128;
const UA_Byte DS_MESSAGEHEADER_DS_MESSAGE_TYPE_MASK = 15;
const UA_Byte DS_MESSAGEHEADER_TIMESTAMP_ENABLED_MASK = 16;
const UA_Byte DS_MESSAGEHEADER_PICOSECONDS_INCLUDED_MASK = 32;
const UA_Byte NM_SHIFT_LEN = 2;
const UA_Byte DS_MH_SHIFT_LEN = 1;

typedef struct {
    u8 *pos;
    const u8 *end;
} EncodeCtx;

static UA_Boolean UA_NetworkMessage_ExtendedFlags1Enabled(const UA_NetworkMessage* src);
static UA_Boolean UA_NetworkMessage_ExtendedFlags2Enabled(const UA_NetworkMessage* src);
static UA_Boolean UA_DataSetMessageHeader_DataSetFlags2Enabled(const UA_DataSetMessageHeader* src);

UA_StatusCode
UA_NetworkMessage_updateBufferedMessage(UA_NetworkMessageOffsetBuffer *buffer) {
    UA_StatusCode rv = UA_STATUSCODE_GOOD;
    const UA_Byte *bufEnd = &buffer->buffer.data[buffer->buffer.length];
    for(size_t i = 0; i < buffer->offsetsSize; ++i) {
        UA_NetworkMessageOffset *nmo = &buffer->offsets[i];
        UA_Byte *bufPos = &buffer->buffer.data[nmo->offset];
        switch(nmo->contentType) {
            case UA_PUBSUB_OFFSETTYPE_DATASETMESSAGE_SEQUENCENUMBER:
            case UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_SEQUENCENUMBER:
                rv = UA_UInt16_encodeBinary(&nmo->content.sequenceNumber, &bufPos, bufEnd);
                nmo->content.sequenceNumber++;
                break;
            case UA_PUBSUB_OFFSETTYPE_PAYLOAD_DATAVALUE:
                rv = UA_DataValue_encodeBinary(&nmo->content.value, &bufPos, bufEnd);
                break;
            case UA_PUBSUB_OFFSETTYPE_PAYLOAD_VARIANT:
                rv = UA_Variant_encodeBinary(&nmo->content.value.value, &bufPos, bufEnd);
                break;
            case UA_PUBSUB_OFFSETTYPE_PAYLOAD_RAW:
                rv = UA_encodeBinaryInternal(nmo->content.value.value.data,
                                             nmo->content.value.value.type,
                                             &bufPos, &bufEnd, NULL, NULL);
                break;
            default:
                break; /* The other fields are assumed to not change between messages.
                        * Only used for RT decoding (not encoding). */
        }
    }
    return rv;
}

UA_StatusCode
UA_NetworkMessage_updateBufferedNwMessage(UA_NetworkMessageOffsetBuffer *buffer,
                                          const UA_ByteString *src, size_t *bufferPosition) {
    /* The offset buffer was not prepared */
    UA_NetworkMessage *nm = buffer->nm;
    if(!nm)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* The source string is too short */
    if(src->length < buffer->buffer.length + *bufferPosition)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* If this remains at UA_UINT32_MAX, then no raw fields are contained */
    size_t smallestRawOffset = UA_UINT32_MAX;

    /* Considering one DSM in RT TODO: Clarify multiple DSM */
    UA_DataSetMessage* dsm = nm->payload.dataSetPayload.dataSetMessages;

    size_t pos = 0;
    size_t payloadCounter = 0;
    UA_DataSetMessageHeader header;
    UA_StatusCode rv = UA_STATUSCODE_GOOD;
    for(size_t i = 0; i < buffer->offsetsSize; ++i) {
        pos = buffer->offsets[i].offset + *bufferPosition;
        switch(buffer->offsets[i].contentType) {
        case UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_FIELDENCDODING:
            rv = UA_DataSetMessageHeader_decodeBinary(src, &pos, &header);
            break;
        case UA_PUBSUB_OFFSETTYPE_PUBLISHERID:
            switch(nm->publisherIdType) {
            case UA_PUBLISHERIDTYPE_BYTE:
                rv = UA_Byte_decodeBinary(src, &pos, &nm->publisherId.byte);
                break;
            case UA_PUBLISHERIDTYPE_UINT16:
                rv = UA_UInt16_decodeBinary(src, &pos, &nm->publisherId.uint16);
                break;
            case UA_PUBLISHERIDTYPE_UINT32:
                rv = UA_UInt32_decodeBinary(src, &pos, &nm->publisherId.uint32);
                break;
            case UA_PUBLISHERIDTYPE_UINT64:
                rv = UA_UInt64_decodeBinary(src, &pos, &nm->publisherId.uint64);
                break;
            default:
                /* UA_PUBLISHERIDTYPE_STRING is not supported because of
                 * UA_PUBSUB_RT_FIXED_SIZE */
                return UA_STATUSCODE_BADNOTSUPPORTED;
            }
            break;
        case UA_PUBSUB_OFFSETTYPE_WRITERGROUPID:
            rv = UA_UInt16_decodeBinary(src, &pos, &nm->groupHeader.writerGroupId);
            break;
        case UA_PUBSUB_OFFSETTYPE_DATASETWRITERID:
            rv = UA_UInt16_decodeBinary(src, &pos,
                                        &nm->payloadHeader.dataSetPayloadHeader.dataSetWriterIds[0]); /* TODO */
            break;
        case UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_SEQUENCENUMBER:
            rv = UA_UInt16_decodeBinary(src, &pos, &nm->groupHeader.sequenceNumber);
            break;
        case UA_PUBSUB_OFFSETTYPE_DATASETMESSAGE_SEQUENCENUMBER:
            rv = UA_UInt16_decodeBinary(src, &pos, &dsm->header.dataSetMessageSequenceNr);
            break;
        case UA_PUBSUB_OFFSETTYPE_PAYLOAD_DATAVALUE:
            UA_DataValue_clear(&dsm->data.keyFrameData.dataSetFields[payloadCounter]);
            rv = UA_DataValue_decodeBinary(src, &pos,
                                           &dsm->data.keyFrameData.dataSetFields[payloadCounter]);
            payloadCounter++;
            break;
        case UA_PUBSUB_OFFSETTYPE_PAYLOAD_VARIANT:
            UA_Variant_clear(&dsm->data.keyFrameData.dataSetFields[payloadCounter].value);
            rv = UA_Variant_decodeBinary(src, &pos,
                                         &dsm->data.keyFrameData.dataSetFields[payloadCounter].value);
            dsm->data.keyFrameData.dataSetFields[payloadCounter].hasValue =
                (rv == UA_STATUSCODE_GOOD);
            payloadCounter++;
            break;
        case UA_PUBSUB_OFFSETTYPE_PAYLOAD_RAW:
            /* We need only the start address of the raw fields */
            if(smallestRawOffset > pos){
                smallestRawOffset = pos;
                dsm->data.keyFrameData.rawFields.data = &src->data[pos];
                dsm->data.keyFrameData.rawFields.length = buffer->rawMessageLength;
            }
            payloadCounter++;
            break;
        default:
            return UA_STATUSCODE_BADNOTSUPPORTED;
        }
        UA_CHECK_STATUS(rv, return rv);
    }

    /* Check if the frame is of type "raw" payload. If yes, set the new buffer
     * position to the start position of the raw fields plus the length of the
     * raw fields. */
    if(smallestRawOffset != UA_UINT32_MAX) {
        *bufferPosition = smallestRawOffset + buffer->rawMessageLength;
    } else {
        *bufferPosition = pos;
    }

    return rv;
}

static UA_StatusCode
UA_NetworkMessageHeader_encodeBinary(EncodeCtx *ctx,
                                     const UA_NetworkMessage *src) {
    /* UADPVersion + UADP Flags */
    UA_Byte v = src->version;
    if(src->publisherIdEnabled)
        v |= NM_PUBLISHER_ID_ENABLED_MASK;

    if(src->groupHeaderEnabled)
        v |= NM_GROUP_HEADER_ENABLED_MASK;

    if(src->payloadHeaderEnabled)
        v |= NM_PAYLOAD_HEADER_ENABLED_MASK;

    if(UA_NetworkMessage_ExtendedFlags1Enabled(src))
        v |= NM_EXTENDEDFLAGS1_ENABLED_MASK;

    UA_StatusCode rv = UA_Byte_encodeBinary(&v, &ctx->pos, ctx->end);
    UA_CHECK_STATUS(rv, return rv);
    // ExtendedFlags1
    if(UA_NetworkMessage_ExtendedFlags1Enabled(src)) {
        v = (UA_Byte)src->publisherIdType;

        if(src->dataSetClassIdEnabled)
            v |= NM_DATASET_CLASSID_ENABLED_MASK;

        if(src->securityEnabled)
            v |= NM_SECURITY_ENABLED_MASK;

        if(src->timestampEnabled)
            v |= NM_TIMESTAMP_ENABLED_MASK;

        if(src->picosecondsEnabled)
            v |= NM_PICOSECONDS_ENABLED_MASK;

        if(UA_NetworkMessage_ExtendedFlags2Enabled(src))
            v |= NM_EXTENDEDFLAGS2_ENABLED_MASK;

        rv = UA_Byte_encodeBinary(&v, &ctx->pos, ctx->end);
        UA_CHECK_STATUS(rv, return rv);

        // ExtendedFlags2
        if(UA_NetworkMessage_ExtendedFlags2Enabled(src)) {
            v = (UA_Byte)src->networkMessageType;
            // shift left 2 bit
            v = (UA_Byte) (v << NM_SHIFT_LEN);

            if(src->chunkMessage)
                v |= NM_CHUNK_MESSAGE_MASK;

            if(src->promotedFieldsEnabled)
                v |= NM_PROMOTEDFIELDS_ENABLED_MASK;

            rv = UA_Byte_encodeBinary(&v, &ctx->pos, ctx->end);
            UA_CHECK_STATUS(rv, return rv);
        }
    }

    // PublisherId
    if(src->publisherIdEnabled) {
        switch (src->publisherIdType) {
        case UA_PUBLISHERIDTYPE_BYTE:
            rv = UA_Byte_encodeBinary(&src->publisherId.byte, &ctx->pos, ctx->end);
            break;

        case UA_PUBLISHERIDTYPE_UINT16:
            rv = UA_UInt16_encodeBinary(&src->publisherId.uint16, &ctx->pos, ctx->end);
            break;

        case UA_PUBLISHERIDTYPE_UINT32:
            rv = UA_UInt32_encodeBinary(&src->publisherId.uint32, &ctx->pos, ctx->end);
            break;

        case UA_PUBLISHERIDTYPE_UINT64:
            rv = UA_UInt64_encodeBinary(&src->publisherId.uint64, &ctx->pos, ctx->end);
            break;

        case UA_PUBLISHERIDTYPE_STRING:
            rv = UA_String_encodeBinary(&src->publisherId.string, &ctx->pos, ctx->end);
            break;

        default:
            rv = UA_STATUSCODE_BADINTERNALERROR;
            break;
        }
        UA_CHECK_STATUS(rv, return rv);
    }

    // DataSetClassId
    if(src->dataSetClassIdEnabled) {
        rv = UA_Guid_encodeBinary(&src->dataSetClassId, &ctx->pos, ctx->end);
        UA_CHECK_STATUS(rv, return rv);
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_GroupHeader_encodeBinary(EncodeCtx *ctx, const UA_NetworkMessage* src) {
    UA_Byte v = 0;
    if(src->groupHeader.writerGroupIdEnabled)
        v |= GROUP_HEADER_WRITER_GROUPID_ENABLED;

    if(src->groupHeader.groupVersionEnabled)
        v |= GROUP_HEADER_GROUP_VERSION_ENABLED;

    if(src->groupHeader.networkMessageNumberEnabled)
        v |= GROUP_HEADER_NM_NUMBER_ENABLED;

    if(src->groupHeader.sequenceNumberEnabled)
        v |= GROUP_HEADER_SEQUENCE_NUMBER_ENABLED;

    UA_StatusCode rv = UA_Byte_encodeBinary(&v, &ctx->pos, ctx->end);
    if(src->groupHeader.writerGroupIdEnabled)
        rv |= UA_UInt16_encodeBinary(&src->groupHeader.writerGroupId,
                                     &ctx->pos, ctx->end);

    if(src->groupHeader.groupVersionEnabled)
        rv |= UA_UInt32_encodeBinary(&src->groupHeader.groupVersion,
                                     &ctx->pos, ctx->end);

    if(src->groupHeader.networkMessageNumberEnabled)
        rv |= UA_UInt16_encodeBinary(&src->groupHeader.networkMessageNumber,
                                     &ctx->pos, ctx->end);

    if(src->groupHeader.sequenceNumberEnabled)
        rv |= UA_UInt16_encodeBinary(&src->groupHeader.sequenceNumber,
                                     &ctx->pos, ctx->end);

    return rv;
}

static UA_StatusCode
UA_PayloadHeader_encodeBinary(EncodeCtx *ctx, const UA_NetworkMessage* src) {
    if(src->networkMessageType != UA_NETWORKMESSAGE_DATASET)
        return UA_STATUSCODE_BADNOTIMPLEMENTED;

    if(src->payloadHeader.dataSetPayloadHeader.dataSetWriterIds == NULL)
        return UA_STATUSCODE_BADENCODINGERROR;

    UA_Byte count = src->payloadHeader.dataSetPayloadHeader.count;
    UA_StatusCode rv = UA_Byte_encodeBinary(&count, &ctx->pos, ctx->end);

    for(UA_Byte i = 0; i < count; i++) {
        UA_UInt16 dswId = src->payloadHeader.dataSetPayloadHeader.dataSetWriterIds[i];
        rv |= UA_UInt16_encodeBinary(&dswId, &ctx->pos, ctx->end);
    }

    return rv;
}

static UA_StatusCode
UA_ExtendedNetworkMessageHeader_encodeBinary(EncodeCtx *ctx, const UA_NetworkMessage* src) {
    UA_StatusCode rv = UA_STATUSCODE_GOOD;
    if(src->timestampEnabled)
        rv |= UA_DateTime_encodeBinary(&src->timestamp, &ctx->pos, ctx->end);

    if(src->picosecondsEnabled)
        rv |= UA_UInt16_encodeBinary(&src->picoseconds, &ctx->pos, ctx->end);

    if(src->promotedFieldsEnabled) {
        /* Size (calculate & encode) */
        UA_UInt16 pfSize = 0;
        for(UA_UInt16 i = 0; i < src->promotedFieldsSize; i++)
            pfSize = (UA_UInt16)(pfSize + UA_Variant_calcSizeBinary(&src->promotedFields[i]));
        rv |= UA_UInt16_encodeBinary(&pfSize, &ctx->pos, ctx->end);

        for(UA_UInt16 i = 0; i < src->promotedFieldsSize; i++)
            rv |= UA_Variant_encodeBinary(&src->promotedFields[i], &ctx->pos, ctx->end);
    }

    return rv;
}

static UA_StatusCode
UA_SecurityHeader_encodeBinary(EncodeCtx *ctx, const UA_NetworkMessage* src) {
    /* SecurityFlags */
    UA_Byte v = 0;
    if(src->securityHeader.networkMessageSigned)
        v |= SECURITY_HEADER_NM_SIGNED;

    if(src->securityHeader.networkMessageEncrypted)
        v |= SECURITY_HEADER_NM_ENCRYPTED;

    if(src->securityHeader.securityFooterEnabled)
        v |= SECURITY_HEADER_SEC_FOOTER_ENABLED;

    if(src->securityHeader.forceKeyReset)
        v |= SECURITY_HEADER_FORCE_KEY_RESET;

    UA_StatusCode rv = UA_Byte_encodeBinary(&v, &ctx->pos, ctx->end);

    /* SecurityTokenId */
    rv |= UA_UInt32_encodeBinary(&src->securityHeader.securityTokenId,
                                 &ctx->pos, ctx->end);

    /* NonceLength */
    UA_Byte nonceLength = (UA_Byte)src->securityHeader.messageNonceSize;
    rv |= UA_Byte_encodeBinary(&nonceLength, &ctx->pos, ctx->end);

    /* MessageNonce */
    for(size_t i = 0; i < src->securityHeader.messageNonceSize; i++) {
        rv |= UA_Byte_encodeBinary(&src->securityHeader.messageNonce[i],
                                   &ctx->pos, ctx->end);
    }

    /* SecurityFooterSize */
    if(src->securityHeader.securityFooterEnabled) {
        rv |= UA_UInt16_encodeBinary(&src->securityHeader.securityFooterSize,
                                     &ctx->pos, ctx->end);
    }

    return rv;
}

UA_StatusCode
UA_NetworkMessage_encodeHeaders(const UA_NetworkMessage* src, UA_Byte **bufPos,
                                const UA_Byte *bufEnd) {
    EncodeCtx ctx;
    ctx.pos = *bufPos;
    ctx.end = bufEnd;
    
    /* Message Header */
    UA_StatusCode rv = UA_NetworkMessageHeader_encodeBinary(&ctx, src);

    /* Group Header */
    if(src->groupHeaderEnabled)
        rv |= UA_GroupHeader_encodeBinary(&ctx, src);

    /* Payload Header */
    if(src->payloadHeaderEnabled)
        rv |= UA_PayloadHeader_encodeBinary(&ctx, src);

    /* Extended Network Message Header */
    rv |= UA_ExtendedNetworkMessageHeader_encodeBinary(&ctx, src);

    /* SecurityHeader */
    if(src->securityEnabled)
        rv |= UA_SecurityHeader_encodeBinary(&ctx, src);

    *bufPos = ctx.pos;
    return rv;
}


UA_StatusCode
UA_NetworkMessage_encodePayload(const UA_NetworkMessage* src, UA_Byte **bufPos,
                                const UA_Byte *bufEnd) {
    // Payload
    if(src->networkMessageType != UA_NETWORKMESSAGE_DATASET)
        return UA_STATUSCODE_BADNOTIMPLEMENTED;

    EncodeCtx ctx;
    ctx.pos = *bufPos;
    ctx.end = bufEnd;

    UA_Byte count = 1;
    UA_StatusCode rv;
    if(src->payloadHeaderEnabled) {
        count = src->payloadHeader.dataSetPayloadHeader.count;
        if(count > 1) {
            for(UA_Byte i = 0; i < count; i++) {
                /* Calculate the size, if not specified */
                UA_UInt16 sz = 0;
                if((src->payload.dataSetPayload.sizes != NULL) &&
                   (src->payload.dataSetPayload.sizes[i] != 0)) {
                    sz = src->payload.dataSetPayload.sizes[i];
                } else {
                    UA_DataSetMessage *dsm = &src->payload.dataSetPayload.dataSetMessages[i];
                    sz = (UA_UInt16)UA_DataSetMessage_calcSizeBinary(dsm, NULL, 0);
                }

                rv = UA_UInt16_encodeBinary(&sz, &ctx.pos, ctx.end);
                UA_CHECK_STATUS(rv, return rv);
            }
        }
    }

    for(UA_Byte i = 0; i < count; i++) {
        UA_DataSetMessage *dsm = &src->payload.dataSetPayload.dataSetMessages[i];
        rv = UA_DataSetMessage_encodeBinary(dsm, &ctx.pos, ctx.end);
        UA_CHECK_STATUS(rv, return rv);
    }

    *bufPos = ctx.pos;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_NetworkMessage_encodeFooters(const UA_NetworkMessage* src, UA_Byte **bufPos,
                                const UA_Byte *bufEnd) {
    UA_StatusCode rv = UA_STATUSCODE_GOOD;
    if(src->securityEnabled &&
       src->securityHeader.securityFooterEnabled) {
        for(size_t i = 0; i < src->securityHeader.securityFooterSize; i++) {
            rv |= UA_Byte_encodeBinary(&src->securityFooter.data[i], bufPos, bufEnd);
        }
    }
    return rv;
}

UA_StatusCode
UA_NetworkMessage_encodeBinary(const UA_NetworkMessage* src, UA_Byte **bufPos,
                               const UA_Byte *bufEnd, UA_Byte **dataToEncryptStart) {
    UA_StatusCode rv = UA_NetworkMessage_encodeHeaders(src, bufPos, bufEnd);

    if(dataToEncryptStart)
        *dataToEncryptStart = *bufPos;

    rv |= UA_NetworkMessage_encodePayload(src, bufPos, bufEnd);
    rv |= UA_NetworkMessage_encodeFooters(src, bufPos, bufEnd);
    return rv;
}

UA_StatusCode
UA_NetworkMessageHeader_decodeBinary(const UA_ByteString *src, size_t *offset,
                                     UA_NetworkMessage *dst) {
    UA_Byte decoded = 0;
    UA_StatusCode rv = UA_Byte_decodeBinary(src, offset, &decoded);
    UA_CHECK_STATUS(rv, return rv);

    dst->version = decoded & NM_VERSION_MASK;

    if((decoded & NM_PUBLISHER_ID_ENABLED_MASK) != 0)
        dst->publisherIdEnabled = true;

    if((decoded & NM_GROUP_HEADER_ENABLED_MASK) != 0)
        dst->groupHeaderEnabled = true;

    if((decoded & NM_PAYLOAD_HEADER_ENABLED_MASK) != 0)
        dst->payloadHeaderEnabled = true;

    if((decoded & NM_EXTENDEDFLAGS1_ENABLED_MASK) != 0) {
        decoded = 0;
        rv = UA_Byte_decodeBinary(src, offset, &decoded);
        UA_CHECK_STATUS(rv, return rv);

        dst->publisherIdType = (UA_PublisherIdType)(decoded & NM_PUBLISHER_ID_MASK);
        if((decoded & NM_DATASET_CLASSID_ENABLED_MASK) != 0)
            dst->dataSetClassIdEnabled = true;

        if((decoded & NM_SECURITY_ENABLED_MASK) != 0)
            dst->securityEnabled = true;

        if((decoded & NM_TIMESTAMP_ENABLED_MASK) != 0)
            dst->timestampEnabled = true;

        if((decoded & NM_PICOSECONDS_ENABLED_MASK) != 0)
            dst->picosecondsEnabled = true;

        if((decoded & NM_EXTENDEDFLAGS2_ENABLED_MASK) != 0) {
            decoded = 0;
            rv = UA_Byte_decodeBinary(src, offset, &decoded);
            UA_CHECK_STATUS(rv, return rv);

            if((decoded & NM_CHUNK_MESSAGE_MASK) != 0)
                dst->chunkMessage = true;

            if((decoded & NM_PROMOTEDFIELDS_ENABLED_MASK) != 0)
                dst->promotedFieldsEnabled = true;

            decoded = decoded & NM_NETWORK_MSG_TYPE_MASK;
            decoded = (UA_Byte) (decoded >> NM_SHIFT_LEN);
            dst->networkMessageType = (UA_NetworkMessageType)decoded;
        }
    }

    if(dst->publisherIdEnabled) {
        switch (dst->publisherIdType) {
            case UA_PUBLISHERIDTYPE_BYTE:
                rv = UA_Byte_decodeBinary(src, offset, &dst->publisherId.byte);
                break;

            case UA_PUBLISHERIDTYPE_UINT16:
                rv = UA_UInt16_decodeBinary(src, offset, &dst->publisherId.uint16);
                break;

            case UA_PUBLISHERIDTYPE_UINT32:
                rv = UA_UInt32_decodeBinary(src, offset, &dst->publisherId.uint32);
                break;

            case UA_PUBLISHERIDTYPE_UINT64:
                rv = UA_UInt64_decodeBinary(src, offset, &dst->publisherId.uint64);
                break;

            case UA_PUBLISHERIDTYPE_STRING:
                rv = UA_String_decodeBinary(src, offset, &dst->publisherId.string);
                break;

            default:
                rv = UA_STATUSCODE_BADINTERNALERROR;
                break;
        }
        UA_CHECK_STATUS(rv, return rv);
    }

    if(dst->dataSetClassIdEnabled) {
        rv = UA_Guid_decodeBinary(src, offset, &dst->dataSetClassId);
        UA_CHECK_STATUS(rv, return rv);
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_GroupHeader_decodeBinary(const UA_ByteString *src, size_t *offset,
                         UA_NetworkMessage* dst) {
    UA_Byte decoded = 0;
    UA_StatusCode rv = UA_Byte_decodeBinary(src, offset, &decoded);

    if((decoded & GROUP_HEADER_WRITER_GROUPID_ENABLED) != 0) {
        dst->groupHeader.writerGroupIdEnabled = true;
        rv |= UA_UInt16_decodeBinary(src, offset, &dst->groupHeader.writerGroupId);
    }

    if((decoded & GROUP_HEADER_GROUP_VERSION_ENABLED) != 0) {
        dst->groupHeader.groupVersionEnabled = true;
        rv |= UA_UInt32_decodeBinary(src, offset, &dst->groupHeader.groupVersion);
    }

    if((decoded & GROUP_HEADER_NM_NUMBER_ENABLED) != 0) {
        dst->groupHeader.networkMessageNumberEnabled = true;
        rv |= UA_UInt16_decodeBinary(src, offset, &dst->groupHeader.networkMessageNumber);
    }

    if((decoded & GROUP_HEADER_SEQUENCE_NUMBER_ENABLED) != 0) {
        dst->groupHeader.sequenceNumberEnabled = true;
        rv |= UA_UInt16_decodeBinary(src, offset, &dst->groupHeader.sequenceNumber);
    }

    return rv;
}

static UA_StatusCode
UA_PayloadHeader_decodeBinary(const UA_ByteString *src, size_t *offset,
                              UA_NetworkMessage* dst) {
    if(dst->networkMessageType != UA_NETWORKMESSAGE_DATASET)
        return UA_STATUSCODE_BADNOTIMPLEMENTED;

    UA_DataSetPayloadHeader *h = &dst->payloadHeader.dataSetPayloadHeader;
    UA_StatusCode rv = UA_Byte_decodeBinary(src, offset, &h->count);
    UA_CHECK_STATUS(rv, return rv);

    if(h->count == 0)
        return UA_STATUSCODE_GOOD;

    h->dataSetWriterIds = (UA_UInt16*)UA_Array_new(h->count, &UA_TYPES[UA_TYPES_UINT16]);
    if(!h->dataSetWriterIds) {
        h->count = 0;
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    for(UA_Byte i = 0; i < h->count; i++) {
        rv |= UA_UInt16_decodeBinary(src, offset, &h->dataSetWriterIds[i]);
    }
    return rv;
}

static UA_StatusCode
UA_ExtendedNetworkMessageHeader_decodeBinary(const UA_ByteString *src, size_t *offset,
                                             UA_NetworkMessage* dst) {
    UA_StatusCode rv;

    /* Timestamp*/
    if(dst->timestampEnabled) {
        rv = UA_DateTime_decodeBinary(src, offset, &dst->timestamp);
        UA_CHECK_STATUS(rv, return rv);
    }

    /* Picoseconds */
    if(dst->picosecondsEnabled) {
        rv = UA_UInt16_decodeBinary(src, offset, &dst->picoseconds);
        UA_CHECK_STATUS(rv, return rv);
    }

    /* PromotedFields */
    if(UA_LIKELY(!dst->promotedFieldsEnabled))
        return UA_STATUSCODE_GOOD;

    UA_UInt16 promotedFieldsSize = 0; /* Size in bytes, not in number of fields */
    rv = UA_UInt16_decodeBinary(src, offset, &promotedFieldsSize);
    UA_CHECK_STATUS(rv, return rv);
    if(promotedFieldsSize == 0)
        return UA_STATUSCODE_GOOD;

    size_t offsetEnd = (*offset) + promotedFieldsSize;
    unsigned int counter = 0;
    do {
        UA_Variant *tmp = (UA_Variant*)
            UA_realloc(dst->promotedFields, (size_t)
                       UA_TYPES[UA_TYPES_VARIANT].memSize * (counter + 1));
        UA_CHECK_MEM(tmp, return UA_STATUSCODE_BADOUTOFMEMORY);
        dst->promotedFields = tmp;
        dst->promotedFieldsSize = (UA_UInt16) (counter + 1);

        UA_Variant_init(&dst->promotedFields[counter]);
        rv = UA_Variant_decodeBinary(src, offset, &dst->promotedFields[counter]);
        UA_CHECK_STATUS(rv, return rv);

        counter++;
    } while(*offset < offsetEnd);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_SecurityHeader_decodeBinary(const UA_ByteString *src, size_t *offset,
                              UA_NetworkMessage* dst) {
    UA_Byte decoded = 0;
    // SecurityFlags
    decoded = 0;
    UA_StatusCode rv = UA_Byte_decodeBinary(src, offset, &decoded);
    UA_CHECK_STATUS(rv, return rv);

    if((decoded & SECURITY_HEADER_NM_SIGNED) != 0)
        dst->securityHeader.networkMessageSigned = true;

    if((decoded & SECURITY_HEADER_NM_ENCRYPTED) != 0)
        dst->securityHeader.networkMessageEncrypted = true;

    if((decoded & SECURITY_HEADER_SEC_FOOTER_ENABLED) != 0)
        dst->securityHeader.securityFooterEnabled = true;

    if((decoded & SECURITY_HEADER_FORCE_KEY_RESET) != 0)
        dst->securityHeader.forceKeyReset = true;

    // SecurityTokenId
    rv = UA_UInt32_decodeBinary(src, offset, &dst->securityHeader.securityTokenId);
    UA_CHECK_STATUS(rv, return rv);

    // MessageNonce
    UA_Byte nonceLength;
    rv = UA_Byte_decodeBinary(src, offset, &nonceLength);
    UA_CHECK_STATUS(rv, return rv);
    if(nonceLength > UA_NETWORKMESSAGE_MAX_NONCE_LENGTH)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    if(nonceLength > 0) {
        dst->securityHeader.messageNonceSize = nonceLength;
        for(UA_Byte i = 0; i < nonceLength; i++) {
            rv = UA_Byte_decodeBinary(src, offset,
                                      &dst->securityHeader.messageNonce[i]);
            UA_CHECK_STATUS(rv, return rv);
        }
    }

    // SecurityFooterSize
    if(dst->securityHeader.securityFooterEnabled) {
        rv = UA_UInt16_decodeBinary(src, offset, &dst->securityHeader.securityFooterSize);
        UA_CHECK_STATUS(rv, return rv);
    }
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_NetworkMessage_decodeHeaders(const UA_ByteString *src, size_t *offset,
                                UA_NetworkMessage *dst) {
    UA_StatusCode rv = UA_NetworkMessageHeader_decodeBinary(src, offset, dst);
    UA_CHECK_STATUS(rv, return rv);

    if(dst->groupHeaderEnabled) {
        rv = UA_GroupHeader_decodeBinary(src, offset, dst);
        UA_CHECK_STATUS(rv, return rv);
    }

    if(dst->payloadHeaderEnabled) {
        rv = UA_PayloadHeader_decodeBinary(src, offset, dst);
        UA_CHECK_STATUS(rv, return rv);
    }

    rv = UA_ExtendedNetworkMessageHeader_decodeBinary(src, offset, dst);
    UA_CHECK_STATUS(rv, return rv);

    if(dst->securityEnabled) {
        rv = UA_SecurityHeader_decodeBinary(src, offset, dst);
        UA_CHECK_STATUS(rv, return rv);
    }

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_NetworkMessage_decodePayload(const UA_ByteString *src, size_t *offset, UA_NetworkMessage *dst,
                                const UA_DataTypeArray *customTypes, UA_DataSetMetaDataType *dsm) {
    // Payload
    if(dst->networkMessageType != UA_NETWORKMESSAGE_DATASET)
        return UA_STATUSCODE_BADNOTIMPLEMENTED;

    UA_StatusCode rv;

    UA_Byte count = 1;
    if(dst->payloadHeaderEnabled) {
        count = dst->payloadHeader.dataSetPayloadHeader.count;
        if(count > 1) {
            dst->payload.dataSetPayload.sizes = (UA_UInt16 *)
                UA_Array_new(count, &UA_TYPES[UA_TYPES_UINT16]);
            for(UA_Byte i = 0; i < count; i++) {
                rv = UA_UInt16_decodeBinary(src, offset,
                                            &dst->payload.dataSetPayload.sizes[i]);
                UA_CHECK_STATUS(rv, return rv);
            }
        }
    }

    dst->payload.dataSetPayload.dataSetMessages = (UA_DataSetMessage*)
        UA_calloc(count, sizeof(UA_DataSetMessage));
    UA_CHECK_MEM(dst->payload.dataSetPayload.dataSetMessages,
                 return UA_STATUSCODE_BADOUTOFMEMORY);

    if(count == 1) {
        rv = UA_DataSetMessage_decodeBinary(src, offset,
                                            &dst->payload.dataSetPayload.dataSetMessages[0],
                                            0, customTypes, dsm);
    } else {
        for(UA_Byte i = 0; i < count; i++) {
            rv = UA_DataSetMessage_decodeBinary(src, offset,
                                                &dst->payload.dataSetPayload.dataSetMessages[i],
                                                dst->payload.dataSetPayload.sizes[i], customTypes,
                                                dsm);
        }
    }
    UA_CHECK_STATUS(rv, return rv);

    return UA_STATUSCODE_GOOD;

    /**
     * TODO: check if making the cleanup to free its own allocated memory is better,
     *       currently the free happens in a parent context
     */
}

UA_StatusCode
UA_NetworkMessage_decodeFooters(const UA_ByteString *src, size_t *offset,
                                UA_NetworkMessage *dst) {
    if(!dst->securityEnabled)
        return UA_STATUSCODE_GOOD;

    // SecurityFooter
    UA_StatusCode rv = UA_STATUSCODE_GOOD;
    if(dst->securityHeader.securityFooterEnabled &&
       dst->securityHeader.securityFooterSize > 0) {
        rv = UA_ByteString_allocBuffer(&dst->securityFooter,
                                       dst->securityHeader.securityFooterSize);
        UA_CHECK_STATUS(rv, return rv);

        for(UA_UInt16 i = 0; i < dst->securityHeader.securityFooterSize; i++) {
            rv |= UA_Byte_decodeBinary(src, offset, &dst->securityFooter.data[i]);
        }
    }
    return rv;
}

UA_StatusCode
UA_NetworkMessage_decodeBinary(const UA_ByteString *src, size_t *offset,
                               UA_NetworkMessage* dst,
                               const UA_DataTypeArray *customTypes) {
    /* headers only need to be decoded when not in encryption mode
     * because headers are already decoded when encryption mode is enabled
     * to check for security parameters and decrypt/verify
     *
     * TODO: check if there is a workaround to use this function
     *       also when encryption is enabled
     */
    // #ifndef UA_ENABLE_PUBSUB_ENCRYPTION
    // if(*offset == 0) {
    //    rv = UA_NetworkMessage_decodeHeaders(src, offset, dst);
    //    UA_CHECK_STATUS(rv, return rv);
    // }
    // #endif

    UA_StatusCode rv = UA_NetworkMessage_decodeHeaders(src, offset, dst);
    UA_CHECK_STATUS(rv, return rv);

    rv = UA_NetworkMessage_decodePayload(src, offset, dst, customTypes, NULL);
    UA_CHECK_STATUS(rv, return rv);

    rv = UA_NetworkMessage_decodeFooters(src, offset, dst);
    UA_CHECK_STATUS(rv, return rv);

    return UA_STATUSCODE_GOOD;
}

static UA_Boolean
increaseOffsetArray(UA_NetworkMessageOffsetBuffer *offsetBuffer) {
    UA_NetworkMessageOffset *tmpOffsets = (UA_NetworkMessageOffset *)
        UA_realloc(offsetBuffer->offsets,
                   sizeof(UA_NetworkMessageOffset) *
                   (offsetBuffer->offsetsSize + (size_t)1));
    UA_CHECK_MEM(tmpOffsets, return false);

    offsetBuffer->offsets = tmpOffsets;
    offsetBuffer->offsetsSize++;
    return true;
}

size_t
UA_NetworkMessage_calcSizeBinary(UA_NetworkMessage *p,
                                 UA_NetworkMessageOffsetBuffer *offsetBuffer) {
    size_t size = 1; /* byte */
    if(UA_NetworkMessage_ExtendedFlags1Enabled(p)) {
        size += 1; /* byte */
        if(UA_NetworkMessage_ExtendedFlags2Enabled(p))
            size += 1; /* byte */
    }

    if(p->publisherIdEnabled) {
        if(offsetBuffer) {
            size_t pos = offsetBuffer->offsetsSize;
            if(!increaseOffsetArray(offsetBuffer))
                return 0;

            offsetBuffer->offsets[pos].offset = size;
            offsetBuffer->offsets[pos].contentType = UA_PUBSUB_OFFSETTYPE_PUBLISHERID;
        }

        switch(p->publisherIdType) {
            case UA_PUBLISHERIDTYPE_BYTE:
                size += 1; /* byte */
                break;
            case UA_PUBLISHERIDTYPE_UINT16:
                size += 2; /* uint16 */
                break;
            case UA_PUBLISHERIDTYPE_UINT32:
                size += 4; /* uint32 */
                break;
            case UA_PUBLISHERIDTYPE_UINT64:
                size += 8; /* uint64 */
                break;
            case UA_PUBLISHERIDTYPE_STRING:
                size += UA_String_calcSizeBinary(&p->publisherId.string);
                break;
        }
    }

    if(p->dataSetClassIdEnabled)
        size += 16; /* guid */

    // Group Header
    if(p->groupHeaderEnabled) {
        size += 1; /* byte */

        if(p->groupHeader.writerGroupIdEnabled) {
            if(offsetBuffer) {
                size_t pos = offsetBuffer->offsetsSize;
                if(!increaseOffsetArray(offsetBuffer))
                    return 0;

                offsetBuffer->offsets[pos].offset = size;
                offsetBuffer->offsets[pos].contentType = UA_PUBSUB_OFFSETTYPE_WRITERGROUPID;
            }
            size += 2; /* UA_UInt16_calcSizeBinary(&p->groupHeader.writerGroupId) */
        }

        if(p->groupHeader.groupVersionEnabled)
            size += 4; /* UA_UInt32_calcSizeBinary(&p->groupHeader.groupVersion) */

        if(p->groupHeader.networkMessageNumberEnabled) {
            size += 2; /* UA_UInt16_calcSizeBinary(&p->groupHeader.networkMessageNumber) */
        }

        if(p->groupHeader.sequenceNumberEnabled){
            if(offsetBuffer){
                size_t pos = offsetBuffer->offsetsSize;
                if(!increaseOffsetArray(offsetBuffer))
                    return 0;
                offsetBuffer->offsets[pos].offset = size;
                offsetBuffer->offsets[pos].content.sequenceNumber =
                    p->groupHeader.sequenceNumber;
                offsetBuffer->offsets[pos].contentType =
                    UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_SEQUENCENUMBER;
            }
            size += 2; /* UA_UInt16_calcSizeBinary(&p->groupHeader.sequenceNumber) */
        }
    }

    // Payload Header
    if(p->payloadHeaderEnabled) {
        if(p->networkMessageType != UA_NETWORKMESSAGE_DATASET)
            return 0; /* not implemented */
        if(!p->payloadHeader.dataSetPayloadHeader.dataSetWriterIds)
            return 0; /* no dataSetWriterIds given! */
        size += 1; /* p->payloadHeader.dataSetPayloadHeader.count */
        if(offsetBuffer) {
            size_t pos = offsetBuffer->offsetsSize;
            if(!increaseOffsetArray(offsetBuffer))
                return 0;
            offsetBuffer->offsets[pos].offset = size;
            offsetBuffer->offsets[pos].contentType = UA_PUBSUB_OFFSETTYPE_DATASETWRITERID;
        }
        size += (size_t)(2LU * p->payloadHeader.dataSetPayloadHeader.count); /* uint16 */
    }

    if(p->timestampEnabled) {
        if(offsetBuffer){
            size_t pos = offsetBuffer->offsetsSize;
            if(!increaseOffsetArray(offsetBuffer))
                return 0;
            offsetBuffer->offsets[pos].offset = size;
            offsetBuffer->offsets[pos].contentType = UA_PUBSUB_OFFSETTYPE_TIMESTAMP;
        }
        size += 8; /* UA_DateTime_calcSizeBinary(&p->timestamp) */
    }

    if(p->picosecondsEnabled){
        if(offsetBuffer) {
            size_t pos = offsetBuffer->offsetsSize;
            if(!increaseOffsetArray(offsetBuffer))
                return 0;
            offsetBuffer->offsets[pos].offset = size;
            offsetBuffer->offsets[pos].contentType = UA_PUBSUB_OFFSETTYPE_TIMESTAMP_PICOSECONDS;
        }
        size += 2; /* UA_UInt16_calcSizeBinary(&p->picoseconds) */
    }

    if(p->promotedFieldsEnabled) {
        size += 2; /* UA_UInt16_calcSizeBinary(&p->promotedFieldsSize) */
        for(UA_UInt16 i = 0; i < p->promotedFieldsSize; i++)
            size += UA_Variant_calcSizeBinary(&p->promotedFields[i]);
    }

    if(p->securityEnabled) {
        size += 1; /* UA_Byte_calcSizeBinary(&byte) */
        size += 4; /* UA_UInt32_calcSizeBinary(&p->securityHeader.securityTokenId) */
        size += 1; /* UA_Byte_calcSizeBinary(&p->securityHeader.nonceLength) */
        size += p->securityHeader.messageNonceSize;
        if(p->securityHeader.securityFooterEnabled)
            size += 2; /* UA_UInt16_calcSizeBinary(&p->securityHeader.securityFooterSize) */
    }

    /* Encode the payload */
    if(p->networkMessageType != UA_NETWORKMESSAGE_DATASET)
        return 0; /* not implemented */
    UA_Byte count = 1;
    if(p->payloadHeaderEnabled) {
        count = p->payloadHeader.dataSetPayloadHeader.count;
        if(count > 1)
            size += (size_t)(2LU * count); /* uint16 */
    }
    for(size_t i = 0; i < count; i++) {
        UA_DataSetMessage *dsm = &p->payload.dataSetPayload.dataSetMessages[i];
        size = UA_DataSetMessage_calcSizeBinary(dsm, offsetBuffer, size);
    }

    if(p->securityEnabled && p->securityHeader.securityFooterEnabled)
        size += p->securityHeader.securityFooterSize;

    return size;
}

void
UA_NetworkMessage_clear(UA_NetworkMessage* p) {
    if(p->promotedFieldsEnabled) {
        UA_Array_delete(p->promotedFields, p->promotedFieldsSize,
                        &UA_TYPES[UA_TYPES_VARIANT]);
    }

    if(p->networkMessageType == UA_NETWORKMESSAGE_DATASET) {
        if(p->payloadHeader.dataSetPayloadHeader.dataSetWriterIds &&
           p->payloadHeader.dataSetPayloadHeader.dataSetWriterIds != UA_EMPTY_ARRAY_SENTINEL)
            UA_free(p->payloadHeader.dataSetPayloadHeader.dataSetWriterIds);

        if(p->payload.dataSetPayload.sizes)
            UA_free(p->payload.dataSetPayload.sizes);

        if(p->payload.dataSetPayload.dataSetMessages) {
            UA_Byte count = 1;
            if(p->payloadHeaderEnabled)
                count = p->payloadHeader.dataSetPayloadHeader.count;
            for(size_t i = 0; i < count; i++)
                UA_DataSetMessage_clear(&p->payload.dataSetPayload.dataSetMessages[i]);
            UA_free(p->payload.dataSetPayload.dataSetMessages);
        }
    }

    UA_ByteString_clear(&p->securityFooter);
    UA_String_clear(&p->messageId);

    if(p->publisherIdEnabled &&
       p->publisherIdType == UA_PUBLISHERIDTYPE_STRING)
       UA_String_clear(&p->publisherId.string);

    memset(p, 0, sizeof(UA_NetworkMessage));
}

UA_Boolean
UA_NetworkMessage_ExtendedFlags1Enabled(const UA_NetworkMessage* src) {
    if(src->publisherIdType != UA_PUBLISHERIDTYPE_BYTE ||
       src->dataSetClassIdEnabled || src->securityEnabled ||
       src->timestampEnabled || src->picosecondsEnabled ||
       UA_NetworkMessage_ExtendedFlags2Enabled(src))
        return true;
    return false;
}

UA_Boolean
UA_NetworkMessage_ExtendedFlags2Enabled(const UA_NetworkMessage* src) {
    if(src->chunkMessage || src->promotedFieldsEnabled ||
       src->networkMessageType != UA_NETWORKMESSAGE_DATASET)
        return true;
    return false;
}

UA_Boolean
UA_DataSetMessageHeader_DataSetFlags2Enabled(const UA_DataSetMessageHeader* src) {
    if(src->dataSetMessageType != UA_DATASETMESSAGE_DATAKEYFRAME ||
       src->timestampEnabled || src->picoSecondsIncluded)
        return true;
    return false;
}

UA_StatusCode
UA_DataSetMessageHeader_encodeBinary(const UA_DataSetMessageHeader* src, UA_Byte **bufPos,
                                     const UA_Byte *bufEnd) {
    UA_Byte v;
    // DataSetFlags1
    v = (UA_Byte)src->fieldEncoding;
    // shift left 1 bit
    v = (UA_Byte)(v << DS_MH_SHIFT_LEN);

    if(src->dataSetMessageValid)
        v |= DS_MESSAGEHEADER_DS_MSG_VALID;

    if(src->dataSetMessageSequenceNrEnabled)
        v |= DS_MESSAGEHEADER_SEQ_NR_ENABLED_MASK;

    if(src->statusEnabled)
        v |= DS_MESSAGEHEADER_STATUS_ENABLED_MASK;

    if(src->configVersionMajorVersionEnabled)
        v |= DS_MESSAGEHEADER_CONFIGMAJORVERSION_ENABLED_MASK;

    if(src->configVersionMinorVersionEnabled)
        v |= DS_MESSAGEHEADER_CONFIGMINORVERSION_ENABLED_MASK;

    if(UA_DataSetMessageHeader_DataSetFlags2Enabled(src))
        v |= DS_MESSAGEHEADER_FLAGS2_ENABLED_MASK;

    UA_StatusCode rv = UA_Byte_encodeBinary(&v, bufPos, bufEnd);
    UA_CHECK_STATUS(rv, return rv);

    // DataSetFlags2
    if(UA_DataSetMessageHeader_DataSetFlags2Enabled(src)) {
        v = (UA_Byte)src->dataSetMessageType;

        if(src->timestampEnabled)
            v |= DS_MESSAGEHEADER_TIMESTAMP_ENABLED_MASK;

        if(src->picoSecondsIncluded)
            v |= DS_MESSAGEHEADER_PICOSECONDS_INCLUDED_MASK;

        rv = UA_Byte_encodeBinary(&v, bufPos, bufEnd);
        UA_CHECK_STATUS(rv, return rv);
    }

    // DataSetMessageSequenceNr
    if(src->dataSetMessageSequenceNrEnabled) {
        rv = UA_UInt16_encodeBinary(&src->dataSetMessageSequenceNr, bufPos, bufEnd);
        UA_CHECK_STATUS(rv, return rv);
    }

    // Timestamp
    if(src->timestampEnabled) {
        rv = UA_DateTime_encodeBinary(&src->timestamp, bufPos, bufEnd); /* UtcTime */
        UA_CHECK_STATUS(rv, return rv);
    }

    // PicoSeconds
    if(src->picoSecondsIncluded) {
        rv = UA_UInt16_encodeBinary(&src->picoSeconds, bufPos, bufEnd);
        UA_CHECK_STATUS(rv, return rv);
    }

    // Status
    if(src->statusEnabled) {
        rv = UA_UInt16_encodeBinary(&src->status, bufPos, bufEnd);
        UA_CHECK_STATUS(rv, return rv);
    }

    // ConfigVersionMajorVersion
    if(src->configVersionMajorVersionEnabled) {
        rv = UA_UInt32_encodeBinary(&src->configVersionMajorVersion, bufPos, bufEnd);
        UA_CHECK_STATUS(rv, return rv);
    }

    // ConfigVersionMinorVersion
    if(src->configVersionMinorVersionEnabled) {
        rv = UA_UInt32_encodeBinary(&src->configVersionMinorVersion, bufPos, bufEnd);
        UA_CHECK_STATUS(rv, return rv);
    }

    return UA_STATUSCODE_GOOD;
}

#ifdef UA_ENABLE_PUBSUB_ENCRYPTION

UA_StatusCode
UA_NetworkMessage_signEncrypt(UA_NetworkMessage *nm, UA_MessageSecurityMode securityMode,
                              UA_PubSubSecurityPolicy *policy, void *policyContext,
                              UA_Byte *messageStart, UA_Byte *encryptStart,
                              UA_Byte *sigStart) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;

    /* Encrypt the payload */
    if(securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
        /* Set the temporary MessageNonce in the SecurityPolicy */
        const UA_ByteString nonce = {
            (size_t)nm->securityHeader.messageNonceSize,
            nm->securityHeader.messageNonce
        };
        res = policy->setMessageNonce(policyContext, &nonce);
        UA_CHECK_STATUS(res, return res);

        /* The encryption is done in-place, no need to encode again */
        UA_ByteString encryptBuf;
        encryptBuf.data = encryptStart;
        encryptBuf.length = (uintptr_t)sigStart - (uintptr_t)encryptStart;
        res = policy->symmetricModule.cryptoModule.encryptionAlgorithm.
            encrypt(policyContext, &encryptBuf);
        UA_CHECK_STATUS(res, return res);
    }

    /* Sign the entire message */
    if(securityMode == UA_MESSAGESECURITYMODE_SIGN ||
       securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
        UA_ByteString sigBuf;
        sigBuf.length = (uintptr_t)sigStart - (uintptr_t)messageStart;
        sigBuf.data = messageStart;
        size_t sigSize = policy->symmetricModule.cryptoModule.
            signatureAlgorithm.getLocalSignatureSize(policyContext);
        UA_ByteString sig = {sigSize, sigStart};
        res = policy->symmetricModule.cryptoModule.
            signatureAlgorithm.sign(policyContext, &sigBuf, &sig);
    }

    return res;
}
#endif

UA_StatusCode
UA_DataSetMessageHeader_decodeBinary(const UA_ByteString *src, size_t *offset,
                                     UA_DataSetMessageHeader* dst) {
    memset(dst, 0, sizeof(UA_DataSetMessageHeader));
    UA_Byte v = 0;
    UA_StatusCode rv = UA_Byte_decodeBinary(src, offset, &v);
    UA_CHECK_STATUS(rv, return rv);

    UA_Byte v2 = v & DS_MESSAGEHEADER_FIELD_ENCODING_MASK;
    v2 = (UA_Byte)(v2 >> DS_MH_SHIFT_LEN);
    dst->fieldEncoding = (UA_FieldEncoding)v2;

    if((v & DS_MESSAGEHEADER_DS_MSG_VALID) != 0)
        dst->dataSetMessageValid = true;

    if((v & DS_MESSAGEHEADER_SEQ_NR_ENABLED_MASK) != 0)
        dst->dataSetMessageSequenceNrEnabled = true;

    if((v & DS_MESSAGEHEADER_STATUS_ENABLED_MASK) != 0)
        dst->statusEnabled = true;

    if((v & DS_MESSAGEHEADER_CONFIGMAJORVERSION_ENABLED_MASK) != 0)
        dst->configVersionMajorVersionEnabled = true;

    if((v & DS_MESSAGEHEADER_CONFIGMINORVERSION_ENABLED_MASK) != 0)
        dst->configVersionMinorVersionEnabled = true;

    if((v & DS_MESSAGEHEADER_FLAGS2_ENABLED_MASK) != 0) {
        v = 0;
        rv = UA_Byte_decodeBinary(src, offset, &v);
        UA_CHECK_STATUS(rv, return rv);

        dst->dataSetMessageType = (UA_DataSetMessageType)(v & DS_MESSAGEHEADER_DS_MESSAGE_TYPE_MASK);

        if((v & DS_MESSAGEHEADER_TIMESTAMP_ENABLED_MASK) != 0)
            dst->timestampEnabled = true;

        if((v & DS_MESSAGEHEADER_PICOSECONDS_INCLUDED_MASK) != 0)
            dst->picoSecondsIncluded = true;
    } else {
        dst->dataSetMessageType = UA_DATASETMESSAGE_DATAKEYFRAME;
        dst->picoSecondsIncluded = false;
    }

    if(dst->dataSetMessageSequenceNrEnabled) {
        rv = UA_UInt16_decodeBinary(src, offset, &dst->dataSetMessageSequenceNr);
        UA_CHECK_STATUS(rv, return rv);
    } else {
        dst->dataSetMessageSequenceNr = 0;
    }

    if(dst->timestampEnabled) {
        rv = UA_DateTime_decodeBinary(src, offset, &dst->timestamp); /* UtcTime */
        UA_CHECK_STATUS(rv, return rv);
    } else {
        dst->timestamp = 0;
    }

    if(dst->picoSecondsIncluded) {
        rv = UA_UInt16_decodeBinary(src, offset, &dst->picoSeconds);
        UA_CHECK_STATUS(rv, return rv);
    } else {
        dst->picoSeconds = 0;
    }

    if(dst->statusEnabled) {
        rv = UA_UInt16_decodeBinary(src, offset, &dst->status);
        UA_CHECK_STATUS(rv, return rv);
    } else {
        dst->status = 0;
    }

    if(dst->configVersionMajorVersionEnabled) {
        rv = UA_UInt32_decodeBinary(src, offset, &dst->configVersionMajorVersion);
        UA_CHECK_STATUS(rv, return rv);
    } else {
        dst->configVersionMajorVersion = 0;
    }

    if(dst->configVersionMinorVersionEnabled) {
        rv = UA_UInt32_decodeBinary(src, offset, &dst->configVersionMinorVersion);
        UA_CHECK_STATUS(rv, return rv);
    } else {
        dst->configVersionMinorVersion = 0;
    }

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_DataSetMessage_keyFrame_encodeBinary(const UA_DataSetMessage* src, UA_Byte **bufPos,
                                        const UA_Byte *bufEnd) {
    /* Heartbeat: "DataSetMessage is a key frame that only contains header
     * information" */
    if(src->data.keyFrameData.fieldCount == 0)
        return UA_STATUSCODE_GOOD;

    UA_StatusCode rv;
    if(src->header.fieldEncoding != UA_FIELDENCODING_RAWDATA) {
        rv = UA_UInt16_encodeBinary(&src->data.keyFrameData.fieldCount,
                                    bufPos, bufEnd);
        UA_CHECK_STATUS(rv, return rv);
    }
    
    for(UA_UInt16 i = 0; i < src->data.keyFrameData.fieldCount; i++) {
        const UA_DataValue *v = &src->data.keyFrameData.dataSetFields[i];
        
        if(src->header.fieldEncoding == UA_FIELDENCODING_VARIANT) {
            rv = UA_Variant_encodeBinary(&v->value, bufPos, bufEnd);
        } else if(src->header.fieldEncoding == UA_FIELDENCODING_RAWDATA) {
            UA_FieldMetaData *fmd =
                &src->data.keyFrameData.dataSetMetaDataType->fields[i];
            // For arrays we need to encode the dimension sizes before the actual data
            size_t elementCount = 1;
            for(size_t cnt = 0; cnt < fmd->arrayDimensionsSize; cnt++) {
                elementCount *= fmd->arrayDimensions[cnt];
                rv = UA_UInt32_encodeBinary(&fmd->arrayDimensions[cnt], bufPos, bufEnd);
                UA_CHECK_STATUS(rv, return rv);
            }
            // Check if Array size matches the one specified in metadata
            if(fmd->valueRank > 0 && elementCount != v->value.arrayLength) {
                return UA_STATUSCODE_BADENCODINGERROR;
            }
            UA_Byte *valuePtr = (UA_Byte *)v->value.data;
            for(size_t cnt = 0; cnt < elementCount; cnt++) {
                if(fmd->maxStringLength != 0 &&
                   (v->value.type->typeKind == UA_DATATYPEKIND_STRING ||
                    v->value.type->typeKind == UA_DATATYPEKIND_BYTESTRING)) {
                    rv = UA_encodeBinaryInternal(valuePtr, v->value.type, bufPos, &bufEnd,
                                                 NULL, NULL);
                    size_t lengthDifference =
                        fmd->maxStringLength - ((UA_String *)valuePtr)->length;
                    memset(*bufPos, 0, lengthDifference);
                    *bufPos += lengthDifference;
                } else {
                    /* padding not yet supported for strings as part of structures */
                    rv = UA_encodeBinaryInternal(valuePtr, v->value.type, bufPos, &bufEnd,
                                                 NULL, NULL);
                }
                valuePtr += v->value.type->memSize;
            }
        } else if(src->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) {
            rv = UA_DataValue_encodeBinary(v, bufPos, bufEnd);
        }
        
        UA_CHECK_STATUS(rv, return rv);
    }
    return rv;
}

static UA_StatusCode
UA_DataSetMessage_deltaFrame_encodeBinary(const UA_DataSetMessage* src, UA_Byte **bufPos,
                                          const UA_Byte *bufEnd) {
    if(src->header.fieldEncoding == UA_FIELDENCODING_RAWDATA)
        return UA_STATUSCODE_BADNOTIMPLEMENTED;

    // Here the FieldCount is always present
    const UA_DataSetMessage_DataDeltaFrameData *dfd = &src->data.deltaFrameData;
    UA_StatusCode rv = UA_UInt16_encodeBinary(&dfd->fieldCount, bufPos, bufEnd);
    if(src->header.fieldEncoding == UA_FIELDENCODING_VARIANT) {
        for(UA_UInt16 i = 0; i < dfd->fieldCount; i++) {
            rv |= UA_UInt16_encodeBinary(&dfd->deltaFrameFields[i].fieldIndex,
                                         bufPos, bufEnd);
            rv |= UA_Variant_encodeBinary(&dfd->deltaFrameFields[i].fieldValue.value,
                                         bufPos, bufEnd);
        }
    } else if(src->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) {
        for(UA_UInt16 i = 0; i < dfd->fieldCount; i++) {
            rv |= UA_UInt16_encodeBinary(&dfd->deltaFrameFields[i].fieldIndex,
                                         bufPos, bufEnd);
            rv |= UA_DataValue_encodeBinary(&dfd->deltaFrameFields[i].fieldValue,
                                            bufPos, bufEnd);
        }
    }
    return rv;
}

UA_StatusCode
UA_DataSetMessage_encodeBinary(const UA_DataSetMessage* src, UA_Byte **bufPos,
                               const UA_Byte *bufEnd) {
    /* Encode Header */
    UA_StatusCode rv = UA_DataSetMessageHeader_encodeBinary(&src->header,
                                                            bufPos, bufEnd);
    UA_CHECK_STATUS(rv, return rv);

    /* Encode Payload */
    switch(src->header.dataSetMessageType) {
    case UA_DATASETMESSAGE_DATAKEYFRAME:
        rv = UA_DataSetMessage_keyFrame_encodeBinary(src, bufPos, bufEnd);
        break;
    case UA_DATASETMESSAGE_DATADELTAFRAME:
        rv = UA_DataSetMessage_deltaFrame_encodeBinary(src, bufPos, bufEnd);
        break;
    case UA_DATASETMESSAGE_KEEPALIVE:
        break; /* Keep-Alive Message contains no Payload Data */
    default:
        return UA_STATUSCODE_BADNOTIMPLEMENTED;
    }

    /* Padding */
    if(src->configuredSize > 0 && src->header.dataSetMessageValid) {
        size_t padding = (size_t)(bufEnd - *bufPos);
        memset(*bufPos, 0, padding); /* Set the bytes to 0*/
        *bufPos += padding; /* move the bufpos accordingly*/
    }
    UA_CHECK_STATUS(rv, return rv);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_DataSetMessage_keyFrame_decodeBinary(const UA_ByteString *src, size_t *offset,
                                        size_t initialOffset, UA_DataSetMessage* dst,
                                        UA_UInt16 dsmSize, const UA_DataTypeArray *customTypes,
                                        UA_DataSetMetaDataType *dsm) {
    if(*offset == src->length)
        return UA_STATUSCODE_GOOD; /* Messages ends after the header --> Heartbeat */

    UA_StatusCode rv = UA_STATUSCODE_GOOD;
    UA_DataSetMessage_DataKeyFrameData *kfd = &dst->data.keyFrameData;
    switch(dst->header.fieldEncoding) {
    case UA_FIELDENCODING_VARIANT:
        rv = UA_UInt16_decodeBinary(src, offset, &kfd->fieldCount);
        UA_CHECK_STATUS(rv, return rv);

        kfd->dataSetFields = (UA_DataValue *)
            UA_Array_new(dst->data.keyFrameData.fieldCount,
                         &UA_TYPES[UA_TYPES_DATAVALUE]);
        if(!kfd->dataSetFields) {
            kfd->fieldCount = 0;
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }

        for(UA_UInt16 i = 0; i < kfd->fieldCount; i++) {
            UA_DataValue_init(&kfd->dataSetFields[i]);
            rv = UA_decodeBinaryInternal(src, offset, &kfd->dataSetFields[i].value,
                                         &UA_TYPES[UA_TYPES_VARIANT], customTypes);
            UA_CHECK_STATUS(rv, return rv);
            kfd->dataSetFields[i].hasValue = true;
        }
        break;

    case UA_FIELDENCODING_DATAVALUE:
        rv = UA_UInt16_decodeBinary(src, offset, &kfd->fieldCount);
        UA_CHECK_STATUS(rv, return rv);

        kfd->dataSetFields = (UA_DataValue *)
            UA_Array_new(kfd->fieldCount, &UA_TYPES[UA_TYPES_DATAVALUE]);
        if(!kfd->dataSetFields) {
            kfd->fieldCount = 0;
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }

        for(UA_UInt16 i = 0; i < kfd->fieldCount; i++) {
            rv = UA_decodeBinaryInternal(src, offset, &kfd->dataSetFields[i],
                                         &UA_TYPES[UA_TYPES_DATAVALUE], customTypes);
            UA_CHECK_STATUS(rv, return rv);
        }
        break;

    case UA_FIELDENCODING_RAWDATA:
        kfd->rawFields.data = &src->data[*offset];
        kfd->rawFields.length = dsmSize;
        if(dsmSize != 0) {
            *offset += (dsmSize - (*offset - initialOffset));
            break;
        }

        if(dsm == NULL) {
            //TODO calculate the length of the DSM-Payload for a single DSM
            //Problem: Size is not set and MetaData information are needed.
            //Increase offset to avoid endless chunk loop. Needs to be fixed when
            //pubsub security footer and signatur is enabled.
            *offset += 1500;
            break;
        }

        // calculate the length of the DSM-Payload for a single DSM
        size_t tmpOffset = 0;
        dst->data.keyFrameData.fieldCount = (UA_UInt16)dsm->fieldsSize;
        for(size_t i = 0; i < dsm->fieldsSize; i++) {
            /* TODO The datatype reference should be part of the internal
             * pubsub configuration to avoid the time-expensive lookup */
            const UA_DataType *type =
                UA_findDataTypeWithCustom(&dsm->fields[i].dataType, customTypes);
            if(!type)
                return UA_STATUSCODE_BADINTERNALERROR;
            dst->data.keyFrameData.rawFields.length += type->memSize;
            UA_STACKARRAY(UA_Byte, value, type->memSize);
            rv = UA_decodeBinaryInternal(&dst->data.keyFrameData.rawFields,
                                         &tmpOffset, value, type, NULL);
            UA_CHECK_STATUS(rv, return rv); 
            if(dsm->fields[i].maxStringLength != 0) {
                if(type->typeKind == UA_DATATYPEKIND_STRING ||
                   type->typeKind == UA_DATATYPEKIND_BYTESTRING) {
                    UA_ByteString *bs = (UA_ByteString *) value;
                    // Check if length < maxStringLength, The types ByteString
                    // and String are equal in their base definition
                    size_t lengthDifference = dsm->fields[i].maxStringLength - bs->length;
                    tmpOffset += lengthDifference;
                    dst->data.keyFrameData.rawFields.length += lengthDifference;
                }
            }
            UA_clear(value, type);
        }
        break;

    default:
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    return rv;
}

static UA_StatusCode
UA_DataSetMessage_deltaFrame_decodeBinary(const UA_ByteString *src, size_t *offset,
                                          UA_DataSetMessage* dst, UA_UInt16 dsmSize,
                                          const UA_DataTypeArray *customTypes) {
    if(dst->header.fieldEncoding == UA_FIELDENCODING_RAWDATA)
        return UA_STATUSCODE_BADNOTIMPLEMENTED;

    if(dst->header.fieldEncoding != UA_FIELDENCODING_VARIANT &&
       dst->header.fieldEncoding != UA_FIELDENCODING_DATAVALUE)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_DataSetMessage_DataDeltaFrameData *dfd = &dst->data.deltaFrameData;
    UA_StatusCode rv = UA_UInt16_decodeBinary(src, offset, &dfd->fieldCount);
    UA_CHECK_STATUS(rv, return rv);

    dfd->deltaFrameFields = (UA_DataSetMessage_DeltaFrameField*)
        UA_calloc(dfd->fieldCount, sizeof(UA_DataSetMessage_DeltaFrameField));
    if(!dst->data.deltaFrameData.deltaFrameFields) {
        dfd->fieldCount = 0;
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    for(UA_UInt16 i = 0; i < dfd->fieldCount; i++) {
        rv = UA_UInt16_decodeBinary(src, offset, &dfd->deltaFrameFields[i].fieldIndex);
        UA_CHECK_STATUS(rv, return rv);

        if(dst->header.fieldEncoding == UA_FIELDENCODING_VARIANT) {
            rv = UA_decodeBinaryInternal(src, offset,
                                         &dfd->deltaFrameFields[i].fieldValue.value,
                                         &UA_TYPES[UA_TYPES_VARIANT], customTypes);
            UA_CHECK_STATUS(rv, return rv);
            dfd->deltaFrameFields[i].fieldValue.hasValue = true;
        } else {
            rv = UA_decodeBinaryInternal(src, offset,
                                         &dfd->deltaFrameFields[i].fieldValue,
                                         &UA_TYPES[UA_TYPES_DATAVALUE], customTypes);
            UA_CHECK_STATUS(rv, return rv);
        }
    }

    return rv;
}

UA_StatusCode
UA_DataSetMessage_decodeBinary(const UA_ByteString *src, size_t *offset,
                               UA_DataSetMessage* dst, UA_UInt16 dsmSize,
                               const UA_DataTypeArray *customTypes, UA_DataSetMetaDataType *dsm) {
    size_t initialOffset = *offset;
    memset(dst, 0, sizeof(UA_DataSetMessage));
    UA_StatusCode rv = UA_DataSetMessageHeader_decodeBinary(src, offset, &dst->header);
    UA_CHECK_STATUS(rv, return rv);

    switch(dst->header.dataSetMessageType) {
    case UA_DATASETMESSAGE_DATAKEYFRAME:
        rv = UA_DataSetMessage_keyFrame_decodeBinary(src, offset, initialOffset, dst,
                                                     dsmSize, customTypes, dsm);
        break;
    case UA_DATASETMESSAGE_DATADELTAFRAME:
        rv = UA_DataSetMessage_deltaFrame_decodeBinary(src, offset, dst,
                                                       dsmSize, customTypes);
        break;
    case UA_DATASETMESSAGE_KEEPALIVE:
        break; /* Keep-Alive Message contains no Payload Data */
    default:
        return UA_STATUSCODE_BADNOTIMPLEMENTED;
    }

    return rv;
}

size_t
UA_DataSetMessage_calcSizeBinary(UA_DataSetMessage* p,
                                 UA_NetworkMessageOffsetBuffer *offsetBuffer,
                                 size_t currentOffset) {
    size_t size = currentOffset;

    if(offsetBuffer) {
        size_t pos = offsetBuffer->offsetsSize;
        if(!increaseOffsetArray(offsetBuffer))
            return 0;
        offsetBuffer->offsets[pos].offset = size;
        UA_DataValue_init(&offsetBuffer->offsets[pos].content.value);
        UA_Variant_setScalar(&offsetBuffer->offsets[pos].content.value.value,
                             &p->header.fieldEncoding, &UA_TYPES[UA_TYPES_UINT32]);
        offsetBuffer->offsets[pos].contentType =
            UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_FIELDENCDODING;
    }

    size += 1; /* byte: DataSetMessage Type + Flags */
    if(UA_DataSetMessageHeader_DataSetFlags2Enabled(&p->header))
        size += 1; /* byte */

    if(p->header.dataSetMessageSequenceNrEnabled) {
        if(offsetBuffer) {
            size_t pos = offsetBuffer->offsetsSize;
            if(!increaseOffsetArray(offsetBuffer))
                return 0;
            offsetBuffer->offsets[pos].offset = size;
            offsetBuffer->offsets[pos].content.sequenceNumber =
                p->header.dataSetMessageSequenceNr;
            offsetBuffer->offsets[pos].contentType =
                UA_PUBSUB_OFFSETTYPE_DATASETMESSAGE_SEQUENCENUMBER;
        }
        size += 2; /* UA_UInt16_calcSizeBinary(&p->header.dataSetMessageSequenceNr) */
    }

    if(p->header.timestampEnabled)
        size += 8; /* UA_DateTime_calcSizeBinary(&p->header.timestamp) */

    if(p->header.picoSecondsIncluded)
        size += 2; /* UA_UInt16_calcSizeBinary(&p->header.picoSeconds) */

    if(p->header.statusEnabled)
        size += 2; /* UA_UInt16_calcSizeBinary(&p->header.status) */

    if(p->header.configVersionMajorVersionEnabled)
        size += 4; /* UA_UInt32_calcSizeBinary(&p->header.configVersionMajorVersion) */

    if(p->header.configVersionMinorVersionEnabled)
        size += 4; /* UA_UInt32_calcSizeBinary(&p->header.configVersionMinorVersion) */

    /* Keyframe with no fields is a heartbeat */
    if(p->header.dataSetMessageType == UA_DATASETMESSAGE_KEEPALIVE ||
       (p->header.dataSetMessageType == UA_DATASETMESSAGE_DATAKEYFRAME &&
        p->data.keyFrameData.fieldCount == 0))
        return size;

    if(p->header.dataSetMessageType == UA_DATASETMESSAGE_DATAKEYFRAME) {
        if(p->header.fieldEncoding != UA_FIELDENCODING_RAWDATA)
            size += 2; /* p->data.keyFrameData.fieldCount */

        for(UA_UInt16 i = 0; i < p->data.keyFrameData.fieldCount; i++){
            UA_NetworkMessageOffset *nmo = NULL;
            const UA_DataValue *v = &p->data.keyFrameData.dataSetFields[i];
            if(offsetBuffer) {
                size_t pos = offsetBuffer->offsetsSize;
                if(!increaseOffsetArray(offsetBuffer))
                    return 0;
                nmo = &offsetBuffer->offsets[pos];
                nmo->offset = size;
                if(p->data.keyFrameData.dataSetFields != NULL) {
                    nmo->content.value = *v;
                    nmo->content.value.value.storageType = UA_VARIANT_DATA_NODELETE;
                } else {
                   UA_DataValue_init(&nmo->content.value);
                }
            }

            if(p->header.fieldEncoding == UA_FIELDENCODING_VARIANT) {
                if(offsetBuffer)
                    nmo->contentType = UA_PUBSUB_OFFSETTYPE_PAYLOAD_VARIANT;
                size += UA_calcSizeBinary(&v->value, &UA_TYPES[UA_TYPES_VARIANT]);
            } else if(p->header.fieldEncoding == UA_FIELDENCODING_RAWDATA) {
                if(p->data.keyFrameData.dataSetFields != NULL) {
                    if(offsetBuffer) {
                        if(!v->value.type->pointerFree)
                            return 0; /* only integer types for now */
                        /* Count the memory size of the specific field */
                        offsetBuffer->rawMessageLength += v->value.type->memSize;
                        nmo->contentType = UA_PUBSUB_OFFSETTYPE_PAYLOAD_RAW;
                    }
                    UA_FieldMetaData *fmd =
                        &p->data.keyFrameData.dataSetMetaDataType->fields[i];
                    // For arrays add encoded array length (4 bytes for each dimension)
                    size += fmd->arrayDimensionsSize * sizeof(UA_UInt32);
                    // We need to know how many elements there are
                    size_t elemCnt = 1;
                    for(size_t cnt = 0; cnt < fmd->arrayDimensionsSize; cnt++) {
                        elemCnt *= fmd->arrayDimensions[cnt];
                    }
                    size += (elemCnt * UA_calcSizeBinary(v->value.data, v->value.type));

                    /* Handle zero-padding for strings with max-string-length.
                     * Currently not supported for strings that are a part of larger
                     * structures. */
                    if(fmd->maxStringLength != 0 &&
                       (v->value.type->typeKind == UA_DATATYPEKIND_STRING ||
                        v->value.type->typeKind == UA_DATATYPEKIND_BYTESTRING)) {
                        /* Check if length < maxStringLength, The types ByteString
                         * and String are equal in their base definition */
                        size_t lengthDifference = fmd->maxStringLength -
                            ((UA_String *)v->value.data)->length;
                        size += lengthDifference;
                    }
                } else {
                    /* get length calculated in UA_DataSetMessage_decodeBinary */
                    if(offsetBuffer) {
                        offsetBuffer->rawMessageLength = p->data.keyFrameData.rawFields.length;
                        nmo->contentType = UA_PUBSUB_OFFSETTYPE_PAYLOAD_RAW;
                    }
                    size += p->data.keyFrameData.rawFields.length;
                    /* no iteration needed */
                    break;
                }
            } else if(p->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE) {
                if(offsetBuffer)
                    nmo->contentType = UA_PUBSUB_OFFSETTYPE_PAYLOAD_DATAVALUE;
                size += UA_calcSizeBinary(v, &UA_TYPES[UA_TYPES_DATAVALUE]);
            }
        }
    } else if(p->header.dataSetMessageType == UA_DATASETMESSAGE_DATADELTAFRAME) {
        if(offsetBuffer)
            return 0; /* Not supported for RT */

        if(p->header.fieldEncoding == UA_FIELDENCODING_RAWDATA)
            return 0; /* not supported */

        size += 2; /* p->data.deltaFrameData.fieldCount */
        size += (size_t)(2LU * p->data.deltaFrameData.fieldCount); /* fieldIndex per field */

        for(UA_UInt16 i = 0; i < p->data.deltaFrameData.fieldCount; i++) {
            const UA_DataValue *v = &p->data.deltaFrameData.deltaFrameFields[i].fieldValue;
            if(p->header.fieldEncoding == UA_FIELDENCODING_VARIANT)
                size += UA_calcSizeBinary(&v->value, &UA_TYPES[UA_TYPES_VARIANT]);
            else if(p->header.fieldEncoding == UA_FIELDENCODING_DATAVALUE)
                size += UA_calcSizeBinary(v, &UA_TYPES[UA_TYPES_DATAVALUE]);
        }
    } else {
        return 0;
    }

    if(p->configuredSize > 0) {
        /* If the message is larger than the configuredSize, it shall be set to not valid */
        if(p->configuredSize < size) 
            p->header.dataSetMessageValid = UA_FALSE;
        
        size = p->configuredSize;
    }
    
    /* KeepAlive-Message contains no Payload Data */
    return size;
}

void
UA_DataSetMessage_clear(UA_DataSetMessage* p) {
    if(p->header.dataSetMessageType == UA_DATASETMESSAGE_DATAKEYFRAME) {
        if(p->data.keyFrameData.dataSetFields) {
            UA_Array_delete(p->data.keyFrameData.dataSetFields,
                            p->data.keyFrameData.fieldCount,
                            &UA_TYPES[UA_TYPES_DATAVALUE]);
        }

        /* Json keys */
        if(p->data.keyFrameData.fieldNames){
            UA_Array_delete(p->data.keyFrameData.fieldNames,
                            p->data.keyFrameData.fieldCount,
                            &UA_TYPES[UA_TYPES_STRING]);
        }
    } else if(p->header.dataSetMessageType == UA_DATASETMESSAGE_DATADELTAFRAME) {
        if(p->data.deltaFrameData.deltaFrameFields) {
            for(UA_UInt16 i = 0; i < p->data.deltaFrameData.fieldCount; i++) {
                UA_DataSetMessage_DeltaFrameField *f =
                    &p->data.deltaFrameData.deltaFrameFields[i];
                UA_DataValue_clear(&f->fieldValue);
            }
            UA_free(p->data.deltaFrameData.deltaFrameFields);
        }
    }

    memset(p, 0, sizeof(UA_DataSetMessage));
}

void
UA_NetworkMessageOffsetBuffer_clear(UA_NetworkMessageOffsetBuffer *nmob) {
    UA_ByteString_clear(&nmob->buffer);

    if(nmob->nm) {
        UA_NetworkMessage_clear(nmob->nm);
        UA_free(nmob->nm);
    }

#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
    UA_ByteString_clear(&nmob->encryptBuffer);
#endif

    if(nmob->offsetsSize == 0)
        return;

    for(size_t i = 0; i < nmob->offsetsSize; i++) {
        UA_NetworkMessageOffset *offset = &nmob->offsets[i];
        if(offset->contentType == UA_PUBSUB_OFFSETTYPE_PAYLOAD_VARIANT ||
           offset->contentType == UA_PUBSUB_OFFSETTYPE_PAYLOAD_DATAVALUE ||
           offset->contentType == UA_PUBSUB_OFFSETTYPE_PAYLOAD_RAW) {
            UA_DataValue_clear(&offset->content.value);
            continue;
        }

        if(offset->contentType == UA_PUBSUB_OFFSETTYPE_NETWORKMESSAGE_FIELDENCDODING) {
            offset->content.value.value.data = NULL;
            UA_DataValue_clear(&offset->content.value);
        }
    }

    UA_free(nmob->offsets);

    memset(nmob, 0, sizeof(UA_NetworkMessageOffsetBuffer));
}

#endif /* UA_ENABLE_PUBSUB */

/**** amalgamated original file "/src/pubsub/ua_pubsub_eventloop.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2023 Fraunhofer IOSB (Author: Julius Pfrommer)
 */


#ifdef UA_ENABLE_PUBSUB /* conditional compilation */

/********************/
/* PubSubConnection */
/********************/

static UA_StatusCode
UA_PubSubConnection_connectUDP(UA_Server *server, UA_PubSubConnection *c,
                               UA_Boolean validate);

static UA_StatusCode
UA_PubSubConnection_connectETH(UA_Server *server, UA_PubSubConnection *c,
                               UA_Boolean validate);

static UA_StatusCode
UA_ReaderGroup_connectMQTT(UA_Server *server, UA_ReaderGroup *rg,
                           UA_Boolean validate);

static UA_StatusCode
UA_WriterGroup_connectMQTT(UA_Server *server, UA_WriterGroup *wg,
                           UA_Boolean validate);

static UA_StatusCode
UA_WriterGroup_connectUDPUnicast(UA_Server *server, UA_WriterGroup *wg,
                                 UA_Boolean validate);

#define UA_PUBSUB_PROFILES_SIZE 4

typedef struct  {
    UA_String profileURI;
    UA_String protocol;
    UA_Boolean json;
    UA_StatusCode (*connect)(UA_Server *server, UA_PubSubConnection *c,
                             UA_Boolean validate);
    UA_StatusCode (*connectWriterGroup)(UA_Server *server, UA_WriterGroup *wg,
                                        UA_Boolean validate);
    UA_StatusCode (*connectReaderGroup)(UA_Server *server, UA_ReaderGroup *rg,
                                        UA_Boolean validate);
} ProfileMapping;

static ProfileMapping transportProfiles[UA_PUBSUB_PROFILES_SIZE] = {
    {UA_STRING_STATIC("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp"),
     UA_STRING_STATIC("udp"), false, UA_PubSubConnection_connectUDP,
     UA_WriterGroup_connectUDPUnicast, NULL},
    {UA_STRING_STATIC("http://opcfoundation.org/UA-Profile/Transport/pubsub-mqtt-uadp"),
     UA_STRING_STATIC("mqtt"), false, NULL,
     UA_WriterGroup_connectMQTT, UA_ReaderGroup_connectMQTT},
    {UA_STRING_STATIC("http://opcfoundation.org/UA-Profile/Transport/pubsub-mqtt-json"),
     UA_STRING_STATIC("mqtt"), true, NULL,
     UA_WriterGroup_connectMQTT, UA_ReaderGroup_connectMQTT},
    {UA_STRING_STATIC("http://opcfoundation.org/UA-Profile/Transport/pubsub-eth-uadp"),
     UA_STRING_STATIC("eth"), false, UA_PubSubConnection_connectETH, NULL, NULL}
};

static ProfileMapping *
getProfile(UA_String profileUri) {    
    for(size_t profile = 0; profile < UA_PUBSUB_PROFILES_SIZE; profile++) {
        if(UA_String_equal(&profileUri, &transportProfiles[profile].profileURI))
            return &transportProfiles[profile];
    }
    return NULL;
}

static UA_ConnectionManager *
getCM(UA_EventLoop *el, UA_String protocol) {    
    for(UA_EventSource *es = el->eventSources; es != NULL; es = es->next) {
        if(es->eventSourceType != UA_EVENTSOURCETYPE_CONNECTIONMANAGER)
            continue;
        UA_ConnectionManager *cm = (UA_ConnectionManager*)es;
        if(UA_String_equal(&protocol, &cm->protocol))
            return cm;
    }
    return NULL;
}

static void
UA_PubSubConnection_removeConnection(UA_PubSubConnection *c,
                                     uintptr_t connectionId) {
    if(c->sendChannel == connectionId) {
        c->sendChannel = 0;
        return;
    }
    for(size_t i = 0; i < UA_PUBSUB_MAXCHANNELS; i++) {
        if(c->recvChannels[i] != connectionId)
            continue;
        c->recvChannels[i] = 0;
        c->recvChannelsSize--;
        return;
    }
}

static UA_StatusCode
UA_PubSubConnection_addSendConnection(UA_PubSubConnection *c,
                                      uintptr_t connectionId) {
    if(c->sendChannel != 0 && c->sendChannel != connectionId)
        return UA_STATUSCODE_BADINTERNALERROR;
    c->sendChannel = connectionId;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_PubSubConnection_addRecvConnection(UA_PubSubConnection *c,
                                      uintptr_t connectionId) {
    for(size_t i = 0; i < UA_PUBSUB_MAXCHANNELS; i++) {
        if(c->recvChannels[i] == connectionId)
            return UA_STATUSCODE_GOOD;
    }
    if(c->recvChannelsSize >= UA_PUBSUB_MAXCHANNELS)
        return UA_STATUSCODE_BADINTERNALERROR;
    for(size_t i = 0; i < UA_PUBSUB_MAXCHANNELS; i++) {
        if(c->recvChannels[i] != 0)
            continue;
        c->recvChannels[i] = connectionId;
        c->recvChannelsSize++;
        break;
    }
    return UA_STATUSCODE_GOOD;
}

void
UA_PubSubConnection_disconnect(UA_PubSubConnection *c) {   
    if(!c->cm)
        return;
    if(c->sendChannel != 0)
        c->cm->closeConnection(c->cm, c->sendChannel);
    for(size_t i = 0; i < UA_PUBSUB_MAXCHANNELS; i++) {
        if(c->recvChannels[i] != 0)
            c->cm->closeConnection(c->cm, c->recvChannels[i]);
    }
}

static void
PubSubChannelCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
                     void *application, void **connectionContext,
                     UA_ConnectionState state, const UA_KeyValueMap *params,
                     UA_ByteString msg, UA_Boolean recv) {
    if(!connectionContext)
        return;

    /* Get the context pointers */
    UA_Server *server = (UA_Server*)application;
    UA_PubSubConnection *psc = (UA_PubSubConnection*)*connectionContext;

    UA_LOCK(&server->serviceMutex);

    /* The connection is closing in the EventLoop. This is the last callback
     * from that connection. Clean up the SecureChannel in the client. */
    if(state == UA_CONNECTIONSTATE_CLOSING) {
        /* Reset the connection identifiers */
        UA_PubSubConnection_removeConnection(psc, connectionId);

        /* PSC marked for deletion and the last EventLoop connection has closed */
        if(psc->deleteFlag && psc->recvChannelsSize == 0 && psc->sendChannel == 0) {
            UA_PubSubConnection_delete(server, psc);
            UA_UNLOCK(&server->serviceMutex);
            return;
        }

        /* Reconnect automatically if the connection was operational. This sets
         * the connection state if connecting fails. Attention! If there are
         * several send or recv channels, then the connection is only reopened if
         * all of them close - which is usually the case. */
        if(psc->state == UA_PUBSUBSTATE_OPERATIONAL)
            UA_PubSubConnection_connect(server, psc, false);

        UA_UNLOCK(&server->serviceMutex);
        return;
    }

    /* Store the connectionId (if a new connection) */
    UA_StatusCode res = (recv) ?
        UA_PubSubConnection_addRecvConnection(psc, connectionId) :
        UA_PubSubConnection_addSendConnection(psc, connectionId);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_CONNECTION(server->config.logging, psc,
                                  "No more space for an additional EventLoop connection");
        if(psc->cm)
            psc->cm->closeConnection(psc->cm, connectionId);
        UA_UNLOCK(&server->serviceMutex);
        return;
    }

    /* Connection open, set to operational if not already done */
    UA_PubSubConnection_setPubSubState(server, psc, psc->state);

    /* Message received */
    if(UA_LIKELY(recv && msg.length > 0))
        UA_PubSubConnection_process(server, psc, msg);
    
    UA_UNLOCK(&server->serviceMutex);
}

static void
PubSubRecvChannelCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
                         void *application, void **connectionContext,
                         UA_ConnectionState state, const UA_KeyValueMap *params,
                         UA_ByteString msg) {
    PubSubChannelCallback(cm, connectionId, application, connectionContext,
                         state, params, msg, true);
}

static void
PubSubSendChannelCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
                         void *application, void **connectionContext,
                         UA_ConnectionState state, const UA_KeyValueMap *params,
                         UA_ByteString msg) {
    PubSubChannelCallback(cm, connectionId, application, connectionContext,
                         state, params, msg, false);
}

static UA_StatusCode
UA_PubSubConnection_connectUDP(UA_Server *server, UA_PubSubConnection *c,
                               UA_Boolean validate) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_NetworkAddressUrlDataType *addressUrl = (UA_NetworkAddressUrlDataType*)
        c->config.address.data;

    /* Extract hostname and port */
    UA_String address;
    UA_UInt16 port;
    UA_StatusCode res = UA_parseEndpointUrl(&addressUrl->url, &address, &port, NULL);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_CONNECTION(server->config.logging, c,
                                "Could not parse the UDP network URL");
        return res;
    }

    /* Detect a wildcard address for unicast receiving. The individual
     * DataSetWriters then contain additional target hostnames for sending.
     *
     * "localhost" and the empty hostname are used as a special "receive all"
     * wildcard for PubSub UDP. All other addresses (also the 127.0.0/8 and ::1
     * range) are handled differently. For them we only receive messages that
     * originate from these addresses.
     *
     * The EventLoop backend detects whether an address is multicast capable and
     * registers it for the multicast group in the background. */
    UA_String localhostAddr = UA_STRING_STATIC("localhost");
    UA_Boolean receive_all =
        (address.length == 0) || UA_String_equal(&localhostAddr, &address);

    /* Set up the connection parameters */
    UA_Boolean listen = true;
    UA_Boolean reuse = true;
    UA_Boolean loopback = true;
    UA_KeyValuePair kvp[7];
    UA_KeyValueMap kvm = {5, kvp};
    kvp[0].key = UA_QUALIFIEDNAME(0, "port");
    UA_Variant_setScalar(&kvp[0].value, &port, &UA_TYPES[UA_TYPES_UINT16]);
    kvp[1].key = UA_QUALIFIEDNAME(0, "listen");
    UA_Variant_setScalar(&kvp[1].value, &listen, &UA_TYPES[UA_TYPES_BOOLEAN]);
    kvp[2].key = UA_QUALIFIEDNAME(0, "validate");
    UA_Variant_setScalar(&kvp[2].value, &validate, &UA_TYPES[UA_TYPES_BOOLEAN]);
    kvp[3].key = UA_QUALIFIEDNAME(0, "reuse");
    UA_Variant_setScalar(&kvp[3].value, &reuse, &UA_TYPES[UA_TYPES_BOOLEAN]);
    kvp[4].key = UA_QUALIFIEDNAME(0, "loopback");
    UA_Variant_setScalar(&kvp[4].value, &loopback, &UA_TYPES[UA_TYPES_BOOLEAN]);
    if(!receive_all) {
        /* The "receive all" wildcard is different in the eventloop UDP layer.
         * Omit the address entirely to receive all.*/
        kvp[5].key = UA_QUALIFIEDNAME(0, "address");
        UA_Variant_setScalar(&kvp[5].value, &address, &UA_TYPES[UA_TYPES_STRING]);
        kvm.mapSize++;
    }
    if(!UA_String_isEmpty(&addressUrl->networkInterface)) {
        kvp[kvm.mapSize].key = UA_QUALIFIEDNAME(0, "interface");
        UA_Variant_setScalar(&kvp[kvm.mapSize].value, &addressUrl->networkInterface,
                             &UA_TYPES[UA_TYPES_STRING]);
        kvm.mapSize++;
    }

    /* Open a recv connection */
    if(c->recvChannelsSize == 0) {
        /* Validate only if no ReaderGroup configured */
        validate = (c->readerGroupsSize == 0);
        if(validate) {
            UA_LOG_INFO_CONNECTION(server->config.logging, c,
                                   "No ReaderGroups configured. "
                                   "Only validate the connection parameters "
                                   "instead of opening a receiving channel.");
        }

        UA_UNLOCK(&server->serviceMutex);
        res = c->cm->openConnection(c->cm, &kvm, server, c, PubSubRecvChannelCallback);
        UA_LOCK(&server->serviceMutex);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR_CONNECTION(server->config.logging, c,
                                    "Could not open an UDP channel for receiving");
            return res;
        }
    }

    /* Receive all -- sending is handled in the DataSetWriter */
    if(receive_all) {
        UA_LOG_INFO_CONNECTION(server->config.logging, c,
                               "Localhost address - don't open UDP send connection");
        return UA_STATUSCODE_GOOD;
    }

    /* Open a send connection */
    if(c->sendChannel == 0) {
        /* Validate only if no WriterGroup configured */
        validate = (c->writerGroupsSize == 0);
        if(validate) {
            UA_LOG_INFO_CONNECTION(server->config.logging, c,
                                   "No WriterGroups configured. "
                                   "Only validate the connection parameters "
                                   "instead of opening a channel for sending.");
        }

        listen = false;
        UA_UNLOCK(&server->serviceMutex);
        res = c->cm->openConnection(c->cm, &kvm, server, c, PubSubSendChannelCallback);
        UA_LOCK(&server->serviceMutex);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR_CONNECTION(server->config.logging, c,
                                    "Could not open an UDP recv channel");
            return res;
        }
    }

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_PubSubConnection_connectETH(UA_Server *server, UA_PubSubConnection *c,
                               UA_Boolean validate) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_NetworkAddressUrlDataType *addressUrl = (UA_NetworkAddressUrlDataType*)
        c->config.address.data;

    /* Extract hostname and port */
    UA_String address;
    UA_String vidPCP = UA_STRING_NULL;
    UA_StatusCode res = UA_parseEndpointUrl(&addressUrl->url, &address, NULL, &vidPCP);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_CONNECTION(server->config.logging, c,
                                "Could not parse the ETH network URL");
        return res;
    }

    /* Set up the connection parameters.
     * TDOD: Complete the considered parameters. VID, PCP, etc. */
    UA_Boolean listen = true;
    UA_KeyValuePair kvp[4];
    UA_KeyValueMap kvm = {4, kvp};
    kvp[0].key = UA_QUALIFIEDNAME(0, "address");
    UA_Variant_setScalar(&kvp[0].value, &address, &UA_TYPES[UA_TYPES_STRING]);
    kvp[1].key = UA_QUALIFIEDNAME(0, "listen");
    UA_Variant_setScalar(&kvp[1].value, &listen, &UA_TYPES[UA_TYPES_BOOLEAN]);
    kvp[2].key = UA_QUALIFIEDNAME(0, "interface");
    UA_Variant_setScalar(&kvp[2].value, &addressUrl->networkInterface,
                         &UA_TYPES[UA_TYPES_STRING]);
    kvp[3].key = UA_QUALIFIEDNAME(0, "validate");
    UA_Variant_setScalar(&kvp[3].value, &validate, &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* Open recv channels */
    if(c->recvChannelsSize == 0) {
        UA_UNLOCK(&server->serviceMutex);
        res = c->cm->openConnection(c->cm, &kvm, server, c, PubSubRecvChannelCallback);
        UA_LOCK(&server->serviceMutex);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR_CONNECTION(server->config.logging, c,
                                    "Could not open an ETH recv channel");
            return res;
        }
    }

    /* Open send channels */
    if(c->sendChannel == 0) {
        listen = false;
        UA_UNLOCK(&server->serviceMutex);
        res = c->cm->openConnection(c->cm, &kvm, server, c, PubSubSendChannelCallback);
        UA_LOCK(&server->serviceMutex);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR_CONNECTION(server->config.logging, c,
                                    "Could not open an ETH channel for sending");
        }
    }

    return res;
}

static UA_Boolean
UA_PubSubConnection_isConnected(UA_PubSubConnection *c) {
    if(c->sendChannel == 0 && c->writerGroupsSize > 0)
        return false;
    if(c->recvChannelsSize == 0 && c->readerGroupsSize > 0)
        return false;
    return true;
}

UA_StatusCode
UA_PubSubConnection_connect(UA_Server *server, UA_PubSubConnection *c,
                            UA_Boolean validate) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Already connected -> success */
    if(UA_PubSubConnection_isConnected(c) && !validate)
        return UA_STATUSCODE_GOOD;

    UA_EventLoop *el = UA_PubSubConnection_getEL(server, c);
    if(!el) {
        UA_LOG_ERROR_CONNECTION(server->config.logging, c, "No EventLoop configured");
        UA_PubSubConnection_setPubSubState(server, c, UA_PUBSUBSTATE_ERROR);
        return UA_STATUSCODE_BADINTERNALERROR;;
    }

    /* Look up the connection manager for the connection */
    ProfileMapping *profile = getProfile(c->config.transportProfileUri);
    UA_ConnectionManager *cm = NULL;
    if(profile)
        cm = getCM(el, profile->protocol);
    if(!cm) {
        UA_LOG_ERROR_CONNECTION(server->config.logging, c,
                                "The requested protocol is not supported");
        UA_PubSubConnection_setPubSubState(server, c, UA_PUBSUBSTATE_ERROR);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Are we changing the protocol after the initial connect? */
    if(c->cm && cm != c->cm) {
        UA_LOG_ERROR_CONNECTION(server->config.logging, c,
                                "The connection is configured for a different protocol already");
        UA_PubSubConnection_setPubSubState(server, c, UA_PUBSUBSTATE_ERROR);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Check the configuration address type */
    if(!UA_Variant_hasScalarType(&c->config.address,
                                 &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE])) {
        UA_LOG_ERROR_CONNECTION(server->config.logging, c, "No NetworkAddressUrlDataType "
                                "for the address configuration");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Connect */
    c->cm = cm;
    c->json = profile->json;
    return (profile->connect) ? profile->connect(server, c, validate) : UA_STATUSCODE_GOOD;
}

/***************/
/* WriterGroup */
/***************/

static void
WriterGroupChannelCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
                          void *application, void **connectionContext,
                          UA_ConnectionState state, const UA_KeyValueMap *params,
                          UA_ByteString msg) {
    if(!connectionContext)
        return;

    /* Get the context pointers */
    UA_Server *server = (UA_Server*)application;
    UA_WriterGroup *wg = (UA_WriterGroup*)*connectionContext;

    UA_LOCK(&server->serviceMutex);

    /* The connection is closing in the EventLoop. This is the last callback
     * from that connection. Clean up the SecureChannel in the client. */
    if(state == UA_CONNECTIONSTATE_CLOSING) {
        if(wg->sendChannel == connectionId) {
            /* Reset the connection channel */
            wg->sendChannel = 0;

            /* PSC marked for deletion and the last EventLoop connection has closed */
            if(wg->deleteFlag) {
                UA_WriterGroup_remove(server, wg);
                UA_UNLOCK(&server->serviceMutex);
                return;
            }
        }

        /* Reconnect automatically if the connection was operational. This sets
         * the connection state if connecting fails. Attention! If there are
         * several send or recv channels, then the connection is only reopened if
         * all of them close - which is usually the case. */
        if(wg->state == UA_PUBSUBSTATE_OPERATIONAL)
            UA_WriterGroup_connect(server, wg, false);

        UA_UNLOCK(&server->serviceMutex);
        return;
    }

    /* Store the connectionId (if a new connection) */
    if(wg->sendChannel && wg->sendChannel != connectionId) {
        UA_LOG_WARNING_WRITERGROUP(server->config.logging, wg,
                                  "WriterGroup is already bound to a different channel");
        UA_UNLOCK(&server->serviceMutex);
        return;
    }
    wg->sendChannel = connectionId;

    /* Connection open, set to operational if not already done */
    UA_WriterGroup_setPubSubState(server, wg, wg->state);
    
    /* Send-channels don't receive messages */
    UA_UNLOCK(&server->serviceMutex);
}

static UA_StatusCode
UA_WriterGroup_connectUDPUnicast(UA_Server *server, UA_WriterGroup *wg,
                                 UA_Boolean validate) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Already connected? */
    if(wg->sendChannel != 0 && !validate)
        return UA_STATUSCODE_GOOD;

    /* Check if address is available in TransportSettings */
    if(((wg->config.transportSettings.encoding == UA_EXTENSIONOBJECT_DECODED ||
         wg->config.transportSettings.encoding == UA_EXTENSIONOBJECT_DECODED_NODELETE) &&
        wg->config.transportSettings.content.decoded.type ==
        &UA_TYPES[UA_TYPES_DATAGRAMWRITERGROUPTRANSPORTDATATYPE]))
        return UA_STATUSCODE_GOOD;

    /* Unpack the TransportSettings */
    if((wg->config.transportSettings.encoding != UA_EXTENSIONOBJECT_DECODED &&
        wg->config.transportSettings.encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) ||
       wg->config.transportSettings.content.decoded.type !=
       &UA_TYPES[UA_TYPES_DATAGRAMWRITERGROUPTRANSPORT2DATATYPE]) {
        UA_LOG_ERROR_WRITERGROUP(server->config.logging, wg,
                                 "Invalid TransportSettings for a UDP Connection");
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    UA_DatagramWriterGroupTransport2DataType *ts =
        (UA_DatagramWriterGroupTransport2DataType*)
        wg->config.transportSettings.content.decoded.data;

    /* Unpack the address */
    if((ts->address.encoding != UA_EXTENSIONOBJECT_DECODED &&
        ts->address.encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) ||
       ts->address.content.decoded.type != &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]) {
        UA_LOG_ERROR_WRITERGROUP(server->config.logging, wg,
                                 "Invalid TransportSettings Address for a UDP Connection");
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    UA_NetworkAddressUrlDataType *addressUrl = (UA_NetworkAddressUrlDataType *)
        ts->address.content.decoded.data;

    /* Extract hostname and port */
    UA_String address;
    UA_UInt16 port;
    UA_StatusCode res = UA_parseEndpointUrl(&addressUrl->url, &address, &port, NULL);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_WRITERGROUP(server->config.logging, wg,
                                "Could not parse the UDP network URL");
        return res;
    }

    /* Set up the connection parameters */
    UA_Boolean listen = false;
    UA_KeyValuePair kvp[5];
    UA_KeyValueMap kvm = {4, kvp};
    kvp[0].key = UA_QUALIFIEDNAME(0, "address");
    UA_Variant_setScalar(&kvp[0].value, &address, &UA_TYPES[UA_TYPES_STRING]);
    kvp[1].key = UA_QUALIFIEDNAME(0, "port");
    UA_Variant_setScalar(&kvp[1].value, &port, &UA_TYPES[UA_TYPES_UINT16]);
    kvp[2].key = UA_QUALIFIEDNAME(0, "listen");
    UA_Variant_setScalar(&kvp[2].value, &listen, &UA_TYPES[UA_TYPES_BOOLEAN]);
    kvp[3].key = UA_QUALIFIEDNAME(0, "validate");
    UA_Variant_setScalar(&kvp[3].value, &validate, &UA_TYPES[UA_TYPES_BOOLEAN]);
    if(!UA_String_isEmpty(&addressUrl->networkInterface)) {
        kvp[4].key = UA_QUALIFIEDNAME(0, "interface");
        UA_Variant_setScalar(&kvp[4].value, &addressUrl->networkInterface,
                             &UA_TYPES[UA_TYPES_STRING]);
        kvm.mapSize++;
    }

    /* Connect */
    UA_ConnectionManager *cm = wg->linkedConnection->cm;
    UA_UNLOCK(&server->serviceMutex);
    res = cm->openConnection(cm, &kvm, server, wg, WriterGroupChannelCallback);
    UA_LOCK(&server->serviceMutex);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_WRITERGROUP(server->config.logging, wg,
                                 "Could not open a UDP send channel");
    }
    return res;
}

static UA_StatusCode
UA_WriterGroup_connectMQTT(UA_Server *server, UA_WriterGroup *wg,
                           UA_Boolean validate) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_PubSubConnection *c = wg->linkedConnection;
    UA_NetworkAddressUrlDataType *addressUrl = (UA_NetworkAddressUrlDataType*)
        c->config.address.data;

    /* Get the TransportSettings */
    UA_ExtensionObject *ts = &wg->config.transportSettings;
    if((ts->encoding != UA_EXTENSIONOBJECT_DECODED &&
        ts->encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) ||
       ts->content.decoded.type !=
       &UA_TYPES[UA_TYPES_BROKERWRITERGROUPTRANSPORTDATATYPE]) {
        UA_LOG_ERROR_WRITERGROUP(server->config.logging, wg,
                                 "Wrong TransportSettings type for MQTT");
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    UA_BrokerWriterGroupTransportDataType *transportSettings =
        (UA_BrokerWriterGroupTransportDataType*)ts->content.decoded.data;

    /* Extract hostname and port */
    UA_String address;
    UA_UInt16 port = 1883; /* Default */
    UA_StatusCode res = UA_parseEndpointUrl(&addressUrl->url, &address, &port, NULL);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_CONNECTION(server->config.logging, c,
                                "Could not parse the MQTT network URL");
        return res;
    }

    /* Set up the connection parameters.
     * TODO: Complete the MQTT parameters. */
    UA_Boolean listen = false;
    UA_KeyValuePair kvp[5];
    UA_KeyValueMap kvm = {5, kvp};
    kvp[0].key = UA_QUALIFIEDNAME(0, "address");
    UA_Variant_setScalar(&kvp[0].value, &address, &UA_TYPES[UA_TYPES_STRING]);
    kvp[1].key = UA_QUALIFIEDNAME(0, "subscribe");
    UA_Variant_setScalar(&kvp[1].value, &listen, &UA_TYPES[UA_TYPES_BOOLEAN]);
    kvp[2].key = UA_QUALIFIEDNAME(0, "port");
    UA_Variant_setScalar(&kvp[2].value, &port, &UA_TYPES[UA_TYPES_UINT16]);
    kvp[3].key = UA_QUALIFIEDNAME(0, "topic");
    UA_Variant_setScalar(&kvp[3].value, &transportSettings->queueName,
                         &UA_TYPES[UA_TYPES_STRING]);
    kvp[4].key = UA_QUALIFIEDNAME(0, "validate");
    UA_Variant_setScalar(&kvp[4].value, &validate, &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* Connect */
    UA_UNLOCK(&server->serviceMutex);
    res = c->cm->openConnection(c->cm, &kvm, server, wg, WriterGroupChannelCallback);
    UA_LOCK(&server->serviceMutex);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_WRITERGROUP(server->config.logging, wg,
                                 "Could not open the MQTT connection");
    }
    return res;
}

void
UA_WriterGroup_disconnect(UA_WriterGroup *wg) {
    if(wg->sendChannel == 0)
        return;
    UA_PubSubConnection *c = wg->linkedConnection;
    c->cm->closeConnection(c->cm, c->sendChannel);
}

UA_StatusCode
UA_WriterGroup_connect(UA_Server *server, UA_WriterGroup *wg, UA_Boolean validate) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Check if already connected or no WG TransportSettings */
    if(!UA_WriterGroup_canConnect(wg) && !validate)
        return UA_STATUSCODE_GOOD;

    /* Is this a WriterGroup with custom TransportSettings beyond the
     * PubSubConnection? */
    if(wg->config.transportSettings.encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY)
        return UA_STATUSCODE_GOOD;

    UA_EventLoop *el = UA_PubSubConnection_getEL(server, wg->linkedConnection);
    if(!el) {
        UA_LOG_ERROR_WRITERGROUP(server->config.logging, wg, "No EventLoop configured");
        UA_WriterGroup_setPubSubState(server, wg, UA_PUBSUBSTATE_ERROR);
        return UA_STATUSCODE_BADINTERNALERROR;;
    }

    UA_PubSubConnection *c = wg->linkedConnection;
    if(!c)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Look up the connection manager for the connection */
    ProfileMapping *profile = getProfile(c->config.transportProfileUri);
    UA_ConnectionManager *cm = NULL;
    if(profile)
        cm = getCM(el, profile->protocol);
    if(!cm || (c->cm && cm != c->cm)) {
        UA_LOG_ERROR_CONNECTION(server->config.logging, c,
                                "The requested protocol is not supported");
        UA_PubSubConnection_setPubSubState(server, c, UA_PUBSUBSTATE_ERROR);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    c->cm = cm;
    c->json = profile->json;

    /* Connect */
    if(profile->connectWriterGroup)
        return profile->connectWriterGroup(server, wg, validate);
    return UA_STATUSCODE_GOOD;
}

/***************/
/* ReaderGroup */
/***************/

static void
UA_ReaderGroup_removeConnection(UA_ReaderGroup *rg,
                                uintptr_t connectionId) {
    for(size_t i = 0; i < UA_PUBSUB_MAXCHANNELS; i++) {
        if(rg->recvChannels[i] != connectionId)
            continue;
        rg->recvChannels[i] = 0;
        rg->recvChannelsSize--;
        return;
    }
}

static UA_StatusCode
UA_ReaderGroup_addRecvConnection(UA_ReaderGroup*c,
                                 uintptr_t connectionId) {
    for(size_t i = 0; i < UA_PUBSUB_MAXCHANNELS; i++) {
        if(c->recvChannels[i] == connectionId)
            return UA_STATUSCODE_GOOD;
    }
    if(c->recvChannelsSize >= UA_PUBSUB_MAXCHANNELS)
        return UA_STATUSCODE_BADINTERNALERROR;
    for(size_t i = 0; i < UA_PUBSUB_MAXCHANNELS; i++) {
        if(c->recvChannels[i] != 0)
            continue;
        c->recvChannels[i] = connectionId;
        c->recvChannelsSize++;
        break;
    }
    return UA_STATUSCODE_GOOD;
}

static void
ReaderGroupChannelCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
                          void *application, void **connectionContext,
                          UA_ConnectionState state, const UA_KeyValueMap *params,
                          UA_ByteString msg) {
    if(!connectionContext)
        return;

    /* Get the context pointers */
    UA_Server *server = (UA_Server*)application;
    UA_ReaderGroup *rg = (UA_ReaderGroup*)*connectionContext;

    UA_LOCK(&server->serviceMutex);

    /* The connection is closing in the EventLoop. This is the last callback
     * from that connection. Clean up the SecureChannel in the client. */
    if(state == UA_CONNECTIONSTATE_CLOSING) {
        /* Reset the connection identifiers */
        UA_ReaderGroup_removeConnection(rg, connectionId);

        /* PSC marked for deletion and the last EventLoop connection has closed */
        if(rg->deleteFlag && rg->recvChannelsSize == 0) {
            UA_ReaderGroup_remove(server, rg);
            UA_UNLOCK(&server->serviceMutex);
            return;
        }

        /* Reconnect if still operational */
        UA_ReaderGroup_setPubSubState(server, rg, rg->state);
        UA_UNLOCK(&server->serviceMutex);
        return;
    }

    /* Store the connectionId (if a new connection) */
    UA_StatusCode res = UA_ReaderGroup_addRecvConnection(rg, connectionId);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_READERGROUP(server->config.logging, rg,
                                  "No more space for an additional EventLoop connection");
        UA_PubSubConnection *c = rg->linkedConnection;
        if(c && c->cm)
            c->cm->closeConnection(c->cm, connectionId);
        UA_UNLOCK(&server->serviceMutex);
        return;
    }

    /* The connection has opened - set the ReaderGroup to operational */
    UA_ReaderGroup_setPubSubState(server, rg, rg->state);

    /* No message received */
    if(msg.length == 0) {
        UA_UNLOCK(&server->serviceMutex);
        return;
    }

    if(rg->state != UA_PUBSUBSTATE_OPERATIONAL) {
        UA_LOG_WARNING_READERGROUP(server->config.logging, rg,
                                   "Received a messaage for a non-operational ReaderGroup");
        UA_UNLOCK(&server->serviceMutex);
        return;
    }

    /* ReaderGroup with realtime processing */
    if(rg->config.rtLevel == UA_PUBSUB_RT_FIXED_SIZE) {
        UA_ReaderGroup_decodeAndProcessRT(server, rg, &msg);
        UA_UNLOCK(&server->serviceMutex);
        return;
    }

    /* Decode message */
    UA_NetworkMessage nm;
    memset(&nm, 0, sizeof(UA_NetworkMessage));
    if(rg->config.encodingMimeType == UA_PUBSUB_ENCODING_UADP) {
        size_t currentPosition = 0;
        res = decodeNetworkMessage(server, &msg, &currentPosition,
                                   &nm, rg->linkedConnection);
    } else { /* if(writerGroup->config.encodingMimeType == UA_PUBSUB_ENCODING_JSON) */
#ifdef UA_ENABLE_JSON_ENCODING
        res = UA_NetworkMessage_decodeJson(&nm, &msg);
#else
        res = UA_STATUSCODE_BADNOTSUPPORTED;
#endif
    }
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_READERGROUP(server->config.logging, rg,
                                  "Verify, decrypt and decode network message failed");
        UA_UNLOCK(&server->serviceMutex);
        return;
    }

    /* Process the decoded message */
    UA_ReaderGroup_process(server, rg, &nm);
    UA_NetworkMessage_clear(&nm);
    UA_UNLOCK(&server->serviceMutex);
}

static UA_StatusCode
UA_ReaderGroup_connectMQTT(UA_Server *server, UA_ReaderGroup *rg,
                           UA_Boolean validate) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_PubSubConnection *c = rg->linkedConnection;
    UA_NetworkAddressUrlDataType *addressUrl = (UA_NetworkAddressUrlDataType*)
        c->config.address.data;

    /* Get the TransportSettings */
    UA_ExtensionObject *ts = &rg->config.transportSettings;
    if((ts->encoding != UA_EXTENSIONOBJECT_DECODED &&
        ts->encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) ||
       ts->content.decoded.type !=
       &UA_TYPES[UA_TYPES_BROKERDATASETREADERTRANSPORTDATATYPE]) {
        UA_LOG_ERROR_READERGROUP(server->config.logging, rg,
                                "Wrong TransportSettings type for MQTT");
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    UA_BrokerDataSetReaderTransportDataType *transportSettings =
        (UA_BrokerDataSetReaderTransportDataType*)ts->content.decoded.data;

    /* Extract hostname and port */
    UA_String address;
    UA_UInt16 port = 1883; /* Default */
    UA_StatusCode res = UA_parseEndpointUrl(&addressUrl->url, &address, &port, NULL);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_CONNECTION(server->config.logging, c,
                                "Could not parse the MQTT network URL");
        return res;
    }

    /* Set up the connection parameters.
     * TODO: Complete the MQTT parameters. */
    UA_Boolean listen = true;
    UA_KeyValuePair kvp[5];
    UA_KeyValueMap kvm = {5, kvp};
    kvp[0].key = UA_QUALIFIEDNAME(0, "address");
    UA_Variant_setScalar(&kvp[0].value, &address, &UA_TYPES[UA_TYPES_STRING]);
    kvp[1].key = UA_QUALIFIEDNAME(0, "subscribe");
    UA_Variant_setScalar(&kvp[1].value, &listen, &UA_TYPES[UA_TYPES_BOOLEAN]);
    kvp[2].key = UA_QUALIFIEDNAME(0, "port");
    UA_Variant_setScalar(&kvp[2].value, &port, &UA_TYPES[UA_TYPES_UINT16]);
    kvp[3].key = UA_QUALIFIEDNAME(0, "topic");
    UA_Variant_setScalar(&kvp[3].value, &transportSettings->queueName,
                         &UA_TYPES[UA_TYPES_STRING]);
    kvp[4].key = UA_QUALIFIEDNAME(0, "validate");
    UA_Variant_setScalar(&kvp[4].value, &validate, &UA_TYPES[UA_TYPES_BOOLEAN]);

    /* Connect */
    UA_UNLOCK(&server->serviceMutex);
    res = c->cm->openConnection(c->cm, &kvm, server, rg, ReaderGroupChannelCallback);
    UA_LOCK(&server->serviceMutex);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_READERGROUP(server->config.logging, rg,
                                 "Could not open the MQTT connection");
    }
    return res;
}

void
UA_ReaderGroup_disconnect(UA_ReaderGroup *rg) {
    UA_PubSubConnection *c = rg->linkedConnection;
    if(!c)
        return;
    for(size_t i = 0; i < UA_PUBSUB_MAXCHANNELS; i++) {
        if(rg->recvChannels[i] != 0)
            c->cm->closeConnection(c->cm, rg->recvChannels[i]);
    }
}

UA_StatusCode
UA_ReaderGroup_connect(UA_Server *server, UA_ReaderGroup *rg, UA_Boolean validate) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Already connected */
    if(rg->recvChannelsSize != 0 && !validate)
        return UA_STATUSCODE_GOOD;

    /* Is this a ReaderGroup with custom TransportSettings beyond the
     * PubSubConnection? */
    if(rg->config.transportSettings.encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY)
        return UA_STATUSCODE_GOOD;

    UA_EventLoop *el = UA_PubSubConnection_getEL(server, rg->linkedConnection);
    if(!el) {
        UA_LOG_ERROR_READERGROUP(server->config.logging, rg, "No EventLoop configured");
        return UA_STATUSCODE_BADINTERNALERROR;;
    }

    UA_PubSubConnection *c = rg->linkedConnection;
    if(!c)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Look up the connection manager for the connection */
    ProfileMapping *profile = getProfile(c->config.transportProfileUri);
    UA_ConnectionManager *cm = NULL;
    if(profile)
        cm = getCM(el, profile->protocol);
    if(!cm || (c->cm && cm != c->cm)) {
        UA_LOG_ERROR_CONNECTION(server->config.logging, c,
                                "The requested protocol is not supported");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    c->cm = cm;
    c->json = profile->json;

    /* Connect */
    if(profile->connectReaderGroup)
        return profile->connectReaderGroup(server, rg, validate);
    return UA_STATUSCODE_GOOD;
}

#endif /* UA_ENABLE_PUBSUB */

/**** amalgamated original file "/src/pubsub/ua_pubsub_connection.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2017-2022 Fraunhofer IOSB (Author: Andreas Ebner)
 * Copyright (c) 2019, 2022 Fraunhofer IOSB (Author: Julius Pfrommer)
 * Copyright (c) 2019 Kalycito Infotech Private Limited
 * Copyright (c) 2021 Fraunhofer IOSB (Author: Jan Hermes)
 * Copyright (c) 2022 Siemens AG (Author: Thomas Fischer)
 * Copyright (c) 2022 Fraunhofer IOSB (Author: Noel Graf)
 */


#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
#endif

#ifdef UA_ENABLE_PUBSUB /* conditional compilation */

UA_StatusCode
decodeNetworkMessage(UA_Server *server, UA_ByteString *buffer, size_t *pos,
                     UA_NetworkMessage *nm, UA_PubSubConnection *connection) {
#ifdef UA_DEBUG_DUMP_PKGS
    UA_dump_hex_pkg(buffer->data, buffer->length);
#endif

    UA_StatusCode rv = UA_NetworkMessage_decodeHeaders(buffer, pos, nm);
    if(rv != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_CONNECTION(server->config.logging, connection,
                                  "PubSub receive. decoding headers failed");
        UA_NetworkMessage_clear(nm);
        return rv;
    }

#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
    UA_Boolean processed = false;
    UA_ReaderGroup *readerGroup;
    UA_DataSetReader *reader;

    /* Choose a correct readergroup for decrypt/verify this message
     * (there could be multiple) */
    LIST_FOREACH(readerGroup, &connection->readerGroups, listEntry) {
        LIST_FOREACH(reader, &readerGroup->readers, listEntry) {
            UA_StatusCode retval =
                UA_DataSetReader_checkIdentifier(server, nm, reader, readerGroup->config);
            if(retval != UA_STATUSCODE_GOOD)
                continue;
            processed = true;
            rv = verifyAndDecryptNetworkMessage(server->config.logging, buffer, pos,
                                                nm, readerGroup);
            if(rv != UA_STATUSCODE_GOOD) {
                UA_LOG_WARNING_CONNECTION(server->config.logging, connection,
                                          "Subscribe failed, verify and decrypt "
                                          "network message failed.");
                UA_NetworkMessage_clear(nm);
                return rv;
            }

            /* break out of all loops when first verify & decrypt was successful */
            goto loops_exit;
        }
    }

loops_exit:
    if(!processed) {
        UA_LOG_INFO_CONNECTION(server->config.logging, connection,
                               "Dataset reader not found. Check PublisherId, "
                               "WriterGroupId and DatasetWriterId");
        /* Possible multicast scenario: there are multiple connections (with one
         * or more ReaderGroups) within a multicast group every connection
         * receives all network messages, even if some of them are not meant for
         * the connection currently processed -> therefore it is ok if the
         * connection does not have a DataSetReader for every received network
         * message. We must not return an error here, but continue with the
         * buffer decoding and see if we have a matching DataSetReader for the
         * next network message. */
    }
#endif

    rv = UA_NetworkMessage_decodePayload(buffer, pos, nm, server->config.customDataTypes, NULL);
    if(rv != UA_STATUSCODE_GOOD) {
        UA_NetworkMessage_clear(nm);
        return rv;
    }

    rv = UA_NetworkMessage_decodeFooters(buffer, pos, nm);
    if(rv != UA_STATUSCODE_GOOD) {
        UA_NetworkMessage_clear(nm);
        return rv;
    }

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_PubSubConnectionConfig_copy(const UA_PubSubConnectionConfig *src,
                               UA_PubSubConnectionConfig *dst) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    memcpy(dst, src, sizeof(UA_PubSubConnectionConfig));
    if(src->publisherIdType == UA_PUBLISHERIDTYPE_STRING) {
        res |= UA_String_copy(&src->publisherId.string, &dst->publisherId.string);
    }
    res |= UA_String_copy(&src->name, &dst->name);
    res |= UA_Variant_copy(&src->address, &dst->address);
    res |= UA_String_copy(&src->transportProfileUri, &dst->transportProfileUri);
    res |= UA_Variant_copy(&src->connectionTransportSettings,
                           &dst->connectionTransportSettings);
    res |= UA_KeyValueMap_copy(&src->connectionProperties,
                               &dst->connectionProperties);
    if(res != UA_STATUSCODE_GOOD)
        UA_PubSubConnectionConfig_clear(dst);
    return res;
}

UA_StatusCode
UA_Server_getPubSubConnectionConfig(UA_Server *server, const UA_NodeId connection,
                                    UA_PubSubConnectionConfig *config) {
    if(!config)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    UA_LOCK(&server->serviceMutex);
    UA_PubSubConnection *currentPubSubConnection =
        UA_PubSubConnection_findConnectionbyId(server, connection);
    UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND;
    if(currentPubSubConnection)
        res = UA_PubSubConnectionConfig_copy(&currentPubSubConnection->config, config);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_PubSubConnection *
UA_PubSubConnection_findConnectionbyId(UA_Server *server, UA_NodeId connectionIdentifier) {
    UA_PubSubConnection *pubSubConnection;
    TAILQ_FOREACH(pubSubConnection, &server->pubSubManager.connections, listEntry){
        if(UA_NodeId_equal(&connectionIdentifier, &pubSubConnection->identifier))
            break;
    }
    return pubSubConnection;
}

void
UA_PubSubConnectionConfig_clear(UA_PubSubConnectionConfig *connectionConfig) {
    if(connectionConfig->publisherIdType == UA_PUBLISHERIDTYPE_STRING)
        UA_String_clear(&connectionConfig->publisherId.string);
    UA_String_clear(&connectionConfig->name);
    UA_String_clear(&connectionConfig->transportProfileUri);
    UA_Variant_clear(&connectionConfig->connectionTransportSettings);
    UA_Variant_clear(&connectionConfig->address);
    UA_KeyValueMap_clear(&connectionConfig->connectionProperties);
}

UA_StatusCode
UA_PubSubConnection_create(UA_Server *server, const UA_PubSubConnectionConfig *cc,
                           UA_NodeId *cId) {
    if(!server || !cc)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Allocate */
    UA_PubSubConnection *c = (UA_PubSubConnection*)
        UA_calloc(1, sizeof(UA_PubSubConnection));
    if(!c)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    c->componentType = UA_PUBSUB_COMPONENT_CONNECTION;

    /* Copy the connection config */
    UA_StatusCode ret = UA_PubSubConnectionConfig_copy(cc, &c->config);
    UA_CHECK_STATUS(ret, UA_free(c); return ret);

    /* Assign the connection identifier */
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    /* Internally create a unique id */
    addPubSubConnectionRepresentation(server, c);
#else
    /* Create a unique NodeId that does not correspond to a Node */
    UA_PubSubManager_generateUniqueNodeId(&server->pubSubManager,
                                          &c->identifier);
#endif

    /* Register */
    UA_PubSubManager *pubSubManager = &server->pubSubManager;
    TAILQ_INSERT_HEAD(&pubSubManager->connections, c, listEntry);
    pubSubManager->connectionsSize++;

    /* Cache the log string */
    UA_String idStr = UA_STRING_NULL;
    UA_NodeId_print(&c->identifier, &idStr);
    char tmpLogIdStr[128];
    mp_snprintf(tmpLogIdStr, 128, "PubSubConnection %.*s\t| ",
                (int)idStr.length, idStr.data);
    c->logIdString = UA_STRING_ALLOC(tmpLogIdStr);
    UA_String_clear(&idStr);

    UA_LOG_INFO_CONNECTION(server->config.logging, c, "Connection created");

    /* Validate-connect to check the parameters */
    ret = UA_PubSubConnection_connect(server, c, true);
    if(ret != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_CONNECTION(server->config.logging, c,
                                "Could not validate connection parameters");
        UA_PubSubConnection_delete(server, c);
        return ret;
    }

    /* Make the connection operational */
    ret = UA_PubSubConnection_setPubSubState(server, c, UA_PUBSUBSTATE_OPERATIONAL);
    if(ret != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Copy the created NodeId to the output. Cannot fail as we create a
     * numerical NodeId. */
    if(cId)
        UA_NodeId_copy(&c->identifier, cId);

 cleanup:
    if(ret != UA_STATUSCODE_GOOD)
        UA_PubSubConnection_delete(server, c);
    return ret;
}

UA_StatusCode
UA_Server_addPubSubConnection(UA_Server *server, const UA_PubSubConnectionConfig *cc,
                              UA_NodeId *cId) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = UA_PubSubConnection_create(server, cc, cId);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

static void
delayedPubSubConnection_delete(void *application, void *context) {
    UA_Server *server = (UA_Server*)application;
    UA_PubSubConnection *c = (UA_PubSubConnection*)context;
    UA_LOCK(&server->serviceMutex);
    UA_PubSubConnection_delete(server, c);
    UA_UNLOCK(&server->serviceMutex);
}

/* Clean up the PubSubConnection. If no EventLoop connection is attached we can
 * immediately free. Otherwise we close the EventLoop connections and free in
 * the connection callback. */
void
UA_PubSubConnection_delete(UA_Server *server, UA_PubSubConnection *c) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Stop and unfreeze all ReaderGroupds and WriterGroups attached to the
     * Connection. Do this before removing them because we need to unfreeze all
     * to remove the Connection.*/
    UA_ReaderGroup *readerGroup, *tmpReaderGroup;
    LIST_FOREACH(readerGroup, &c->readerGroups, listEntry) {
        UA_ReaderGroup_setPubSubState(server, readerGroup, UA_PUBSUBSTATE_DISABLED);
        UA_ReaderGroup_unfreezeConfiguration(server, readerGroup);
    }

    UA_WriterGroup *writerGroup, *tmpWriterGroup;
    LIST_FOREACH(writerGroup, &c->writerGroups, listEntry) {
        UA_WriterGroup_setPubSubState(server, writerGroup, UA_PUBSUBSTATE_DISABLED);
        UA_WriterGroup_unfreezeConfiguration(server, writerGroup);
    }

    /* Remove all ReaderGorups and WriterGroups */
    LIST_FOREACH_SAFE(readerGroup, &c->readerGroups, listEntry, tmpReaderGroup) {
        UA_ReaderGroup_remove(server, readerGroup);
    }

    LIST_FOREACH_SAFE(writerGroup, &c->writerGroups, listEntry, tmpWriterGroup) {
        UA_WriterGroup_remove(server, writerGroup);
    }

    /* Disconnect only once */
    if(!c->deleteFlag)
        UA_PubSubConnection_disconnect(c);
    c->deleteFlag = true;

    /* Not all sockets are closed. This method will be called again */
    if(c->sendChannel != 0 || c->recvChannelsSize > 0)
        return;

    /* The WriterGroups / ReaderGroups are not deleted. Try again in the next
     * iteration of the event loop.*/
    if(!LIST_EMPTY(&c->writerGroups) || !LIST_EMPTY(&c->readerGroups)) {
        UA_EventLoop *el = UA_PubSubConnection_getEL(server, c);
        c->dc.callback = delayedPubSubConnection_delete;
        c->dc.application = server;
        c->dc.context = c;
        el->addDelayedCallback(el, &c->dc);
        return;
    }

    /* Remove from the information model */
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    deleteNode(server, c->identifier, true);
#endif

    /* Unlink from the server */
    TAILQ_REMOVE(&server->pubSubManager.connections, c, listEntry);
    server->pubSubManager.connectionsSize--;

    UA_LOG_INFO_CONNECTION(server->config.logging, c, "Connection deleted");

    UA_PubSubConnectionConfig_clear(&c->config);
    UA_NodeId_clear(&c->identifier);
    UA_String_clear(&c->logIdString);
    UA_free(c);
}

UA_StatusCode
UA_Server_removePubSubConnection(UA_Server *server, const UA_NodeId connection) {
    UA_LOCK(&server->serviceMutex);
    UA_PubSubConnection *psc =
        UA_PubSubConnection_findConnectionbyId(server, connection);
    if(!psc) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADNOTFOUND;
    }
    UA_PubSubConnection_setPubSubState(server, psc, UA_PUBSUBSTATE_DISABLED);
    UA_PubSubConnection_delete(server, psc);
    UA_UNLOCK(&server->serviceMutex);
    return UA_STATUSCODE_GOOD;
}

void
UA_PubSubConnection_process(UA_Server *server, UA_PubSubConnection *c,
                            UA_ByteString msg) {
    /* Process RT ReaderGroups */
    UA_ReaderGroup *rg;
    UA_Boolean processed = false;
    UA_ReaderGroup *nonRtRg = NULL;
    LIST_FOREACH(rg, &c->readerGroups, listEntry) {
        if(rg->state != UA_PUBSUBSTATE_OPERATIONAL &&
           rg->state != UA_PUBSUBSTATE_PREOPERATIONAL)
            continue;
        if(rg->config.rtLevel != UA_PUBSUB_RT_FIXED_SIZE) {
            nonRtRg = rg;
            continue;
        } 
        processed |= UA_ReaderGroup_decodeAndProcessRT(server, rg, &msg);
    }

    /* Any non-RT ReaderGroups? */
    if(!nonRtRg)
        goto finish;

    /* Decode the received message for the non-RT ReaderGroups */
    UA_StatusCode res;
    UA_NetworkMessage nm;
    memset(&nm, 0, sizeof(UA_NetworkMessage));
    if(nonRtRg->config.encodingMimeType == UA_PUBSUB_ENCODING_UADP) {
        size_t currentPosition = 0;
        res = decodeNetworkMessage(server, &msg, &currentPosition, &nm, c);
    } else { /* if(writerGroup->config.encodingMimeType == UA_PUBSUB_ENCODING_JSON) */
#ifdef UA_ENABLE_JSON_ENCODING
        res = UA_NetworkMessage_decodeJson(&nm, &msg);
#else
        res = UA_STATUSCODE_BADNOTSUPPORTED;
#endif
    }
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_CONNECTION(server->config.logging, c,
                                  "Verify, decrypt and decode network message failed");
        return;
    }

    /* Process the received message for the non-RT ReaderGroups */
    LIST_FOREACH(rg, &c->readerGroups, listEntry) {
        if(rg->state != UA_PUBSUBSTATE_OPERATIONAL &&
           rg->state != UA_PUBSUBSTATE_PREOPERATIONAL)
            continue;
        if(rg->config.rtLevel == UA_PUBSUB_RT_FIXED_SIZE)
            continue;
        processed |= UA_ReaderGroup_process(server, rg, &nm);
    }
    UA_NetworkMessage_clear(&nm);

 finish:
    if(!processed) {
        UA_LOG_WARNING_CONNECTION(server->config.logging, c,
                                  "Message received that could not be processed. "
                                  "Check PublisherID, WriterGroupID and DatasetWriterID.");
    }
}

UA_StatusCode
UA_PubSubConnection_setPubSubState(UA_Server *server, UA_PubSubConnection *c,
                                   UA_PubSubState targetState) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    UA_PubSubState oldState = c->state;

 set_state:

    switch(targetState) {
        case UA_PUBSUBSTATE_ERROR:
        case UA_PUBSUBSTATE_PAUSED:
        case UA_PUBSUBSTATE_DISABLED:
            /* Close the EventLoop connection */
            UA_PubSubConnection_disconnect(c);
            c->state = targetState;
            break;

        case UA_PUBSUBSTATE_PREOPERATIONAL:
        case UA_PUBSUBSTATE_OPERATIONAL:
            /* Called also if the connection is already operational. We might to
             * open an additional recv connection, etc. Sets the new state
             * internally. */
            if(oldState == UA_PUBSUBSTATE_PREOPERATIONAL || oldState == UA_PUBSUBSTATE_OPERATIONAL)
                c->state = UA_PUBSUBSTATE_OPERATIONAL;
            else
                c->state = UA_PUBSUBSTATE_PREOPERATIONAL;

            /* This is the only place where UA_PubSubConnection_connect is
             * called (other than to validate the parameters). So we handle the
             * fallout of a failed connection here. */
            ret = UA_PubSubConnection_connect(server, c, false);
            if(ret != UA_STATUSCODE_GOOD) {
                targetState = UA_PUBSUBSTATE_ERROR;
                goto set_state;
            }
            break;
        default:
            UA_LOG_WARNING_CONNECTION(server->config.logging, c,
                                      "Received unknown PubSub state!");
            return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Inform application about state change */
    if(c->state != oldState) {
        UA_ServerConfig *config = &server->config;
        UA_LOG_INFO_CONNECTION(config->logging, c, "State change: %s -> %s",
                               UA_PubSubState_name(oldState),
                               UA_PubSubState_name(c->state));
        UA_UNLOCK(&server->serviceMutex);
        if(config->pubSubConfig.stateChangeCallback)
            config->pubSubConfig.stateChangeCallback(server, &c->identifier, targetState, ret);
        UA_LOCK(&server->serviceMutex);
    }

    /* Update Reader and WriterGroups. This will set them to PAUSED (if
     * they were operational) as the Connection is now
     * non-operational. */
    UA_ReaderGroup *readerGroup;
    LIST_FOREACH(readerGroup, &c->readerGroups, listEntry) {
        UA_ReaderGroup_setPubSubState(server, readerGroup, readerGroup->state);
    }
    UA_WriterGroup *writerGroup;
    LIST_FOREACH(writerGroup, &c->writerGroups, listEntry) {
        UA_WriterGroup_setPubSubState(server, writerGroup, writerGroup->state);
    }
    return ret;
}

static UA_StatusCode
enablePubSubConnection(UA_Server *server, const UA_NodeId connectionId) {
    UA_PubSubConnection *psc = UA_PubSubConnection_findConnectionbyId(server, connectionId);
    return (psc) ? UA_PubSubConnection_setPubSubState(server, psc, UA_PUBSUBSTATE_OPERATIONAL)
        : UA_STATUSCODE_BADNOTFOUND;
}

static UA_StatusCode
disablePubSubConnection(UA_Server *server, const UA_NodeId connectionId) {
    UA_PubSubConnection *psc = UA_PubSubConnection_findConnectionbyId(server, connectionId);
    return (psc) ? UA_PubSubConnection_setPubSubState(server, psc, UA_PUBSUBSTATE_DISABLED)
        : UA_STATUSCODE_BADNOTFOUND;
}

UA_StatusCode
UA_Server_enablePubSubConnection(UA_Server *server,
                                 const UA_NodeId connectionId) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = enablePubSubConnection(server, connectionId);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_Server_disablePubSubConnection(UA_Server *server,
                                  const UA_NodeId connectionId) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = disablePubSubConnection(server, connectionId);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_EventLoop *
UA_PubSubConnection_getEL(UA_Server *server, UA_PubSubConnection *c) {
    if(c->config.eventLoop)
        return c->config.eventLoop;
    return server->config.eventLoop;
}

#endif /* UA_ENABLE_PUBSUB */

/**** amalgamated original file "/src/pubsub/ua_pubsub_dataset.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2017-2019 Fraunhofer IOSB (Author: Andreas Ebner)
 * Copyright (c) 2019 Fraunhofer IOSB (Author: Julius Pfrommer)
 * Copyright (c) 2019-2021 Kalycito Infotech Private Limited
 * Copyright (c) 2020 Yannick Wallerer, Siemens AG
 * Copyright (c) 2020 Thomas Fischer, Siemens AG
 * Copyright (c) 2021 Fraunhofer IOSB (Author: Jan Hermes)
 */


#ifdef UA_ENABLE_PUBSUB /* conditional compilation */

static void
UA_DataSetField_clear(UA_DataSetField *field) {
    UA_DataSetFieldConfig_clear(&field->config);
    UA_NodeId_clear(&field->identifier);
    UA_NodeId_clear(&field->publishedDataSet);
    UA_FieldMetaData_clear(&field->fieldMetaData);
}

UA_StatusCode
UA_PublishedDataSetConfig_copy(const UA_PublishedDataSetConfig *src,
                               UA_PublishedDataSetConfig *dst) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    memcpy(dst, src, sizeof(UA_PublishedDataSetConfig));
    res |= UA_String_copy(&src->name, &dst->name);
    switch(src->publishedDataSetType) {
        case UA_PUBSUB_DATASET_PUBLISHEDITEMS:
            //no additional items
            break;

        case UA_PUBSUB_DATASET_PUBLISHEDITEMS_TEMPLATE:
            if(src->config.itemsTemplate.variablesToAddSize > 0) {
                dst->config.itemsTemplate.variablesToAdd = (UA_PublishedVariableDataType *)
                    UA_calloc(src->config.itemsTemplate.variablesToAddSize,
                              sizeof(UA_PublishedVariableDataType));
                if(!dst->config.itemsTemplate.variablesToAdd) {
                    res = UA_STATUSCODE_BADOUTOFMEMORY;
                    break;
                }
                dst->config.itemsTemplate.variablesToAddSize =
                    src->config.itemsTemplate.variablesToAddSize;
            }

            for(size_t i = 0; i < src->config.itemsTemplate.variablesToAddSize; i++) {
                res |= UA_PublishedVariableDataType_copy(&src->config.itemsTemplate.variablesToAdd[i],
                                                         &dst->config.itemsTemplate.variablesToAdd[i]);
            }
            res |= UA_DataSetMetaDataType_copy(&src->config.itemsTemplate.metaData,
                                               &dst->config.itemsTemplate.metaData);
            break;

        default:
            res = UA_STATUSCODE_BADINVALIDARGUMENT;
            break;
    }

    if(res != UA_STATUSCODE_GOOD)
        UA_PublishedDataSetConfig_clear(dst);
    return res;
}

UA_StatusCode
getPublishedDataSetConfig(UA_Server *server, const UA_NodeId pds,
                          UA_PublishedDataSetConfig *config) {
    if(!config)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    UA_PublishedDataSet *currentPDS = UA_PublishedDataSet_findPDSbyId(server, pds);
    UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND;
    if(currentPDS)
        res = UA_PublishedDataSetConfig_copy(&currentPDS->config, config);
    return res;
}

UA_StatusCode
UA_Server_getPublishedDataSetConfig(UA_Server *server, const UA_NodeId pds,
                                    UA_PublishedDataSetConfig *config) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = getPublishedDataSetConfig(server, pds, config);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_Server_getPublishedDataSetMetaData(UA_Server *server, const UA_NodeId pds,
                                      UA_DataSetMetaDataType *metaData) {
    if(!metaData)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    UA_LOCK(&server->serviceMutex);
    UA_PublishedDataSet *currentPDS = UA_PublishedDataSet_findPDSbyId(server, pds);
    UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND;
    if(currentPDS)
        res = UA_DataSetMetaDataType_copy(&currentPDS->dataSetMetaData, metaData);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_PublishedDataSet *
UA_PublishedDataSet_findPDSbyId(UA_Server *server, UA_NodeId identifier) {
    UA_PublishedDataSet *tmpPDS = NULL;
    TAILQ_FOREACH(tmpPDS, &server->pubSubManager.publishedDataSets, listEntry) {
        if(UA_NodeId_equal(&tmpPDS->identifier, &identifier))
            break;
    }
    return tmpPDS;
}

UA_PublishedDataSet *
UA_PublishedDataSet_findPDSbyName(UA_Server *server, UA_String name) {
    UA_PublishedDataSet *tmpPDS = NULL;
    TAILQ_FOREACH(tmpPDS, &server->pubSubManager.publishedDataSets, listEntry) {
        if(UA_String_equal(&name, &tmpPDS->config.name))
            break;
    }

    return tmpPDS;
}

void
UA_PublishedDataSetConfig_clear(UA_PublishedDataSetConfig *pdsConfig) {
    //delete pds config
    UA_String_clear(&pdsConfig->name);
    switch (pdsConfig->publishedDataSetType){
        case UA_PUBSUB_DATASET_PUBLISHEDITEMS:
            //no additional items
            break;
        case UA_PUBSUB_DATASET_PUBLISHEDITEMS_TEMPLATE:
            if(pdsConfig->config.itemsTemplate.variablesToAddSize > 0){
                for(size_t i = 0; i < pdsConfig->config.itemsTemplate.variablesToAddSize; i++){
                    UA_PublishedVariableDataType_clear(&pdsConfig->config.itemsTemplate.variablesToAdd[i]);
                }
                UA_free(pdsConfig->config.itemsTemplate.variablesToAdd);
            }
            UA_DataSetMetaDataType_clear(&pdsConfig->config.itemsTemplate.metaData);
            break;
        default:
            break;
    }
}

void
UA_PublishedDataSet_clear(UA_Server *server, UA_PublishedDataSet *publishedDataSet) {
    UA_DataSetField *field, *tmpField;
    TAILQ_FOREACH_SAFE(field, &publishedDataSet->fields, listEntry, tmpField) {
        /* Code in this block is a duplication of similar code in UA_DataSetField_remove, but
         * this is intentional. We don't want to call UA_DataSetField_remove here as that
         * function regenerates DataSetMetaData, which is not necessary if we want to
         * clear the whole PDS anyway. */
        if(field->configurationFrozen) {
            UA_LOG_WARNING_DATASET(server->config.logging, publishedDataSet,
                                   "Clearing a frozen field.");
        }
        field->fieldMetaData.arrayDimensions = NULL;
        field->fieldMetaData.properties = NULL;
        field->fieldMetaData.name = UA_STRING_NULL;
        field->fieldMetaData.description.locale = UA_STRING_NULL;
        field->fieldMetaData.description.text = UA_STRING_NULL;
        UA_DataSetField_clear(field);
        TAILQ_REMOVE(&publishedDataSet->fields, field, listEntry);
        UA_free(field);
    }
    UA_PublishedDataSetConfig_clear(&publishedDataSet->config);
    UA_DataSetMetaDataType_clear(&publishedDataSet->dataSetMetaData);
    UA_NodeId_clear(&publishedDataSet->identifier);
    UA_String_clear(&publishedDataSet->logIdString);
}

/* The fieldMetaData variable has to be cleaned up external in case of an error */
static UA_StatusCode
generateFieldMetaData(UA_Server *server, UA_PublishedDataSet *pds,
                      UA_DataSetField *field, UA_FieldMetaData *fieldMetaData) {
    if(field->config.dataSetFieldType != UA_PUBSUB_DATASETFIELD_VARIABLE)
        return UA_STATUSCODE_BADNOTSUPPORTED;

    /* Set the field identifier */
    fieldMetaData->dataSetFieldId = UA_PubSubManager_generateUniqueGuid(server);

    /* Set the description */
    fieldMetaData->description = UA_LOCALIZEDTEXT_ALLOC("", "");

    /* Set the name */
    const UA_DataSetVariableConfig *var = &field->config.field.variable;
    UA_StatusCode res = UA_String_copy(&var->fieldNameAlias, &fieldMetaData->name);
    UA_CHECK_STATUS(res, return res);

    /* Static value source. ToDo after freeze PR, the value source must be
     * checked (other behavior for static value source) */
    if(var->rtValueSource.rtFieldSourceEnabled &&
       !var->rtValueSource.rtInformationModelNode) {
        const UA_DataValue *svs = *var->rtValueSource.staticValueSource;
        if(svs->value.arrayDimensionsSize > 0) {
            fieldMetaData->arrayDimensions = (UA_UInt32 *)
                UA_calloc(svs->value.arrayDimensionsSize, sizeof(UA_UInt32));
            if(fieldMetaData->arrayDimensions == NULL)
                return UA_STATUSCODE_BADOUTOFMEMORY;
            memcpy(fieldMetaData->arrayDimensions, svs->value.arrayDimensions,
                   sizeof(UA_UInt32) * svs->value.arrayDimensionsSize);
        }
        fieldMetaData->arrayDimensionsSize = svs->value.arrayDimensionsSize;

        if(svs->value.type)
            res = UA_NodeId_copy(&svs->value.type->typeId, &fieldMetaData->dataType);
        UA_CHECK_STATUS(res, return res);

        //TODO collect value rank for the static field source
        fieldMetaData->properties = NULL;
        fieldMetaData->propertiesSize = 0;
        fieldMetaData->fieldFlags = UA_DATASETFIELDFLAGS_NONE;
        return UA_STATUSCODE_GOOD;
    }

    /* Set the Array Dimensions */
    const UA_PublishedVariableDataType *pp = &var->publishParameters;
    UA_Variant value;
    UA_Variant_init(&value);
    res = readWithReadValue(server, &pp->publishedVariable,
                            UA_ATTRIBUTEID_ARRAYDIMENSIONS, &value);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_DATASET(server->config.logging, pds,
                               "PubSub meta data generation: Reading the array dimensions failed");
        return res;
    }

    if(value.arrayDimensionsSize > 0) {
        fieldMetaData->arrayDimensions = (UA_UInt32 *)
            UA_calloc(value.arrayDimensionsSize, sizeof(UA_UInt32));
        if(!fieldMetaData->arrayDimensions)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        memcpy(fieldMetaData->arrayDimensions, value.arrayDimensions,
               sizeof(UA_UInt32)*value.arrayDimensionsSize);
    }
    fieldMetaData->arrayDimensionsSize = value.arrayDimensionsSize;

    UA_Variant_clear(&value);

    /* Set the DataType */
    res = readWithReadValue(server, &pp->publishedVariable,
                            UA_ATTRIBUTEID_DATATYPE, &fieldMetaData->dataType);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_DATASET(server->config.logging, pds,
                               "PubSub meta data generation: Reading the datatype failed");
        return res;
    }

    if(!UA_NodeId_isNull(&fieldMetaData->dataType)) {
        const UA_DataType *currentDataType =
            UA_findDataTypeWithCustom(&fieldMetaData->dataType,
                                      server->config.customDataTypes);
#ifdef UA_ENABLE_TYPEDESCRIPTION
        UA_LOG_DEBUG_DATASET(server->config.logging, pds,
                             "MetaData creation: Found DataType %s",
                             currentDataType->typeName);
#endif
        /* Check if the datatype is a builtInType, if yes set the builtinType. */
        if(currentDataType->typeKind <= UA_DATATYPEKIND_ENUM)
            fieldMetaData->builtInType = (UA_Byte)currentDataType->typeId.identifier.numeric;
        /* set the maxStringLength attribute */
        if(field->config.field.variable.maxStringLength != 0){
            if(currentDataType->typeKind == UA_DATATYPEKIND_BYTESTRING ||
            currentDataType->typeKind == UA_DATATYPEKIND_STRING ||
            currentDataType->typeKind == UA_DATATYPEKIND_LOCALIZEDTEXT) {
                fieldMetaData->maxStringLength = field->config.field.variable.maxStringLength;
            } else {
                UA_LOG_WARNING_DATASET(server->config.logging, pds,
                                       "PubSub meta data generation: MaxStringLength with incompatible DataType configured.");
            }
        }
    } else {
        UA_LOG_WARNING_DATASET(server->config.logging, pds,
                               "PubSub meta data generation: DataType is UA_NODEID_NULL");
    }

    /* Set the ValueRank */
    UA_Int32 valueRank;
    res = readWithReadValue(server, &pp->publishedVariable,
                            UA_ATTRIBUTEID_VALUERANK, &valueRank);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_DATASET(server->config.logging, pds,
                               "PubSub meta data generation: Reading the value rank failed");
        return res;
    }
    fieldMetaData->valueRank = valueRank;

    /* PromotedField? */
    if(var->promotedField)
        fieldMetaData->fieldFlags = UA_DATASETFIELDFLAGS_PROMOTEDFIELD;
    else
        fieldMetaData->fieldFlags = UA_DATASETFIELDFLAGS_NONE;

    /* Properties */
    fieldMetaData->properties = NULL;
    fieldMetaData->propertiesSize = 0;

    //TODO collect the following fields*/
    //fieldMetaData.builtInType
    //fieldMetaData.maxStringLength

    return UA_STATUSCODE_GOOD;
}

UA_DataSetFieldResult
UA_DataSetField_create(UA_Server *server, const UA_NodeId publishedDataSet,
                       const UA_DataSetFieldConfig *fieldConfig,
                       UA_NodeId *fieldIdentifier) {
    UA_DataSetFieldResult result;
    memset(&result, 0, sizeof(UA_DataSetFieldResult));
    if(!fieldConfig) {
        result.result = UA_STATUSCODE_BADINVALIDARGUMENT;
        return result;
    }

    UA_PublishedDataSet *currDS =
        UA_PublishedDataSet_findPDSbyId(server, publishedDataSet);
    if(!currDS) {
        result.result = UA_STATUSCODE_BADNOTFOUND;
        return result;
    }

    if(currDS->configurationFreezeCounter > 0) {
        UA_LOG_WARNING_DATASET(server->config.logging, currDS,
                               "Adding DataSetField failed: PublishedDataSet is frozen");
        result.result = UA_STATUSCODE_BADCONFIGURATIONERROR;
        return result;
    }

    if(currDS->config.publishedDataSetType != UA_PUBSUB_DATASET_PUBLISHEDITEMS) {
        result.result = UA_STATUSCODE_BADNOTIMPLEMENTED;
        return result;
    }

    UA_DataSetField *newField = (UA_DataSetField*)UA_calloc(1, sizeof(UA_DataSetField));
    if(!newField) {
        result.result = UA_STATUSCODE_BADINTERNALERROR;
        return result;
    }

    result.result = UA_DataSetFieldConfig_copy(fieldConfig, &newField->config);
    if(result.result != UA_STATUSCODE_GOOD) {
        UA_free(newField);
        return result;
    }

    result.result = UA_NodeId_copy(&currDS->identifier, &newField->publishedDataSet);
    if(result.result != UA_STATUSCODE_GOOD) {
        UA_DataSetFieldConfig_clear(&newField->config);
        UA_free(newField);
        return result;
    }

    /* Initialize the field metadata. Also generates a FieldId */
    UA_FieldMetaData fmd;
    UA_FieldMetaData_init(&fmd);
    result.result = generateFieldMetaData(server, currDS, newField, &fmd);
    if(result.result != UA_STATUSCODE_GOOD) {
        UA_FieldMetaData_clear(&fmd);
        UA_DataSetFieldConfig_clear(&newField->config);
        UA_NodeId_clear(&newField->publishedDataSet);
        UA_free(newField);
        return result;
    }

    /* Append to the metadata fields array. Point of last return. */
    result.result = UA_Array_appendCopy((void**)&currDS->dataSetMetaData.fields,
                                    &currDS->dataSetMetaData.fieldsSize,
                                    &fmd, &UA_TYPES[UA_TYPES_FIELDMETADATA]);
    if(result.result != UA_STATUSCODE_GOOD) {
        UA_FieldMetaData_clear(&fmd);
        UA_DataSetFieldConfig_clear(&newField->config);
        UA_NodeId_clear(&newField->publishedDataSet);
        UA_free(newField);
        return result;
    }

    /* Copy the identifier from the metadata. Cannot fail with a guid NodeId. */
    newField->identifier = UA_NODEID_GUID(1, fmd.dataSetFieldId);
    if(fieldIdentifier)
        UA_NodeId_copy(&newField->identifier, fieldIdentifier);
    UA_FieldMetaData_clear(&fmd);

    /* Register the field. The order of DataSetFields should be the same in both
     * creating and publishing. So adding DataSetFields at the the end of the
     * DataSets using the TAILQ structure. */
    TAILQ_INSERT_TAIL(&currDS->fields, newField, listEntry);
    currDS->fieldSize++;

    if(newField->config.field.variable.promotedField)
        currDS->promotedFieldsCount++;

    /* The values of the metadata are "borrowed" in a mirrored structure in the
     * pds. Reset them after resizing the array. */
    size_t counter = 0;
    UA_DataSetField *dsf;
    TAILQ_FOREACH(dsf, &currDS->fields, listEntry) {
        dsf->fieldMetaData = currDS->dataSetMetaData.fields[counter++];
    }

    /* Update major version of parent published data set */
    UA_EventLoop *el = server->config.eventLoop;
    currDS->dataSetMetaData.configurationVersion.majorVersion =
        UA_PubSubConfigurationVersionTimeDifference(el->dateTime_now(el));

    result.configurationVersion.majorVersion =
        currDS->dataSetMetaData.configurationVersion.majorVersion;
    result.configurationVersion.minorVersion =
        currDS->dataSetMetaData.configurationVersion.minorVersion;
    return result;
}

UA_DataSetFieldResult
UA_Server_addDataSetField(UA_Server *server, const UA_NodeId publishedDataSet,
                          const UA_DataSetFieldConfig *fieldConfig,
                          UA_NodeId *fieldIdentifier) {
    UA_LOCK(&server->serviceMutex);
    UA_DataSetFieldResult res =
        UA_DataSetField_create(server, publishedDataSet, fieldConfig, fieldIdentifier);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_DataSetFieldResult
UA_DataSetField_remove(UA_Server *server, UA_DataSetField *currentField) {
    UA_DataSetFieldResult result;
    memset(&result, 0, sizeof(UA_DataSetFieldResult));

    UA_PublishedDataSet *pds =
        UA_PublishedDataSet_findPDSbyId(server, currentField->publishedDataSet);
    if(!pds) {
        result.result = UA_STATUSCODE_BADNOTFOUND;
        return result;
    }

    if(currentField->configurationFrozen) {
        UA_LOG_WARNING_DATASET(server->config.logging, pds,
                               "Remove DataSetField failed: DataSetField is frozen");
        result.result = UA_STATUSCODE_BADCONFIGURATIONERROR;
        return result;
    }

    if(pds->configurationFreezeCounter > 0) {
        UA_LOG_WARNING_DATASET(server->config.logging, pds,
                               "Remove DataSetField failed: PublishedDataSet is frozen");
        result.result = UA_STATUSCODE_BADCONFIGURATIONERROR;
        return result;
    }

    /* Reduce the counters before the config is cleaned up */
    if(currentField->config.field.variable.promotedField)
        pds->promotedFieldsCount--;
    pds->fieldSize--;

    /* Update major version of PublishedDataSet */
    UA_EventLoop *el = server->config.eventLoop;
    pds->dataSetMetaData.configurationVersion.majorVersion =
        UA_PubSubConfigurationVersionTimeDifference(el->dateTime_now(el));

    /* Clean up */
    currentField->fieldMetaData.arrayDimensions = NULL;
    currentField->fieldMetaData.properties = NULL;
    currentField->fieldMetaData.name = UA_STRING_NULL;
    currentField->fieldMetaData.description.locale = UA_STRING_NULL;
    currentField->fieldMetaData.description.text = UA_STRING_NULL;
    UA_DataSetField_clear(currentField);

    /* Remove */
    TAILQ_REMOVE(&pds->fields, currentField, listEntry);
    UA_free(currentField);

    /* Regenerate DataSetMetaData */
    pds->dataSetMetaData.fieldsSize--;
    if(pds->dataSetMetaData.fieldsSize > 0) {
        for(size_t i = 0; i < pds->dataSetMetaData.fieldsSize+1; i++) {
            UA_FieldMetaData_clear(&pds->dataSetMetaData.fields[i]);
        }
        UA_free(pds->dataSetMetaData.fields);
        UA_FieldMetaData *fieldMetaData = (UA_FieldMetaData *)
            UA_calloc(pds->dataSetMetaData.fieldsSize, sizeof(UA_FieldMetaData));
        if(!fieldMetaData) {
            result.result =  UA_STATUSCODE_BADOUTOFMEMORY;
            return result;
        }
        UA_DataSetField *tmpDSF;
        size_t counter = 0;
        TAILQ_FOREACH(tmpDSF, &pds->fields, listEntry) {
            result.result = generateFieldMetaData(server, pds, tmpDSF, &fieldMetaData[counter]);
            if(result.result != UA_STATUSCODE_GOOD) {
                UA_FieldMetaData_clear(&fieldMetaData[counter]);
                UA_LOG_WARNING_DATASET(server->config.logging, pds,
                                       "PubSub MetaData regeneration failed "
                                       "after removing a field!");
                break;
            }
            // The contents of the metadata is shared between the PDS and its fields.
            tmpDSF->fieldMetaData = fieldMetaData[counter++];
        }
        pds->dataSetMetaData.fields = fieldMetaData;
    } else {
        UA_FieldMetaData_delete(pds->dataSetMetaData.fields);
        pds->dataSetMetaData.fields = NULL;
    }

    result.configurationVersion.majorVersion =
        pds->dataSetMetaData.configurationVersion.majorVersion;
    result.configurationVersion.minorVersion =
        pds->dataSetMetaData.configurationVersion.minorVersion;
    return result;
}

UA_DataSetFieldResult
UA_Server_removeDataSetField(UA_Server *server, const UA_NodeId dsf) {
    UA_LOCK(&server->serviceMutex);
    UA_DataSetFieldResult res;
    memset(&res, 0, sizeof(UA_DataSetFieldResult));
    UA_DataSetField *field = UA_DataSetField_findDSFbyId(server, dsf);
    if(!field) {
        res.result = UA_STATUSCODE_BADNOTFOUND;
        UA_UNLOCK(&server->serviceMutex);
        return res;
    }
    res = UA_DataSetField_remove(server, field);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_DataSetFieldConfig_copy(const UA_DataSetFieldConfig *src,
                           UA_DataSetFieldConfig *dst) {
    if(src->dataSetFieldType != UA_PUBSUB_DATASETFIELD_VARIABLE)
        return UA_STATUSCODE_BADNOTSUPPORTED;
    memcpy(dst, src, sizeof(UA_DataSetFieldConfig));
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    res |= UA_String_copy(&src->field.variable.fieldNameAlias,
                          &dst->field.variable.fieldNameAlias);
    res |= UA_PublishedVariableDataType_copy(&src->field.variable.publishParameters,
                                             &dst->field.variable.publishParameters);
    if(res != UA_STATUSCODE_GOOD)
        UA_DataSetFieldConfig_clear(dst);
    return res;
}

UA_StatusCode
UA_Server_getDataSetFieldConfig(UA_Server *server, const UA_NodeId dsf,
                                UA_DataSetFieldConfig *config) {
    if(!config)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    UA_LOCK(&server->serviceMutex);
    UA_DataSetField *currentDataSetField = UA_DataSetField_findDSFbyId(server, dsf);
    UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND;
    if(currentDataSetField)
        res = UA_DataSetFieldConfig_copy(&currentDataSetField->config, config);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_DataSetField *
UA_DataSetField_findDSFbyId(UA_Server *server, UA_NodeId identifier) {
    UA_PublishedDataSet *tmpPDS;
    TAILQ_FOREACH(tmpPDS, &server->pubSubManager.publishedDataSets, listEntry) {
        UA_DataSetField *tmpField;
        TAILQ_FOREACH(tmpField, &tmpPDS->fields, listEntry) {
            if(UA_NodeId_equal(&tmpField->identifier, &identifier))
                return tmpField;
        }
    }
    return NULL;
}

void
UA_DataSetFieldConfig_clear(UA_DataSetFieldConfig *dataSetFieldConfig) {
    if(dataSetFieldConfig->dataSetFieldType == UA_PUBSUB_DATASETFIELD_VARIABLE) {
        UA_String_clear(&dataSetFieldConfig->field.variable.fieldNameAlias);
        UA_PublishedVariableDataType_clear(&dataSetFieldConfig->field.variable.publishParameters);
    }
}

/* Obtain the latest value for a specific DataSetField. This method is currently
 * called inside the DataSetMessage generation process. */
void
UA_PubSubDataSetField_sampleValue(UA_Server *server, UA_DataSetField *field,
                                  UA_DataValue *value) {
    UA_PublishedVariableDataType *params = &field->config.field.variable.publishParameters;

    /* Read the value */
    if(field->config.field.variable.rtValueSource.rtInformationModelNode) {
        const UA_VariableNode *rtNode = (const UA_VariableNode *)
            UA_NODESTORE_GET(server, &params->publishedVariable);
        *value = **rtNode->valueBackend.backend.external.value;
        value->value.storageType = UA_VARIANT_DATA_NODELETE;
        UA_NODESTORE_RELEASE(server, (const UA_Node *) rtNode);
    } else if(field->config.field.variable.rtValueSource.rtFieldSourceEnabled == false){
        UA_ReadValueId rvid;
        UA_ReadValueId_init(&rvid);
        rvid.nodeId = params->publishedVariable;
        rvid.attributeId = params->attributeId;
        rvid.indexRange = params->indexRange;
        *value = readWithSession(server, &server->adminSession,
                                 &rvid, UA_TIMESTAMPSTORETURN_BOTH);
    } else {
        *value = **field->config.field.variable.rtValueSource.staticValueSource;
        value->value.storageType = UA_VARIANT_DATA_NODELETE;
    }
}

UA_AddPublishedDataSetResult
UA_PublishedDataSet_create(UA_Server *server,
                           const UA_PublishedDataSetConfig *publishedDataSetConfig,
                           UA_NodeId *pdsIdentifier) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_AddPublishedDataSetResult result = {UA_STATUSCODE_BADINVALIDARGUMENT, 0, NULL, {0, 0}};
    if(!publishedDataSetConfig){
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "PublishedDataSet creation failed. No config passed in.");
        return result;
    }

    if(publishedDataSetConfig->publishedDataSetType != UA_PUBSUB_DATASET_PUBLISHEDITEMS){
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "PublishedDataSet creation failed. Unsupported PublishedDataSet type.");
        return result;
    }

    if(UA_String_isEmpty(&publishedDataSetConfig->name)) {
        // DataSet has to have a valid name
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "PublishedDataSet creation failed. Invalid name.");
        return result;
    }

    if(UA_PublishedDataSet_findPDSbyName(server, publishedDataSetConfig->name)) {
        // DataSet name has to be unique in the publisher
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "PublishedDataSet creation failed. DataSet with the same name already exists.");
        result.addResult = UA_STATUSCODE_BADBROWSENAMEDUPLICATED;
        return result;
    }

    /* Create new PDS and add to UA_PubSubManager */
    UA_PublishedDataSet *newPDS = (UA_PublishedDataSet *)
        UA_calloc(1, sizeof(UA_PublishedDataSet));
    if(!newPDS) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "PublishedDataSet creation failed. Out of Memory.");
        result.addResult = UA_STATUSCODE_BADOUTOFMEMORY;
        return result;
    }
    TAILQ_INIT(&newPDS->fields);

    UA_PublishedDataSetConfig *newConfig = &newPDS->config;

    /* Deep copy the given connection config */
    UA_StatusCode res = UA_PublishedDataSetConfig_copy(publishedDataSetConfig, newConfig);
    if(res != UA_STATUSCODE_GOOD){
        UA_free(newPDS);
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "PublishedDataSet creation failed. Configuration copy failed.");
        result.addResult = UA_STATUSCODE_BADINTERNALERROR;
        return result;
    }

    /* TODO: Parse template config and add fields (later PubSub batch) */
    if(newConfig->publishedDataSetType == UA_PUBSUB_DATASET_PUBLISHEDITEMS_TEMPLATE) {
    }

    /* Fill the DataSetMetaData */
    UA_EventLoop *el = server->config.eventLoop;
    result.configurationVersion.majorVersion =
        UA_PubSubConfigurationVersionTimeDifference(el->dateTime_now(el));
    result.configurationVersion.minorVersion =
        UA_PubSubConfigurationVersionTimeDifference(el->dateTime_now(el));
    switch(newConfig->publishedDataSetType) {
    case UA_PUBSUB_DATASET_PUBLISHEDEVENTS_TEMPLATE:
        res = UA_STATUSCODE_BADNOTSUPPORTED;
        break;
    case UA_PUBSUB_DATASET_PUBLISHEDEVENTS:
        res = UA_STATUSCODE_BADNOTSUPPORTED;
        break;
    case UA_PUBSUB_DATASET_PUBLISHEDITEMS:
        newPDS->dataSetMetaData.configurationVersion.majorVersion =
            UA_PubSubConfigurationVersionTimeDifference(el->dateTime_now(el));
        newPDS->dataSetMetaData.configurationVersion.minorVersion =
            UA_PubSubConfigurationVersionTimeDifference(el->dateTime_now(el));
        newPDS->dataSetMetaData.description = UA_LOCALIZEDTEXT_ALLOC("", "");
        newPDS->dataSetMetaData.dataSetClassId = UA_GUID_NULL;
        res = UA_String_copy(&newConfig->name, &newPDS->dataSetMetaData.name);
        break;
    case UA_PUBSUB_DATASET_PUBLISHEDITEMS_TEMPLATE:
        res = UA_DataSetMetaDataType_copy(&newConfig->config.itemsTemplate.metaData,
                                          &newPDS->dataSetMetaData);
        break;
    default:
        res = UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Abort? */
    result.addResult = res;
    if(result.addResult != UA_STATUSCODE_GOOD) {
        UA_PublishedDataSetConfig_clear(newConfig);
        UA_free(newPDS);
        return result;
    }

    /* Insert into the queue of the manager */
    TAILQ_INSERT_TAIL(&server->pubSubManager.publishedDataSets, newPDS, listEntry);
    server->pubSubManager.publishedDataSetsSize++;

#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    /* Create representation and unique id */
    addPublishedDataItemsRepresentation(server, newPDS);
#else
    /* Generate unique nodeId */
    UA_PubSubManager_generateUniqueNodeId(&server->pubSubManager, &newPDS->identifier);
#endif

    /* Cache the log string */
    UA_String idStr = UA_STRING_NULL;
    UA_NodeId_print(&newPDS->identifier, &idStr);
    char tmpLogIdStr[128];
    mp_snprintf(tmpLogIdStr, 128, "PublishedDataset %.*s\t| ", (int)idStr.length, idStr.data);
    newPDS->logIdString = UA_STRING_ALLOC(tmpLogIdStr);
    UA_String_clear(&idStr);

    UA_LOG_INFO_DATASET(server->config.logging, newPDS, "DataSet created");

    /* Return the created identifier */
    if(pdsIdentifier)
        UA_NodeId_copy(&newPDS->identifier, pdsIdentifier);
    return result;
}

UA_AddPublishedDataSetResult
UA_Server_addPublishedDataSet(UA_Server *server,
                              const UA_PublishedDataSetConfig *publishedDataSetConfig,
                              UA_NodeId *pdsIdentifier) {
    UA_LOCK(&server->serviceMutex);
    UA_AddPublishedDataSetResult res =
        UA_PublishedDataSet_create(server, publishedDataSetConfig, pdsIdentifier);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_PublishedDataSet_remove(UA_Server *server, UA_PublishedDataSet *publishedDataSet) {
    if(publishedDataSet->configurationFreezeCounter > 0) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Remove PublishedDataSet failed. PublishedDataSet is frozen.");
        return UA_STATUSCODE_BADCONFIGURATIONERROR;
    }

    //search for referenced writers -> delete this writers. (Standard: writer must be connected with PDS)
    UA_PubSubConnection *tmpConnectoin;
    TAILQ_FOREACH(tmpConnectoin, &server->pubSubManager.connections, listEntry){
        UA_WriterGroup *writerGroup;
        LIST_FOREACH(writerGroup, &tmpConnectoin->writerGroups, listEntry){
            UA_DataSetWriter *currentWriter, *tmpWriterGroup;
            LIST_FOREACH_SAFE(currentWriter, &writerGroup->writers, listEntry, tmpWriterGroup){
                if(UA_NodeId_equal(&currentWriter->connectedDataSet,
                                   &publishedDataSet->identifier)) {
                    UA_DataSetWriter_remove(server, currentWriter);
                }
            }
        }
    }

#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    deleteNode(server, publishedDataSet->identifier, true);
#endif

    UA_LOG_INFO_DATASET(server->config.logging, publishedDataSet, "DataSet deleted");

    UA_PublishedDataSet_clear(server, publishedDataSet);
    server->pubSubManager.publishedDataSetsSize--;

    TAILQ_REMOVE(&server->pubSubManager.publishedDataSets, publishedDataSet, listEntry);
    UA_free(publishedDataSet);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_removePublishedDataSet(UA_Server *server, const UA_NodeId pds) {
    UA_LOCK(&server->serviceMutex);
    UA_PublishedDataSet *currentPDS = UA_PublishedDataSet_findPDSbyId(server, pds);
    if(!currentPDS) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADNOTFOUND;
    }
    UA_StatusCode res = UA_PublishedDataSet_remove(server, currentPDS);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}


UA_StandaloneSubscribedDataSet *
UA_StandaloneSubscribedDataSet_findSDSbyId(UA_Server *server, UA_NodeId identifier) {
    UA_StandaloneSubscribedDataSet *subscribedDataSet;
    TAILQ_FOREACH(subscribedDataSet, &server->pubSubManager.subscribedDataSets,
                  listEntry) {
        if(UA_NodeId_equal(&identifier, &subscribedDataSet->identifier))
            return subscribedDataSet;
    }
    return NULL;
}

UA_StandaloneSubscribedDataSet *
UA_StandaloneSubscribedDataSet_findSDSbyName(UA_Server *server, UA_String identifier) {
    UA_StandaloneSubscribedDataSet *subscribedDataSet;
    TAILQ_FOREACH(subscribedDataSet, &server->pubSubManager.subscribedDataSets,
                  listEntry) {
        if(UA_String_equal(&identifier, &subscribedDataSet->config.name))
            return subscribedDataSet;
    }
    return NULL;
}

UA_StatusCode
UA_StandaloneSubscribedDataSetConfig_copy(const UA_StandaloneSubscribedDataSetConfig *src,
                                          UA_StandaloneSubscribedDataSetConfig *dst) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    memcpy(dst, src, sizeof(UA_StandaloneSubscribedDataSetConfig));
    res = UA_DataSetMetaDataType_copy(&src->dataSetMetaData, &dst->dataSetMetaData);
    res |= UA_String_copy(&src->name, &dst->name);
    res |= UA_Boolean_copy(&src->isConnected, &dst->isConnected);
    res |= UA_TargetVariablesDataType_copy(&src->subscribedDataSet.target,
                                           &dst->subscribedDataSet.target);

    if(res != UA_STATUSCODE_GOOD)
        UA_StandaloneSubscribedDataSetConfig_clear(dst);
    return res;
}

void
UA_StandaloneSubscribedDataSetConfig_clear(
    UA_StandaloneSubscribedDataSetConfig *sdsConfig) {
    UA_String_clear(&sdsConfig->name);
    UA_DataSetMetaDataType_clear(&sdsConfig->dataSetMetaData);
    UA_TargetVariablesDataType_clear(&sdsConfig->subscribedDataSet.target);
}

void
UA_StandaloneSubscribedDataSet_clear(UA_Server *server,
                                     UA_StandaloneSubscribedDataSet *subscribedDataSet) {
    UA_StandaloneSubscribedDataSetConfig_clear(&subscribedDataSet->config);
    UA_NodeId_clear(&subscribedDataSet->identifier);
    UA_NodeId_clear(&subscribedDataSet->connectedReader);
}

#endif /* UA_ENABLE_PUBSUB */

/**** amalgamated original file "/src/pubsub/ua_pubsub_writer.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2017-2019 Fraunhofer IOSB (Author: Andreas Ebner)
 * Copyright (c) 2019 Fraunhofer IOSB (Author: Julius Pfrommer)
 * Copyright (c) 2019-2021 Kalycito Infotech Private Limited
 * Copyright (c) 2020 Yannick Wallerer, Siemens AG
 * Copyright (c) 2020 Thomas Fischer, Siemens AG
 * Copyright (c) 2021 Fraunhofer IOSB (Author: Jan Hermes)
 */


#ifdef UA_ENABLE_PUBSUB /* conditional compilation */


#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
#endif


UA_StatusCode
UA_DataSetWriterConfig_copy(const UA_DataSetWriterConfig *src,
                            UA_DataSetWriterConfig *dst){
    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    memcpy(dst, src, sizeof(UA_DataSetWriterConfig));
    retVal |= UA_String_copy(&src->name, &dst->name);
    retVal |= UA_String_copy(&src->dataSetName, &dst->dataSetName);
    retVal |= UA_ExtensionObject_copy(&src->messageSettings, &dst->messageSettings);
    retVal |= UA_KeyValueMap_copy(&src->dataSetWriterProperties, &dst->dataSetWriterProperties);
    if(retVal != UA_STATUSCODE_GOOD)
        UA_DataSetWriterConfig_clear(dst);
    return retVal;
}

UA_StatusCode
UA_Server_getDataSetWriterConfig(UA_Server *server, const UA_NodeId dsw,
                                 UA_DataSetWriterConfig *config) {
    if(!config)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    UA_LOCK(&server->serviceMutex);
    UA_DataSetWriter *currentDataSetWriter = UA_DataSetWriter_findDSWbyId(server, dsw);
    UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND;
    if(currentDataSetWriter)
        res = UA_DataSetWriterConfig_copy(&currentDataSetWriter->config, config);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_Server_DataSetWriter_getState(UA_Server *server, UA_NodeId dataSetWriterIdentifier,
                               UA_PubSubState *state) {
    if((server == NULL) || (state == NULL))
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    UA_LOCK(&server->serviceMutex);
    UA_DataSetWriter *currentDataSetWriter =
        UA_DataSetWriter_findDSWbyId(server, dataSetWriterIdentifier);
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(currentDataSetWriter) {
        *state = currentDataSetWriter->state;
    } else {
        res = UA_STATUSCODE_BADNOTFOUND;
    }
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_DataSetWriter *
UA_DataSetWriter_findDSWbyId(UA_Server *server, UA_NodeId identifier) {
    UA_PubSubConnection *pubSubConnection;
    TAILQ_FOREACH(pubSubConnection, &server->pubSubManager.connections, listEntry){
        UA_WriterGroup *tmpWriterGroup;
        LIST_FOREACH(tmpWriterGroup, &pubSubConnection->writerGroups, listEntry){
            UA_DataSetWriter *tmpWriter;
            LIST_FOREACH(tmpWriter, &tmpWriterGroup->writers, listEntry){
                if(UA_NodeId_equal(&tmpWriter->identifier, &identifier)){
                    return tmpWriter;
                }
            }
        }
    }
    return NULL;
}

void
UA_DataSetWriterConfig_clear(UA_DataSetWriterConfig *pdsConfig) {
    UA_String_clear(&pdsConfig->name);
    UA_String_clear(&pdsConfig->dataSetName);
    UA_KeyValueMap_clear(&pdsConfig->dataSetWriterProperties);
    UA_ExtensionObject_clear(&pdsConfig->messageSettings);
    memset(pdsConfig, 0, sizeof(UA_DataSetWriterConfig));
}

UA_StatusCode
UA_Server_enableDataSetWriter(UA_Server *server, const UA_NodeId dswId) {
    UA_LOCK(&server->serviceMutex);
    UA_DataSetWriter *dsw = UA_DataSetWriter_findDSWbyId(server, dswId);
    if(!dsw) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADNOTFOUND;
    }

    UA_StatusCode ret =
        UA_DataSetWriter_setPubSubState(server, dsw, UA_PUBSUBSTATE_OPERATIONAL);
    UA_UNLOCK(&server->serviceMutex);
    return ret;
}

UA_StatusCode
UA_Server_disableDataSetWriter(UA_Server *server, const UA_NodeId dswId) {
    UA_LOCK(&server->serviceMutex);
    UA_DataSetWriter *dsw = UA_DataSetWriter_findDSWbyId(server, dswId);
    if(!dsw) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADNOTFOUND;
    }

    UA_StatusCode ret =
        UA_DataSetWriter_setPubSubState(server, dsw, UA_PUBSUBSTATE_DISABLED);
    UA_UNLOCK(&server->serviceMutex);
    return ret;
}

UA_StatusCode
UA_DataSetWriter_setPubSubState(UA_Server *server, UA_DataSetWriter *dsw,
                                UA_PubSubState targetState) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    UA_WriterGroup *wg = dsw->linkedWriterGroup;
    UA_assert(wg);

    UA_PubSubState oldState = dsw->state;
    dsw->state = targetState;

    switch(dsw->state) {
        /* Disabled */
    case UA_PUBSUBSTATE_DISABLED:
    case UA_PUBSUBSTATE_ERROR:
        break;

        /* Enabled */
    case UA_PUBSUBSTATE_PAUSED:
    case UA_PUBSUBSTATE_PREOPERATIONAL:
    case UA_PUBSUBSTATE_OPERATIONAL:
        if(wg->state == UA_PUBSUBSTATE_DISABLED ||
           wg->state == UA_PUBSUBSTATE_ERROR) {
            dsw->state = UA_PUBSUBSTATE_PAUSED; /* WG is disabled -> paused */
        } else {
            dsw->state = wg->state; /* WG is enabled -> same state */
        }
        break;

    default:
        dsw->state = UA_PUBSUBSTATE_ERROR;
        res = UA_STATUSCODE_BADINTERNALERROR;
        break;
    }

    /* Inform application about state change */
    if(dsw->state != oldState) {
        UA_ServerConfig *config = &server->config;
        UA_LOG_INFO_WRITER(config->logging, dsw, "State change: %s -> %s",
                           UA_PubSubState_name(oldState),
                           UA_PubSubState_name(dsw->state));
        if(config->pubSubConfig.stateChangeCallback != 0) {
            UA_UNLOCK(&server->serviceMutex);
            config->pubSubConfig.
                stateChangeCallback(server, &dsw->identifier, dsw->state, res);
            UA_LOCK(&server->serviceMutex);
        }
    }

    return res;
}

UA_StatusCode
UA_DataSetWriter_create(UA_Server *server,
                        const UA_NodeId writerGroup, const UA_NodeId dataSet,
                        const UA_DataSetWriterConfig *dataSetWriterConfig,
                        UA_NodeId *writerIdentifier) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    if(!dataSetWriterConfig)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup);
    if(!wg)
        return UA_STATUSCODE_BADNOTFOUND;

    /* Make checks for a heartbeat */
    if(UA_NodeId_isNull(&dataSet) && dataSetWriterConfig->keyFrameCount != 1) {
        UA_LOG_WARNING_WRITERGROUP(server->config.logging, wg,
                                   "Adding DataSetWriter failed: DataSet can be null only for "
                                   "a heartbeat in which case KeyFrameCount shall be 1");
        return UA_STATUSCODE_BADCONFIGURATIONERROR;
    }

    if(wg->configurationFrozen) {
        UA_LOG_WARNING_WRITERGROUP(server->config.logging, wg,
                                   "Adding DataSetWriter failed: WriterGroup is frozen");
        return UA_STATUSCODE_BADCONFIGURATIONERROR;
    }

    UA_PublishedDataSet *currentDataSetContext = NULL;

    if(!UA_NodeId_isNull(&dataSet)) {
        currentDataSetContext = UA_PublishedDataSet_findPDSbyId(server, dataSet);
        if(!currentDataSetContext)
            return UA_STATUSCODE_BADNOTFOUND;

        if(currentDataSetContext->configurationFreezeCounter > 0) {
            UA_LOG_WARNING_DATASET(server->config.logging, currentDataSetContext,
                                   "Adding DataSetWriter failed: PublishedDataSet is frozen");
            return UA_STATUSCODE_BADCONFIGURATIONERROR;
        }

        if(wg->config.rtLevel != UA_PUBSUB_RT_NONE) {
            UA_DataSetField *tmpDSF;
            TAILQ_FOREACH(tmpDSF, &currentDataSetContext->fields, listEntry) {
                if(!tmpDSF->config.field.variable.rtValueSource.rtFieldSourceEnabled &&
                   !tmpDSF->config.field.variable.rtValueSource.rtInformationModelNode) {
                    UA_LOG_WARNING_DATASET(server->config.logging, currentDataSetContext,
                                           "Adding DataSetWriter failed: "
                                           "Fields in PDS are not RT capable");
                    return UA_STATUSCODE_BADCONFIGURATIONERROR;
                }
            }
        }
    }

    UA_DataSetWriter *newDataSetWriter = (UA_DataSetWriter *)
        UA_calloc(1, sizeof(UA_DataSetWriter));
    if(!newDataSetWriter)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    newDataSetWriter->componentType = UA_PUBSUB_COMPONENT_DATASETWRITER;
    newDataSetWriter->linkedWriterGroup = wg;

    /* Copy the config into the new dataSetWriter */
    UA_StatusCode res =
        UA_DataSetWriterConfig_copy(dataSetWriterConfig, &newDataSetWriter->config);
    UA_CHECK_STATUS(res, UA_free(newDataSetWriter); return res);

    if(!UA_NodeId_isNull(&dataSet) && currentDataSetContext != NULL) {
        /* Save the current version of the connected PublishedDataSet */
        newDataSetWriter->connectedDataSetVersion =
            currentDataSetContext->dataSetMetaData.configurationVersion;

        if(server->config.pubSubConfig.enableDeltaFrames) {
            /* Initialize the queue for the last values */
            if(currentDataSetContext->fieldSize > 0) {
                newDataSetWriter->lastSamples = (UA_DataSetWriterSample*)
                    UA_calloc(currentDataSetContext->fieldSize, sizeof(UA_DataSetWriterSample));
                if(!newDataSetWriter->lastSamples) {
                    UA_DataSetWriterConfig_clear(&newDataSetWriter->config);
                    UA_free(newDataSetWriter);
                    return UA_STATUSCODE_BADOUTOFMEMORY;
                }
                newDataSetWriter->lastSamplesCount = currentDataSetContext->fieldSize;
                for(size_t i = 0; i < newDataSetWriter->lastSamplesCount; i++) {
                    UA_DataValue_init(&newDataSetWriter->lastSamples[i].value);
                    newDataSetWriter->lastSamples[i].valueChanged = false;
                }
            }
        }
        /* Connect PublishedDataSet with DataSetWriter */
        newDataSetWriter->connectedDataSet = currentDataSetContext->identifier;
    } else {
        /* If the dataSet is NULL, we are adding a heartbeat writer */
        newDataSetWriter->connectedDataSetVersion.majorVersion = 0;
        newDataSetWriter->connectedDataSetVersion.minorVersion = 0;
        newDataSetWriter->connectedDataSet = UA_NODEID_NULL;
    }

    /* Add the new writer to the group */
    LIST_INSERT_HEAD(&wg->writers, newDataSetWriter, listEntry);
    wg->writersCount++;

    /* Add to the information model */
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    res |= addDataSetWriterRepresentation(server, newDataSetWriter);
#else
    UA_PubSubManager_generateUniqueNodeId(&server->pubSubManager,
                                          &newDataSetWriter->identifier);
#endif

    /* Cache the log string */
    UA_String idStr = UA_STRING_NULL;
    UA_NodeId_print(&newDataSetWriter->identifier, &idStr);
    char tmpLogIdStr[128];
    mp_snprintf(tmpLogIdStr, 128, "%.*sDataSetWriter %.*s\t| ",
                (int)newDataSetWriter->linkedWriterGroup->logIdString.length,
                (char*)newDataSetWriter->linkedWriterGroup->logIdString.data,
                (int)idStr.length, idStr.data);
    newDataSetWriter->logIdString = UA_STRING_ALLOC(tmpLogIdStr);
    UA_String_clear(&idStr);

    UA_LOG_INFO_WRITER(server->config.logging, newDataSetWriter, "Writer created");

    /* Enable, depending on the state of the WriterGroup */
    UA_DataSetWriter_setPubSubState(server, newDataSetWriter,
                                    UA_PUBSUBSTATE_OPERATIONAL);

    if(writerIdentifier)
        UA_NodeId_copy(&newDataSetWriter->identifier, writerIdentifier);
    return res;
}

UA_StatusCode
UA_Server_addDataSetWriter(UA_Server *server,
                           const UA_NodeId writerGroup, const UA_NodeId dataSet,
                           const UA_DataSetWriterConfig *dataSetWriterConfig,
                           UA_NodeId *writerIdentifier) {
    UA_LOCK(&server->serviceMutex);
    /* Delete the reserved IDs if the related session no longer exists. */
    UA_PubSubManager_freeIds(server);
    UA_StatusCode res = UA_DataSetWriter_create(server, writerGroup, dataSet,
                                                dataSetWriterConfig, writerIdentifier);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

void
UA_DataSetWriter_freezeConfiguration(UA_Server *server,
                                     UA_DataSetWriter *dsw) {
    UA_PublishedDataSet *pds =
        UA_PublishedDataSet_findPDSbyId(server, dsw->connectedDataSet);
    if(pds) { /* Skip for heartbeat writers */
        pds->configurationFreezeCounter++;
        UA_DataSetField *dsf;
        TAILQ_FOREACH(dsf, &pds->fields, listEntry) {
            dsf->configurationFrozen = true;
        }
    }
    dsw->configurationFrozen = true;
}

void
UA_DataSetWriter_unfreezeConfiguration(UA_Server *server,
                                       UA_DataSetWriter *dsw) {
    UA_PublishedDataSet *pds =
        UA_PublishedDataSet_findPDSbyId(server, dsw->connectedDataSet);
    if(pds) { /* Skip for heartbeat writers */
        pds->configurationFreezeCounter--;
        if(pds->configurationFreezeCounter == 0) {
            UA_DataSetField *dsf;
            TAILQ_FOREACH(dsf, &pds->fields, listEntry){
                dsf->configurationFrozen = false;
            }
        }
        dsw->configurationFrozen = false;
    }
}

UA_StatusCode
UA_DataSetWriter_prepareDataSet(UA_Server *server, UA_DataSetWriter *dsw,
                                UA_DataSetMessage *dsm) {
    /* Find the dataset */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    UA_PublishedDataSet *pds =
        UA_PublishedDataSet_findPDSbyId(server, dsw->connectedDataSet);
    if(!pds) {
        if(!UA_NodeId_isNull(&dsw->connectedDataSet)) {
            UA_LOG_WARNING_WRITER(server->config.logging, dsw,
                                  "PubSub-RT configuration fail: "
                                  "PublishedDataSet not found");
            return UA_STATUSCODE_BADINTERNALERROR;
        }

        res = UA_DataSetWriter_generateDataSetMessage(server, dsm, dsw);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING_WRITER(server->config.logging, dsw,
                                  "PubSub-RT configuration fail: "
                                  "Heartbeat DataSetMessage creation failed");
        }
        return res;
    }

    if(pds->promotedFieldsCount > 0) {
        UA_LOG_WARNING_WRITER(server->config.logging, dsw,
                              "PubSub-RT configuration fail: "
                              "PDS contains promoted fields");
        return UA_STATUSCODE_BADNOTSUPPORTED;
    }

    /* Test the DataSetFields */
    UA_DataSetField *dsf;
    TAILQ_FOREACH(dsf, &pds->fields, listEntry) {
        UA_NodeId *publishedVariable =
            &dsf->config.field.variable.publishParameters.publishedVariable;
        const UA_VariableNode *rtNode = (const UA_VariableNode*)
            UA_NODESTORE_GET(server, publishedVariable);
        if(rtNode != NULL &&
           rtNode->valueBackend.backendType != UA_VALUEBACKENDTYPE_EXTERNAL) {
            UA_LOG_WARNING_WRITER(server->config.logging, dsw,
                                  "PubSub-RT configuration fail: "
                                  "PDS contains field without external data source");
            UA_NODESTORE_RELEASE(server, (const UA_Node *)rtNode);
            return UA_STATUSCODE_BADNOTSUPPORTED;
        }

        UA_NODESTORE_RELEASE(server, (const UA_Node *)rtNode);

        if((UA_NodeId_equal(&dsf->fieldMetaData.dataType,
                            &UA_TYPES[UA_TYPES_STRING].typeId) ||
            UA_NodeId_equal(&dsf->fieldMetaData.dataType,
                            &UA_TYPES[UA_TYPES_BYTESTRING].typeId)) &&
           dsf->fieldMetaData.maxStringLength == 0) {
            UA_LOG_WARNING_WRITER(server->config.logging, dsw,
                                  "PubSub-RT configuration fail: "
                                  "PDS contains String/ByteString with dynamic length");
            return UA_STATUSCODE_BADNOTSUPPORTED;
        } else if(!UA_DataType_isNumeric(UA_findDataType(&dsf->fieldMetaData.dataType)) &&
                  !UA_NodeId_equal(&dsf->fieldMetaData.dataType,
                                   &UA_TYPES[UA_TYPES_BOOLEAN].typeId)) {
            UA_LOG_WARNING_WRITER(server->config.logging, dsw,
                                  "PubSub-RT configuration fail: "
                                  "PDS contains variable with dynamic size");
            return UA_STATUSCODE_BADNOTSUPPORTED;
        }
    }

    /* Generate the DSM */
    res = UA_DataSetWriter_generateDataSetMessage(server, dsm, dsw);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_WRITER(server->config.logging, dsw,
                              "PubSub-RT configuration fail: "
                              "DataSetMessage buffering failed");
    }

    return res;
}

UA_StatusCode
UA_DataSetWriter_remove(UA_Server *server, UA_DataSetWriter *dataSetWriter) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Frozen? */
    if(dataSetWriter->configurationFrozen) {
        UA_LOG_WARNING_WRITER(server->config.logging, dataSetWriter,
                              "Remove DataSetWriter failed: WriterGroup is frozen");
        return UA_STATUSCODE_BADCONFIGURATIONERROR;
    }

    /* Remove from information model */
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    deleteNode(server, dataSetWriter->identifier, true);
#endif

    /* Remove DataSetWriter from group */
    UA_WriterGroup *linkedWriterGroup = dataSetWriter->linkedWriterGroup;
    LIST_REMOVE(dataSetWriter, listEntry);
    linkedWriterGroup->writersCount--;

    UA_LOG_INFO_WRITER(server->config.logging, dataSetWriter, "Writer deleted");

    UA_DataSetWriterConfig_clear(&dataSetWriter->config);
    UA_NodeId_clear(&dataSetWriter->identifier);
    UA_NodeId_clear(&dataSetWriter->connectedDataSet);

    if(server->config.pubSubConfig.enableDeltaFrames) {
        /* Delete lastSamples store */
        for(size_t i = 0; i < dataSetWriter->lastSamplesCount; i++) {
            UA_DataValue_clear(&dataSetWriter->lastSamples[i].value);
        }
        UA_free(dataSetWriter->lastSamples);
        dataSetWriter->lastSamples = NULL;
        dataSetWriter->lastSamplesCount = 0;
    }

    UA_String_clear(&dataSetWriter->logIdString);
    UA_free(dataSetWriter);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_removeDataSetWriter(UA_Server *server, const UA_NodeId dsw) {
    UA_LOCK(&server->serviceMutex);
    UA_DataSetWriter *dataSetWriter = UA_DataSetWriter_findDSWbyId(server, dsw);
    if(!dataSetWriter) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADNOTFOUND;
    }
    UA_StatusCode res = UA_DataSetWriter_remove(server, dataSetWriter);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

/*********************************************************/
/*               PublishValues handling                  */
/*********************************************************/

/* Compare two variants. Internally used for value change detection. */
static UA_Boolean
valueChangedVariant(UA_Variant *oldValue, UA_Variant *newValue) {
    if(!oldValue || !newValue)
        return false;

    size_t oldValueEncodingSize = UA_calcSizeBinary(oldValue, &UA_TYPES[UA_TYPES_VARIANT]);
    size_t newValueEncodingSize = UA_calcSizeBinary(newValue, &UA_TYPES[UA_TYPES_VARIANT]);
    if(oldValueEncodingSize == 0 || newValueEncodingSize == 0)
        return false;

    if(oldValueEncodingSize != newValueEncodingSize)
        return true;

    UA_ByteString oldValueEncoding = UA_BYTESTRING_NULL;
    UA_StatusCode res = UA_ByteString_allocBuffer(&oldValueEncoding, oldValueEncodingSize);
    if(res != UA_STATUSCODE_GOOD)
        return false;

    UA_ByteString newValueEncoding = UA_BYTESTRING_NULL;
    res = UA_ByteString_allocBuffer(&newValueEncoding, newValueEncodingSize);
    if(res != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&oldValueEncoding);
        return false;
    }

    UA_Byte *bufPosOldValue = oldValueEncoding.data;
    const UA_Byte *bufEndOldValue = &oldValueEncoding.data[oldValueEncoding.length];
    UA_Byte *bufPosNewValue = newValueEncoding.data;
    const UA_Byte *bufEndNewValue = &newValueEncoding.data[newValueEncoding.length];

    UA_Boolean compareResult = false; /* default */

    res = UA_encodeBinaryInternal(oldValue, &UA_TYPES[UA_TYPES_VARIANT],
                                  &bufPosOldValue, &bufEndOldValue, NULL, NULL);
    if(res != UA_STATUSCODE_GOOD)
        goto cleanup;

    res = UA_encodeBinaryInternal(newValue, &UA_TYPES[UA_TYPES_VARIANT],
                                  &bufPosNewValue, &bufEndNewValue, NULL, NULL);
    if(res != UA_STATUSCODE_GOOD)
        goto cleanup;

    oldValueEncoding.length = (uintptr_t)bufPosOldValue - (uintptr_t)oldValueEncoding.data;
    newValueEncoding.length = (uintptr_t)bufPosNewValue - (uintptr_t)newValueEncoding.data;
    compareResult = !UA_ByteString_equal(&oldValueEncoding, &newValueEncoding);

 cleanup:
    UA_ByteString_clear(&oldValueEncoding);
    UA_ByteString_clear(&newValueEncoding);
    return compareResult;
}

static UA_StatusCode
UA_PubSubDataSetWriter_generateKeyFrameMessage(UA_Server *server,
                                               UA_DataSetMessage *dataSetMessage,
                                               UA_DataSetWriter *dataSetWriter) {
    UA_PublishedDataSet *currentDataSet =
        UA_PublishedDataSet_findPDSbyId(server, dataSetWriter->connectedDataSet);
    if(!currentDataSet)
        return UA_STATUSCODE_BADNOTFOUND;

    /* Prepare DataSetMessageContent */
    dataSetMessage->header.dataSetMessageValid = true;
    dataSetMessage->header.dataSetMessageType = UA_DATASETMESSAGE_DATAKEYFRAME;
    dataSetMessage->data.keyFrameData.fieldCount = currentDataSet->fieldSize;
    dataSetMessage->data.keyFrameData.dataSetFields = (UA_DataValue *)
            UA_Array_new(currentDataSet->fieldSize, &UA_TYPES[UA_TYPES_DATAVALUE]);
    UA_PublishedDataSet *pds = UA_PublishedDataSet_findPDSbyId(server, dataSetWriter->connectedDataSet);
    dataSetMessage->data.keyFrameData.dataSetMetaDataType = &pds->dataSetMetaData;
    if(!dataSetMessage->data.keyFrameData.dataSetFields)
        return UA_STATUSCODE_BADOUTOFMEMORY;

#ifdef UA_ENABLE_JSON_ENCODING
    dataSetMessage->data.keyFrameData.fieldNames = (UA_String *)
        UA_Array_new(currentDataSet->fieldSize, &UA_TYPES[UA_TYPES_STRING]);
    if(!dataSetMessage->data.keyFrameData.fieldNames) {
        UA_DataSetMessage_clear(dataSetMessage);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
#endif

    /* Loop over the fields */
    size_t counter = 0;
    UA_DataSetField *dsf;
    TAILQ_FOREACH(dsf, &currentDataSet->fields, listEntry) {
#ifdef UA_ENABLE_JSON_ENCODING
        /* Set the field name alias */
        UA_String_copy(&dsf->config.field.variable.fieldNameAlias,
                       &dataSetMessage->data.keyFrameData.fieldNames[counter]);
#endif

        /* Sample the value */
        UA_DataValue *dfv = &dataSetMessage->data.keyFrameData.dataSetFields[counter];
        UA_PubSubDataSetField_sampleValue(server, dsf, dfv);

        /* Deactivate statuscode? */
        if(((u64)dataSetWriter->config.dataSetFieldContentMask &
            (u64)UA_DATASETFIELDCONTENTMASK_STATUSCODE) == 0)
            dfv->hasStatus = false;

        /* Deactivate timestamps */
        if(((u64)dataSetWriter->config.dataSetFieldContentMask &
            (u64)UA_DATASETFIELDCONTENTMASK_SOURCETIMESTAMP) == 0)
            dfv->hasSourceTimestamp = false;
        if(((u64)dataSetWriter->config.dataSetFieldContentMask &
            (u64)UA_DATASETFIELDCONTENTMASK_SOURCEPICOSECONDS) == 0)
            dfv->hasSourcePicoseconds = false;
        if(((u64)dataSetWriter->config.dataSetFieldContentMask &
            (u64)UA_DATASETFIELDCONTENTMASK_SERVERTIMESTAMP) == 0)
            dfv->hasServerTimestamp = false;
        if(((u64)dataSetWriter->config.dataSetFieldContentMask &
            (u64)UA_DATASETFIELDCONTENTMASK_SERVERPICOSECONDS) == 0)
            dfv->hasServerPicoseconds = false;

        if(server->config.pubSubConfig.enableDeltaFrames) {
            /* Update lastValue store */
            UA_DataValue_clear(&dataSetWriter->lastSamples[counter].value);
            UA_DataValue_copy(dfv, &dataSetWriter->lastSamples[counter].value);
        }
        counter++;
    }
    return UA_STATUSCODE_GOOD;
}

/* the input message is already initialized and that the method 
 * must not be called twice for the same message */
static UA_StatusCode
UA_PubSubDataSetWriter_generateDeltaFrameMessage(UA_Server *server,
                                                 UA_DataSetMessage *dataSetMessage,
                                                 UA_DataSetWriter *dataSetWriter) {
    UA_PublishedDataSet *currentDataSet =
        UA_PublishedDataSet_findPDSbyId(server, dataSetWriter->connectedDataSet);
    if(!currentDataSet)
        return UA_STATUSCODE_BADNOTFOUND;

    /* Prepare DataSetMessageContent */
    dataSetMessage->header.dataSetMessageValid = true;
    dataSetMessage->header.dataSetMessageType = UA_DATASETMESSAGE_DATADELTAFRAME;
    if(currentDataSet->fieldSize == 0)
        return UA_STATUSCODE_GOOD;

    UA_DataSetField *dsf;
    UA_UInt16 counter = 0;
    TAILQ_FOREACH(dsf, &currentDataSet->fields, listEntry) {
        /* Sample the value */
        UA_DataValue value;
        UA_DataValue_init(&value);
        UA_PubSubDataSetField_sampleValue(server, dsf, &value);

        /* Check if the value has changed */
        UA_DataSetWriterSample *ls = &dataSetWriter->lastSamples[counter];
        if(valueChangedVariant(&ls->value.value, &value.value)) {
            /* increase fieldCount for current delta message */
            dataSetMessage->data.deltaFrameData.fieldCount++;
            ls->valueChanged = true;

            /* Update last stored sample */
            UA_DataValue_clear(&ls->value);
            ls->value = value;
        } else {
            UA_DataValue_clear(&value);
            ls->valueChanged = false;
        }

        counter++;
    }

    /* Allocate DeltaFrameFields */
    UA_DataSetMessage_DeltaFrameField *deltaFields = (UA_DataSetMessage_DeltaFrameField *)
        UA_calloc(counter, sizeof(UA_DataSetMessage_DeltaFrameField));
    if(!deltaFields)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    dataSetMessage->data.deltaFrameData.deltaFrameFields = deltaFields;
    dataSetMessage->data.deltaFrameData.fieldCount = counter;

    size_t currentDeltaField = 0;
    for(size_t i = 0; i < currentDataSet->fieldSize; i++) {
        if(!dataSetWriter->lastSamples[i].valueChanged)
            continue;

        UA_DataSetMessage_DeltaFrameField *dff = &deltaFields[currentDeltaField];

        dff->fieldIndex = (UA_UInt16) i;
        UA_DataValue_copy(&dataSetWriter->lastSamples[i].value, &dff->fieldValue);

        /* Reset the changed flag */
        dataSetWriter->lastSamples[i].valueChanged = false;

        /* Deactivate statuscode? */
        if(((u64)dataSetWriter->config.dataSetFieldContentMask &
            (u64)UA_DATASETFIELDCONTENTMASK_STATUSCODE) == 0)
            dff->fieldValue.hasStatus = false;

        /* Deactivate timestamps? */
        if(((u64)dataSetWriter->config.dataSetFieldContentMask &
            (u64)UA_DATASETFIELDCONTENTMASK_SOURCETIMESTAMP) == 0)
            dff->fieldValue.hasSourceTimestamp = false;
        if(((u64)dataSetWriter->config.dataSetFieldContentMask &
            (u64)UA_DATASETFIELDCONTENTMASK_SOURCEPICOSECONDS) == 0)
            dff->fieldValue.hasServerPicoseconds = false;
        if(((u64)dataSetWriter->config.dataSetFieldContentMask &
            (u64)UA_DATASETFIELDCONTENTMASK_SERVERTIMESTAMP) == 0)
            dff->fieldValue.hasServerTimestamp = false;
        if(((u64)dataSetWriter->config.dataSetFieldContentMask &
            (u64)UA_DATASETFIELDCONTENTMASK_SERVERPICOSECONDS) == 0)
            dff->fieldValue.hasServerPicoseconds = false;

        currentDeltaField++;
    }
    return UA_STATUSCODE_GOOD;
}

/* Generate a DataSetMessage for the given writer. */
UA_StatusCode
UA_DataSetWriter_generateDataSetMessage(UA_Server *server,
                                        UA_DataSetMessage *dataSetMessage,
                                        UA_DataSetWriter *dataSetWriter) {
    UA_Boolean heartbeat = false;
    UA_PublishedDataSet *currentDataSet = NULL;

    if(UA_NodeId_isNull(&dataSetWriter->connectedDataSet)){
        heartbeat = true;
    } else {
        currentDataSet =
            UA_PublishedDataSet_findPDSbyId(server, dataSetWriter->connectedDataSet);
        if(!currentDataSet){
            return UA_STATUSCODE_BADNOTFOUND;
        }
    }

    UA_WriterGroup *wg = dataSetWriter->linkedWriterGroup;
    UA_EventLoop *el = UA_PubSubConnection_getEL(server, wg->linkedConnection);

    /* Reset the message */
    memset(dataSetMessage, 0, sizeof(UA_DataSetMessage));

    /* The configuration Flags are included
     * inside the std. defined UA_UadpDataSetWriterMessageDataType */
    UA_UadpDataSetWriterMessageDataType defaultUadpConfiguration;
    UA_UadpDataSetWriterMessageDataType *dsm = NULL;
    UA_JsonDataSetWriterMessageDataType *jsonDsm = NULL;
    const UA_ExtensionObject *ms = &dataSetWriter->config.messageSettings;
    if((ms->encoding == UA_EXTENSIONOBJECT_DECODED ||
        ms->encoding == UA_EXTENSIONOBJECT_DECODED_NODELETE) &&
       ms->content.decoded.type == &UA_TYPES[UA_TYPES_UADPDATASETWRITERMESSAGEDATATYPE]) {
        dsm = (UA_UadpDataSetWriterMessageDataType*)ms->content.decoded.data; /* type is UADP */
    } else if((ms->encoding == UA_EXTENSIONOBJECT_DECODED ||
               ms->encoding == UA_EXTENSIONOBJECT_DECODED_NODELETE) &&
              ms->content.decoded.type == &UA_TYPES[UA_TYPES_JSONDATASETWRITERMESSAGEDATATYPE]) {
        jsonDsm = (UA_JsonDataSetWriterMessageDataType*)ms->content.decoded.data; /* type is JSON */
    } else {
        /* Create default flag configuration if no
         * UadpDataSetWriterMessageDataType was passed in */
        memset(&defaultUadpConfiguration, 0, sizeof(UA_UadpDataSetWriterMessageDataType));
        defaultUadpConfiguration.dataSetMessageContentMask = (UA_UadpDataSetMessageContentMask)
            ((u64)UA_UADPDATASETMESSAGECONTENTMASK_TIMESTAMP |
             (u64)UA_UADPDATASETMESSAGECONTENTMASK_MAJORVERSION |
             (u64)UA_UADPDATASETMESSAGECONTENTMASK_MINORVERSION);
        dsm = &defaultUadpConfiguration; /* type is UADP */
    }

    /* The field encoding depends on the flags inside the writer config. */
    if(dataSetWriter->config.dataSetFieldContentMask &
       (u64)UA_DATASETFIELDCONTENTMASK_RAWDATA) {
        dataSetMessage->header.fieldEncoding = UA_FIELDENCODING_RAWDATA;
    } else if((u64)dataSetWriter->config.dataSetFieldContentMask &
              ((u64)UA_DATASETFIELDCONTENTMASK_SOURCETIMESTAMP |
               (u64)UA_DATASETFIELDCONTENTMASK_SERVERPICOSECONDS |
               (u64)UA_DATASETFIELDCONTENTMASK_SOURCEPICOSECONDS |
               (u64)UA_DATASETFIELDCONTENTMASK_STATUSCODE)) {
        dataSetMessage->header.fieldEncoding = UA_FIELDENCODING_DATAVALUE;
    } else {
        dataSetMessage->header.fieldEncoding = UA_FIELDENCODING_VARIANT;
    }

    if(dsm) {
        /* Sanity-test the configuration */
        if(dsm->networkMessageNumber != 0 ||
           dsm->dataSetOffset != 0 ||
           dsm->configuredSize != 0) {
            UA_LOG_WARNING_WRITER(server->config.logging, dataSetWriter,
                                  "Static DSM configuration not supported, using defaults");
            dsm->networkMessageNumber = 0;
            dsm->dataSetOffset = 0;
          //  dsm->configuredSize = 0;
        }

        /* setting configured size in the dataSetMessage to add padding later on */
        dataSetMessage->configuredSize = dsm->configuredSize;

        /* Std: 'The DataSetMessageContentMask defines the flags for the content
         * of the DataSetMessage header.' */
        if((u64)dsm->dataSetMessageContentMask &
           (u64)UA_UADPDATASETMESSAGECONTENTMASK_MAJORVERSION) {
            dataSetMessage->header.configVersionMajorVersionEnabled = true;
            if(heartbeat){
                dataSetMessage->header.configVersionMajorVersion = 0;
            } else {
                dataSetMessage->header.configVersionMajorVersion =
                    currentDataSet->dataSetMetaData.configurationVersion.majorVersion;
            }
        }
        if((u64)dsm->dataSetMessageContentMask &
           (u64)UA_UADPDATASETMESSAGECONTENTMASK_MINORVERSION) {
            dataSetMessage->header.configVersionMinorVersionEnabled = true;
            if(heartbeat){
                dataSetMessage->header.configVersionMinorVersion = 0;
            } else {
                dataSetMessage->header.configVersionMinorVersion =
                    currentDataSet->dataSetMetaData.configurationVersion.minorVersion;
            }
        }

        if((u64)dsm->dataSetMessageContentMask &
           (u64)UA_UADPDATASETMESSAGECONTENTMASK_SEQUENCENUMBER) {
            dataSetMessage->header.dataSetMessageSequenceNrEnabled = true;
            dataSetMessage->header.dataSetMessageSequenceNr =
                dataSetWriter->actualDataSetMessageSequenceCount;
        }

        if((u64)dsm->dataSetMessageContentMask &
           (u64)UA_UADPDATASETMESSAGECONTENTMASK_TIMESTAMP) {
            dataSetMessage->header.timestampEnabled = true;
            dataSetMessage->header.timestamp = el->dateTime_now(el);
        }

        /* TODO: Picoseconds resolution not supported atm */
        if((u64)dsm->dataSetMessageContentMask &
           (u64)UA_UADPDATASETMESSAGECONTENTMASK_PICOSECONDS) {
            dataSetMessage->header.picoSecondsIncluded = false;
        }

        /* TODO: Statuscode not supported yet */
        if((u64)dsm->dataSetMessageContentMask &
           (u64)UA_UADPDATASETMESSAGECONTENTMASK_STATUS) {
            dataSetMessage->header.statusEnabled = true;
        }
    } else if(jsonDsm) {
        if((u64)jsonDsm->dataSetMessageContentMask &
           (u64)UA_JSONDATASETMESSAGECONTENTMASK_METADATAVERSION) {
            dataSetMessage->header.configVersionMajorVersionEnabled = true;
            if(heartbeat){
                dataSetMessage->header.configVersionMajorVersion = 0;
            } else {
                dataSetMessage->header.configVersionMajorVersion =
                currentDataSet->dataSetMetaData.configurationVersion.majorVersion;
            }
       }
        if((u64)jsonDsm->dataSetMessageContentMask &
           (u64)UA_JSONDATASETMESSAGECONTENTMASK_METADATAVERSION) {
            dataSetMessage->header.configVersionMinorVersionEnabled = true;
            if(heartbeat){
                dataSetMessage->header.configVersionMinorVersion = 0;
            } else {
                dataSetMessage->header.configVersionMinorVersion =
                currentDataSet->dataSetMetaData.configurationVersion.minorVersion;
            }
       }

        if((u64)jsonDsm->dataSetMessageContentMask &
           (u64)UA_JSONDATASETMESSAGECONTENTMASK_SEQUENCENUMBER) {
            dataSetMessage->header.dataSetMessageSequenceNrEnabled = true;
            dataSetMessage->header.dataSetMessageSequenceNr =
                dataSetWriter->actualDataSetMessageSequenceCount;
        }

        if((u64)jsonDsm->dataSetMessageContentMask &
           (u64)UA_JSONDATASETMESSAGECONTENTMASK_TIMESTAMP) {
            dataSetMessage->header.timestampEnabled = true;
            dataSetMessage->header.timestamp = el->dateTime_now(el);
        }

        /* TODO: Statuscode not supported yet */
        if((u64)jsonDsm->dataSetMessageContentMask &
           (u64)UA_JSONDATASETMESSAGECONTENTMASK_STATUS) {
            dataSetMessage->header.statusEnabled = true;
        }
    }

    /* Set the sequence count. Automatically rolls over to zero */
    dataSetWriter->actualDataSetMessageSequenceCount++;

    if(heartbeat) {
        /* Prepare DataSetMessageContent */
        dataSetMessage->header.dataSetMessageValid = true;
        dataSetMessage->header.dataSetMessageType = UA_DATASETMESSAGE_DATAKEYFRAME;
        dataSetMessage->data.keyFrameData.fieldCount = 0;
        return UA_STATUSCODE_GOOD;
    }

    /* JSON does not differ between deltaframes and keyframes, only keyframes
     * are currently used. */
    if(dsm && server->config.pubSubConfig.enableDeltaFrames) {
        /* Check if the PublishedDataSet version has changed -> if yes flush the
         * lastValue store and send a KeyFrame */
        if(dataSetWriter->connectedDataSetVersion.majorVersion !=
           currentDataSet->dataSetMetaData.configurationVersion.majorVersion ||
           dataSetWriter->connectedDataSetVersion.minorVersion !=
           currentDataSet->dataSetMetaData.configurationVersion.minorVersion) {
            /* Remove old samples */
            for(size_t i = 0; i < dataSetWriter->lastSamplesCount; i++)
                UA_DataValue_clear(&dataSetWriter->lastSamples[i].value);

            /* Realloc PDS dependent memory */
            dataSetWriter->lastSamplesCount = currentDataSet->fieldSize;
            UA_DataSetWriterSample *newSamplesArray = (UA_DataSetWriterSample * )
                UA_realloc(dataSetWriter->lastSamples,
                           sizeof(UA_DataSetWriterSample) * dataSetWriter->lastSamplesCount);
            if(!newSamplesArray)
                return UA_STATUSCODE_BADOUTOFMEMORY;
            dataSetWriter->lastSamples = newSamplesArray;
            memset(dataSetWriter->lastSamples, 0,
                   sizeof(UA_DataSetWriterSample) * dataSetWriter->lastSamplesCount);

            dataSetWriter->connectedDataSetVersion =
                currentDataSet->dataSetMetaData.configurationVersion;
            UA_PubSubDataSetWriter_generateKeyFrameMessage(server, dataSetMessage,
                                                           dataSetWriter);
            dataSetWriter->deltaFrameCounter = 0;
            return UA_STATUSCODE_GOOD;
        }

        /* The standard defines: if a PDS contains only one fields no delta messages
         * should be generated because they need more memory than a keyframe with 1
         * field. */
        if(currentDataSet->fieldSize > 1 && dataSetWriter->deltaFrameCounter > 0 &&
           dataSetWriter->deltaFrameCounter <= dataSetWriter->config.keyFrameCount) {
            UA_PubSubDataSetWriter_generateDeltaFrameMessage(server, dataSetMessage,
                                                             dataSetWriter);
            dataSetWriter->deltaFrameCounter++;
            return UA_STATUSCODE_GOOD;
        }

        dataSetWriter->deltaFrameCounter = 1;
    }

    return UA_PubSubDataSetWriter_generateKeyFrameMessage(server, dataSetMessage,
                                                          dataSetWriter);
}

#endif /* UA_ENABLE_PUBSUB */

/**** amalgamated original file "/src/pubsub/ua_pubsub_writergroup.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2017-2019 Fraunhofer IOSB (Author: Andreas Ebner)
 * Copyright (c) 2019 Fraunhofer IOSB (Author: Julius Pfrommer)
 * Copyright (c) 2019 Kalycito Infotech Private Limited
 * Copyright (c) 2020 Yannick Wallerer, Siemens AG
 * Copyright (c) 2020 Thomas Fischer, Siemens AG
 * Copyright (c) 2021 Fraunhofer IOSB (Author: Jan Hermes)
 * Copyright (c) 2022 Linutronix GmbH (Author: Muddasir Shakil)
 */


#ifdef UA_ENABLE_PUBSUB /* conditional compilation */


#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
#endif

#define UA_MAX_STACKBUF 128 /* Max size of network messages on the stack */

#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
static UA_StatusCode
encryptAndSign(UA_WriterGroup *wg, const UA_NetworkMessage *nm,
               UA_Byte *signStart, UA_Byte *encryptStart,
               UA_Byte *msgEnd);

#endif

static UA_StatusCode
generateNetworkMessage(UA_PubSubConnection *connection, UA_WriterGroup *wg,
                       UA_DataSetMessage *dsm, UA_UInt16 *writerIds, UA_Byte dsmCount,
                       UA_ExtensionObject *messageSettings,
                       UA_ExtensionObject *transportSettings,
                       UA_NetworkMessage *networkMessage);

UA_Boolean
UA_WriterGroup_canConnect(UA_WriterGroup *wg) {
    /* Already connected */
    if(wg->sendChannel != 0)
        return false;

    /* Is this a WriterGroup with custom TransportSettings beyond the
     * PubSubConnection? */
    if(wg->config.transportSettings.encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY)
        return false;

    return true;
}

UA_StatusCode
UA_WriterGroup_addPublishCallback(UA_Server *server, UA_WriterGroup *wg) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Already registered */
    if(wg->publishCallbackId != 0)
        return UA_STATUSCODE_GOOD;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(wg->config.pubsubManagerCallback.addCustomCallback) {
        /* Use configured mechanism for cyclic callbacks */
        retval = wg->config.pubsubManagerCallback.
            addCustomCallback(server, wg->identifier,
                              (UA_ServerCallback)UA_WriterGroup_publishCallback,
                              wg, wg->config.publishingInterval,
                              NULL, UA_TIMER_HANDLE_CYCLEMISS_WITH_CURRENTTIME,
                              &wg->publishCallbackId);
    } else {
        /* Use EventLoop for cyclic callbacks */
        UA_EventLoop *el = UA_PubSubConnection_getEL(server, wg->linkedConnection);
        retval = el->addCyclicCallback(el, (UA_Callback)UA_WriterGroup_publishCallback,
                                       server, wg, wg->config.publishingInterval,
                                       NULL /* TODO: use basetime */,
                                       UA_TIMER_HANDLE_CYCLEMISS_WITH_CURRENTTIME,
                                       &wg->publishCallbackId);
    }

    return retval;
}

static void
UA_WriterGroup_removePublishCallback(UA_Server *server, UA_WriterGroup *wg) {
    if(wg->publishCallbackId == 0)
        return;
    if(wg->config.pubsubManagerCallback.removeCustomCallback) {
        wg->config.pubsubManagerCallback.
            removeCustomCallback(server, wg->identifier, wg->publishCallbackId);
    } else {
        UA_EventLoop *el = UA_PubSubConnection_getEL(server, wg->linkedConnection);
        el->removeCyclicCallback(el, wg->publishCallbackId);
    }
    wg->publishCallbackId = 0;
}

UA_StatusCode
UA_WriterGroup_create(UA_Server *server, const UA_NodeId connection,
                      const UA_WriterGroupConfig *writerGroupConfig,
                      UA_NodeId *writerGroupIdentifier) {
    /* Delete the reserved IDs if the related session no longer exists. */
    UA_PubSubManager_freeIds(server);
    if(!writerGroupConfig)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    /* Search the connection by the given connectionIdentifier */
    UA_PubSubConnection *currentConnectionContext =
        UA_PubSubConnection_findConnectionbyId(server, connection);
    if(!currentConnectionContext)
        return UA_STATUSCODE_BADNOTFOUND;

    if(currentConnectionContext->configurationFreezeCounter > 0) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Adding WriterGroup failed. PubSubConnection is frozen.");
        return UA_STATUSCODE_BADCONFIGURATIONERROR;
    }

    /* Validate messageSettings type */
    const UA_ExtensionObject *ms = &writerGroupConfig->messageSettings;
    if(ms->content.decoded.type) {
        if(writerGroupConfig->encodingMimeType == UA_PUBSUB_ENCODING_JSON &&
           (ms->encoding != UA_EXTENSIONOBJECT_DECODED ||
            ms->content.decoded.type != &UA_TYPES[UA_TYPES_JSONWRITERGROUPMESSAGEDATATYPE])) {
            return UA_STATUSCODE_BADTYPEMISMATCH;
        }

        if(writerGroupConfig->encodingMimeType == UA_PUBSUB_ENCODING_UADP &&
           (ms->encoding != UA_EXTENSIONOBJECT_DECODED ||
            ms->content.decoded.type != &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE])) {
            return UA_STATUSCODE_BADTYPEMISMATCH;
        }
    }

    /* Allocate new WriterGroup */
    UA_WriterGroup *newWriterGroup = (UA_WriterGroup*)UA_calloc(1, sizeof(UA_WriterGroup));
    if(!newWriterGroup)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    newWriterGroup->componentType = UA_PUBSUB_COMPONENT_WRITERGROUP;
    newWriterGroup->linkedConnection = currentConnectionContext;

    /* Deep copy of the config */
    UA_WriterGroupConfig *newConfig = &newWriterGroup->config;
    UA_StatusCode res = UA_WriterGroupConfig_copy(writerGroupConfig, newConfig);
    if(res != UA_STATUSCODE_GOOD) {
        UA_free(newWriterGroup);
        return res;
    }

    /* Create the datatype value if not present */
    if(!newConfig->messageSettings.content.decoded.type) {
        UA_UadpWriterGroupMessageDataType *wgm = UA_UadpWriterGroupMessageDataType_new();
        newConfig->messageSettings.content.decoded.data = wgm;
        newConfig->messageSettings.content.decoded.type =
            &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE];
        newConfig->messageSettings.encoding = UA_EXTENSIONOBJECT_DECODED;
    }

    /* Attach to the connection */
    LIST_INSERT_HEAD(&currentConnectionContext->writerGroups, newWriterGroup, listEntry);
    currentConnectionContext->writerGroupsSize++;

    /* Add representation / create unique identifier */
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    res = addWriterGroupRepresentation(server, newWriterGroup);
    if(res != UA_STATUSCODE_GOOD) {
        UA_WriterGroup_remove(server, newWriterGroup);
        return res;
    }
#else
    UA_PubSubManager_generateUniqueNodeId(&server->pubSubManager,
                                          &newWriterGroup->identifier);
#endif

    /* Cache the log string */
    UA_String idStr = UA_STRING_NULL;
    UA_NodeId_print(&newWriterGroup->identifier, &idStr);
    char tmpLogIdStr[128];
    mp_snprintf(tmpLogIdStr, 128, "%.*sWriterGroup %.*s\t| ",
                (int)currentConnectionContext->logIdString.length,
                (char*)currentConnectionContext->logIdString.data,
                (int)idStr.length, idStr.data);
    newWriterGroup->logIdString = UA_STRING_ALLOC(tmpLogIdStr);
    UA_String_clear(&idStr);

    UA_LOG_INFO_WRITERGROUP(server->config.logging, newWriterGroup, "WriterGroup created");

    /* Validate the connection settings */
    res = UA_WriterGroup_connect(server, newWriterGroup, true);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_WRITERGROUP(server->config.logging, newWriterGroup,
                                 "Could not validate the connection parameters");
        UA_WriterGroup_remove(server, newWriterGroup);
        return res;
    }

#ifdef UA_ENABLE_PUBSUB_SKS
    if(writerGroupConfig->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
       writerGroupConfig->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
        if(!UA_String_isEmpty(&writerGroupConfig->securityGroupId) &&
           writerGroupConfig->securityPolicy) {
            /* Does the key storage already exist? */
            newWriterGroup->keyStorage =
                UA_PubSubKeyStorage_findKeyStorage(server, writerGroupConfig->securityGroupId);

            if(!newWriterGroup->keyStorage) {
                /* Create a new key storage */
                newWriterGroup->keyStorage = (UA_PubSubKeyStorage *)
                    UA_calloc(1, sizeof(UA_PubSubKeyStorage));
                if(!newWriterGroup->keyStorage) {
                    UA_WriterGroup_remove(server, newWriterGroup);
                    return UA_STATUSCODE_BADOUTOFMEMORY;
                }
                res = UA_PubSubKeyStorage_init(server, newWriterGroup->keyStorage,
                                               &writerGroupConfig->securityGroupId,
                                               writerGroupConfig->securityPolicy, 0, 0);
                if(res != UA_STATUSCODE_GOOD) {
                    UA_WriterGroup_remove(server, newWriterGroup);
                    return res;
                }
            }

            /* Increase the ref count */
            newWriterGroup->keyStorage->referenceCount++;
        }
    }

#endif

    /* Trigger the connection */
    UA_PubSubConnection_setPubSubState(server, currentConnectionContext,
                                       currentConnectionContext->state);

    /* Copying a numeric NodeId always succeeds */
    if(writerGroupIdentifier)
        UA_NodeId_copy(&newWriterGroup->identifier, writerGroupIdentifier);

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_addWriterGroup(UA_Server *server, const UA_NodeId connection,
                         const UA_WriterGroupConfig *writerGroupConfig,
                         UA_NodeId *writerGroupIdentifier) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = UA_WriterGroup_create(server, connection, writerGroupConfig,
                                              writerGroupIdentifier);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_WriterGroup_remove(UA_Server *server, UA_WriterGroup *wg) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    if(wg->configurationFrozen) {
        UA_LOG_WARNING_WRITERGROUP(server->config.logging, wg,
                                   "Deleting the WriterGroup failed. "
                                   "WriterGroup is frozen.");
        return UA_STATUSCODE_BADCONFIGURATIONERROR;
    }

    UA_PubSubConnection *connection = wg->linkedConnection;
    UA_assert(connection);
    if(connection->configurationFreezeCounter > 0) {
        UA_LOG_WARNING_WRITERGROUP(server->config.logging, wg,
                                   "Deleting the WriterGroup failed. "
                                   "PubSubConnection is frozen.");
        return UA_STATUSCODE_BADCONFIGURATIONERROR;
    }

    if(wg->state == UA_PUBSUBSTATE_OPERATIONAL)
        UA_WriterGroup_removePublishCallback(server, wg);

    UA_DataSetWriter *dsw, *dsw_tmp;
    LIST_FOREACH_SAFE(dsw, &wg->writers, listEntry, dsw_tmp) {
        UA_DataSetWriter_remove(server, dsw);
    }

#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
    if(wg->config.securityPolicy && wg->securityPolicyContext) {
        wg->config.securityPolicy->deleteContext(wg->securityPolicyContext);
        wg->securityPolicyContext = NULL;
    }
#endif

#ifdef UA_ENABLE_PUBSUB_SKS
    if(wg->keyStorage) {
        UA_PubSubKeyStorage_detachKeyStorage(server, wg->keyStorage);
        wg->keyStorage = NULL;
    }
#endif

    /* Disconnect only once */
    if(!wg->deleteFlag)
        UA_WriterGroup_disconnect(wg);
    wg->deleteFlag = true;

    if(wg->sendChannel == 0) {
        /* Unlink from the connection */
        LIST_REMOVE(wg, listEntry);
        connection->writerGroupsSize--;
        wg->linkedConnection = NULL;

        /* Actually remove the WriterGroup */
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
        deleteNode(server, wg->identifier, true);
#endif

        UA_LOG_INFO_WRITERGROUP(server->config.logging, wg, "WriterGroup deleted");

        UA_WriterGroupConfig_clear(&wg->config);
        UA_NodeId_clear(&wg->identifier);
        UA_String_clear(&wg->logIdString);
        UA_NetworkMessageOffsetBuffer_clear(&wg->bufferedMessage);
        UA_free(wg);
    }

    /* Update the connection state */
    UA_PubSubConnection_setPubSubState(server, connection, connection->state);

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_removeWriterGroup(UA_Server *server, const UA_NodeId writerGroup) {
    UA_LOCK(&server->serviceMutex);
    UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup);
    if(!wg) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADNOTFOUND;
    }
    UA_StatusCode res = UA_WriterGroup_remove(server, wg);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_WriterGroup_freezeConfiguration(UA_Server *server, UA_WriterGroup *wg) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    if(wg->configurationFrozen)
        return UA_STATUSCODE_GOOD;

    /* PubSubConnection freezeCounter++ */
    UA_PubSubConnection *pubSubConnection =  wg->linkedConnection;
    pubSubConnection->configurationFreezeCounter++;

    /* WriterGroup freeze */
    wg->configurationFrozen = true;

    /* DataSetWriter freeze */
    UA_DataSetWriter *dsw;
    LIST_FOREACH(dsw, &wg->writers, listEntry) {
        UA_DataSetWriter_freezeConfiguration(server, dsw);
    }

    /* Enabling RT? */
    if(wg->config.rtLevel != UA_PUBSUB_RT_FIXED_SIZE)
        return UA_STATUSCODE_GOOD;

    /* Check if RT is possible */
    if(wg->config.encodingMimeType != UA_PUBSUB_ENCODING_UADP) {
        UA_LOG_WARNING_WRITERGROUP(server->config.logging, wg,
                                   "PubSub-RT configuration fail: Non-RT capable encoding.");
        return UA_STATUSCODE_BADNOTSUPPORTED;
    }

    //TODO Clarify: should we only allow = maxEncapsulatedDataSetMessageCount == 1 with RT?
    //TODO Clarify: Behaviour if the finale size is more than MTU

    /* Prepare the DataSetMessages */
    UA_STACKARRAY(UA_UInt16, dsWriterIds, wg->writersCount);
    UA_STACKARRAY(UA_DataSetMessage, dsmStore, wg->writersCount);
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    size_t dsmCount = 0;
    LIST_FOREACH(dsw, &wg->writers, listEntry) {
        dsWriterIds[dsmCount] = dsw->config.dataSetWriterId;
        res = UA_DataSetWriter_prepareDataSet(server, dsw, &dsmStore[dsmCount]);
        if(res != UA_STATUSCODE_GOOD) {
            for(size_t i = 0; i < dsmCount; i++) {
                UA_DataSetMessage_clear(&dsmStore[i]);
            }
            return res;
        }
        dsmCount++;
    }

    /* Define variables here for goto */
    size_t msgSize;
    UA_ByteString buf;
    UA_NetworkMessage networkMessage;
    const UA_Byte *bufEnd;
    UA_Byte *bufPos;

    if(res != UA_STATUSCODE_GOOD)
        goto cleanup_dsm;

    memset(&networkMessage, 0, sizeof(networkMessage));
    res = generateNetworkMessage(pubSubConnection, wg, dsmStore, dsWriterIds,
                                 (UA_Byte) dsmCount, &wg->config.messageSettings,
                                 &wg->config.transportSettings, &networkMessage);
    if(res != UA_STATUSCODE_GOOD)
        goto cleanup_dsm;

    /* Generate the offset-buffer (done inside calcSizeBinary) */
    memset(&wg->bufferedMessage, 0, sizeof(UA_NetworkMessageOffsetBuffer));
    msgSize = UA_NetworkMessage_calcSizeBinary(&networkMessage, &wg->bufferedMessage);

#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
    if(wg->config.securityMode > UA_MESSAGESECURITYMODE_NONE) {
        UA_PubSubSecurityPolicy *sp = wg->config.securityPolicy;
        msgSize += sp->symmetricModule.cryptoModule.
                   signatureAlgorithm.getLocalSignatureSize(sp->policyContext);
    }
#endif
    res = UA_ByteString_allocBuffer(&buf, msgSize);
    if(res != UA_STATUSCODE_GOOD)
        goto cleanup;
    wg->bufferedMessage.buffer = buf;

    /* Encode the NetworkMessage */
    bufEnd = &wg->bufferedMessage.buffer.data[wg->bufferedMessage.buffer.length];
    bufPos = wg->bufferedMessage.buffer.data;

#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
    if(wg->config.securityMode > UA_MESSAGESECURITYMODE_NONE) {
        UA_Byte *payloadPosition;
        UA_NetworkMessage_encodeBinary(&networkMessage, &bufPos, bufEnd, &payloadPosition);
        wg->bufferedMessage.payloadPosition = payloadPosition;

        wg->bufferedMessage.nm = (UA_NetworkMessage *)UA_calloc(1,sizeof(UA_NetworkMessage));
        wg->bufferedMessage.nm->securityHeader = networkMessage.securityHeader;
        UA_ByteString_allocBuffer(&wg->bufferedMessage.encryptBuffer, msgSize);
    }
#endif

    if(wg->config.securityMode <= UA_MESSAGESECURITYMODE_NONE)
        UA_NetworkMessage_encodeBinary(&networkMessage, &bufPos, bufEnd, NULL);

 cleanup:
    UA_free(networkMessage.payload.dataSetPayload.sizes);

    /* Clean up DSM */
 cleanup_dsm:
    for(size_t i = 0; i < dsmCount; i++){
        UA_free(dsmStore[i].data.keyFrameData.dataSetFields);
#ifdef UA_ENABLE_JSON_ENCODING
        UA_Array_delete(dsmStore[i].data.keyFrameData.fieldNames,
                        dsmStore[i].data.keyFrameData.fieldCount,
                        &UA_TYPES[UA_TYPES_STRING]);
#endif
    }

    return res;
}

UA_StatusCode
UA_Server_freezeWriterGroupConfiguration(UA_Server *server,
                                         const UA_NodeId writerGroup) {
    UA_LOCK(&server->serviceMutex);
    UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup);
    if(!wg) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADNOTFOUND;
    }
    UA_StatusCode res = UA_WriterGroup_freezeConfiguration(server, wg);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_WriterGroup_unfreezeConfiguration(UA_Server *server, UA_WriterGroup *wg) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Already unfrozen */
    if(!wg->configurationFrozen)
        return UA_STATUSCODE_GOOD;

    UA_PubSubConnection *pubSubConnection =  wg->linkedConnection;
    pubSubConnection->configurationFreezeCounter--;

    /* DataSetWriter unfreeze */
    UA_DataSetWriter *dsw;
    LIST_FOREACH(dsw, &wg->writers, listEntry) {
        UA_DataSetWriter_unfreezeConfiguration(server, dsw);
    }

    UA_NetworkMessageOffsetBuffer_clear(&wg->bufferedMessage);
    wg->configurationFrozen = false;

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_enableWriterGroup(UA_Server *server,
                                    const UA_NodeId writerGroup)  {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = UA_WriterGroup_enableWriterGroup(server, writerGroup);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_WriterGroup_enableWriterGroup(UA_Server *server,
                                 const UA_NodeId writerGroup) {
    UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND;
    UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup);
    if(wg)
        res = UA_WriterGroup_setPubSubState(server, wg, UA_PUBSUBSTATE_OPERATIONAL);
    return res;
}

UA_StatusCode
UA_Server_unfreezeWriterGroupConfiguration(UA_Server *server,
                                           const UA_NodeId writerGroup) {
    UA_LOCK(&server->serviceMutex);
    UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup);
    if(!wg) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADNOTFOUND;
    }
    UA_StatusCode res = UA_WriterGroup_unfreezeConfiguration(server, wg);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

#ifdef UA_ENABLE_PUBSUB_SKS
UA_StatusCode
UA_Server_setWriterGroupActivateKey(UA_Server *server,
                                    const UA_NodeId writerGroup) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND;
    UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup);
    if(wg) {

        if(wg->keyStorage && wg->keyStorage->currentItem) {
            res = UA_PubSubKeyStorage_activateKeyToChannelContext(
                server, wg->identifier, wg->config.securityGroupId);
            if(res != UA_STATUSCODE_GOOD) {
                UA_UNLOCK(&server->serviceMutex);
                return res;
            }
        }
    }
    UA_UNLOCK(&server->serviceMutex);
    return res;
}
#endif

UA_StatusCode
UA_Server_setWriterGroupDisabled(UA_Server *server,
                                 const UA_NodeId writerGroup) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND;
    UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup);
    if(wg)
        res = UA_WriterGroup_setPubSubState(server, wg, UA_PUBSUBSTATE_DISABLED);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_WriterGroupConfig_copy(const UA_WriterGroupConfig *src,
                          UA_WriterGroupConfig *dst) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    memcpy(dst, src, sizeof(UA_WriterGroupConfig));
    res |= UA_String_copy(&src->name, &dst->name);
    res |= UA_ExtensionObject_copy(&src->transportSettings, &dst->transportSettings);
    res |= UA_ExtensionObject_copy(&src->messageSettings, &dst->messageSettings);
    res |= UA_KeyValueMap_copy(&src->groupProperties, &dst->groupProperties);
#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
    res |= UA_String_copy(&src->securityGroupId, &dst->securityGroupId);
#endif
    if(res != UA_STATUSCODE_GOOD)
        UA_WriterGroupConfig_clear(dst);
    return res;
}

UA_StatusCode
UA_Server_getWriterGroupConfig(UA_Server *server, const UA_NodeId writerGroup,
                               UA_WriterGroupConfig *config) {
    if(!config)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    UA_LOCK(&server->serviceMutex);
    UA_WriterGroup *currentWG = UA_WriterGroup_findWGbyId(server, writerGroup);
    UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND;
    if(currentWG)
        res = UA_WriterGroupConfig_copy(&currentWG->config, config);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_WriterGroup_updateConfig(UA_Server *server, UA_WriterGroup *wg,
                            const UA_WriterGroupConfig *config) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(!config)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    if(wg->configurationFrozen){
        UA_LOG_WARNING_WRITERGROUP(server->config.logging, wg,
                                   "Modify WriterGroup failed. WriterGroup is frozen.");
        return UA_STATUSCODE_BADCONFIGURATIONERROR;
    }

    //The update functionality will be extended during the next PubSub batches.
    //Currently is only a change of the publishing interval possible.
    if(wg->config.maxEncapsulatedDataSetMessageCount != config->maxEncapsulatedDataSetMessageCount) {
        wg->config.maxEncapsulatedDataSetMessageCount = config->maxEncapsulatedDataSetMessageCount;
        if(wg->config.messageSettings.encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY) {
            UA_LOG_WARNING_WRITERGROUP(server->config.logging, wg,
                                       "MaxEncapsulatedDataSetMessag need enabled "
                                       "'PayloadHeader' within the message settings.");
        }
    }

    if(wg->config.publishingInterval != config->publishingInterval) {
        wg->config.publishingInterval = config->publishingInterval;
        if(wg->config.rtLevel == UA_PUBSUB_RT_NONE &&
           wg->state == UA_PUBSUBSTATE_OPERATIONAL) {
            UA_WriterGroup_removePublishCallback(server, wg);
            res = UA_WriterGroup_addPublishCallback(server, wg);
            if(res != UA_STATUSCODE_GOOD) {
                UA_LOG_WARNING_WRITERGROUP(server->config.logging, wg,
                                           "Modify WriterGroup failed. Adding publish callback failed"
                                           "with status code %s", UA_StatusCode_name(res));
                return res;
            }
        }
    }

    if(wg->config.priority != config->priority) {
        UA_LOG_WARNING_WRITERGROUP(server->config.logging, wg,
                                   "Priority parameter is not yet "
                                   "supported for WriterGroup updates");
    }

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_updateWriterGroupConfig(UA_Server *server, UA_NodeId writerGroupIdentifier,
                                  const UA_WriterGroupConfig *config) {
    UA_LOCK(&server->serviceMutex);
    UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroupIdentifier);
    if(!wg) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADNOTFOUND;
    }

    UA_StatusCode res = UA_WriterGroup_updateConfig(server, wg, config);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_Server_WriterGroup_getState(UA_Server *server, UA_NodeId writerGroupIdentifier,
                               UA_PubSubState *state) {
    if((server == NULL) || (state == NULL))
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    UA_LOCK(&server->serviceMutex);
    UA_WriterGroup *currentWriterGroup =
        UA_WriterGroup_findWGbyId(server, writerGroupIdentifier);
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(currentWriterGroup) {
        *state = currentWriterGroup->state;
    } else {
        res = UA_STATUSCODE_BADNOTFOUND;
    }
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_Server_WriterGroup_publish(UA_Server *server, const UA_NodeId writerGroupIdentifier){
    UA_LOCK(&server->serviceMutex);

    //search WriterGroup ToDo create lookup table for more efficiency
    UA_WriterGroup *writerGroup;
    writerGroup = UA_WriterGroup_findWGbyId(server, writerGroupIdentifier);
    if(writerGroup == NULL){
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADNOTFOUND;
    }
    UA_UNLOCK(&server->serviceMutex);
    UA_WriterGroup_publishCallback(server, writerGroup);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_WriterGroup_lastPublishTimestamp(UA_Server *server, const UA_NodeId writerGroupId, UA_DateTime *timestamp){
    UA_LOCK(&server->serviceMutex);
    //search WriterGroup ToDo create lookup table for more efficiency
    UA_WriterGroup *writerGroup;
    writerGroup = UA_WriterGroup_findWGbyId(server, writerGroupId);
    if(writerGroup == NULL){
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADNOTFOUND;
    }
    *timestamp = writerGroup->lastPublishTimeStamp;
    UA_UNLOCK(&server->serviceMutex);
    return UA_STATUSCODE_BADNOTFOUND;
}

UA_WriterGroup *
UA_WriterGroup_findWGbyId(UA_Server *server, UA_NodeId identifier) {
    UA_PubSubConnection *tmpConnection;
    TAILQ_FOREACH(tmpConnection, &server->pubSubManager.connections, listEntry) {
        UA_WriterGroup *tmpWriterGroup;
        LIST_FOREACH(tmpWriterGroup, &tmpConnection->writerGroups, listEntry) {
            if(UA_NodeId_equal(&identifier, &tmpWriterGroup->identifier))
                return tmpWriterGroup;
        }
    }
    return NULL;
}

#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
UA_StatusCode
setWriterGroupEncryptionKeys(UA_Server *server, const UA_NodeId writerGroup,
                             UA_UInt32 securityTokenId,
                             const UA_ByteString signingKey,
                             const UA_ByteString encryptingKey,
                             const UA_ByteString keyNonce) {
    UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroup);
    UA_StatusCode res = UA_STATUSCODE_BAD;

    if(!wg)
        return UA_STATUSCODE_BADNOTFOUND;
    if(wg->config.encodingMimeType == UA_PUBSUB_ENCODING_JSON) {
        UA_LOG_WARNING_WRITERGROUP(server->config.logging, wg,
                                   "JSON encoding is enabled. The message security is only defined for the UADP message mapping.");
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    if(!wg->config.securityPolicy) {
        UA_LOG_WARNING_WRITERGROUP(server->config.logging, wg,
                                   "No SecurityPolicy configured for the WriterGroup");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    if(securityTokenId != wg->securityTokenId) {
        wg->securityTokenId = securityTokenId;
        wg->nonceSequenceNumber = 1;
    }

    if(!wg->securityPolicyContext) {
        /* Create a new context */
        res = wg->config.securityPolicy->
            newContext(wg->config.securityPolicy->policyContext,
                       &signingKey, &encryptingKey, &keyNonce,
                       &wg->securityPolicyContext);
    } else {
        /* Update the context */
         res = wg->config.securityPolicy->
            setSecurityKeys(wg->securityPolicyContext, &signingKey, &encryptingKey, &keyNonce);
    }

    if(res != UA_STATUSCODE_GOOD)
        return res;
    return UA_WriterGroup_setPubSubState(server, wg, wg->state);
}

UA_StatusCode
UA_Server_setWriterGroupEncryptionKeys(UA_Server *server, const UA_NodeId writerGroup,
                                       UA_UInt32 securityTokenId,
                                       const UA_ByteString signingKey,
                                       const UA_ByteString encryptingKey,
                                       const UA_ByteString keyNonce) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = setWriterGroupEncryptionKeys(server, writerGroup, securityTokenId,
                                                     signingKey, encryptingKey, keyNonce);

    UA_UNLOCK(&server->serviceMutex);
    return res;
}
#endif

void
UA_WriterGroupConfig_clear(UA_WriterGroupConfig *writerGroupConfig) {
    UA_String_clear(&writerGroupConfig->name);
    UA_ExtensionObject_clear(&writerGroupConfig->transportSettings);
    UA_ExtensionObject_clear(&writerGroupConfig->messageSettings);
    UA_KeyValueMap_clear(&writerGroupConfig->groupProperties);
#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
    UA_String_clear(&writerGroupConfig->securityGroupId);
#endif
    memset(writerGroupConfig, 0, sizeof(UA_WriterGroupConfig));
}

UA_StatusCode
UA_WriterGroup_setPubSubState(UA_Server *server, UA_WriterGroup *wg,
                              UA_PubSubState targetState) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    UA_PubSubConnection *connection = wg->linkedConnection;
    UA_PubSubState oldState = wg->state;
    wg->state = targetState;

    switch(wg->state) {
        /* Disabled */
    default:
        wg->state = UA_PUBSUBSTATE_ERROR;
        ret = UA_STATUSCODE_BADINTERNALERROR;
        /* fallthrough */
    case UA_PUBSUBSTATE_DISABLED:
    case UA_PUBSUBSTATE_ERROR:
        UA_WriterGroup_disconnect(wg);
        UA_WriterGroup_removePublishCallback(server, wg);
        break;

        /* Enabled */
    case UA_PUBSUBSTATE_PAUSED:
    case UA_PUBSUBSTATE_PREOPERATIONAL:
    case UA_PUBSUBSTATE_OPERATIONAL:
        if(connection->state != UA_PUBSUBSTATE_OPERATIONAL) {
            wg->state = UA_PUBSUBSTATE_PAUSED;
            UA_WriterGroup_disconnect(wg);
            UA_WriterGroup_removePublishCallback(server, wg);
            break;
        }

        ret = UA_WriterGroup_connect(server, wg, false);
        if(ret != UA_STATUSCODE_GOOD)
            break;

        wg->state = UA_PUBSUBSTATE_OPERATIONAL;

        /* Not fully connected -> PreOperational */
        if(UA_WriterGroup_canConnect(wg))
            wg->state = UA_PUBSUBSTATE_PREOPERATIONAL;

        /* Security Mode not set-> PreOperational */
#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
        if(wg->config.securityMode > UA_MESSAGESECURITYMODE_NONE &&
           wg->securityTokenId == 0)
            wg->state = UA_PUBSUBSTATE_PREOPERATIONAL;
#endif

        /* Enable publish callback if operational */
        if(wg->state == UA_PUBSUBSTATE_OPERATIONAL)
            ret = UA_WriterGroup_addPublishCallback(server, wg);
        break;
    }

    /* Failure */
    if(ret != UA_STATUSCODE_GOOD) {
        wg->state = UA_PUBSUBSTATE_ERROR;
        UA_WriterGroup_disconnect(wg);
        UA_WriterGroup_removePublishCallback(server, wg);
    }

    if(wg->state != oldState) {
        /* Inform application about state change */
        UA_ServerConfig *pConfig = &server->config;
        UA_LOG_INFO_WRITERGROUP(pConfig->logging, wg, "State change: %s -> %s",
                               UA_PubSubState_name(oldState),
                               UA_PubSubState_name(wg->state));
        if(pConfig->pubSubConfig.stateChangeCallback != 0) {
            UA_UNLOCK(&server->serviceMutex);
            pConfig->pubSubConfig.
                stateChangeCallback(server, &wg->identifier, wg->state, ret);
            UA_LOCK(&server->serviceMutex);
        }
    }

    UA_DataSetWriter *writer;
    LIST_FOREACH(writer, &wg->writers, listEntry) {
        UA_DataSetWriter_setPubSubState(server, writer, writer->state);
    }

    return ret;
}

#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
static UA_StatusCode
encryptAndSign(UA_WriterGroup *wg, const UA_NetworkMessage *nm,
               UA_Byte *signStart, UA_Byte *encryptStart,
               UA_Byte *msgEnd) {
    UA_StatusCode rv;
    void *channelContext = wg->securityPolicyContext;

    if(nm->securityHeader.networkMessageEncrypted) {
        /* Set the temporary MessageNonce in the SecurityPolicy */
        const UA_ByteString nonce = {
            (size_t)nm->securityHeader.messageNonceSize,
            (UA_Byte*)(uintptr_t)nm->securityHeader.messageNonce
        };
        rv = wg->config.securityPolicy->setMessageNonce(channelContext, &nonce);
        UA_CHECK_STATUS(rv, return rv);

        /* The encryption is done in-place, no need to encode again */
        UA_ByteString toBeEncrypted =
            {(uintptr_t)msgEnd - (uintptr_t)encryptStart, encryptStart};
        rv = wg->config.securityPolicy->symmetricModule.cryptoModule.encryptionAlgorithm.
            encrypt(channelContext, &toBeEncrypted);
        UA_CHECK_STATUS(rv, return rv);
    }

    if(nm->securityHeader.networkMessageSigned) {
        UA_ByteString toBeSigned = {(uintptr_t)msgEnd - (uintptr_t)signStart,
                                    signStart};

        size_t sigSize = wg->config.securityPolicy->symmetricModule.cryptoModule.
                     signatureAlgorithm.getLocalSignatureSize(channelContext);
        UA_ByteString signature = {sigSize, msgEnd};

        rv = wg->config.securityPolicy->symmetricModule.cryptoModule.
            signatureAlgorithm.sign(channelContext, &toBeSigned, &signature);
        UA_CHECK_STATUS(rv, return rv);
    }
    return UA_STATUSCODE_GOOD;
}
#endif

static UA_StatusCode
encodeNetworkMessage(UA_WriterGroup *wg, UA_NetworkMessage *nm,
                     UA_ByteString *buf) {
    UA_Byte *bufPos = buf->data;
    UA_Byte *bufEnd = &buf->data[buf->length];

#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
    UA_Byte *networkMessageStart = bufPos;
#endif
    UA_StatusCode rv = UA_NetworkMessage_encodeHeaders(nm, &bufPos, bufEnd);
    UA_CHECK_STATUS(rv, return rv);

#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
    UA_Byte *payloadStart = bufPos;
#endif
    rv = UA_NetworkMessage_encodePayload(nm, &bufPos, bufEnd);
    UA_CHECK_STATUS(rv, return rv);

    rv = UA_NetworkMessage_encodeFooters(nm, &bufPos, bufEnd);
    UA_CHECK_STATUS(rv, return rv);

#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
    /* Encrypt and Sign the message */
    UA_Byte *footerEnd = bufPos;
    rv = encryptAndSign(wg, nm, networkMessageStart, payloadStart, footerEnd);
    UA_CHECK_STATUS(rv, return rv);
#endif

    return UA_STATUSCODE_GOOD;
}

static void
sendNetworkMessageBuffer(UA_Server *server, UA_WriterGroup *wg, 
                         UA_PubSubConnection *connection, uintptr_t connectionId,
                         UA_ByteString *buffer) {
    UA_StatusCode res = connection->cm->
        sendWithConnection(connection->cm, connectionId,
                           &UA_KEYVALUEMAP_NULL, buffer);

    /* Failure, set the WriterGroup into an error mode */
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_WRITERGROUP(server->config.logging, wg,
                                 "Sending NetworkMessage failed");
        UA_WriterGroup_setPubSubState(server, wg, UA_PUBSUBSTATE_ERROR);
        UA_PubSubConnection_setPubSubState(server, connection, UA_PUBSUBSTATE_ERROR);
        return;
    }

    /* Sending successful - increase the sequence number */
    wg->sequenceNumber++;
}

#ifdef UA_ENABLE_JSON_ENCODING
static UA_StatusCode
sendNetworkMessageJson(UA_Server *server, UA_PubSubConnection *connection, UA_WriterGroup *wg,
                       UA_DataSetMessage *dsm, UA_UInt16 *writerIds, UA_Byte dsmCount) {
    /* Prepare the NetworkMessage */
    UA_NetworkMessage nm;
    memset(&nm, 0, sizeof(UA_NetworkMessage));
    nm.version = 1;
    nm.networkMessageType = UA_NETWORKMESSAGE_DATASET;
    nm.payloadHeaderEnabled = true;
    nm.payloadHeader.dataSetPayloadHeader.count = dsmCount;
    nm.payloadHeader.dataSetPayloadHeader.dataSetWriterIds = writerIds;
    nm.payload.dataSetPayload.dataSetMessages = dsm;
    nm.publisherIdEnabled = true;
    nm.publisherIdType = connection->config.publisherIdType;
    nm.publisherId = connection->config.publisherId;

    /* Compute the message length */
    size_t msgSize = UA_NetworkMessage_calcSizeJson(&nm, NULL, 0, NULL, 0, true);

    UA_ConnectionManager *cm = connection->cm;
    if(!cm)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Select the wg sendchannel if configured */
    uintptr_t sendChannel = connection->sendChannel;
    if(wg->sendChannel != 0)
        sendChannel = wg->sendChannel;
    if(sendChannel == 0) {
        UA_LOG_ERROR_WRITERGROUP(server->config.logging, wg,
                                 "Cannot send, no open connection");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Allocate the buffer */
    UA_ByteString buf;
    UA_StatusCode res = cm->allocNetworkBuffer(cm, sendChannel, &buf, msgSize);
    UA_CHECK_STATUS(res, return res);

    /* Encode the message */
    UA_Byte *bufPos = buf.data;
    const UA_Byte *bufEnd = &buf.data[msgSize];
    res = UA_NetworkMessage_encodeJson(&nm, &bufPos, &bufEnd, NULL, 0, NULL, 0, true);
    if(res != UA_STATUSCODE_GOOD) {
        cm->freeNetworkBuffer(cm, sendChannel, &buf);
        return res;
    }
    UA_assert(bufPos == bufEnd);

    /* Send the prepared messages */
    sendNetworkMessageBuffer(server, wg, connection, sendChannel, &buf);
    return UA_STATUSCODE_GOOD;
}
#endif

static UA_StatusCode
generateNetworkMessage(UA_PubSubConnection *connection, UA_WriterGroup *wg,
                       UA_DataSetMessage *dsm, UA_UInt16 *writerIds, UA_Byte dsmCount,
                       UA_ExtensionObject *messageSettings,
                       UA_ExtensionObject *transportSettings,
                       UA_NetworkMessage *networkMessage) {
    if(messageSettings->content.decoded.type !=
       &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE])
        return UA_STATUSCODE_BADINTERNALERROR;
    UA_UadpWriterGroupMessageDataType *wgm = (UA_UadpWriterGroupMessageDataType*)
            messageSettings->content.decoded.data;

    networkMessage->publisherIdEnabled =
        ((u64)wgm->networkMessageContentMask &
         (u64)UA_UADPNETWORKMESSAGECONTENTMASK_PUBLISHERID) != 0;
    networkMessage->groupHeaderEnabled =
        ((u64)wgm->networkMessageContentMask &
         (u64)UA_UADPNETWORKMESSAGECONTENTMASK_GROUPHEADER) != 0;
    networkMessage->groupHeader.writerGroupIdEnabled =
        ((u64)wgm->networkMessageContentMask &
         (u64)UA_UADPNETWORKMESSAGECONTENTMASK_WRITERGROUPID) != 0;
    networkMessage->groupHeader.groupVersionEnabled =
        ((u64)wgm->networkMessageContentMask &
         (u64)UA_UADPNETWORKMESSAGECONTENTMASK_GROUPVERSION) != 0;
    networkMessage->groupHeader.networkMessageNumberEnabled =
        ((u64)wgm->networkMessageContentMask &
         (u64)UA_UADPNETWORKMESSAGECONTENTMASK_NETWORKMESSAGENUMBER) != 0;
    networkMessage->groupHeader.sequenceNumberEnabled =
        ((u64)wgm->networkMessageContentMask &
         (u64)UA_UADPNETWORKMESSAGECONTENTMASK_SEQUENCENUMBER) != 0;
    networkMessage->payloadHeaderEnabled =
        ((u64)wgm->networkMessageContentMask &
         (u64)UA_UADPNETWORKMESSAGECONTENTMASK_PAYLOADHEADER) != 0;
    networkMessage->timestampEnabled =
        ((u64)wgm->networkMessageContentMask &
         (u64)UA_UADPNETWORKMESSAGECONTENTMASK_TIMESTAMP) != 0;
    networkMessage->picosecondsEnabled =
        ((u64)wgm->networkMessageContentMask &
         (u64)UA_UADPNETWORKMESSAGECONTENTMASK_PICOSECONDS) != 0;
    networkMessage->dataSetClassIdEnabled =
        ((u64)wgm->networkMessageContentMask &
         (u64)UA_UADPNETWORKMESSAGECONTENTMASK_DATASETCLASSID) != 0;
    networkMessage->promotedFieldsEnabled =
        ((u64)wgm->networkMessageContentMask &
         (u64)UA_UADPNETWORKMESSAGECONTENTMASK_PROMOTEDFIELDS) != 0;

    /* Set the SecurityHeader */
#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
    if(wg->config.securityMode > UA_MESSAGESECURITYMODE_NONE) {
        networkMessage->securityEnabled = true;
        networkMessage->securityHeader.networkMessageSigned = true;
        if(wg->config.securityMode >= UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
            networkMessage->securityHeader.networkMessageEncrypted = true;
        networkMessage->securityHeader.securityTokenId = wg->securityTokenId;

        /* Generate the MessageNonce. Four random bytes followed by a four-byte
         * sequence number */
        UA_ByteString nonce = {4, networkMessage->securityHeader.messageNonce};
        UA_StatusCode rv = wg->config.securityPolicy->symmetricModule.
            generateNonce(wg->config.securityPolicy->policyContext, &nonce);
        if(rv != UA_STATUSCODE_GOOD)
            return rv;
        UA_Byte *pos = &networkMessage->securityHeader.messageNonce[4];
        const UA_Byte *end = &networkMessage->securityHeader.messageNonce[8];
        UA_UInt32_encodeBinary(&wg->nonceSequenceNumber, &pos, end);
        networkMessage->securityHeader.messageNonceSize = 8;
    }
#endif

    networkMessage->version = 1;
    networkMessage->networkMessageType = UA_NETWORKMESSAGE_DATASET;
    networkMessage->publisherIdType = connection->config.publisherIdType;
    /* shallow copy of the PublisherId from connection configuration
        -> the configuration needs to be stable during publishing process
        -> it must not be cleaned after network message has been sent */
    networkMessage->publisherId = connection->config.publisherId;

    if(networkMessage->groupHeader.sequenceNumberEnabled)
        networkMessage->groupHeader.sequenceNumber = wg->sequenceNumber;

    if(networkMessage->groupHeader.groupVersionEnabled)
        networkMessage->groupHeader.groupVersion = wgm->groupVersion;

    /* Compute the length of the dsm separately for the header */
    UA_UInt16 *dsmLengths = (UA_UInt16 *) UA_calloc(dsmCount, sizeof(UA_UInt16));
    if(!dsmLengths)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    for(UA_Byte i = 0; i < dsmCount; i++)
        dsmLengths[i] = (UA_UInt16) UA_DataSetMessage_calcSizeBinary(&dsm[i], NULL, 0);

    networkMessage->payloadHeader.dataSetPayloadHeader.count = dsmCount;
    networkMessage->payloadHeader.dataSetPayloadHeader.dataSetWriterIds = writerIds;
    networkMessage->groupHeader.writerGroupId = wg->config.writerGroupId;
    /* number of the NetworkMessage inside a PublishingInterval */
    networkMessage->groupHeader.networkMessageNumber = 1;
    networkMessage->payload.dataSetPayload.sizes = dsmLengths;
    networkMessage->payload.dataSetPayload.dataSetMessages = dsm;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
sendNetworkMessageBinary(UA_Server *server, UA_PubSubConnection *connection, UA_WriterGroup *wg,
                         UA_DataSetMessage *dsm, UA_UInt16 *writerIds, UA_Byte dsmCount) {
    UA_NetworkMessage nm;
    memset(&nm, 0, sizeof(UA_NetworkMessage));

    /* Fill the message structure */
    UA_StatusCode rv =
        generateNetworkMessage(connection, wg, dsm, writerIds, dsmCount,
                               &wg->config.messageSettings,
                               &wg->config.transportSettings, &nm);
    UA_CHECK_STATUS(rv, return rv);

    /* Compute the message size. Add the overhead for the security signature.
     * There is no padding and the encryption incurs no size overhead. */
    size_t msgSize = UA_NetworkMessage_calcSizeBinary(&nm, NULL);
#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
    if(wg->config.securityMode > UA_MESSAGESECURITYMODE_NONE) {
        UA_PubSubSecurityPolicy *sp = wg->config.securityPolicy;
        msgSize += sp->symmetricModule.cryptoModule.
            signatureAlgorithm.getLocalSignatureSize(sp->policyContext);
    }
#endif

    UA_ConnectionManager *cm = connection->cm;
    if(!cm)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Select the wg sendchannel if configured */
    uintptr_t sendChannel = connection->sendChannel;
    if(wg->sendChannel != 0)
        sendChannel = wg->sendChannel;
    if(sendChannel == 0) {
        UA_LOG_ERROR_WRITERGROUP(server->config.logging, wg,
                                 "Cannot send, no open connection");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Allocate the buffer. Allocate on the stack if the buffer is small. */
    UA_ByteString buf = UA_BYTESTRING_NULL;
    rv = cm->allocNetworkBuffer(cm, sendChannel, &buf, msgSize);
    UA_CHECK_STATUS(rv, return rv);

    /* Encode and encrypt the message */
    rv = encodeNetworkMessage(wg, &nm, &buf);
    if(rv != UA_STATUSCODE_GOOD) {
        cm->freeNetworkBuffer(cm, sendChannel, &buf);
        UA_free(nm.payload.dataSetPayload.sizes);
        return rv;
    }

    /* Send out the message */
    sendNetworkMessageBuffer(server, wg, connection, sendChannel, &buf);

    UA_free(nm.payload.dataSetPayload.sizes);
    return UA_STATUSCODE_GOOD;
}

static void
publishRT(UA_Server *server, UA_WriterGroup *writerGroup, UA_PubSubConnection *connection) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_StatusCode res =
        UA_NetworkMessage_updateBufferedMessage(&writerGroup->bufferedMessage);

    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_DEBUG_WRITERGROUP(server->config.logging, writerGroup,
                                 "PubSub sending. Unknown field type.");
        return;
    }

    UA_ByteString *buf = &writerGroup->bufferedMessage.buffer;

#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
    /* Send the encrypted buffered message if PubSub encryption is enabled */
    if(writerGroup->config.securityMode > UA_MESSAGESECURITYMODE_NONE) {
        size_t sigSize = writerGroup->config.securityPolicy->symmetricModule.cryptoModule.
            signatureAlgorithm.getLocalSignatureSize(writerGroup->securityPolicyContext);

        UA_Byte payloadOffset = (UA_Byte)(writerGroup->bufferedMessage.payloadPosition -
                                          writerGroup->bufferedMessage.buffer.data);
        memcpy(writerGroup->bufferedMessage.encryptBuffer.data,
               writerGroup->bufferedMessage.buffer.data,
               writerGroup->bufferedMessage.buffer.length);
        res = encryptAndSign(writerGroup, writerGroup->bufferedMessage.nm,
                             writerGroup->bufferedMessage.encryptBuffer.data,
                             writerGroup->bufferedMessage.encryptBuffer.data + payloadOffset,
                             writerGroup->bufferedMessage.encryptBuffer.data +
                                 writerGroup->bufferedMessage.encryptBuffer.length - sigSize);

        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR_WRITERGROUP(server->config.logging, writerGroup,
                                     "PubSub Encryption failed");
            return;
        }

        buf = &writerGroup->bufferedMessage.encryptBuffer;
    }
#endif

    UA_ConnectionManager *cm = connection->cm;
    if(!cm)
        return;

    /* Select the wg sendchannel if configured */
    uintptr_t sendChannel = connection->sendChannel;
    if(writerGroup->sendChannel != 0)
        sendChannel = writerGroup->sendChannel;
    if(sendChannel == 0) {
        UA_LOG_ERROR_WRITERGROUP(server->config.logging, writerGroup,
                                 "Cannot send, no open connection");
        return;
    }

    /* Copy into the network buffer */
    UA_ByteString outBuf;
    res = cm->allocNetworkBuffer(cm, sendChannel, &outBuf, buf->length);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_WRITERGROUP(server->config.logging, writerGroup,
                                 "PubSub message memory allocation failed");
        return;
    }
    memcpy(outBuf.data, buf->data, buf->length);
    sendNetworkMessageBuffer(server, writerGroup, connection, sendChannel, &outBuf);
}

static void
sendNetworkMessage(UA_Server *server, UA_WriterGroup *wg, UA_PubSubConnection *connection,
                   UA_DataSetMessage *dsm, UA_UInt16 *writerIds, UA_Byte dsmCount) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    switch(wg->config.encodingMimeType) {
    case UA_PUBSUB_ENCODING_UADP:
        res = sendNetworkMessageBinary(server, connection, wg, dsm, writerIds, dsmCount);
        break;
#ifdef UA_ENABLE_JSON_ENCODING
    case UA_PUBSUB_ENCODING_JSON:
        res = sendNetworkMessageJson(server, connection, wg, dsm, writerIds, dsmCount);
        break;
#endif
    default:
        res = UA_STATUSCODE_BADNOTSUPPORTED;
        break;
    }

    /* If sending failed, disable all writer of the writergroup */
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_WRITERGROUP(server->config.logging, wg,
                                 "PubSub Publish: Could not send a NetworkMessage "
                                 "with status code %s", UA_StatusCode_name(res));
        UA_WriterGroup_setPubSubState(server, wg, UA_PUBSUBSTATE_ERROR);
    }
}

/* This callback triggers the collection and publish of NetworkMessages and the
 * contained DataSetMessages. */
void
UA_WriterGroup_publishCallback(UA_Server *server, UA_WriterGroup *writerGroup) {
    UA_assert(writerGroup != NULL);
    UA_assert(server != NULL);

    UA_LOCK(&server->serviceMutex);

    UA_LOG_DEBUG_WRITERGROUP(server->config.logging, writerGroup, "Publish Callback");

    /* Nothing to do? */
    if(writerGroup->writersCount == 0) {
        UA_UNLOCK(&server->serviceMutex);
        return;
    }

    /* Find the connection associated with the writer */
    UA_PubSubConnection *connection = writerGroup->linkedConnection;
    if(!connection) {
        UA_LOG_ERROR_WRITERGROUP(server->config.logging, writerGroup,
                                 "Publish failed. PubSubConnection invalid");
        UA_WriterGroup_setPubSubState(server, writerGroup, UA_PUBSUBSTATE_ERROR);
        UA_UNLOCK(&server->serviceMutex);
        return;
    }

    /* Realtime path - update the buffer message and send directly */
    if(writerGroup->config.rtLevel == UA_PUBSUB_RT_FIXED_SIZE) {
        publishRT(server, writerGroup, connection);
        UA_UNLOCK(&server->serviceMutex);
        return;
    }

    /* How many DSM can be sent in one NM? */
    UA_Byte maxDSM = (UA_Byte)writerGroup->config.maxEncapsulatedDataSetMessageCount;
    if(writerGroup->config.maxEncapsulatedDataSetMessageCount > UA_BYTE_MAX)
        maxDSM = UA_BYTE_MAX;
    if(maxDSM == 0)
        maxDSM = 1; /* Send at least one dsm */

    /* It is possible to put several DataSetMessages into one NetworkMessage.
     * But only if they do not contain promoted fields. NM with promoted fields
     * are sent out right away. The others are kept in a buffer for
     * "batching". */
    size_t dsmCount = 0;
    UA_STACKARRAY(UA_UInt16, dsWriterIds, writerGroup->writersCount);
    UA_STACKARRAY(UA_DataSetMessage, dsmStore, writerGroup->writersCount);

    UA_DataSetWriter *dsw;
    UA_EventLoop *el = UA_PubSubConnection_getEL(server, writerGroup->linkedConnection);
    LIST_FOREACH(dsw, &writerGroup->writers, listEntry) {
        if(dsw->state != UA_PUBSUBSTATE_OPERATIONAL)
            continue;

        /* Heartbeats are send when no dataset is attached */
        UA_Boolean heartbeat = UA_NodeId_isNull(&dsw->connectedDataSet);
        UA_PublishedDataSet *pds = (heartbeat) ? NULL :
            UA_PublishedDataSet_findPDSbyId(server, dsw->connectedDataSet);
        if(!heartbeat && !pds) {
            UA_LOG_ERROR_WRITER(server->config.logging, dsw,
                                "PubSub Publish: PublishedDataSet not found");
            UA_DataSetWriter_setPubSubState(server, dsw, UA_PUBSUBSTATE_ERROR);
            continue;
        }

        /* Generate the DSM */
        dsWriterIds[dsmCount] = dsw->config.dataSetWriterId;
        UA_StatusCode res =
            UA_DataSetWriter_generateDataSetMessage(server, &dsmStore[dsmCount], dsw);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR_WRITER(server->config.logging, dsw,
                         "PubSub Publish: DataSetMessage creation failed");
            UA_DataSetWriter_setPubSubState(server, dsw, UA_PUBSUBSTATE_ERROR);
            continue;
        }

        /* There is no promoted field -> send right away */
        if(pds && pds->promotedFieldsCount > 0) {
            writerGroup->lastPublishTimeStamp = el->dateTime_nowMonotonic(el);
            sendNetworkMessage(server, writerGroup, connection, &dsmStore[dsmCount],
                               &dsWriterIds[dsmCount], 1);

            /* Clean up the current store entry */
            if(writerGroup->config.rtLevel == UA_PUBSUB_RT_DIRECT_VALUE_ACCESS &&
               dsmStore[dsmCount].header.dataSetMessageType == UA_DATASETMESSAGE_DATAKEYFRAME) {
                for(size_t i = 0; i < dsmStore[dsmCount].data.keyFrameData.fieldCount; ++i) {
                    dsmStore[dsmCount].data.keyFrameData.dataSetFields[i].value.data = NULL;
                }
            }
            UA_DataSetMessage_clear(&dsmStore[dsmCount]);

            continue; /* Don't increase the dsmCount, reuse the slot */
        }

        dsmCount++;
    }

    /* Send the NetworkMessages with batched DataSetMessages */
    UA_Byte nmDsmCount = 0;
    for(size_t i = 0; i < dsmCount; i += nmDsmCount) {
        /* How many dsm are batched in this iteration? */
        nmDsmCount = (i + maxDSM > dsmCount) ? (UA_Byte)(dsmCount - i) : maxDSM;
        writerGroup->lastPublishTimeStamp = el->dateTime_nowMonotonic(el);
        /* Send the batched messages */
        sendNetworkMessage(server, writerGroup, connection, &dsmStore[i],
                           &dsWriterIds[i], nmDsmCount);
    }

    /* Clean up DSM */
    for(size_t i = 0; i < dsmCount; i++) {
        if(writerGroup->config.rtLevel == UA_PUBSUB_RT_DIRECT_VALUE_ACCESS &&
           dsmStore[i].header.dataSetMessageType == UA_DATASETMESSAGE_DATAKEYFRAME) {
            for(size_t j = 0; j < dsmStore[i].data.keyFrameData.fieldCount; ++j) {
                dsmStore[i].data.keyFrameData.dataSetFields[j].value.data = NULL;
            }
        }
        UA_DataSetMessage_clear(&dsmStore[i]);
    }

    UA_UNLOCK(&server->serviceMutex);
}

#endif /* UA_ENABLE_PUBSUB */

/**** amalgamated original file "/src/pubsub/ua_pubsub_reader.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2017-2022 Fraunhofer IOSB (Author: Andreas Ebner)
 * Copyright (c) 2019 Fraunhofer IOSB (Author: Julius Pfrommer)
 * Copyright (c) 2019 Kalycito Infotech Private Limited
 * Copyright (c) 2021 Fraunhofer IOSB (Author: Jan Hermes)
 * Copyright (c) 2022 Siemens AG (Author: Thomas Fischer)
 * Copyright (c) 2022 Fraunhofer IOSB (Author: Noel Graf)
 */


#ifdef UA_ENABLE_PUBSUB /* conditional compilation */

#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
#endif


#ifdef UA_ENABLE_PUBSUB_BUFMALLOC
#endif

#ifdef UA_ENABLE_PUBSUB_MONITORING
static void
UA_DataSetReader_checkMessageReceiveTimeout(UA_Server *server, UA_DataSetReader *dsr);

static void
UA_DataSetReader_handleMessageReceiveTimeout(UA_Server *server, UA_DataSetReader *dsr);
#endif

static UA_Boolean
publisherIdIsMatching(UA_NetworkMessage *msg, UA_Variant publisherId) {
    if(!msg->publisherIdEnabled) {
        return true;
    }
    switch(msg->publisherIdType) {
        case UA_PUBLISHERIDTYPE_BYTE:
            return (publisherId.type == &UA_TYPES[UA_TYPES_BYTE] &&
               msg->publisherId.byte == *(UA_Byte*)publisherId.data);
        case UA_PUBLISHERIDTYPE_UINT16:
            return (publisherId.type == &UA_TYPES[UA_TYPES_UINT16] &&
               msg->publisherId.uint16 == *(UA_UInt16*)publisherId.data);
        case UA_PUBLISHERIDTYPE_UINT32:
            return (publisherId.type == &UA_TYPES[UA_TYPES_UINT32] &&
               msg->publisherId.uint32 == *(UA_UInt32*)publisherId.data);
        case UA_PUBLISHERIDTYPE_UINT64:
            return (publisherId.type == &UA_TYPES[UA_TYPES_UINT64] &&
               msg->publisherId.uint64 == *(UA_UInt64*)publisherId.data);
        case UA_PUBLISHERIDTYPE_STRING:
            return (publisherId.type == &UA_TYPES[UA_TYPES_STRING] &&
               UA_String_equal(&msg->publisherId.string, (UA_String*)publisherId.data));
        default:
            return false;
    }
    return true;
}

UA_StatusCode
UA_DataSetReader_checkIdentifier(UA_Server *server, UA_NetworkMessage *msg,
                                 UA_DataSetReader *reader,
                                 UA_ReaderGroupConfig readerGroupConfig) {
    if(readerGroupConfig.encodingMimeType != UA_PUBSUB_ENCODING_JSON){
        if(!publisherIdIsMatching(msg, reader->config.publisherId)) {
            return UA_STATUSCODE_BADNOTFOUND;
        }
        if(msg->groupHeaderEnabled && msg->groupHeader.writerGroupIdEnabled) {
            if(reader->config.writerGroupId != msg->groupHeader.writerGroupId) {
                UA_LOG_DEBUG_READER(server->config.logging, reader,
                                   "WriterGroupId doesn't match");
                return UA_STATUSCODE_BADNOTFOUND;
            }
        }
        if(msg->payloadHeaderEnabled) {
            UA_Byte totalDataSets = msg->payloadHeader.dataSetPayloadHeader.count;
            UA_Byte iterator = 0;
            for(iterator = 0; iterator < totalDataSets; iterator++) { 
                if(reader->config.dataSetWriterId == msg->payloadHeader.dataSetPayloadHeader.dataSetWriterIds[iterator]) {
                    return UA_STATUSCODE_GOOD;
                }
            }
            if (iterator == totalDataSets) {
                UA_LOG_DEBUG_READER(server->config.logging, reader, "DataSetWriterId doesn't match");
                return UA_STATUSCODE_BADNOTFOUND;
            }
        }
        return UA_STATUSCODE_GOOD;
    } else {
        if (!publisherIdIsMatching(msg, reader->config.publisherId))
            return UA_STATUSCODE_BADNOTFOUND;

        if(reader->config.dataSetWriterId == *msg->payloadHeader.dataSetPayloadHeader.dataSetWriterIds) {
            UA_LOG_DEBUG(server->config.logging, UA_LOGCATEGORY_SERVER,
                         "DataSetReader found. Process NetworkMessage");
            return UA_STATUSCODE_GOOD;
        }
    }
    return UA_STATUSCODE_BADNOTFOUND;
}

UA_StatusCode
UA_DataSetReader_create(UA_Server *server, UA_NodeId readerGroupIdentifier,
                        const UA_DataSetReaderConfig *dataSetReaderConfig,
                        UA_NodeId *readerIdentifier) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Search the reader group by the given readerGroupIdentifier */
    UA_ReaderGroup *readerGroup = UA_ReaderGroup_findRGbyId(server, readerGroupIdentifier);
    if(readerGroup == NULL)
        return UA_STATUSCODE_BADNOTFOUND;

    if(!dataSetReaderConfig)
        return UA_STATUSCODE_BADNOTFOUND;

    if(readerGroup->configurationFrozen) {
        UA_LOG_WARNING_READERGROUP(server->config.logging, readerGroup,
                                   "Add DataSetReader failed, Subscriber configuration is frozen");
        return UA_STATUSCODE_BADCONFIGURATIONERROR;
    }

    /* Allocate memory for new DataSetReader */
    UA_DataSetReader *newDataSetReader = (UA_DataSetReader *)
        UA_calloc(1, sizeof(UA_DataSetReader));
    if(!newDataSetReader)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    newDataSetReader->componentType = UA_PUBSUB_COMPONENT_DATASETREADER;
    newDataSetReader->linkedReaderGroup = readerGroup;

    /* Copy the config into the new dataSetReader */
    UA_DataSetReaderConfig_copy(dataSetReaderConfig, &newDataSetReader->config);

#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    UA_StatusCode retVal = addDataSetReaderRepresentation(server, newDataSetReader);
    if(retVal != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_READERGROUP(server->config.logging, readerGroup,
                                 "Add DataSetReader failed, addDataSetReaderRepresentation failed");
        UA_DataSetReaderConfig_clear(&newDataSetReader->config);
        UA_free(newDataSetReader);
        newDataSetReader = 0;
        return retVal;
    }
#else
    UA_PubSubManager_generateUniqueNodeId(&server->pubSubManager,
                                          &newDataSetReader->identifier);
#endif

    /* Cache the log string */
    UA_String idStr = UA_STRING_NULL;
    UA_NodeId_print(&newDataSetReader->identifier, &idStr);
    char tmpLogIdStr[128];
    mp_snprintf(tmpLogIdStr, 128, "%.*sDataSetReader %.*s\t| ",
                (int)newDataSetReader->linkedReaderGroup->logIdString.length,
                (char*)newDataSetReader->linkedReaderGroup->logIdString.data,
                (int)idStr.length, idStr.data);
    newDataSetReader->logIdString = UA_STRING_ALLOC(tmpLogIdStr);
    UA_String_clear(&idStr);

    UA_LOG_INFO_READER(server->config.logging, newDataSetReader, "DataSetReader created");

#ifdef UA_ENABLE_PUBSUB_MONITORING
    /* Create message receive timeout timer */
    retVal = server->config.pubSubConfig.monitoringInterface.
        createMonitoring(server, newDataSetReader->identifier,
                         UA_PUBSUB_COMPONENT_DATASETREADER,
                         UA_PUBSUB_MONITORING_MESSAGE_RECEIVE_TIMEOUT,
                         newDataSetReader,
                         (void (*)(UA_Server *, void *))
                         UA_DataSetReader_handleMessageReceiveTimeout);
    if(retVal != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_READERGROUP(server->config.logging, readerGroup,
                                 "Add DataSetReader failed, create message "
                                 "receive timeout timer failed");
        UA_DataSetReaderConfig_clear(&newDataSetReader->config);
        UA_free(newDataSetReader);
        newDataSetReader = 0;
        return retVal;
    }
#endif /* UA_ENABLE_PUBSUB_MONITORING */

    /* Add the new reader to the group */
    LIST_INSERT_HEAD(&readerGroup->readers, newDataSetReader, listEntry);
    readerGroup->readersCount++;

    if(!UA_String_isEmpty(&newDataSetReader->config.linkedStandaloneSubscribedDataSetName)) {
        // find sds by name
        UA_StandaloneSubscribedDataSet *subscribedDataSet =
            UA_StandaloneSubscribedDataSet_findSDSbyName(server,
               newDataSetReader->config.linkedStandaloneSubscribedDataSetName);
        if(subscribedDataSet != NULL) {
            if(subscribedDataSet->config.subscribedDataSetType != UA_PUBSUB_SDS_TARGET) {
                UA_LOG_ERROR_READER(server->config.logging, newDataSetReader,
                                    "Not implemented! Currently only SubscribedDataSet as "
                                    "TargetVariables is implemented");
            } else {
                if(subscribedDataSet->config.isConnected) {
                    UA_LOG_ERROR_READER(server->config.logging, newDataSetReader,
                                        "SubscribedDataSet is already connected");
                } else {
                    UA_LOG_DEBUG_READER(server->config.logging, newDataSetReader,
                                        "Found SubscribedDataSet");
                    subscribedDataSet->config.isConnected = true;
                    UA_DataSetMetaDataType_copy(
                        &subscribedDataSet->config.dataSetMetaData,
                        &newDataSetReader->config.dataSetMetaData);
                    UA_FieldTargetVariable *targetVars =
                        (UA_FieldTargetVariable *)UA_calloc(
                            subscribedDataSet->config.subscribedDataSet.target
                                .targetVariablesSize,
                            sizeof(UA_FieldTargetVariable));
                    for(size_t index = 0;
                        index < subscribedDataSet->config.subscribedDataSet.target
                                    .targetVariablesSize;
                        index++) {
                        UA_FieldTargetDataType_copy(
                            &subscribedDataSet->config.subscribedDataSet.target
                                 .targetVariables[index],
                            &targetVars[index].targetVariable);
                    }

                    DataSetReader_createTargetVariables(server, newDataSetReader,
                                                        subscribedDataSet->config.subscribedDataSet.
                                                        target.targetVariablesSize, targetVars);
                    subscribedDataSet->connectedReader = newDataSetReader->identifier;

                    for(size_t index = 0;
                        index < subscribedDataSet->config.subscribedDataSet.target
                                    .targetVariablesSize;
                        index++) {
                        UA_FieldTargetDataType_clear(&targetVars[index].targetVariable);
                    }

                    UA_free(targetVars);

#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
                    connectDataSetReaderToDataSet(server, newDataSetReader->identifier,
                                                  subscribedDataSet->identifier);
#endif
                }
            }
        }
    }

    /* Check if used dataSet metaData is valid in context of the rest of the config */
    if(newDataSetReader->config.dataSetFieldContentMask &
       UA_DATASETFIELDCONTENTMASK_RAWDATA) {
        for(size_t fieldIdx = 0;
            fieldIdx < newDataSetReader->config.dataSetMetaData.fieldsSize; fieldIdx++) {
            const UA_FieldMetaData *field =
                &newDataSetReader->config.dataSetMetaData.fields[fieldIdx];
            if((field->builtInType == UA_TYPES_STRING ||
                field->builtInType == UA_TYPES_BYTESTRING) &&
               field->maxStringLength == 0) {
                /* Fields of type String or ByteString need to have defined
                 * MaxStringLength*/
                UA_LOG_ERROR_READER(server->config.logging, newDataSetReader,
                                    "Add DataSetReader failed. MaxStringLength must be "
                                    "set in MetaData when using RawData field encoding.");
                UA_DataSetReaderConfig_clear(&newDataSetReader->config);
                UA_free(newDataSetReader);
                newDataSetReader = NULL;
                return UA_STATUSCODE_BADCONFIGURATIONERROR;
            }
        }
    }

    if(readerIdentifier)
        UA_NodeId_copy(&newDataSetReader->identifier, readerIdentifier);

    /* Set the DataSetReader state after finalizing the configuration */
    return UA_DataSetReader_setPubSubState(server, newDataSetReader,
                                           UA_PUBSUBSTATE_OPERATIONAL);
}

UA_StatusCode
UA_Server_addDataSetReader(UA_Server *server, UA_NodeId readerGroupIdentifier,
                           const UA_DataSetReaderConfig *dataSetReaderConfig,
                           UA_NodeId *readerIdentifier) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = UA_DataSetReader_create(server, readerGroupIdentifier,
                                                dataSetReaderConfig, readerIdentifier);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_DataSetReader_remove(UA_Server *server, UA_DataSetReader *dsr) {
    if(dsr->configurationFrozen) {
        UA_LOG_WARNING_READER(server->config.logging, dsr,
                              "Remove DataSetReader failed, "
                              "Subscriber configuration is frozen");
        return UA_STATUSCODE_BADCONFIGURATIONERROR;
    }

#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    deleteNode(server, dsr->identifier, true);
#endif

#ifdef UA_ENABLE_PUBSUB_MONITORING
    /* Stop and remove message receive timeout timer */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(dsr->msgRcvTimeoutTimerRunning) {
        res = server->config.pubSubConfig.monitoringInterface.
            stopMonitoring(server, dsr->identifier, UA_PUBSUB_COMPONENT_DATASETREADER,
                           UA_PUBSUB_MONITORING_MESSAGE_RECEIVE_TIMEOUT, dsr);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR_READER(server->config.logging, dsr,
                                "Remove DataSetReader failed. Stop message "
                                "receive timeout timer of DataSetReader '%.*s' failed.",
                                (int) dsr->config.name.length, dsr->config.name.data);
        }
    }

    res |= server->config.pubSubConfig.monitoringInterface.
        deleteMonitoring(server, dsr->identifier, UA_PUBSUB_COMPONENT_DATASETREADER,
                         UA_PUBSUB_MONITORING_MESSAGE_RECEIVE_TIMEOUT, dsr);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_READER(server->config.logging, dsr,
                            "Remove DataSetReader failed. Delete message receive "
                            "timeout timer of DataSetReader '%.*s' failed.",
                            (int) dsr->config.name.length, dsr->config.name.data);
    }
#endif /* UA_ENABLE_PUBSUB_MONITORING */
    /* check if a Standalone-SubscribedDataSet is associated with this reader and disconnect it*/
    if(!UA_String_isEmpty(&dsr->config.linkedStandaloneSubscribedDataSetName)) {
        UA_StandaloneSubscribedDataSet *subscribedDataSet =
            UA_StandaloneSubscribedDataSet_findSDSbyName(
                server, dsr->config.linkedStandaloneSubscribedDataSetName);
        if(subscribedDataSet != NULL) {
            subscribedDataSet->config.isConnected = false;
        }
    }

    /* Delete DataSetReader config */
    UA_DataSetReaderConfig_clear(&dsr->config);

    /* Remove DataSetReader from group */
    LIST_REMOVE(dsr, listEntry);
    UA_ReaderGroup *rg = dsr->linkedReaderGroup;
    rg->readersCount--;

    /* THe offset buffer is only set when the dsr is frozen
     * UA_NetworkMessageOffsetBuffer_clear(&dsr->bufferedMessage); */

    UA_LOG_INFO_READER(server->config.logging, dsr, "DataSetReader deleted");

    UA_NodeId_clear(&dsr->identifier);
    UA_String_clear(&dsr->logIdString);
    UA_free(dsr);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_removeDataSetReader(UA_Server *server, UA_NodeId readerIdentifier) {
    UA_LOCK(&server->serviceMutex);
    UA_DataSetReader *dsr = UA_ReaderGroup_findDSRbyId(server, readerIdentifier);
    if(!dsr) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADNOTFOUND;
    }
    UA_StatusCode res = UA_DataSetReader_remove(server, dsr);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

static UA_StatusCode
DataSetReader_updateConfig(UA_Server *server, UA_ReaderGroup *rg, UA_DataSetReader *dsr,
                           const UA_DataSetReaderConfig *config) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    if(dsr->configurationFrozen) {
        UA_LOG_WARNING_READER(server->config.logging, dsr,
                              "Update DataSetReader config failed. "
                              "Subscriber configuration is frozen.");
        return UA_STATUSCODE_BADCONFIGURATIONERROR;
    }

    if(rg->configurationFrozen) {
        UA_LOG_WARNING_READER(server->config.logging, dsr,
                              "Update DataSetReader config failed. "
                              "Subscriber configuration is frozen.");
        return UA_STATUSCODE_BADCONFIGURATIONERROR;
    }

    if(dsr->config.subscribedDataSetType != UA_PUBSUB_SDS_TARGET) {
        UA_LOG_WARNING_READER(server->config.logging, dsr,
                              "Unsupported SubscribedDataSetType.");
        return UA_STATUSCODE_BADCONFIGURATIONERROR;
    }

    /* The update functionality will be extended during the next PubSub batches.
     * Currently changes for writerGroupId, dataSetWriterId and TargetVariables are possible. */
    if(dsr->config.writerGroupId != config->writerGroupId)
        dsr->config.writerGroupId = config->writerGroupId;
    if(dsr->config.dataSetWriterId != config->dataSetWriterId)
        dsr->config.dataSetWriterId = config->dataSetWriterId;

    UA_TargetVariables *oldTV = &dsr->config.subscribedDataSet.subscribedDataSetTarget;
    const UA_TargetVariables *newTV = &config->subscribedDataSet.subscribedDataSetTarget;
    if(oldTV->targetVariablesSize == newTV->targetVariablesSize) {
        for(size_t i = 0; i < newTV->targetVariablesSize; i++) {
            if(!UA_NodeId_equal(&oldTV->targetVariables[i].targetVariable.targetNodeId,
                                &newTV->targetVariables[i].targetVariable.targetNodeId)) {
                DataSetReader_createTargetVariables(server, dsr,
                                                    newTV->targetVariablesSize,
                                                    newTV->targetVariables);
                break;
            }
        }
    } else {
        DataSetReader_createTargetVariables(server, dsr, newTV->targetVariablesSize,
                                            newTV->targetVariables);
    }

    UA_StatusCode res = UA_STATUSCODE_GOOD;
#ifdef UA_ENABLE_PUBSUB_MONITORING
    if(dsr->config.messageReceiveTimeout != config->messageReceiveTimeout) {
        /* Update message receive timeout timer interval */
        dsr->config.messageReceiveTimeout = config->messageReceiveTimeout;
        if(dsr->msgRcvTimeoutTimerId != 0) {
            res = server->config.pubSubConfig.monitoringInterface.
                updateMonitoringInterval(server, dsr->identifier,
                                         UA_PUBSUB_COMPONENT_DATASETREADER,
                                         UA_PUBSUB_MONITORING_MESSAGE_RECEIVE_TIMEOUT,
                                         dsr);
            if(res != UA_STATUSCODE_GOOD) {
                UA_LOG_ERROR_READER(server->config.logging, dsr,
                                    "Update DataSetReader message receive timeout timer failed.");
            }
        }
    }
#endif /* UA_ENABLE_PUBSUB_MONITORING */
    return res;
}

UA_StatusCode
UA_Server_DataSetReader_updateConfig(UA_Server *server, UA_NodeId dataSetReaderIdentifier,
                                     UA_NodeId readerGroupIdentifier,
                                     const UA_DataSetReaderConfig *config) {
    if(config == NULL)
       return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_LOCK(&server->serviceMutex);
    UA_DataSetReader *dsr = UA_ReaderGroup_findDSRbyId(server, dataSetReaderIdentifier);
    UA_ReaderGroup *rg = UA_ReaderGroup_findRGbyId(server, readerGroupIdentifier);
    if(!dsr || !rg) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADNOTFOUND;
    }
    UA_StatusCode res = DataSetReader_updateConfig(server, rg, dsr, config);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_Server_DataSetReader_getConfig(UA_Server *server, UA_NodeId dataSetReaderIdentifier,
                                 UA_DataSetReaderConfig *config) {
    if(!config)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND;
    UA_DataSetReader *dsr = UA_ReaderGroup_findDSRbyId(server, dataSetReaderIdentifier);
    if(dsr)
        res = UA_DataSetReaderConfig_copy(&dsr->config, config);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_DataSetReaderConfig_copy(const UA_DataSetReaderConfig *src,
                            UA_DataSetReaderConfig *dst) {
    memset(dst, 0, sizeof(UA_DataSetReaderConfig));
    UA_StatusCode retVal = UA_String_copy(&src->name, &dst->name);
    if(retVal != UA_STATUSCODE_GOOD)
        return retVal;

    retVal = UA_Variant_copy(&src->publisherId, &dst->publisherId);
    if(retVal != UA_STATUSCODE_GOOD)
        return retVal;

    dst->writerGroupId = src->writerGroupId;
    dst->dataSetWriterId = src->dataSetWriterId;
    dst->expectedEncoding = src->expectedEncoding;
    retVal = UA_DataSetMetaDataType_copy(&src->dataSetMetaData, &dst->dataSetMetaData);
    if(retVal != UA_STATUSCODE_GOOD)
        return retVal;

    dst->dataSetFieldContentMask = src->dataSetFieldContentMask;
    dst->messageReceiveTimeout = src->messageReceiveTimeout;

    retVal = UA_ExtensionObject_copy(&src->messageSettings, &dst->messageSettings);
    if(retVal != UA_STATUSCODE_GOOD)
        return retVal;

    retVal = UA_ExtensionObject_copy(&src->transportSettings, &dst->transportSettings);
    if(retVal != UA_STATUSCODE_GOOD)
        return retVal;

    if(src->subscribedDataSetType == UA_PUBSUB_SDS_TARGET) {
        retVal = UA_TargetVariables_copy(&src->subscribedDataSet.subscribedDataSetTarget,
                                         &dst->subscribedDataSet.subscribedDataSetTarget);
        if(retVal != UA_STATUSCODE_GOOD) {
            return retVal;
        }
    }

    retVal = UA_String_copy(&src->linkedStandaloneSubscribedDataSetName, &dst->linkedStandaloneSubscribedDataSetName);

    return retVal;
}

void
UA_DataSetReaderConfig_clear(UA_DataSetReaderConfig *cfg) {
    UA_String_clear(&cfg->name);
    UA_String_clear(&cfg->linkedStandaloneSubscribedDataSetName);
    UA_Variant_clear(&cfg->publisherId);
    UA_DataSetMetaDataType_clear(&cfg->dataSetMetaData);
    UA_ExtensionObject_clear(&cfg->messageSettings);
    UA_ExtensionObject_clear(&cfg->transportSettings);
    if(cfg->subscribedDataSetType == UA_PUBSUB_SDS_TARGET) {
        UA_TargetVariables_clear(&cfg->subscribedDataSet.subscribedDataSetTarget);
    }
}

UA_StatusCode
UA_Server_DataSetReader_getState(UA_Server *server, UA_NodeId dsrId,
                                 UA_PubSubState *state) {
    if(!server || !state)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND;
    UA_DataSetReader *dsr = UA_ReaderGroup_findDSRbyId(server, dsrId);
    if(dsr) {
        res = UA_STATUSCODE_GOOD;
        *state = dsr->state;
    }
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_Server_enableDataSetReader(UA_Server *server, const UA_NodeId dsrId) {
    UA_LOCK(&server->serviceMutex);
    UA_DataSetReader *dsr = UA_ReaderGroup_findDSRbyId(server, dsrId);
    if(!dsr) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADNOTFOUND;
    }

    UA_StatusCode ret =
        UA_DataSetReader_setPubSubState(server, dsr, UA_PUBSUBSTATE_OPERATIONAL);
    UA_UNLOCK(&server->serviceMutex);
    return ret;
}

UA_StatusCode
UA_Server_disableDataSetReader(UA_Server *server, const UA_NodeId dsrId) {
    UA_LOCK(&server->serviceMutex);
    UA_DataSetReader *dsr = UA_ReaderGroup_findDSRbyId(server, dsrId);
    if(!dsr) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADNOTFOUND;
    }

    UA_StatusCode ret =
        UA_DataSetReader_setPubSubState(server, dsr, UA_PUBSUBSTATE_DISABLED);
    UA_UNLOCK(&server->serviceMutex);
    return ret;
}

UA_StatusCode
UA_DataSetReader_setPubSubState(UA_Server *server, UA_DataSetReader *dsr,
                                UA_PubSubState targetState) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    UA_ReaderGroup *rg = dsr->linkedReaderGroup;
    UA_assert(rg);

    UA_PubSubState oldState = dsr->state;
    dsr->state = targetState;

    switch(dsr->state) {
        /* Disabled */
    case UA_PUBSUBSTATE_DISABLED:
    case UA_PUBSUBSTATE_ERROR:
        break;

        /* Enabled */
    case UA_PUBSUBSTATE_PAUSED:
    case UA_PUBSUBSTATE_PREOPERATIONAL:
    case UA_PUBSUBSTATE_OPERATIONAL:
        if(rg->state == UA_PUBSUBSTATE_DISABLED ||
           rg->state == UA_PUBSUBSTATE_ERROR) {
            dsr->state = UA_PUBSUBSTATE_PAUSED; /* RG is disabled -> paused */
        } else {
            dsr->state = rg->state; /* RG is enabled -> same state */
        }
        break;

    default:
        dsr->state = UA_PUBSUBSTATE_ERROR;
        res = UA_STATUSCODE_BADINTERNALERROR;
        break;
    }

    /* Inform application about state change */
    if(dsr->state != oldState) {
        UA_ServerConfig *config = &server->config;
        UA_LOG_INFO_READER(config->logging, dsr, "State change: %s -> %s",
                           UA_PubSubState_name(oldState),
                           UA_PubSubState_name(dsr->state));
        if(config->pubSubConfig.stateChangeCallback != 0) {
            UA_UNLOCK(&server->serviceMutex);
            config->pubSubConfig.
                stateChangeCallback(server, &dsr->identifier, dsr->state, res);
            UA_LOCK(&server->serviceMutex);
        }
    }

    return res;
}

UA_StatusCode
UA_FieldTargetVariable_copy(const UA_FieldTargetVariable *src, UA_FieldTargetVariable *dst) {
    /* Do a simple memcpy */
    memcpy(dst, src, sizeof(UA_FieldTargetVariable));
    return UA_FieldTargetDataType_copy(&src->targetVariable, &dst->targetVariable);
}

UA_StatusCode
UA_TargetVariables_copy(const UA_TargetVariables *src, UA_TargetVariables *dst) {
    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    memcpy(dst, src, sizeof(UA_TargetVariables));
    if(src->targetVariablesSize > 0) {
        dst->targetVariables = (UA_FieldTargetVariable*)
            UA_calloc(src->targetVariablesSize, sizeof(UA_FieldTargetVariable));
        if(!dst->targetVariables)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        for(size_t i = 0; i < src->targetVariablesSize; i++)
            retVal |= UA_FieldTargetVariable_copy(&src->targetVariables[i], &dst->targetVariables[i]);
    }
    return retVal;
}

void
UA_TargetVariables_clear(UA_TargetVariables *subscribedDataSetTarget) {
    for(size_t i = 0; i < subscribedDataSetTarget->targetVariablesSize; i++) {
        UA_FieldTargetDataType_clear(&subscribedDataSetTarget->targetVariables[i].targetVariable);
    }
    if(subscribedDataSetTarget->targetVariablesSize > 0)
        UA_free(subscribedDataSetTarget->targetVariables);
    memset(subscribedDataSetTarget, 0, sizeof(UA_TargetVariables));
}

/* This Method is used to initially set the SubscribedDataSet to
 * TargetVariablesType and to create the list of target Variables of a
 * SubscribedDataSetType. */
UA_StatusCode
DataSetReader_createTargetVariables(UA_Server *server, UA_DataSetReader *dsr,
                                    size_t targetVariablesSize,
                                    const UA_FieldTargetVariable *targetVariables) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    if(dsr->configurationFrozen) {
        UA_LOG_WARNING_READER(server->config.logging, dsr,
                              "Create Target Variables failed. "
                              "Subscriber configuration is frozen.");
        return UA_STATUSCODE_BADCONFIGURATIONERROR;
    }

    if(dsr->config.subscribedDataSet.subscribedDataSetTarget.targetVariablesSize > 0)
        UA_TargetVariables_clear(&dsr->config.subscribedDataSet.subscribedDataSetTarget);

    /* Set subscribed dataset to TargetVariableType */
    dsr->config.subscribedDataSetType = UA_PUBSUB_SDS_TARGET;
    UA_TargetVariables tmp;
    tmp.targetVariablesSize = targetVariablesSize;
    tmp.targetVariables = (UA_FieldTargetVariable*)(uintptr_t)targetVariables;
    return UA_TargetVariables_copy(&tmp, &dsr->config.subscribedDataSet.subscribedDataSetTarget);
}

UA_StatusCode
UA_Server_DataSetReader_createTargetVariables(UA_Server *server,
                                              UA_NodeId dataSetReaderIdentifier,
                                              size_t targetVariablesSize,
                                              const UA_FieldTargetVariable *targetVariables) {
    UA_LOCK(&server->serviceMutex);
    UA_DataSetReader *dataSetReader = UA_ReaderGroup_findDSRbyId(server, dataSetReaderIdentifier);
    if(!dataSetReader) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }
    UA_StatusCode res = DataSetReader_createTargetVariables(server, dataSetReader,
                                                            targetVariablesSize, targetVariables);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

/* This functionality of this API will be used in future to create mirror Variables - TODO */
/* UA_StatusCode
UA_Server_DataSetReader_createDataSetMirror(UA_Server *server, UA_String *parentObjectNodeName,
                                            UA_NodeId dataSetReaderIdentifier) {
    if((server == NULL) || (parentNode == NULL)) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    UA_DataSetReader* pDataSetReader = UA_ReaderGroup_findDSRbyId(server, dataSetReaderIdentifier);
    if(pDataSetReader == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    if(pDataSetReader->configurationFrozen) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Add Target Variables failed. Subscriber configuration is frozen.");
        return UA_STATUSCODE_BADCONFIGURATIONERROR;
    } // TODO: Frozen configuration variable in TargetVariable structure

    UA_TargetVariables targetVars;
    targetVars.targetVariablesSize = pDataSetReader->config.dataSetMetaData.fieldsSize;
    targetVars.targetVariables = (UA_FieldTargetVariable *)
        UA_calloc(targetVars.targetVariablesSize, sizeof(UA_FieldTargetVariable));

    for(size_t i = 0; i < pDataSetReader->config.dataSetMetaData.fieldsSize; i++) {
        UA_VariableAttributes vAttr = UA_VariableAttributes_default;
        vAttr.valueRank = pDataSetReader->config.dataSetMetaData.fields[i].valueRank;
        if(pDataSetReader->config.dataSetMetaData.fields[i].arrayDimensionsSize > 0) {
            retval = UA_Array_copy(pDataSetReader->config.dataSetMetaData.fields[i].arrayDimensions,
                                   pDataSetReader->config.dataSetMetaData.fields[i].arrayDimensionsSize,
                                   (void**)&vAttr.arrayDimensions, &UA_TYPES[UA_TYPES_UINT32]);
            if(retval == UA_STATUSCODE_GOOD) {
                vAttr.arrayDimensionsSize =
                    pDataSetReader->config.dataSetMetaData.fields[i].arrayDimensionsSize;
            }

        }

        vAttr.dataType = pDataSetReader->config.dataSetMetaData.fields[i].dataType;

        vAttr.accessLevel = UA_ACCESSLEVELMASK_READ;
        UA_LocalizedText_copy(&pDataSetReader->config.dataSetMetaData.fields[i].description,
                              &vAttr.description);
        UA_QualifiedName qn;
        UA_QualifiedName_init(&qn);
        char szTmpName[UA_MAX_SIZENAME];
        if(pDataSetReader->config.dataSetMetaData.fields[i].name.length > 0) {
            UA_UInt16 slen = UA_MAX_SIZENAME -1;
            vAttr.displayName.locale = UA_STRING("en-US");
            vAttr.displayName.text = pDataSetReader->config.dataSetMetaData.fields[i].name;
            if(pDataSetReader->config.dataSetMetaData.fields[i].name.length < slen) {
                slen = (UA_UInt16)pDataSetReader->config.dataSetMetaData.fields[i].name.length;
                mp_snprintf(szTmpName, sizeof(szTmpName), "%.*s", (int)slen,
                            (const char*)pDataSetReader->config.dataSetMetaData.fields[i].name.data);
            }

            szTmpName[slen] = '\0';
            qn = UA_QUALIFIEDNAME(1, szTmpName);
        }
        else {
            strcpy(szTmpName, "SubscribedVariable");
            vAttr.displayName = UA_LOCALIZEDTEXT("en-US", szTmpName);
            qn = UA_QUALIFIEDNAME(1, "SubscribedVariable");
        }

        // Add variable to the given parent node
        UA_NodeId newNode;
        retval = UA_Server_addVariableNode(server, UA_NODEID_NULL, *parentNode,
                                           UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), qn,
                                           UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
                                           vAttr, NULL, &newNode);
        if(retval == UA_STATUSCODE_GOOD) {
            UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_USERLAND,
                        "addVariableNode %s succeeded", szTmpName);
        }
        else {
            UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_USERLAND,
                         "addVariableNode: error 0x%" PRIx32, retval);
        }

        targetVars.targetVariables[i].targetVariable.attributeId = UA_ATTRIBUTEID_VALUE;
        UA_NodeId_copy(&newNode, &targetVars.targetVariables[i].targetVariable.targetNodeId);
        UA_NodeId_clear(&newNode);
        if(vAttr.arrayDimensionsSize > 0) {
            UA_Array_delete(vAttr.arrayDimensions, vAttr.arrayDimensionsSize,
                            &UA_TYPES[UA_TYPES_UINT32]);
        }
    }

    UA_TargetVariables_clear(&targetVars);
    return retval;
}*/

static void
DataSetReader_processRaw(UA_Server *server, UA_DataSetReader *dsr,
                         UA_DataSetMessage* msg) {
    UA_LOG_TRACE_READER(server->config.logging, dsr, "Received RAW Frame");
    msg->data.keyFrameData.fieldCount = (UA_UInt16)
        dsr->config.dataSetMetaData.fieldsSize;

    size_t offset = 0;
    /* start iteration from beginning of rawFields buffer */
    msg->data.keyFrameData.rawFields.length = 0;
    for(size_t i = 0; i < dsr->config.dataSetMetaData.fieldsSize; i++) {
        /* TODO The datatype reference should be part of the internal
         * pubsub configuration to avoid the time-expensive lookup */
        const UA_DataType *type =
            UA_findDataTypeWithCustom(&dsr->config.dataSetMetaData.fields[i].dataType,
                                      server->config.customDataTypes);
        size_t fieldLength = 0;
        if(type->typeKind == UA_DATATYPEKIND_STRING || type->typeKind == UA_DATATYPEKIND_BYTESTRING)
        {
            UA_assert(dsr->config.dataSetMetaData.fields[i].maxStringLength != 0);
            // Length of binary encoded string = 4 (string length encoded as uint32) + N (actual string data) bytes.
            // For fixed message layout N equals maxStringlength.
            fieldLength = sizeof(UA_UInt32) + dsr->config.dataSetMetaData.fields[i].maxStringLength;
        }
else
        {
            fieldLength = type->memSize;
        }

        // For arrays the length of the array is encoded before the actual data
        size_t elementCount = 1;
        size_t dimCnt = 0;
        for(int cnt = 0; cnt < dsr->config.dataSetMetaData.fields[i].valueRank; cnt++) {
            UA_UInt32 dimSize =
                *(UA_UInt32 *)&msg->data.keyFrameData.rawFields.data[offset];
            if(dimSize != dsr->config.dataSetMetaData.fields[i].arrayDimensions[cnt]) {
                UA_LOG_INFO_READER(
                    server->config.logging, dsr,
                    "Error during Raw-decode KeyFrame field %u: "
                    "Dimension size in received data doesn't match the dataSetMetaData",
                    (unsigned)i);
                return;
            }
            offset += sizeof(UA_UInt32);
            elementCount *= dimSize;
            dimCnt++;
        }

        msg->data.keyFrameData.rawFields.length +=
            fieldLength * elementCount + dimCnt * sizeof(UA_UInt32);
        UA_STACKARRAY(UA_Byte, value, elementCount * type->memSize);
        UA_Byte *valPtr = value;
        UA_StatusCode res = UA_STATUSCODE_GOOD;
        for(size_t cnt = 0; cnt < elementCount; cnt++) {
            res = UA_decodeBinaryInternal(&msg->data.keyFrameData.rawFields, &offset,
                                          valPtr, type, NULL);
            if(dsr->config.dataSetMetaData.fields[i].maxStringLength != 0) {
                if(type->typeKind == UA_DATATYPEKIND_STRING ||
                    type->typeKind == UA_DATATYPEKIND_BYTESTRING) {
                    UA_ByteString *bs = (UA_ByteString *) valPtr;
                    //check if length < maxStringLength, The types ByteString and String are equal in their base definition
                    size_t lengthDifference = dsr->config.dataSetMetaData.fields[i].maxStringLength - bs->length;
                    offset += lengthDifference;
                }
            }
            if(res != UA_STATUSCODE_GOOD) {
                UA_LOG_INFO_READER(server->config.logging, dsr,
                                "Error during Raw-decode KeyFrame field %u: %s",
                                (unsigned)i, UA_StatusCode_name(res));
                return;
            }
            valPtr += type->memSize;
        }

        UA_FieldTargetVariable *tv =
            &dsr->config.subscribedDataSet.subscribedDataSetTarget.targetVariables[i];

        if(dsr->linkedReaderGroup->config.rtLevel == UA_PUBSUB_RT_FIXED_SIZE) {
            if (tv->beforeWrite) {
                void *pData = (**tv->externalDataValue).value.data;
                (**tv->externalDataValue).value.data = value;   // set raw data as "preview"
                tv->beforeWrite(server, &dsr->identifier, &dsr->linkedReaderGroup->identifier,
                                &tv->targetVariable.targetNodeId,
                                tv->targetVariableContext,
                                tv->externalDataValue);
                (**tv->externalDataValue).value.data = pData;  // restore previous data pointer
            }
            memcpy((**tv->externalDataValue).value.data, value, type->memSize);
            if(tv->afterWrite)
                tv->afterWrite(server, &dsr->identifier,
                                &dsr->linkedReaderGroup->identifier,
                                &tv->targetVariable.targetNodeId,
                                tv->targetVariableContext,
                                tv->externalDataValue);
            continue; /* No dynamic allocation for fixed-size msg, no need to _clear */
        }

        UA_WriteValue writeVal;
        UA_WriteValue_init(&writeVal);
        writeVal.attributeId = tv->targetVariable.attributeId;
        writeVal.indexRange = tv->targetVariable.receiverIndexRange;
        writeVal.nodeId = tv->targetVariable.targetNodeId;
        if(dsr->config.dataSetMetaData.fields[i].valueRank > 0) {
            UA_Variant_setArray(&writeVal.value.value, value, elementCount, type);
        } else {
            UA_Variant_setScalar(&writeVal.value.value, value, type);
        }
        writeVal.value.hasValue = true;
        Operation_Write(server, &server->adminSession, NULL, &writeVal, &res);
        UA_clear(value, type);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_INFO_READER(server->config.logging, dsr,
                               "Error writing KeyFrame field %u: %s",
                               (unsigned)i, UA_StatusCode_name(res));
        }
    }
}

static void
DataSetReader_processFixedSize(UA_Server *server, UA_DataSetReader *dsr,
                               UA_DataSetMessage *msg, size_t fieldCount) {
    for(size_t i = 0; i < fieldCount; i++) {
        if(!msg->data.keyFrameData.dataSetFields[i].hasValue)
            continue;

        UA_FieldTargetVariable *tv =
            &dsr->config.subscribedDataSet.subscribedDataSetTarget.targetVariables[i];
        if(tv->targetVariable.attributeId != UA_ATTRIBUTEID_VALUE)
            continue;

        if(msg->data.keyFrameData.dataSetFields[i].value.type !=
           (*tv->externalDataValue)->value.type) {
            UA_LOG_WARNING_READER(server->config.logging, dsr,
                                  "Mismatching type");
            continue;
        }

        if (tv->beforeWrite) {
            UA_DataValue *tmp = &msg->data.keyFrameData.dataSetFields[i];
            tv->beforeWrite(server, &dsr->identifier, &dsr->linkedReaderGroup->identifier,
                            &tv->targetVariable.targetNodeId,
                            tv->targetVariableContext, &tmp);
        }
        if(UA_LIKELY(tv->externalDataValue != NULL)) {
            memcpy((**tv->externalDataValue).value.data,
                   msg->data.keyFrameData.dataSetFields[i].value.data,
                   msg->data.keyFrameData.dataSetFields[i].value.type->memSize);
        }
        if(tv->afterWrite)
            tv->afterWrite(server, &dsr->identifier, &dsr->linkedReaderGroup->identifier,
                           &tv->targetVariable.targetNodeId,
                           tv->targetVariableContext, tv->externalDataValue);
    }
}

void
UA_DataSetReader_process(UA_Server *server, UA_DataSetReader *dsr,
                         UA_DataSetMessage *msg) {
    if(!dsr || !msg || !server)
        return;

    /* Received a (first) message for the Reader.
     * Transition from PreOperational to Operational. */
    if(dsr->state == UA_PUBSUBSTATE_PREOPERATIONAL)
        UA_DataSetReader_setPubSubState(server, dsr, UA_PUBSUBSTATE_OPERATIONAL);

    /* Check the metadata, to see if this reader is configured for a heartbeat */
    if(dsr->config.dataSetMetaData.fieldsSize == 0 &&
       dsr->config.dataSetMetaData.configurationVersion.majorVersion == 0 &&
       dsr->config.dataSetMetaData.configurationVersion.minorVersion == 0) {
        /* Expecting a heartbeat, check the message */
        if(msg->header.dataSetMessageType != UA_DATASETMESSAGE_DATAKEYFRAME ||
            msg->header.configVersionMajorVersion != 0 ||
            msg->header.configVersionMinorVersion != 0 ||
            msg->data.keyFrameData.fieldCount != 0) {
            UA_LOG_INFO_READER(server->config.logging, dsr,
                               "This DSR expects heartbeat, but the received "
                               "message doesn't seem to be so.");
        }
#ifdef UA_ENABLE_PUBSUB_MONITORING
        UA_DataSetReader_checkMessageReceiveTimeout(server, dsr);
#endif
        UA_EventLoop *el = UA_PubSubConnection_getEL(server,
                                                     dsr->linkedReaderGroup->linkedConnection);
        dsr->lastHeartbeatReceived = el->dateTime_nowMonotonic(el);
        return;
    }

    UA_LOG_DEBUG_READER(server->config.logging, dsr,
                        "DataSetReader '%.*s': received a network message",
                        (int)dsr->config.name.length, dsr->config.name.data);

    if(!msg->header.dataSetMessageValid) {
        UA_LOG_INFO_READER(server->config.logging, dsr,
                           "DataSetMessage is discarded: message is not valid");
        /* To Do check ConfigurationVersion */
        /* if(msg->header.configVersionMajorVersionEnabled) {
         *     if(msg->header.configVersionMajorVersion !=
         *            dsr->config.dataSetMetaData.configurationVersion.majorVersion) {
         *         UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
         *                        "DataSetMessage is discarded: ConfigurationVersion "
         *                        "MajorVersion does not match");
         *         return;
         *     }
         * } */
        return;
    }

    if(msg->header.dataSetMessageType != UA_DATASETMESSAGE_DATAKEYFRAME) {
        UA_LOG_WARNING_READER(server->config.logging, dsr,
                       "DataSetMessage is discarded: Only keyframes are supported");
        return;
    }

    /* Process message with raw encoding (realtime and non-realtime) */
    if(msg->header.fieldEncoding == UA_FIELDENCODING_RAWDATA) {
        DataSetReader_processRaw(server, dsr, msg);
#ifdef UA_ENABLE_PUBSUB_MONITORING
        UA_DataSetReader_checkMessageReceiveTimeout(server, dsr);
#endif
        return;
    }

    /* Check and adjust the field count
     * TODO Throw an error if non-matching? */
    size_t fieldCount = msg->data.keyFrameData.fieldCount;
    if(dsr->config.dataSetMetaData.fieldsSize < fieldCount)
        fieldCount = dsr->config.dataSetMetaData.fieldsSize;

    if(dsr->config.subscribedDataSet.subscribedDataSetTarget.targetVariablesSize < fieldCount)
        fieldCount = dsr->config.subscribedDataSet.subscribedDataSetTarget.targetVariablesSize;

    /* Process message with fixed size fields (realtime capable) */
    if(dsr->linkedReaderGroup->config.rtLevel == UA_PUBSUB_RT_FIXED_SIZE) {
        DataSetReader_processFixedSize(server, dsr, msg, fieldCount);
#ifdef UA_ENABLE_PUBSUB_MONITORING
        UA_DataSetReader_checkMessageReceiveTimeout(server, dsr);
#endif
        return;
    }

    /* Write the message fields via the write service (non realtime) */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    for(size_t i = 0; i < fieldCount; i++) {
        if(!msg->data.keyFrameData.dataSetFields[i].hasValue)
            continue;

        UA_FieldTargetVariable *tv =
            &dsr->config.subscribedDataSet.subscribedDataSetTarget.targetVariables[i];

        UA_WriteValue writeVal;
        UA_WriteValue_init(&writeVal);
        writeVal.attributeId = tv->targetVariable.attributeId;
        writeVal.indexRange = tv->targetVariable.receiverIndexRange;
        writeVal.nodeId = tv->targetVariable.targetNodeId;
        writeVal.value = msg->data.keyFrameData.dataSetFields[i];
        Operation_Write(server, &server->adminSession, NULL, &writeVal, &res);
        if(res != UA_STATUSCODE_GOOD)
            UA_LOG_INFO_READER(server->config.logging, dsr,
                               "Error writing KeyFrame field %u: %s",
                               (unsigned)i, UA_StatusCode_name(res));
    }

#ifdef UA_ENABLE_PUBSUB_MONITORING
    UA_DataSetReader_checkMessageReceiveTimeout(server, dsr);
#endif
}

#ifdef UA_ENABLE_PUBSUB_MONITORING

static void
UA_DataSetReader_checkMessageReceiveTimeout(UA_Server *server,
                                            UA_DataSetReader *dsr) {
    UA_assert(server != 0);
    UA_assert(dsr != 0);

    /* If previous reader state was error (because we haven't received messages
     * and ran into timeout) we should set the state back to operational */
    if(dsr->state == UA_PUBSUBSTATE_ERROR) {
        UA_DataSetReader_setPubSubState(server, dsr, UA_PUBSUBSTATE_OPERATIONAL);
    }

    /* Stop message receive timeout timer */
    UA_StatusCode res;
    if(dsr->msgRcvTimeoutTimerRunning) {
        res = server->config.pubSubConfig.monitoringInterface.
            stopMonitoring(server, dsr->identifier, UA_PUBSUB_COMPONENT_DATASETREADER,
                           UA_PUBSUB_MONITORING_MESSAGE_RECEIVE_TIMEOUT, dsr);
        if(res == UA_STATUSCODE_GOOD) {
            dsr->msgRcvTimeoutTimerRunning = false;
        } else {
            UA_LOG_ERROR_READER(server->config.logging, dsr,
                                "DataSetReader '%.*s': stop receive timeout timer failed",
                                (int)dsr->config.name.length, dsr->config.name.data);
            UA_DataSetReader_setPubSubState(server, dsr, UA_PUBSUBSTATE_ERROR);
        }
    }

    /* Start message receive timeout timer */
    res = server->config.pubSubConfig.monitoringInterface.
        startMonitoring(server, dsr->identifier, UA_PUBSUB_COMPONENT_DATASETREADER,
                        UA_PUBSUB_MONITORING_MESSAGE_RECEIVE_TIMEOUT, dsr);
    if(res == UA_STATUSCODE_GOOD) {
        UA_LOG_DEBUG_READER(server->config.logging, dsr,
                            "Info: DataSetReader '%.*s': start receive timeout timer",
                            (int)dsr->config.name.length, dsr->config.name.data);
        dsr->msgRcvTimeoutTimerRunning = true;
    } else {
        UA_LOG_ERROR_READER(server->config.logging, dsr,
                            "Starting Message Receive Timeout timer failed.");
        UA_DataSetReader_setPubSubState(server, dsr, UA_PUBSUBSTATE_ERROR);
    }
}

/* Timeout callback for DataSetReader MessageReceiveTimeout handling */
static void
UA_DataSetReader_handleMessageReceiveTimeout(UA_Server *server, UA_DataSetReader *dsr) {
    UA_assert(server);
    UA_assert(dsr);

    if(dsr->componentType != UA_PUBSUB_COMPONENT_DATASETREADER) {
        UA_LOG_ERROR_READER(server->config.logging, dsr,
                            "UA_DataSetReader_handleMessageReceiveTimeout(): "
                            "input param is not of type DataSetReader");
        return;
    }

    /* Don't signal an error if we don't expect messages to arrive */
    if(dsr->state != UA_PUBSUBSTATE_OPERATIONAL &&
       dsr->state != UA_PUBSUBSTATE_PREOPERATIONAL)
        return;

    UA_LOG_DEBUG_READER(server->config.logging, dsr,
                        "UA_DataSetReader_handleMessageReceiveTimeout(): "
                        "MessageReceiveTimeout occurred at DataSetReader "
                        "'%.*s': MessageReceiveTimeout = %f Timer Id = %u ",
                        (int)dsr->config.name.length, dsr->config.name.data,
                        dsr->config.messageReceiveTimeout,
                        (UA_UInt32) dsr->msgRcvTimeoutTimerId);

    UA_DataSetReader_setPubSubState(server, dsr, UA_PUBSUBSTATE_ERROR);
}
#endif /* UA_ENABLE_PUBSUB_MONITORING */

UA_StatusCode
UA_DataSetReader_prepareOffsetBuffer(UA_Server *server, UA_DataSetReader *reader,
                                     UA_ByteString *buf, size_t *pos) {
    UA_NetworkMessage *nm = (UA_NetworkMessage*)UA_calloc(1, sizeof(UA_NetworkMessage));
    if(!nm)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Decode using the non-rt decoding */
    UA_StatusCode rv = UA_NetworkMessage_decodeHeaders(buf, pos, nm);
    if(rv != UA_STATUSCODE_GOOD) {
        UA_NetworkMessage_clear(nm);
        UA_free(nm);
        return rv;
    }
    rv |= UA_NetworkMessage_decodePayload(buf, pos, nm, server->config.customDataTypes, &reader->config.dataSetMetaData);
    rv |= UA_NetworkMessage_decodeFooters(buf, pos, nm);
    if(rv != UA_STATUSCODE_GOOD) {
        UA_NetworkMessage_clear(nm);
        UA_free(nm);
        return rv;
    }

    /* Compute and store the offsets necessary to decode */
    size_t nmSize = UA_NetworkMessage_calcSizeBinary(nm, &reader->bufferedMessage);
    if(nmSize == 0) {
        UA_NetworkMessage_clear(nm);
        UA_free(nm);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Set the offset buffer in the reader */
    reader->bufferedMessage.nm = nm;

    return rv;
}

void
UA_DataSetReader_decodeAndProcessRT(UA_Server *server, UA_DataSetReader *dsr,
                                    UA_ByteString *buf) {
    size_t pos = 0;
    UA_StatusCode rv;
    if(!dsr->bufferedMessage.nm) {
        /* This is the first message being received for the RT fastpath.
         * Prepare the offset buffer. */
        rv = UA_DataSetReader_prepareOffsetBuffer(server, dsr, buf, &pos);
    } else {
        /* Decode with offset information and update the networkMessage */
        rv = UA_NetworkMessage_updateBufferedNwMessage(&dsr->bufferedMessage, buf, &pos);
    }
    if(rv != UA_STATUSCODE_GOOD) {
        UA_LOG_INFO_READER(server->config.logging, dsr,
                           "PubSub decoding failed. Could not decode with "
                           "status code %s.", UA_StatusCode_name(rv));
        return;
    }

    UA_DataSetReader_process(server, dsr,
                             dsr->bufferedMessage.nm->payload.dataSetPayload.dataSetMessages);
}

#endif /* UA_ENABLE_PUBSUB */

/**** amalgamated original file "/src/pubsub/ua_pubsub_readergroup.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2017-2018 Fraunhofer IOSB (Author: Andreas Ebner)
 * Copyright (c) 2019 Fraunhofer IOSB (Author: Julius Pfrommer)
 * Copyright (c) 2019 Kalycito Infotech Private Limited
 * Copyright (c) 2021 Fraunhofer IOSB (Author: Jan Hermes)
 * Copyright (c) 2022 Linutronix GmbH (Author: Muddasir Shakil)
 */


#ifdef UA_ENABLE_PUBSUB /* conditional compilation */

#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
#endif

UA_ReaderGroup *
UA_ReaderGroup_findRGbyId(UA_Server *server, UA_NodeId identifier) {
    UA_ReaderGroup *rg;
    UA_PubSubConnection *psc;
    TAILQ_FOREACH(psc, &server->pubSubManager.connections, listEntry) {
        LIST_FOREACH(rg, &psc->readerGroups, listEntry) {
            if(UA_NodeId_equal(&identifier, &rg->identifier))
                return rg;
        }
    }
    return NULL;
}

UA_DataSetReader *
UA_ReaderGroup_findDSRbyId(UA_Server *server, UA_NodeId identifier) {
    UA_ReaderGroup *rg;
    UA_PubSubConnection *psc;
    UA_DataSetReader *tmpReader;
    TAILQ_FOREACH(psc, &server->pubSubManager.connections, listEntry) {
        LIST_FOREACH(rg, &psc->readerGroups, listEntry) {
            LIST_FOREACH(tmpReader, &rg->readers, listEntry) {
                if(UA_NodeId_equal(&tmpReader->identifier, &identifier))
                    return tmpReader;
            }
        }
    }
    return NULL;
}

/* ReaderGroup Config Handling */

UA_StatusCode
UA_ReaderGroupConfig_copy(const UA_ReaderGroupConfig *src,
                          UA_ReaderGroupConfig *dst) {
    memcpy(dst, src, sizeof(UA_ReaderGroupConfig));
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    res |= UA_String_copy(&src->name, &dst->name);
    res |= UA_KeyValueMap_copy(&src->groupProperties, &dst->groupProperties);
#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
    res = UA_String_copy(&src->securityGroupId, &dst->securityGroupId);
#endif
    if(res != UA_STATUSCODE_GOOD)
        UA_ReaderGroupConfig_clear(dst);
    return res;
}

void
UA_ReaderGroupConfig_clear(UA_ReaderGroupConfig *readerGroupConfig) {
    UA_String_clear(&readerGroupConfig->name);
    UA_KeyValueMap_clear(&readerGroupConfig->groupProperties);
#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
    UA_String_clear(&readerGroupConfig->securityGroupId);
#endif
}

/* ReaderGroup Lifecycle */

UA_StatusCode
UA_ReaderGroup_create(UA_Server *server, UA_NodeId connectionId,
                      const UA_ReaderGroupConfig *rgc,
                      UA_NodeId *readerGroupId) {
    /* Check for valid readergroup configuration */
    if(!rgc)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    /* Search the connection by the given connectionIdentifier */
    UA_PubSubConnection *connection =
        UA_PubSubConnection_findConnectionbyId(server, connectionId);
    if(!connection)
        return UA_STATUSCODE_BADNOTFOUND;

    if(connection->configurationFreezeCounter > 0) {
        UA_LOG_WARNING_CONNECTION(server->config.logging, connection,
                                  "Adding ReaderGroup failed. "
                                  "Connection configuration is frozen.");
        return UA_STATUSCODE_BADCONFIGURATIONERROR;
    }

    /* Allocate memory for new reader group and add settings */
    UA_ReaderGroup *newGroup = (UA_ReaderGroup *)UA_calloc(1, sizeof(UA_ReaderGroup));
    if(!newGroup)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    newGroup->componentType = UA_PUBSUB_COMPONENT_READERGROUP;
    newGroup->linkedConnection = connection;

    /* Deep copy of the config */
    UA_StatusCode retval = UA_ReaderGroupConfig_copy(rgc, &newGroup->config);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free(newGroup);
        return retval;
    }

    /* Add to the connection */
    LIST_INSERT_HEAD(&connection->readerGroups, newGroup, listEntry);
    connection->readerGroupsSize++;

#ifdef UA_ENABLE_PUBSUB_SKS
    if(rgc->securityMode == UA_MESSAGESECURITYMODE_SIGN ||
       rgc->securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
        if(!UA_String_isEmpty(&rgc->securityGroupId) && rgc->securityPolicy) {
            /* Does the key storage already exist? */
            newGroup->keyStorage =
                UA_PubSubKeyStorage_findKeyStorage(server, rgc->securityGroupId);

            if(!newGroup->keyStorage) {
                /* Create a new key storage */
                newGroup->keyStorage = (UA_PubSubKeyStorage *)
                    UA_calloc(1, sizeof(UA_PubSubKeyStorage));
                if(!newGroup->keyStorage) {
                    UA_ReaderGroup_remove(server, newGroup);
                    return UA_STATUSCODE_BADOUTOFMEMORY;
                }
                retval = UA_PubSubKeyStorage_init(server, newGroup->keyStorage,
                                                  &rgc->securityGroupId,
                                                  rgc->securityPolicy, 0, 0);
                if(retval != UA_STATUSCODE_GOOD) {
                    UA_ReaderGroup_remove(server, newGroup);
                    return retval;
                }
            }

            /* Increase the ref count */
            newGroup->keyStorage->referenceCount++;
        }
    }
#endif

#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    retval |= addReaderGroupRepresentation(server, newGroup);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ReaderGroup_remove(server, newGroup);
        return retval;
    }
#else
    UA_PubSubManager_generateUniqueNodeId(&server->pubSubManager,
                                          &newGroup->identifier);
#endif

    /* Cache the log string */
    UA_String idStr = UA_STRING_NULL;
    UA_NodeId_print(&newGroup->identifier, &idStr);
    char tmpLogIdStr[128];
    mp_snprintf(tmpLogIdStr, 128, "%.*sReaderGroup %.*s\t| ",
                (int)connection->logIdString.length,
                (char*)connection->logIdString.data,
                (int)idStr.length, idStr.data);
    newGroup->logIdString = UA_STRING_ALLOC(tmpLogIdStr);
    UA_String_clear(&idStr);

    UA_LOG_INFO_READERGROUP(server->config.logging, newGroup, "ReaderGroup created");

    /* Validate the connection settings */
    retval = UA_ReaderGroup_connect(server, newGroup, true);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_READERGROUP(server->config.logging, newGroup,
                                 "Could not validate the connection parameters");
        UA_ReaderGroup_remove(server, newGroup);
        return retval;
    }

    /* Trigger the connection */
    UA_PubSubConnection_setPubSubState(server, connection, connection->state);

    /* Copying a numeric NodeId always succeeds */
    if(readerGroupId)
        UA_NodeId_copy(&newGroup->identifier, readerGroupId);

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_addReaderGroup(UA_Server *server, UA_NodeId connectionIdentifier,
                         const UA_ReaderGroupConfig *readerGroupConfig,
                         UA_NodeId *readerGroupIdentifier) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res =
        UA_ReaderGroup_create(server, connectionIdentifier,
                              readerGroupConfig, readerGroupIdentifier);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_ReaderGroup_remove(UA_Server *server, UA_ReaderGroup *rg) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    if(rg->configurationFrozen) {
        UA_LOG_WARNING_READERGROUP(server->config.logging, rg,
                                   "Remove ReaderGroup failed. "
                                   "Subscriber configuration is frozen.");
        return UA_STATUSCODE_BADCONFIGURATIONERROR;
    }

    UA_PubSubConnection *connection = rg->linkedConnection;
    UA_assert(connection);
    if(connection->configurationFreezeCounter > 0) {
        UA_LOG_WARNING_READERGROUP(server->config.logging, rg,
                                   "Deleting the ReaderGroup failed. "
                                   "PubSubConnection is frozen.");
        return UA_STATUSCODE_BADCONFIGURATIONERROR;
    }

    UA_DataSetReader *dsr, *tmp_dsr;
    LIST_FOREACH_SAFE(dsr, &rg->readers, listEntry, tmp_dsr) {
        UA_DataSetReader_remove(server, dsr);
    }

#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
    if(rg->config.securityPolicy && rg->securityPolicyContext) {
        rg->config.securityPolicy->deleteContext(rg->securityPolicyContext);
        rg->securityPolicyContext = NULL;
    }
#endif

#ifdef UA_ENABLE_PUBSUB_SKS
    if(rg->keyStorage) {
        UA_PubSubKeyStorage_detachKeyStorage(server, rg->keyStorage);
        rg->keyStorage = NULL;
    }
#endif

    /* Disconnect only once */
    if(!rg->deleteFlag)
        UA_ReaderGroup_disconnect(rg);
    rg->deleteFlag = true;

    if(rg->recvChannelsSize == 0) {
        /* Unlink from the connection */
        LIST_REMOVE(rg, listEntry);
        connection->readerGroupsSize--;
        rg->linkedConnection = NULL;

        /* Actually remove the ReaderGroup */
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
        deleteNode(server, rg->identifier, true);
#endif

        UA_LOG_INFO_READERGROUP(server->config.logging, rg, "ReaderGroup deleted");

        UA_ReaderGroupConfig_clear(&rg->config);
        UA_NodeId_clear(&rg->identifier);
        UA_String_clear(&rg->logIdString);
        UA_free(rg);
    }

    /* Update the connection state */
    UA_PubSubConnection_setPubSubState(server, connection, connection->state);

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_removeReaderGroup(UA_Server *server, UA_NodeId groupIdentifier) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND;
    UA_ReaderGroup *rg = UA_ReaderGroup_findRGbyId(server, groupIdentifier);
    if(rg)
        res = UA_ReaderGroup_remove(server, rg);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_Server_ReaderGroup_getConfig(UA_Server *server, UA_NodeId readerGroupIdentifier,
                                UA_ReaderGroupConfig *config) {
    if(!config)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_LOCK(&server->serviceMutex);

    /* Identify the readergroup through the readerGroupIdentifier */
    UA_ReaderGroup *currentReaderGroup =
        UA_ReaderGroup_findRGbyId(server, readerGroupIdentifier);
    if(!currentReaderGroup) {
        UA_UNLOCK(&server->serviceMutex);
        return UA_STATUSCODE_BADNOTFOUND;
    }

    UA_StatusCode ret =
        UA_ReaderGroupConfig_copy(&currentReaderGroup->config, config);

    UA_UNLOCK(&server->serviceMutex);
    return ret;
}

UA_StatusCode
UA_Server_ReaderGroup_getState(UA_Server *server, UA_NodeId readerGroupIdentifier,
                               UA_PubSubState *state) {
    if((server == NULL) || (state == NULL))
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode ret = UA_STATUSCODE_BADNOTFOUND;
    UA_ReaderGroup *rg = UA_ReaderGroup_findRGbyId(server, readerGroupIdentifier);
    if(rg) {
        *state = rg->state;
        ret = UA_STATUSCODE_GOOD;
    }
    UA_UNLOCK(&server->serviceMutex);
    return ret;
}

UA_StatusCode
UA_ReaderGroup_setPubSubState(UA_Server *server, UA_ReaderGroup *rg,
                              UA_PubSubState targetState) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    UA_PubSubConnection *connection = rg->linkedConnection;
    UA_PubSubState oldState = rg->state;
    rg->state = targetState;

    switch(rg->state) {
        /* Disabled */
    default:
        rg->state = UA_PUBSUBSTATE_ERROR;
        ret = UA_STATUSCODE_BADINTERNALERROR;
        /* fallthrough */
    case UA_PUBSUBSTATE_DISABLED:
    case UA_PUBSUBSTATE_ERROR:
        UA_ReaderGroup_disconnect(rg);
        rg->hasReceived = false;
        break;

        /* Enabled */
    case UA_PUBSUBSTATE_PAUSED:
    case UA_PUBSUBSTATE_PREOPERATIONAL:
    case UA_PUBSUBSTATE_OPERATIONAL:
        if(connection->state == UA_PUBSUBSTATE_DISABLED ||
           connection->state == UA_PUBSUBSTATE_ERROR) {
            /* Connection is disabled -> paused */
            rg->state = UA_PUBSUBSTATE_PAUSED;
        } else {
            /* Pre-operational until a message was received */
            rg->state = connection->state;
            if(rg->state == UA_PUBSUBSTATE_OPERATIONAL && !rg->hasReceived)
                rg->state = UA_PUBSUBSTATE_PREOPERATIONAL;

            /* Connect RG-specific connections. For example for MQTT. */
            ret = UA_ReaderGroup_connect(server, rg, false);
            if(ret != UA_STATUSCODE_GOOD)
                rg->state = UA_PUBSUBSTATE_ERROR;
        }
        break;
    }

    /* Inform application about state change */
    if(rg->state != oldState) {
        UA_ServerConfig *pConfig = &server->config;
        UA_LOG_INFO_READERGROUP(pConfig->logging, rg, "State change: %s -> %s",
                                UA_PubSubState_name(oldState),
                                UA_PubSubState_name(rg->state));
        if(pConfig->pubSubConfig.stateChangeCallback != 0) {
            UA_UNLOCK(&server->serviceMutex);
            pConfig->pubSubConfig.
                stateChangeCallback(server, &rg->identifier, rg->state, ret);
            UA_LOCK(&server->serviceMutex);
        }
    }

    /* Update the attached DataSetReaders */
    UA_DataSetReader *dsr;
    LIST_FOREACH(dsr, &rg->readers, listEntry) {
        UA_DataSetReader_setPubSubState(server, dsr, dsr->state);
    }

    return ret;
}

#ifdef UA_ENABLE_PUBSUB_SKS
UA_StatusCode
UA_Server_setReaderGroupActivateKey(UA_Server *server,
                                    const UA_NodeId readerGroupId) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode ret = UA_STATUSCODE_BADNOTFOUND;
    UA_ReaderGroup *rg = UA_ReaderGroup_findRGbyId(server, readerGroupId);
    if(rg) {
        if(rg->keyStorage && rg->keyStorage->currentItem) {
            UA_StatusCode retval = UA_PubSubKeyStorage_activateKeyToChannelContext(
                server, rg->identifier, rg->config.securityGroupId);
            if(retval != UA_STATUSCODE_GOOD) {
                UA_UNLOCK(&server->serviceMutex);
                return retval;
            }
        }
    }
    UA_UNLOCK(&server->serviceMutex);
    return ret;
}
#endif

UA_StatusCode
UA_Server_enableReaderGroup(UA_Server *server, const UA_NodeId readerGroupId){
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode ret = UA_STATUSCODE_BADNOTFOUND;
    UA_ReaderGroup *rg = UA_ReaderGroup_findRGbyId(server, readerGroupId);
    if(rg)
        ret = UA_ReaderGroup_setPubSubState(server, rg, UA_PUBSUBSTATE_OPERATIONAL);
    UA_UNLOCK(&server->serviceMutex);
    return ret;
}

UA_StatusCode
UA_Server_disableReaderGroup(UA_Server *server, const UA_NodeId readerGroupId){
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode ret = UA_STATUSCODE_BADNOTFOUND;
    UA_ReaderGroup *rg = UA_ReaderGroup_findRGbyId(server, readerGroupId);
    if(rg)
        ret = UA_ReaderGroup_setPubSubState(server, rg, UA_PUBSUBSTATE_DISABLED);
    UA_UNLOCK(&server->serviceMutex);
    return ret;
}

#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
UA_StatusCode
setReaderGroupEncryptionKeys(UA_Server *server, const UA_NodeId readerGroup,
                             UA_UInt32 securityTokenId,
                             const UA_ByteString signingKey,
                             const UA_ByteString encryptingKey,
                             const UA_ByteString keyNonce) {
    UA_ReaderGroup *rg = UA_ReaderGroup_findRGbyId(server, readerGroup);
    UA_CHECK_MEM(rg, return UA_STATUSCODE_BADNOTFOUND);
    if(rg->config.encodingMimeType == UA_PUBSUB_ENCODING_JSON) {
        UA_LOG_WARNING_READERGROUP(server->config.logging, rg,
                                   "JSON encoding is enabled. The message security is "
                                   "only defined for the UADP message mapping.");
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    if(!rg->config.securityPolicy) {
        UA_LOG_WARNING_READERGROUP(server->config.logging, rg,
                                   "No SecurityPolicy configured for the ReaderGroup");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    if(securityTokenId != rg->securityTokenId) {
        rg->securityTokenId = securityTokenId;
        rg->nonceSequenceNumber = 1;
    }

    /* Create a new context */
    if(!rg->securityPolicyContext) {
        return rg->config.securityPolicy->
            newContext(rg->config.securityPolicy->policyContext,
                       &signingKey, &encryptingKey, &keyNonce,
                       &rg->securityPolicyContext);
    }

    /* Update the context */
    return rg->config.securityPolicy->
        setSecurityKeys(rg->securityPolicyContext, &signingKey,
                        &encryptingKey, &keyNonce);
}

UA_StatusCode
UA_Server_setReaderGroupEncryptionKeys(UA_Server *server,
                                       const UA_NodeId readerGroup,
                                       UA_UInt32 securityTokenId,
                                       const UA_ByteString signingKey,
                                       const UA_ByteString encryptingKey,
                                       const UA_ByteString keyNonce) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = setReaderGroupEncryptionKeys(server, readerGroup,
                                                     securityTokenId, signingKey,
                                                     encryptingKey, keyNonce);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}
#endif

/* Freezing of the configuration */

UA_StatusCode
UA_ReaderGroup_freezeConfiguration(UA_Server *server, UA_ReaderGroup *rg) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    if(rg->configurationFrozen)
        return UA_STATUSCODE_GOOD;

    /* PubSubConnection freezeCounter++ */
    UA_PubSubConnection *pubSubConnection = rg->linkedConnection;
    pubSubConnection->configurationFreezeCounter++;

    /* ReaderGroup freeze */
    /* TODO: Clarify on the freeze functionality in multiple DSR, multiple
     * networkMessage conf in a RG */
    rg->configurationFrozen = true;

    /* DataSetReader freeze */
    UA_DataSetReader *dsr;
    UA_UInt16 dsrCount = 0;
    LIST_FOREACH(dsr, &rg->readers, listEntry){
        dsr->configurationFrozen = true;
        dsrCount++;
        /* TODO: Configuration frozen for subscribedDataSet once
         * UA_Server_DataSetReader_addTargetVariables API modified to support
         * adding target variable one by one or in a group stored in a list. */
    }

    /* Not rt, we don't have to adjust anything */
    if(rg->config.rtLevel != UA_PUBSUB_RT_FIXED_SIZE)
        return UA_STATUSCODE_GOOD;

    if(dsrCount > 1) {
        UA_LOG_WARNING_READERGROUP(server->config.logging, rg,
                                   "Mutiple DSR in a readerGroup not supported in RT "
                                   "fixed size configuration");
        return UA_STATUSCODE_BADNOTIMPLEMENTED;
    }

    dsr = LIST_FIRST(&rg->readers);

    /* Support only to UADP encoding */
    if(dsr->config.messageSettings.content.decoded.type !=
       &UA_TYPES[UA_TYPES_UADPDATASETREADERMESSAGEDATATYPE]) {
        UA_LOG_WARNING_READER(server->config.logging, dsr,
                              "PubSub-RT configuration fail: Non-RT capable encoding.");
        return UA_STATUSCODE_BADNOTSUPPORTED;
    }

    /* Don't support string PublisherId for the fast-path (at this time) */
    if(!dsr->config.publisherId.type->pointerFree) {
        UA_LOG_WARNING_READER(server->config.logging, dsr,
                              "PubSub-RT configuration fail: String PublisherId");
        return UA_STATUSCODE_BADNOTSUPPORTED;
    }

    size_t fieldsSize = dsr->config.dataSetMetaData.fieldsSize;
    for(size_t i = 0; i < fieldsSize; i++) {
        UA_FieldTargetVariable *tv =
            &dsr->config.subscribedDataSet.subscribedDataSetTarget.targetVariables[i];
        const UA_VariableNode *rtNode = (const UA_VariableNode *)
            UA_NODESTORE_GET(server, &tv->targetVariable.targetNodeId);
        if(!rtNode ||
           rtNode->valueBackend.backendType != UA_VALUEBACKENDTYPE_EXTERNAL) {
            UA_LOG_WARNING_READER(server->config.logging, dsr,
                                  "PubSub-RT configuration fail: PDS contains field "
                                  "without external data source.");
            UA_NODESTORE_RELEASE(server, (const UA_Node *) rtNode);
            return UA_STATUSCODE_BADNOTSUPPORTED;
        }

        /* Set the external data source in the tv */
        tv->externalDataValue = rtNode->valueBackend.backend.external.value;

        UA_NODESTORE_RELEASE(server, (const UA_Node *) rtNode);

        UA_FieldMetaData *field = &dsr->config.dataSetMetaData.fields[i];
        if((UA_NodeId_equal(&field->dataType, &UA_TYPES[UA_TYPES_STRING].typeId) ||
            UA_NodeId_equal(&field->dataType, &UA_TYPES[UA_TYPES_BYTESTRING].typeId)) &&
           field->maxStringLength == 0) {
            UA_LOG_WARNING_READER(server->config.logging, dsr,
                                  "PubSub-RT configuration fail: "
                                  "PDS contains String/ByteString with dynamic length.");
            return UA_STATUSCODE_BADNOTSUPPORTED;
        } else if(!UA_DataType_isNumeric(UA_findDataType(&field->dataType)) &&
                  !UA_NodeId_equal(&field->dataType, &UA_TYPES[UA_TYPES_BOOLEAN].typeId)) {
            UA_LOG_WARNING_READER(server->config.logging, dsr,
                                  "PubSub-RT configuration fail: "
                                  "PDS contains variable with dynamic size.");
            return UA_STATUSCODE_BADNOTSUPPORTED;
        }
    }

    /* Reset the OffsetBuffer. The OffsetBuffer for a frozen configuration is
     * generated when the first message is received. So we know the exact
     * settings which headers are present, etc. Until then the ReaderGroup is
     * "PreOperational". */
    UA_NetworkMessageOffsetBuffer_clear(&dsr->bufferedMessage);

    /* Set the current state again. This can move the state from Operational to
     * PreOperational. */
    return UA_ReaderGroup_setPubSubState(server, rg, rg->state);
}

UA_StatusCode
UA_Server_freezeReaderGroupConfiguration(UA_Server *server,
                                         const UA_NodeId readerGroupId) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND;
    UA_ReaderGroup *rg = UA_ReaderGroup_findRGbyId(server, readerGroupId);
    if(rg)
        res = UA_ReaderGroup_freezeConfiguration(server, rg);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_ReaderGroup_unfreezeConfiguration(UA_Server *server, UA_ReaderGroup *rg) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Already unfrozen */
    if(!rg->configurationFrozen)
        return UA_STATUSCODE_GOOD;

    /* PubSubConnection freezeCounter-- */
    UA_PubSubConnection *pubSubConnection = rg->linkedConnection;
    pubSubConnection->configurationFreezeCounter--;

    /* ReaderGroup unfreeze */
    rg->configurationFrozen = false;

    /* DataSetReader unfreeze */
    UA_DataSetReader *dataSetReader;
    LIST_FOREACH(dataSetReader, &rg->readers, listEntry) {
        dataSetReader->configurationFrozen = false;
        UA_NetworkMessageOffsetBuffer_clear(&dataSetReader->bufferedMessage);
    }

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_unfreezeReaderGroupConfiguration(UA_Server *server,
                                           const UA_NodeId readerGroupId) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND;
    UA_ReaderGroup *rg = UA_ReaderGroup_findRGbyId(server, readerGroupId);
    if(rg)
        res = UA_ReaderGroup_unfreezeConfiguration(server, rg);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_Boolean
UA_ReaderGroup_process(UA_Server *server, UA_ReaderGroup *readerGroup,
                       UA_NetworkMessage *nm) {
    /* Check if the ReaderGroup is enabled */
    if(readerGroup->state != UA_PUBSUBSTATE_OPERATIONAL &&
       readerGroup->state != UA_PUBSUBSTATE_PREOPERATIONAL)
        return false;

    readerGroup->hasReceived = true;
    if(readerGroup->state == UA_PUBSUBSTATE_PREOPERATIONAL)
        UA_ReaderGroup_setPubSubState(server, readerGroup, UA_PUBSUBSTATE_OPERATIONAL);

    /* Safe iteration. The current Reader might be deleted in the ReaderGroup
     * _setPubSubState callback. */
    UA_Boolean processed = false;
    UA_DataSetReader *reader, *reader_tmp;
    LIST_FOREACH_SAFE(reader, &readerGroup->readers, listEntry, reader_tmp) {
        UA_StatusCode res = UA_DataSetReader_checkIdentifier(server, nm, reader,
                                                             readerGroup->config);
        if(res != UA_STATUSCODE_GOOD)
            continue;

        /* Check if the reader is enabled */
        if(reader->state != UA_PUBSUBSTATE_OPERATIONAL &&
           reader->state != UA_PUBSUBSTATE_PREOPERATIONAL)
            continue;

        /* Update the ReaderGroup state if this is the first received message */
        if(!readerGroup->hasReceived) {
            readerGroup->hasReceived = true;
            UA_ReaderGroup_setPubSubState(server, readerGroup, readerGroup->state);
        }

        /* The message was processed by at least one reader */
        processed = true;

        /* No payload header. The message ontains a single DataSetMessage that
         * is processed by every Reader. */
        if(!nm->payloadHeaderEnabled) {
            UA_DataSetReader_process(server, reader,
                                     nm->payload.dataSetPayload.dataSetMessages);
            continue;
        }

        /* Process only the payloads where the WriterId from the header is expected */
        UA_DataSetPayloadHeader *ph = &nm->payloadHeader.dataSetPayloadHeader;
        for(UA_Byte i = 0; i < ph->count; i++) {
            if(reader->config.dataSetWriterId == ph->dataSetWriterIds[i]) {
                UA_DataSetReader_process(server, reader,
                                         &nm->payload.dataSetPayload.dataSetMessages[i]);
            }
        }
    }

    return processed;
}

UA_Boolean
UA_ReaderGroup_decodeAndProcessRT(UA_Server *server, UA_ReaderGroup *rg,
                                  UA_ByteString *buf) {
    /* Received a (first) message for the ReaderGroup.
     * Transition from PreOperational to Operational. */
    rg->hasReceived = true;
    if(rg->state == UA_PUBSUBSTATE_PREOPERATIONAL)
        UA_ReaderGroup_setPubSubState(server, rg, UA_PUBSUBSTATE_OPERATIONAL);

    UA_Boolean processed = false;
    UA_NetworkMessage currentNetworkMessage;
    memset(&currentNetworkMessage, 0, sizeof(UA_NetworkMessage));

    /* Decode headers necessary for matching identifiers. This can use malloc.
     * So enable membufAlloc if you need RT timings. Reset back to the normal
     * malloc before processing the message. The userland (callbacks) below
     * might rely on that. It needs to be ensured that the membuf-memory is not
     * reset (zeroed out) in "useNormalAlloc". So the decoded memory can be used
     * until the end of this method. */
#ifdef UA_ENABLE_PUBSUB_BUFMALLOC
    useMembufAlloc();
#endif
    size_t pos = 0;
    UA_StatusCode rv = UA_NetworkMessage_decodeHeaders(buf, &pos, &currentNetworkMessage);
#ifdef UA_ENABLE_PUBSUB_BUFMALLOC
    useNormalAlloc();
#endif
    if(rv != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_READERGROUP(server->config.logging, rg,
                              "PubSub receive. decoding headers failed");
        goto cleanup;
    }

    /* Decrypt the message. Keep pos right after the header. */
#ifdef UA_ENABLE_PUBSUB_ENCRYPTION
    rv = verifyAndDecryptNetworkMessage(server->config.logging, buf, &pos,
                                        &currentNetworkMessage, rg);
    if(rv != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_READERGROUP(server->config.logging, rg,
                                   "Subscribe failed. verify and decrypt network "
                                   "message failed.");
        goto cleanup;
    }
#endif

    /* Process the message for each reader */
    UA_DataSetReader *dsr;
    LIST_FOREACH(dsr, &rg->readers, listEntry) {
        /* Check if the reader is enabled */
        if(dsr->state != UA_PUBSUBSTATE_OPERATIONAL &&
           dsr->state != UA_PUBSUBSTATE_PREOPERATIONAL)
            continue;

        /* Check the identifier */
        rv = UA_DataSetReader_checkIdentifier(server, &currentNetworkMessage,
                                              dsr, rg->config);
        if(rv != UA_STATUSCODE_GOOD) {
            UA_LOG_DEBUG_READER(server->config.logging, dsr,
                                "PubSub receive. Message intended for a different reader.");
            continue;
        }

        /* Process the message */
        UA_DataSetReader_decodeAndProcessRT(server, dsr, buf);
        processed = true;
    }

 cleanup:
#ifndef UA_ENABLE_PUBSUB_BUFMALLOC
    UA_NetworkMessage_clear(&currentNetworkMessage);
#endif
    return processed;
}

#endif /* UA_ENABLE_PUBSUB */

/**** amalgamated original file "/src/pubsub/ua_pubsub_manager.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2017-2022 Fraunhofer IOSB (Author: Andreas Ebner)
 * Copyright (c) 2018 Fraunhofer IOSB (Author: Julius Pfrommer)
 * Copyright (c) 2021 Fraunhofer IOSB (Author: Jan Hermes)
 * Copyright (c) 2022 Siemens AG (Author: Thomas Fischer)
 * Copyright (c) 2022 Fraunhofer IOSB (Author: Noel Graf)
 * Copyright (c) 2022 Linutronix GmbH (Author: Muddasir Shakil)
 */


#ifdef UA_ENABLE_PUBSUB /* conditional compilation */

#ifdef UA_ENABLE_PUBSUB_SKS
#endif

#define UA_DATETIMESTAMP_2000 125911584000000000
#define UA_RESERVEID_FIRST_ID 0x8000

static const char *pubSubStateNames[6] = {
    "Disabled", "Paused", "Operational", "Error", "PreOperational", "Invalid"
};

const char *
UA_PubSubState_name(UA_PubSubState state) {
    if(state < UA_PUBSUBSTATE_DISABLED || state > UA_PUBSUBSTATE_PREOPERATIONAL)
        return pubSubStateNames[5];
    return pubSubStateNames[state];
}

static void
UA_PubSubManager_addTopic(UA_PubSubManager *pubSubManager, UA_TopicAssign *topicAssign) {
    TAILQ_INSERT_TAIL(&pubSubManager->topicAssign, topicAssign, listEntry);
    pubSubManager->topicAssignSize++;
}

static UA_TopicAssign *
UA_TopicAssign_new(UA_ReaderGroup *readerGroup,
                   UA_String topic, const UA_Logger *logger) {
    UA_TopicAssign *topicAssign = (UA_TopicAssign *) calloc(1, sizeof(UA_TopicAssign));
    if(!topicAssign) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER,
                     "PubSub TopicAssign creation failed. Out of Memory.");
        return NULL;
    }
    topicAssign->rgIdentifier = readerGroup;
    topicAssign->topic = topic;
    return topicAssign;
}

UA_StatusCode
UA_PubSubManager_addPubSubTopicAssign(UA_Server *server, UA_ReaderGroup *readerGroup, UA_String topic) {
    UA_PubSubManager *pubSubManager = &server->pubSubManager;
    UA_TopicAssign *topicAssign = UA_TopicAssign_new(readerGroup, topic, server->config.logging);
    UA_PubSubManager_addTopic(pubSubManager, topicAssign);
    return UA_STATUSCODE_GOOD;
}

static enum ZIP_CMP
cmpReserveId(const void *a, const void *b) {
    const UA_ReserveId *aa = (const UA_ReserveId*)a;
    const UA_ReserveId *bb = (const UA_ReserveId*)b;
    if(aa->id != bb->id)
        return (aa->id < bb->id) ? ZIP_CMP_LESS : ZIP_CMP_MORE;
    if(aa->reserveIdType != bb->reserveIdType)
        return (aa->reserveIdType < bb->reserveIdType) ? ZIP_CMP_LESS : ZIP_CMP_MORE;
    return (enum ZIP_CMP)UA_order(&aa->transportProfileUri,
                                  &bb->transportProfileUri, &UA_TYPES[UA_TYPES_STRING]);
}

ZIP_FUNCTIONS(UA_ReserveIdTree, UA_ReserveId, treeEntry, UA_ReserveId, id, cmpReserveId)

static UA_ReserveId *
UA_ReserveId_new(UA_Server *server, UA_UInt16 id, UA_String transportProfileUri,
                 UA_ReserveIdType reserveIdType, UA_NodeId sessionId) {
    UA_ReserveId *reserveId = (UA_ReserveId *) calloc(1, sizeof(UA_ReserveId));
    if(!reserveId) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "PubSub ReserveId creation failed. Out of Memory.");
        return NULL;
    }
    reserveId->id = id;
    reserveId->reserveIdType = reserveIdType;
    UA_String_copy(&transportProfileUri, &reserveId->transportProfileUri);
    reserveId->sessionId = sessionId;

    return reserveId;
}

static UA_Boolean
UA_ReserveId_isFree(UA_Server *server,  UA_UInt16 id,
                    UA_String transportProfileUri, UA_ReserveIdType reserveIdType) {
    UA_PubSubManager *pubSubManager = &server->pubSubManager;

    /* Is the id already in use? */
    UA_ReserveId compare;
    compare.id = id;
    compare.reserveIdType = reserveIdType;
    compare.transportProfileUri = transportProfileUri;
    if(ZIP_FIND(UA_ReserveIdTree, &pubSubManager->reserveIds, &compare))
        return false;

    UA_PubSubConnection *tmpConnection;
    TAILQ_FOREACH(tmpConnection, &server->pubSubManager.connections, listEntry) {
        UA_WriterGroup *writerGroup;
        LIST_FOREACH(writerGroup, &tmpConnection->writerGroups, listEntry) {
            if(reserveIdType == UA_WRITER_GROUP) {
                if(UA_String_equal(&tmpConnection->config.transportProfileUri,
                                   &transportProfileUri) &&
                   writerGroup->config.writerGroupId == id)
                    return false;
            /* reserveIdType == UA_DATA_SET_WRITER */
            } else {
                UA_DataSetWriter *currentWriter;
                LIST_FOREACH(currentWriter, &writerGroup->writers, listEntry) {
                    if(UA_String_equal(&tmpConnection->config.transportProfileUri,
                                       &transportProfileUri) &&
                       currentWriter->config.dataSetWriterId == id)
                        return false;
                }
            }
        }
    }
    return true;
}

static UA_UInt16
UA_ReserveId_createId(UA_Server *server,  UA_NodeId sessionId,
                      UA_String transportProfileUri, UA_ReserveIdType reserveIdType) {
    /* Total number of possible Ids */
    UA_UInt16 numberOfIds = 0x8000;
    /* Contains next possible free Id */
    static UA_UInt16 next_id_writerGroup = UA_RESERVEID_FIRST_ID;
    static UA_UInt16 next_id_writer = UA_RESERVEID_FIRST_ID;
    UA_UInt16 next_id;
    UA_Boolean is_free = false;

    if(reserveIdType == UA_WRITER_GROUP)
        next_id = next_id_writerGroup;
    else
        next_id = next_id_writer;

    for(;numberOfIds > 0;numberOfIds--) {
        if(next_id < UA_RESERVEID_FIRST_ID)
            next_id = UA_RESERVEID_FIRST_ID;
        is_free = UA_ReserveId_isFree(server, next_id, transportProfileUri, reserveIdType);
        if(is_free)
            break;
        next_id++;
    }
    if(!is_free) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "PubSub ReserveId creation failed. No free ID could be found.");
        return 0;
    }

    if(reserveIdType == UA_WRITER_GROUP)
        next_id_writerGroup = (UA_UInt16)(next_id + 1);
    else
        next_id_writer = (UA_UInt16)(next_id + 1);

    UA_ReserveId *reserveId =
        UA_ReserveId_new(server, next_id, transportProfileUri, reserveIdType, sessionId);
    if(!reserveId)
        return 0;
    UA_PubSubManager *pubSubManager = &server->pubSubManager;
    ZIP_INSERT(UA_ReserveIdTree, &pubSubManager->reserveIds, reserveId);
    pubSubManager->reserveIdsSize++;
    return next_id;
}

static void *
removeReserveId(void *context, UA_ReserveId *elem) {
    UA_String_clear(&elem->transportProfileUri);
    UA_free(elem);
    return NULL;
}

struct RemoveInactiveReserveIdContext {
    UA_Server *server;
    UA_ReserveIdTree newTree;
};

/* Remove ReserveIds that are not attached to any session */
static void *
removeInactiveReserveId(void *context, UA_ReserveId *elem) {
    struct RemoveInactiveReserveIdContext *ctx =
        (struct RemoveInactiveReserveIdContext*)context;

    if(UA_NodeId_equal(&ctx->server->adminSession.sessionId, &elem->sessionId))
        goto still_active;

    session_list_entry *session;
    LIST_FOREACH(session, &ctx->server->sessions, pointers) {
        if(UA_NodeId_equal(&session->session.sessionId, &elem->sessionId))
            goto still_active;
    }

    ctx->server->pubSubManager.reserveIdsSize--;
    UA_String_clear(&elem->transportProfileUri);
    UA_free(elem);
    return NULL;

 still_active:
    ZIP_INSERT(UA_ReserveIdTree, &ctx->newTree, elem);
    return NULL;
}

void
UA_PubSubManager_freeIds(UA_Server *server) {
    struct RemoveInactiveReserveIdContext removeCtx;
    removeCtx.server = server;
    removeCtx.newTree.root = NULL;
    ZIP_ITER(UA_ReserveIdTree, &server->pubSubManager.reserveIds,
             removeInactiveReserveId, &removeCtx);
    server->pubSubManager.reserveIds = removeCtx.newTree;
}

UA_StatusCode
UA_PubSubManager_reserveIds(UA_Server *server, UA_NodeId sessionId, UA_UInt16 numRegWriterGroupIds,
                            UA_UInt16 numRegDataSetWriterIds, UA_String transportProfileUri,
                            UA_UInt16 **writerGroupIds, UA_UInt16 **dataSetWriterIds) {
    UA_PubSubManager_freeIds(server);

    /* Check the validation of the transportProfileUri */
    UA_String profile_1 = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-mqtt-uadp");
    UA_String profile_2 = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-mqtt-json");
    UA_String profile_3 = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp");
    if(!UA_String_equal(&transportProfileUri, &profile_1) &&
       !UA_String_equal(&transportProfileUri, &profile_2) &&
       !UA_String_equal(&transportProfileUri, &profile_3)) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "PubSub ReserveId creation failed. No valid transport profile uri.");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }
    *writerGroupIds = (UA_UInt16*)UA_Array_new(numRegWriterGroupIds, &UA_TYPES[UA_TYPES_UINT16]);
    *dataSetWriterIds = (UA_UInt16*)UA_Array_new(numRegDataSetWriterIds, &UA_TYPES[UA_TYPES_UINT16]);

    for(int i = 0; i < numRegWriterGroupIds; i++) {
        (*writerGroupIds)[i] =
            UA_ReserveId_createId(server, sessionId, transportProfileUri, UA_WRITER_GROUP);
    }
    for(int i = 0; i < numRegDataSetWriterIds; i++) {
        (*dataSetWriterIds)[i] =
            UA_ReserveId_createId(server, sessionId, transportProfileUri, UA_DATA_SET_WRITER);
    }
    return UA_STATUSCODE_GOOD;
}

/* Calculate the time difference between current time and UTC (00:00) on January
 * 1, 2000. */
UA_UInt32
UA_PubSubConfigurationVersionTimeDifference(UA_DateTime now) {
    UA_UInt32 timeDiffSince2000 = (UA_UInt32)(now - UA_DATETIMESTAMP_2000);
    return timeDiffSince2000;
}

static UA_StatusCode
addStandaloneSubscribedDataSet(UA_Server *server,
                               const UA_StandaloneSubscribedDataSetConfig *sdsConfig,
                               UA_NodeId *sdsIdentifier) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    if(!sdsConfig){
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "SubscribedDataSet creation failed. No config passed in.");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_StandaloneSubscribedDataSetConfig tmpSubscribedDataSetConfig;
    memset(&tmpSubscribedDataSetConfig, 0, sizeof(UA_StandaloneSubscribedDataSetConfig));
    if(UA_StandaloneSubscribedDataSetConfig_copy(sdsConfig, &tmpSubscribedDataSetConfig) != UA_STATUSCODE_GOOD){
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "SubscribedDataSet creation failed. Configuration copy failed.");
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    //create new PDS and add to UA_PubSubManager
    UA_StandaloneSubscribedDataSet *newSubscribedDataSet = (UA_StandaloneSubscribedDataSet *)
            UA_calloc(1, sizeof(UA_StandaloneSubscribedDataSet));
    if(!newSubscribedDataSet) {
        UA_StandaloneSubscribedDataSetConfig_clear(&tmpSubscribedDataSetConfig);
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "SubscribedDataSet creation failed. Out of Memory.");
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    newSubscribedDataSet->config = tmpSubscribedDataSetConfig;
    newSubscribedDataSet->connectedReader = UA_NODEID_NULL;

    TAILQ_INSERT_TAIL(&server->pubSubManager.subscribedDataSets, newSubscribedDataSet, listEntry);
    server->pubSubManager.subscribedDataSetsSize++;

#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    addStandaloneSubscribedDataSetRepresentation(server, newSubscribedDataSet);
#else
    UA_PubSubManager_generateUniqueNodeId(&server->pubSubManager, &newSubscribedDataSet->identifier);
#endif

    if(sdsIdentifier)
        UA_NodeId_copy(&newSubscribedDataSet->identifier, sdsIdentifier);

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_addStandaloneSubscribedDataSet(UA_Server *server,
                                         const UA_StandaloneSubscribedDataSetConfig *sdsConfig,
                                         UA_NodeId *sdsIdentifier) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = addStandaloneSubscribedDataSet(server, sdsConfig, sdsIdentifier);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

static UA_StatusCode
removeStandaloneSubscribedDataSet(UA_Server *server, const UA_NodeId sds) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_StandaloneSubscribedDataSet *subscribedDataSet =
        UA_StandaloneSubscribedDataSet_findSDSbyId(server, sds);
    if(!subscribedDataSet){
        return UA_STATUSCODE_BADNOTFOUND;
    }

    //search for referenced readers.
    UA_PubSubConnection *tmpConnectoin;
    TAILQ_FOREACH(tmpConnectoin, &server->pubSubManager.connections, listEntry){
        UA_ReaderGroup *readerGroup;
        LIST_FOREACH(readerGroup, &tmpConnectoin->readerGroups, listEntry){
            UA_DataSetReader *currentReader, *tmpReader;
            LIST_FOREACH_SAFE(currentReader, &readerGroup->readers, listEntry, tmpReader){
                if(UA_NodeId_equal(&currentReader->identifier, &subscribedDataSet->connectedReader)){
                    UA_DataSetReader_remove(server, currentReader);
                    goto done;
                }
            }
        }
    }

 done:

#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    deleteNode(server, subscribedDataSet->identifier, true);
#endif

    UA_StandaloneSubscribedDataSet_clear(server, subscribedDataSet);
    server->pubSubManager.subscribedDataSetsSize--;

    TAILQ_REMOVE(&server->pubSubManager.subscribedDataSets, subscribedDataSet, listEntry);
    UA_free(subscribedDataSet);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_removeStandaloneSubscribedDataSet(UA_Server *server, const UA_NodeId sds) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = removeStandaloneSubscribedDataSet(server, sds);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

/* Generate a new unique NodeId. This NodeId will be used for the information
 * model representation of PubSub entities. */
#ifndef UA_ENABLE_PUBSUB_INFORMATIONMODEL
void
UA_PubSubManager_generateUniqueNodeId(UA_PubSubManager *psm, UA_NodeId *nodeId) {
    *nodeId = UA_NODEID_NUMERIC(1, ++psm->uniqueIdCount);
}
#endif

UA_Guid
UA_PubSubManager_generateUniqueGuid(UA_Server *server) {
    while(true) {
        UA_NodeId testId = UA_NODEID_GUID(1, UA_Guid_random());
        const UA_Node *testNode = UA_NODESTORE_GET(server, &testId);
        if(!testNode)
            return testId.identifier.guid;
        UA_NODESTORE_RELEASE(server, testNode);
    }
}

static UA_UInt64
generateRandomUInt64(UA_Server *server) {
    UA_UInt64 id = 0;
    UA_Guid ident = UA_Guid_random();

    id = id + ident.data1;
    id = (id << 32) + ident.data2;
    id = (id << 16) + ident.data3;
    return id;
}

/* Initialization the PubSub configuration. */
void
UA_PubSubManager_init(UA_Server *server, UA_PubSubManager *pubSubManager) {
    //TODO: Using the Mac address to generate the defaultPublisherId.
    // In the future, this can be retrieved from the eventloop.
    pubSubManager->defaultPublisherId = generateRandomUInt64(server);

    TAILQ_INIT(&pubSubManager->connections);
    TAILQ_INIT(&pubSubManager->publishedDataSets);
    TAILQ_INIT(&pubSubManager->subscribedDataSets);
    TAILQ_INIT(&pubSubManager->topicAssign);

#ifdef UA_ENABLE_PUBSUB_SKS
    TAILQ_INIT(&pubSubManager->securityGroups);
#endif
}

void
UA_PubSubManager_shutdown(UA_Server *server, UA_PubSubManager *pubSubManager) {
    UA_PubSubConnection *tmpConnection;
    TAILQ_FOREACH(tmpConnection, &server->pubSubManager.connections, listEntry) {
        UA_PubSubConnection_setPubSubState(server, tmpConnection, UA_PUBSUBSTATE_DISABLED);
    }
}

/* Delete the current PubSub configuration including all nested members. This
 * action also delete the configured PubSub transport Layers. */
void
UA_PubSubManager_delete(UA_Server *server, UA_PubSubManager *pubSubManager) {
    UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_SERVER,
                "PubSub cleanup was called.");
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Remove Connections - this also remove WriterGroups and ReaderGroups */
    UA_PubSubConnection *tmpConnection1, *tmpConnection2;
    TAILQ_FOREACH_SAFE(tmpConnection1, &server->pubSubManager.connections,
                       listEntry, tmpConnection2) {
        UA_PubSubConnection_delete(server, tmpConnection1);
    }

    /* Remove the DataSets */
    UA_PublishedDataSet *tmpPDS1, *tmpPDS2;
    TAILQ_FOREACH_SAFE(tmpPDS1, &server->pubSubManager.publishedDataSets,
                       listEntry, tmpPDS2){
        UA_PublishedDataSet_remove(server, tmpPDS1);
    }

    /* Remove the TopicAssigns */
    UA_TopicAssign *tmpTopicAssign1, *tmpTopicAssign2;
    TAILQ_FOREACH_SAFE(tmpTopicAssign1, &server->pubSubManager.topicAssign,
                       listEntry, tmpTopicAssign2){
        server->pubSubManager.topicAssignSize--;
        TAILQ_REMOVE(&server->pubSubManager.topicAssign, tmpTopicAssign1, listEntry);
        UA_free(tmpTopicAssign1);
    }

    /* Remove the ReserveIds*/
    ZIP_ITER(UA_ReserveIdTree, &server->pubSubManager.reserveIds, removeReserveId, NULL);
    server->pubSubManager.reserveIdsSize = 0;

    /* Delete subscribed datasets */
    UA_StandaloneSubscribedDataSet *tmpSDS1, *tmpSDS2;
    TAILQ_FOREACH_SAFE(tmpSDS1, &server->pubSubManager.subscribedDataSets, listEntry, tmpSDS2){
        removeStandaloneSubscribedDataSet(server, tmpSDS1->identifier);
    }

#ifdef UA_ENABLE_PUBSUB_SKS
    /* Remove the SecurityGroups */
    UA_SecurityGroup *tmpSG1, *tmpSG2;
    TAILQ_FOREACH_SAFE(tmpSG1, &server->pubSubManager.securityGroups, listEntry, tmpSG2) {
        removeSecurityGroup(server, tmpSG1);
    }

    /* Remove the keyStorages */
    UA_PubSubKeyStorage *ks, *ksTmp;
    LIST_FOREACH_SAFE(ks, &server->pubSubManager.pubSubKeyList, keyStorageList, ksTmp) {
        UA_PubSubKeyStorage_delete(server, ks);
    }
#endif
}

#ifdef UA_ENABLE_PUBSUB_MONITORING

static UA_StatusCode
UA_PubSubComponent_createMonitoring(UA_Server *server, UA_NodeId Id,
                                    UA_PubSubComponentEnumType eComponentType,
                                    UA_PubSubMonitoringType eMonitoringType,
                                    void *data, UA_ServerCallback callback) {
    if(!server || !data)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    switch (eComponentType) {
        case UA_PUBSUB_COMPONENT_DATASETREADER: {
            UA_DataSetReader *reader = (UA_DataSetReader*) data;
            switch (eMonitoringType) {
                case UA_PUBSUB_MONITORING_MESSAGE_RECEIVE_TIMEOUT:
                    UA_LOG_DEBUG(server->config.logging, UA_LOGCATEGORY_SERVER,
                                 "UA_PubSubComponent_createMonitoring(): DataSetReader '%.*s' "
                                 "- MessageReceiveTimeout",
                                 (UA_Int32) reader->config.name.length,
                                 reader->config.name.data);
                    reader->msgRcvTimeoutTimerCallback = callback;
                    break;
                default:
                    UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                                 "UA_PubSubComponent_createMonitoring(): DataSetReader '%.*s' "
                                 "DataSetReader does not support timeout type '%i'",
                                 (UA_Int32) reader->config.name.length,
                                 reader->config.name.data, eMonitoringType);
                    ret = UA_STATUSCODE_BADNOTSUPPORTED;
                    break;
            }
            break;
        }
        default:
            UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                         "Error UA_PubSubComponent_createMonitoring(): "
                         "PubSub component type '%i' is not supported", eComponentType);
            ret = UA_STATUSCODE_BADNOTSUPPORTED;
            break;
    }
    return ret;
}

static void
monitoringReceiveTimeoutOnce(UA_Server *server, void *data) {
    UA_LOCK(&server->serviceMutex);
    UA_DataSetReader *reader = (UA_DataSetReader*)data;
    reader->msgRcvTimeoutTimerCallback(server, reader);
    UA_EventLoop *el = server->config.eventLoop;
    el->removeCyclicCallback(el, reader->msgRcvTimeoutTimerId);
    reader->msgRcvTimeoutTimerId = 0;
    UA_UNLOCK(&server->serviceMutex);
}

static UA_StatusCode
UA_PubSubComponent_startMonitoring(UA_Server *server, UA_NodeId Id,
                                   UA_PubSubComponentEnumType eComponentType,
                                   UA_PubSubMonitoringType eMonitoringType, void *data) {
    if(!server || !data)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    switch (eComponentType) {
        case UA_PUBSUB_COMPONENT_DATASETREADER: {
            UA_DataSetReader *reader = (UA_DataSetReader*) data;
            switch (eMonitoringType) {
                case UA_PUBSUB_MONITORING_MESSAGE_RECEIVE_TIMEOUT: {
                    /* No timeout configured */
                    if(reader->config.messageReceiveTimeout <= 0.0)
                        return UA_STATUSCODE_GOOD;

                    /* use a timed callback, because one notification is enough,
                     * we assume that MessageReceiveTimeout configuration is in
                     * [ms], we do not handle or check fractions */
                    UA_EventLoop *el = server->config.eventLoop;
                    ret = el->addCyclicCallback(el, (UA_Callback)monitoringReceiveTimeoutOnce,
                                                server, reader,
                                                reader->config.messageReceiveTimeout, NULL,
                                                UA_TIMER_HANDLE_CYCLEMISS_WITH_CURRENTTIME,
                                                &reader->msgRcvTimeoutTimerId);
                    if(ret == UA_STATUSCODE_GOOD) {
                        UA_LOG_DEBUG(server->config.logging, UA_LOGCATEGORY_SERVER,
                                     "UA_PubSubComponent_startMonitoring(): DataSetReader "
                                     "'%.*s'- MessageReceiveTimeout: "
                                     "MessageReceiveTimeout = '%f' Timer Id = '%u'",
                                     (UA_Int32)reader->config.name.length,
                                     reader->config.name.data,
                                     reader->config.messageReceiveTimeout,
                                     (UA_UInt32)reader->msgRcvTimeoutTimerId);
                    } else {
                        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                                     "Error UA_PubSubComponent_startMonitoring(): "
                                     "DataSetReader '%.*s' - MessageReceiveTimeout: "
                                     "start timer failed",
                                     (UA_Int32)reader->config.name.length,
                                     reader->config.name.data);
                    }
                    break;
                }
                default:
                    UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                                 "UA_PubSubComponent_startMonitoring(): DataSetReader '%.*s' "
                                 "DataSetReader does not support timeout type '%i'",
                                 (UA_Int32)reader->config.name.length,
                                 reader->config.name.data,
                                 eMonitoringType);
                    ret = UA_STATUSCODE_BADNOTSUPPORTED;
                    break;
            }
            break;
        }
        default:
            UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                         "Error UA_PubSubComponent_startMonitoring(): PubSub component "
                         "type '%i' is not supported", eComponentType);
            ret = UA_STATUSCODE_BADNOTSUPPORTED;
            break;
    }
    return ret;
}

static UA_StatusCode
UA_PubSubComponent_stopMonitoring(UA_Server *server, UA_NodeId Id,
                                  UA_PubSubComponentEnumType eComponentType,
                                  UA_PubSubMonitoringType eMonitoringType, void *data) {
    if(!server || !data)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    switch (eComponentType) {
        case UA_PUBSUB_COMPONENT_DATASETREADER: {
            UA_DataSetReader *reader = (UA_DataSetReader*) data;
            switch (eMonitoringType) {
                case UA_PUBSUB_MONITORING_MESSAGE_RECEIVE_TIMEOUT: {
                    UA_EventLoop *el = server->config.eventLoop;
                    el->removeCyclicCallback(el, reader->msgRcvTimeoutTimerId);
                    UA_LOG_DEBUG(server->config.logging, UA_LOGCATEGORY_SERVER,
                                 "UA_PubSubComponent_stopMonitoring(): DataSetReader '%.*s' - "
                                 "MessageReceiveTimeout: MessageReceiveTimeout = '%f' "
                                 "Timer Id = '%u'", (UA_Int32) reader->config.name.length,
                                 reader->config.name.data,
                                 reader->config.messageReceiveTimeout,
                                 (UA_UInt32) reader->msgRcvTimeoutTimerId);
                    break;
                }
                default:
                    UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                                 "UA_PubSubComponent_stopMonitoring(): DataSetReader '%.*s' "
                                 "DataSetReader does not support timeout type '%i'",
                                 (UA_Int32) reader->config.name.length,
                                 reader->config.name.data,
                        eMonitoringType);
                    ret = UA_STATUSCODE_BADNOTSUPPORTED;
                    break;
            }
            break;
        }
        default:
            UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                         "Error UA_PubSubComponent_stopMonitoring(): "
                         "PubSub component type '%i' is not supported", eComponentType);
            ret = UA_STATUSCODE_BADNOTSUPPORTED;
            break;
    }
    return ret;
}

static UA_StatusCode
UA_PubSubComponent_updateMonitoringInterval(UA_Server *server, UA_NodeId Id,
                                            UA_PubSubComponentEnumType eComponentType,
                                            UA_PubSubMonitoringType eMonitoringType,
                                            void *data) {
    if(!server || !data)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    switch (eComponentType) {
        case UA_PUBSUB_COMPONENT_DATASETREADER: {
            UA_DataSetReader *reader = (UA_DataSetReader*) data;
            switch (eMonitoringType) {
                case UA_PUBSUB_MONITORING_MESSAGE_RECEIVE_TIMEOUT: {
                    UA_EventLoop *el = server->config.eventLoop;
                    ret = el->modifyCyclicCallback(el, reader->msgRcvTimeoutTimerId,
                                                   reader->config.messageReceiveTimeout, NULL,
                                                   UA_TIMER_HANDLE_CYCLEMISS_WITH_CURRENTTIME);
                    if(ret == UA_STATUSCODE_GOOD) {
                        UA_LOG_DEBUG(server->config.logging, UA_LOGCATEGORY_SERVER,
                                     "UA_PubSubComponent_updateMonitoringInterval(): "
                                     "DataSetReader '%.*s' - MessageReceiveTimeout: new "
                                     "MessageReceiveTimeout = '%f' Timer Id = '%u'",
                                     (UA_Int32) reader->config.name.length,
                                     reader->config.name.data,
                                     reader->config.messageReceiveTimeout,
                                     (UA_UInt32) reader->msgRcvTimeoutTimerId);
                    } else {
                        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                                     "Error UA_PubSubComponent_updateMonitoringInterval(): "
                                     "DataSetReader '%.*s': update timer interval failed",
                                     (UA_Int32) reader->config.name.length,
                                     reader->config.name.data);
                    }
                    break;
                }
                default:
                    UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                                 "UA_PubSubComponent_createMonitoring(): DataSetReader '%.*s' "
                                 "DataSetReader does not support timeout type '%i'",
                                 (UA_Int32) reader->config.name.length,
                                 reader->config.name.data,
                                 eMonitoringType);
                    ret = UA_STATUSCODE_BADNOTSUPPORTED;
                    break;
            }
            break;
        }
        default:
            UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                         "Error UA_PubSubComponent_updateMonitoringInterval(): "
                         "PubSub component type '%i' is not supported", eComponentType);
            ret = UA_STATUSCODE_BADNOTSUPPORTED;
            break;
    }
    return ret;
}

static UA_StatusCode
UA_PubSubComponent_deleteMonitoring(UA_Server *server, UA_NodeId Id,
                                    UA_PubSubComponentEnumType eComponentType,
                                    UA_PubSubMonitoringType eMonitoringType, void *data) {
    if(!server || !data)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    switch (eComponentType) {
        case UA_PUBSUB_COMPONENT_DATASETREADER: {
            UA_DataSetReader *reader = (UA_DataSetReader*) data;
            switch (eMonitoringType) {
                case UA_PUBSUB_MONITORING_MESSAGE_RECEIVE_TIMEOUT:
                    UA_LOG_DEBUG(server->config.logging, UA_LOGCATEGORY_SERVER,
                                 "UA_PubSubComponent_deleteMonitoring(): DataSetReader "
                                 "'%.*s' - MessageReceiveTimeout: Timer Id = '%u'",
                                 (UA_Int32)reader->config.name.length,
                                 reader->config.name.data,
                                 (UA_UInt32)reader->msgRcvTimeoutTimerId);
                    break;
                default:
                    UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                                 "UA_PubSubComponent_deleteMonitoring(): DataSetReader '%.*s' "
                                 "DataSetReader does not support timeout type '%i'",
                                 (UA_Int32)reader->config.name.length,
                                 reader->config.name.data,
                        eMonitoringType);
                    ret = UA_STATUSCODE_BADNOTSUPPORTED;
                    break;
            }
            break;
        }
        default:
            UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                         "Error UA_PubSubComponent_deleteMonitoring(): PubSub component type "
                         "'%i' is not supported", eComponentType);
            ret = UA_STATUSCODE_BADNOTSUPPORTED;
            break;
    }
    return ret;
}

UA_StatusCode
UA_PubSubManager_setDefaultMonitoringCallbacks(UA_PubSubMonitoringInterface *mif) {
    if(!mif)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    mif->createMonitoring = UA_PubSubComponent_createMonitoring;
    mif->startMonitoring = UA_PubSubComponent_startMonitoring;
    mif->stopMonitoring = UA_PubSubComponent_stopMonitoring;
    mif->updateMonitoringInterval = UA_PubSubComponent_updateMonitoringInterval;
    mif->deleteMonitoring = UA_PubSubComponent_deleteMonitoring;
    return UA_STATUSCODE_GOOD;
}

#endif /* UA_ENABLE_PUBSUB_MONITORING */

#endif /* UA_ENABLE_PUBSUB */

/**** amalgamated original file "/src/pubsub/ua_pubsub_ns0.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2017-2022 Fraunhofer IOSB (Author: Andreas Ebner)
 * Copyright (c) 2019-2021 Kalycito Infotech Private Limited
 * Copyright (c) 2020 Yannick Wallerer, Siemens AG
 * Copyright (c) 2020-2022 Thomas Fischer, Siemens AG
 * Copyright (c) 2022 Linutronix GmbH (Author: Muddasir Shakil)
 */


#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL /* conditional compilation */

typedef struct {
    UA_NodeId parentNodeId;
    UA_UInt32 parentClassifier;
    UA_UInt32 elementClassiefier;
} UA_NodePropertyContext;

static UA_StatusCode
writePubSubNs0VariableArray(UA_Server *server, const UA_NodeId id, void *v,
                            size_t length, const UA_DataType *type) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    UA_Variant var;
    UA_Variant_init(&var);
    UA_Variant_setArray(&var, v, length, type);
    return writeValueAttribute(server, id, &var);
}

static UA_NodeId
findSingleChildNode(UA_Server *server, UA_QualifiedName targetName,
                    UA_NodeId referenceTypeId, UA_NodeId startingNode){
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    UA_NodeId resultNodeId;
    UA_RelativePathElement rpe;
    UA_RelativePathElement_init(&rpe);
    rpe.referenceTypeId = referenceTypeId;
    rpe.isInverse = false;
    rpe.includeSubtypes = false;
    rpe.targetName = targetName;
    UA_BrowsePath bp;
    UA_BrowsePath_init(&bp);
    bp.startingNode = startingNode;
    bp.relativePath.elementsSize = 1;
    bp.relativePath.elements = &rpe;
    UA_BrowsePathResult bpr = translateBrowsePathToNodeIds(server, &bp);
    if(bpr.statusCode != UA_STATUSCODE_GOOD ||
       bpr.targetsSize < 1)
        return UA_NODEID_NULL;
    UA_StatusCode res = UA_NodeId_copy(&bpr.targets[0].targetId.nodeId, &resultNodeId);
    if(res != UA_STATUSCODE_GOOD){
        UA_BrowsePathResult_clear(&bpr);
        return UA_NODEID_NULL;
    }
    UA_BrowsePathResult_clear(&bpr);
    return resultNodeId;
}

static void
onReadLocked(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
             const UA_NodeId *nodeid, void *context,
             const UA_NumericRange *range, const UA_DataValue *data) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    const UA_NodePropertyContext *nodeContext = (const UA_NodePropertyContext*)context;
    const UA_NodeId *myNodeId = &nodeContext->parentNodeId;

    UA_PublishedVariableDataType *pvd = NULL;
    UA_PublishedDataSet *publishedDataSet = NULL;

    UA_Variant value;
    UA_Variant_init(&value);

    switch(nodeContext->parentClassifier){
    case UA_NS0ID_PUBSUBCONNECTIONTYPE: {
        UA_PubSubConnection *pubSubConnection =
            UA_PubSubConnection_findConnectionbyId(server, *myNodeId);
        switch(nodeContext->elementClassiefier) {
        case UA_NS0ID_PUBSUBCONNECTIONTYPE_PUBLISHERID:
            switch (pubSubConnection->config.publisherIdType) {
                case UA_PUBLISHERIDTYPE_BYTE:
                    UA_Variant_setScalar(&value, &pubSubConnection->config.publisherId.byte,
                                         &UA_TYPES[UA_TYPES_BYTE]);
                    break;
                case UA_PUBLISHERIDTYPE_UINT16:
                    UA_Variant_setScalar(&value, &pubSubConnection->config.publisherId.uint16,
                                         &UA_TYPES[UA_TYPES_UINT16]);
                    break;
                case UA_PUBLISHERIDTYPE_UINT32:
                    UA_Variant_setScalar(&value, &pubSubConnection->config.publisherId.uint32,
                                         &UA_TYPES[UA_TYPES_UINT32]);
                    break;
                case UA_PUBLISHERIDTYPE_UINT64:
                    UA_Variant_setScalar(&value, &pubSubConnection->config.publisherId.uint64,
                                         &UA_TYPES[UA_TYPES_UINT64]);
                    break;
                case UA_PUBLISHERIDTYPE_STRING:
                    UA_Variant_setScalar(&value, &pubSubConnection->config.publisherId.string,
                                         &UA_TYPES[UA_TYPES_STRING]);
                    break;
                default:
                    UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                           "Read error! Unknown PublisherId type.");
                }
            break;
        default:
            UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                           "Read error! Unknown property.");
        }
        break;
    }
    case UA_NS0ID_READERGROUPTYPE: {
        UA_ReaderGroup *readerGroup = UA_ReaderGroup_findRGbyId(server, *myNodeId);
        if(!readerGroup)
            return;
        switch(nodeContext->elementClassiefier){
        case UA_NS0ID_PUBSUBGROUPTYPE_STATUS_STATE:
            UA_Variant_setScalar(&value, &readerGroup->state,
                                 &UA_TYPES[UA_TYPES_PUBSUBSTATE]);
            break;
        default:
            UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                           "Read error! Unknown property.");
        }
        break;
    }
    case UA_NS0ID_DATASETREADERTYPE: {
        UA_DataSetReader *dataSetReader = UA_ReaderGroup_findDSRbyId(server, *myNodeId);
        if(!dataSetReader)
            return;

        switch(nodeContext->elementClassiefier) {
        case UA_NS0ID_DATASETREADERTYPE_PUBLISHERID:
            UA_Variant_setScalar(&value, dataSetReader->config.publisherId.data,
                                 dataSetReader->config.publisherId.type);
            break;
        case UA_NS0ID_DATASETREADERTYPE_STATUS_STATE:
            UA_Variant_setScalar(&value, &dataSetReader->state,
                                 &UA_TYPES[UA_TYPES_PUBSUBSTATE]);
            break;
        default:
            UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                           "Read error! Unknown property.");
        }
        break;
    }
    case UA_NS0ID_WRITERGROUPTYPE: {
        UA_WriterGroup *writerGroup = UA_WriterGroup_findWGbyId(server, *myNodeId);
        if(!writerGroup)
            return;
        switch(nodeContext->elementClassiefier){
        case UA_NS0ID_WRITERGROUPTYPE_PUBLISHINGINTERVAL:
            UA_Variant_setScalar(&value, &writerGroup->config.publishingInterval,
                                 &UA_TYPES[UA_TYPES_DURATION]);
            break;
        case UA_NS0ID_PUBSUBGROUPTYPE_STATUS_STATE:
            UA_Variant_setScalar(&value, &writerGroup->state,
                                 &UA_TYPES[UA_TYPES_PUBSUBSTATE]);
            break;
        default:
            UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                           "Read error! Unknown property.");
        }
        break;
    }
    case UA_NS0ID_DATASETWRITERTYPE: {
        UA_DataSetWriter *dataSetWriter = UA_DataSetWriter_findDSWbyId(server, *myNodeId);
        if(!dataSetWriter)
            return;

        switch(nodeContext->elementClassiefier) {
            case UA_NS0ID_DATASETWRITERTYPE_DATASETWRITERID:
                UA_Variant_setScalar(&value, &dataSetWriter->config.dataSetWriterId,
                                     &UA_TYPES[UA_TYPES_UINT16]);
                break;
            case UA_NS0ID_DATASETWRITERTYPE_STATUS_STATE:
                UA_Variant_setScalar(&value, &dataSetWriter->state,
                                     &UA_TYPES[UA_TYPES_PUBSUBSTATE]);
                break;
            default:
                UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                               "Read error! Unknown property.");
        }
        break;
    }
    case UA_NS0ID_PUBLISHEDDATAITEMSTYPE: {
        publishedDataSet = UA_PublishedDataSet_findPDSbyId(server, *myNodeId);
        if(!publishedDataSet)
            return;
        switch(nodeContext->elementClassiefier) {
        case UA_NS0ID_PUBLISHEDDATAITEMSTYPE_PUBLISHEDDATA: {
            pvd = (UA_PublishedVariableDataType *)
                UA_calloc(publishedDataSet->fieldSize, sizeof(UA_PublishedVariableDataType));
            size_t counter = 0;
            UA_DataSetField *field;
            TAILQ_FOREACH(field, &publishedDataSet->fields, listEntry) {
                pvd[counter].attributeId = UA_ATTRIBUTEID_VALUE;
                pvd[counter].publishedVariable =
                    field->config.field.variable.publishParameters.publishedVariable;
                UA_NodeId_copy(&field->config.field.variable.publishParameters.publishedVariable,
                               &pvd[counter].publishedVariable);
                counter++;
            }
            UA_Variant_setArray(&value, pvd, publishedDataSet->fieldSize,
                                &UA_TYPES[UA_TYPES_PUBLISHEDVARIABLEDATATYPE]);
            break;
        }
        case UA_NS0ID_PUBLISHEDDATASETTYPE_DATASETMETADATA: {
            UA_Variant_setScalar(&value, &publishedDataSet->dataSetMetaData,
                                 &UA_TYPES[UA_TYPES_DATASETMETADATATYPE]);
            break;
        }
        case UA_NS0ID_PUBLISHEDDATASETTYPE_CONFIGURATIONVERSION: {
            UA_Variant_setScalar(&value, &publishedDataSet->dataSetMetaData.configurationVersion,
                                     &UA_TYPES[UA_TYPES_CONFIGURATIONVERSIONDATATYPE]);
            break;
        }
        default:
            UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                           "Read error! Unknown property.");
        }
        break;
    }    
    case UA_NS0ID_STANDALONESUBSCRIBEDDATASETREFDATATYPE: {
        UA_StandaloneSubscribedDataSet *sds =
            UA_StandaloneSubscribedDataSet_findSDSbyId(server, *myNodeId);
        switch(nodeContext->elementClassiefier) {
            case UA_NS0ID_STANDALONESUBSCRIBEDDATASETTYPE_ISCONNECTED: {
                UA_Variant_setScalar(&value, &sds->config.isConnected,
                                     &UA_TYPES[UA_TYPES_BOOLEAN]);
                break;
            }
            case UA_NS0ID_STANDALONESUBSCRIBEDDATASETTYPE_DATASETMETADATA: {
                UA_Variant_setScalar(&value, &sds->config.dataSetMetaData,
                                     &UA_TYPES[UA_TYPES_DATASETMETADATATYPE]);
                break;
            }
            default:
            UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                            "Read error! Unknown property.");
        }
        break;
    }
    default:
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Read error! Unknown parent element.");
    }

    writeValueAttribute(server, *nodeid, &value);
    if(pvd && publishedDataSet) {
        UA_Array_delete(pvd, publishedDataSet->fieldSize,
                        &UA_TYPES[UA_TYPES_PUBLISHEDVARIABLEDATATYPE]);
    }
}

static void
onRead(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
       const UA_NodeId *nodeid, void *context,
       const UA_NumericRange *range, const UA_DataValue *data) {
    UA_LOCK(&server->serviceMutex);
    onReadLocked(server, sessionId, sessionContext, nodeid, context, range, data);
    UA_UNLOCK(&server->serviceMutex);
}

static void
onWriteLocked(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
              const UA_NodeId *nodeId, void *nodeContext,
              const UA_NumericRange *range, const UA_DataValue *data) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    UA_NodePropertyContext *npc = (UA_NodePropertyContext *)nodeContext;

    UA_WriterGroup *writerGroup = NULL;
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    switch(npc->parentClassifier) {
        case UA_NS0ID_PUBSUBCONNECTIONTYPE:
            //no runtime writable attributes
            break;
        case UA_NS0ID_WRITERGROUPTYPE: {
            writerGroup = UA_WriterGroup_findWGbyId(server, npc->parentNodeId);
            if(!writerGroup)
                return;
            UA_WriterGroupConfig writerGroupConfig;
            memset(&writerGroupConfig, 0, sizeof(writerGroupConfig));
            switch(npc->elementClassiefier) {
                case UA_NS0ID_WRITERGROUPTYPE_PUBLISHINGINTERVAL:
                    if(!UA_Variant_hasScalarType(&data->value, &UA_TYPES[UA_TYPES_DURATION]) &&
                       !UA_Variant_hasScalarType(&data->value, &UA_TYPES[UA_TYPES_DOUBLE])) {
                        res = UA_STATUSCODE_BADTYPEMISMATCH;
                        goto cleanup;
                    }
                    res = UA_WriterGroupConfig_copy(&writerGroup->config, &writerGroupConfig);
                    if(res != UA_STATUSCODE_GOOD)
                        goto cleanup;
                    writerGroupConfig.publishingInterval = *((UA_Duration *) data->value.data);
                    UA_WriterGroup_updateConfig(server, writerGroup, &writerGroupConfig);
                    UA_WriterGroupConfig_clear(&writerGroupConfig);
                    break;
                default:
                    UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                                   "Write error! Unknown property element.");
            }
            break;
        }
        default:
            UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                           "Read error! Unknown parent element.");
    }

 cleanup:
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Changing the ReaderGroupConfig failed with status %s",
                       UA_StatusCode_name(res));
    }
}

static void
onWrite(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
        const UA_NodeId *nodeId, void *nodeContext,
        const UA_NumericRange *range, const UA_DataValue *data) {
    UA_LOCK(&server->serviceMutex);
    onWriteLocked(server, sessionId, sessionContext, nodeId, nodeContext, range, data);
    UA_UNLOCK(&server->serviceMutex);
}

static UA_StatusCode
addVariableValueSource(UA_Server *server, UA_ValueCallback valueCallback,
                       UA_NodeId node, UA_NodePropertyContext *context){
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    setNodeContext(server, node, context);
    return setVariableNode_valueCallback(server, node, valueCallback);
}

static UA_StatusCode
addPubSubConnectionConfig(UA_Server *server, UA_PubSubConnectionDataType *pubsubConnection,
                          UA_NodeId *connectionId) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    UA_NetworkAddressUrlDataType networkAddressUrl;
    memset(&networkAddressUrl, 0, sizeof(networkAddressUrl));
    UA_ExtensionObject *eo = &pubsubConnection->address;
    if(eo->encoding == UA_EXTENSIONOBJECT_DECODED &&
       eo->content.decoded.type == &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]) {
        void *data = eo->content.decoded.data;
        retVal =
            UA_NetworkAddressUrlDataType_copy((UA_NetworkAddressUrlDataType *)data,
                                              &networkAddressUrl);
        if(retVal != UA_STATUSCODE_GOOD)
            return retVal;
    }

    UA_PubSubConnectionConfig connectionConfig;
    memset(&connectionConfig, 0, sizeof(UA_PubSubConnectionConfig));
    connectionConfig.transportProfileUri = pubsubConnection->transportProfileUri;
    connectionConfig.name = pubsubConnection->name;
    //TODO set real connection state
    connectionConfig.enabled = pubsubConnection->enabled;
    //connectionConfig.enabled = pubSubConnection.enabled;
    UA_Variant_setScalar(&connectionConfig.address, &networkAddressUrl,
                         &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]);

    if (pubsubConnection->publisherId.type == &UA_TYPES[UA_TYPES_BYTE]) {
        connectionConfig.publisherIdType = UA_PUBLISHERIDTYPE_BYTE;
        connectionConfig.publisherId.byte = *((UA_Byte*)pubsubConnection->publisherId.data);
    } else if (pubsubConnection->publisherId.type == &UA_TYPES[UA_TYPES_UINT16]) {
        connectionConfig.publisherIdType = UA_PUBLISHERIDTYPE_UINT16;
        connectionConfig.publisherId.uint16 = *((UA_UInt16*)pubsubConnection->publisherId.data);
    } else if (pubsubConnection->publisherId.type == &UA_TYPES[UA_TYPES_UINT32]) {
        connectionConfig.publisherIdType = UA_PUBLISHERIDTYPE_UINT32;
        connectionConfig.publisherId.uint32 = *((UA_UInt32*)pubsubConnection->publisherId.data);
    } else if (pubsubConnection->publisherId.type == &UA_TYPES[UA_TYPES_UINT64]) {
        connectionConfig.publisherIdType = UA_PUBLISHERIDTYPE_UINT64;
        connectionConfig.publisherId.uint64 = *((UA_UInt64*)pubsubConnection->publisherId.data);
    } else if (pubsubConnection->publisherId.type == &UA_TYPES[UA_TYPES_STRING]) {
        connectionConfig.publisherIdType = UA_PUBLISHERIDTYPE_STRING;
        UA_String_copy((UA_String *) pubsubConnection->publisherId.data,
                       &connectionConfig.publisherId.string);
    } else {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Unsupported PublisherId Type used.");
        return UA_STATUSCODE_BADCONFIGURATIONERROR;
    }

    retVal |= UA_PubSubConnection_create(server, &connectionConfig, connectionId);
    UA_NetworkAddressUrlDataType_clear(&networkAddressUrl);
    return retVal;
}

/**
 * **WriterGroup handling**
 *
 * The WriterGroup (WG) is part of the connection and contains the primary
 * configuration parameters for the message creation. */
static UA_StatusCode
addWriterGroupConfig(UA_Server *server, UA_NodeId connectionId,
                     UA_WriterGroupDataType *writerGroup, UA_NodeId *writerGroupId){
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Now we create a new WriterGroupConfig and add the group to the existing
     * PubSubConnection. */
    UA_WriterGroupConfig writerGroupConfig;
    memset(&writerGroupConfig, 0, sizeof(UA_WriterGroupConfig));
    writerGroupConfig.name = writerGroup->name;
    writerGroupConfig.publishingInterval = writerGroup->publishingInterval;
    writerGroupConfig.enabled = writerGroup->enabled;
    writerGroupConfig.writerGroupId = writerGroup->writerGroupId;
    //TODO remove hard coded UADP
    writerGroupConfig.encodingMimeType = UA_PUBSUB_ENCODING_UADP;
    writerGroupConfig.priority = writerGroup->priority;

    UA_UadpWriterGroupMessageDataType writerGroupMessage;
    UA_ExtensionObject *eoWG = &writerGroup->messageSettings;
    if(eoWG->encoding == UA_EXTENSIONOBJECT_DECODED){
        writerGroupConfig.messageSettings.encoding  = UA_EXTENSIONOBJECT_DECODED;
        if(eoWG->content.decoded.type == &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE]){
            if(UA_UadpWriterGroupMessageDataType_copy((UA_UadpWriterGroupMessageDataType *) eoWG->content.decoded.data,
                                                        &writerGroupMessage) != UA_STATUSCODE_GOOD){
                return UA_STATUSCODE_BADOUTOFMEMORY;
            }
            writerGroupConfig.messageSettings.content.decoded.type = &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE];
            writerGroupConfig.messageSettings.content.decoded.data = &writerGroupMessage;
        }
    }

    return UA_WriterGroup_create(server, connectionId, &writerGroupConfig, writerGroupId);
}

/**
 * **DataSetWriter handling**
 *
 * A DataSetWriter (DSW) is the glue between the WG and the PDS. The DSW is
 * linked to exactly one PDS and contains additional informations for the
 * message generation. */
static UA_StatusCode
addDataSetWriterConfig(UA_Server *server, const UA_NodeId *writerGroupId,
                       UA_DataSetWriterDataType *dataSetWriter,
                       UA_NodeId *dataSetWriterId) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_NodeId publishedDataSetId = UA_NODEID_NULL;
    UA_PublishedDataSet *tmpPDS;
    TAILQ_FOREACH(tmpPDS, &server->pubSubManager.publishedDataSets, listEntry){
        if(UA_String_equal(&dataSetWriter->dataSetName, &tmpPDS->config.name)) {
            publishedDataSetId = tmpPDS->identifier;
            break;
        }
    }

    if(UA_NodeId_isNull(&publishedDataSetId))
        return UA_STATUSCODE_BADPARENTNODEIDINVALID;

    /* We need now a DataSetWriter within the WriterGroup. This means we must
     * create a new DataSetWriterConfig and add call the addWriterGroup function. */
    UA_DataSetWriterConfig dataSetWriterConfig;
    memset(&dataSetWriterConfig, 0, sizeof(UA_DataSetWriterConfig));
    dataSetWriterConfig.name = dataSetWriter->name;
    dataSetWriterConfig.dataSetWriterId = dataSetWriter->dataSetWriterId;
    dataSetWriterConfig.keyFrameCount = dataSetWriter->keyFrameCount;
    dataSetWriterConfig.dataSetFieldContentMask =  dataSetWriter->dataSetFieldContentMask;
    return UA_DataSetWriter_create(server, *writerGroupId, publishedDataSetId,
                                   &dataSetWriterConfig, dataSetWriterId);
}

/**
 * **ReaderGroup**
 *
 * ReaderGroup is used to group a list of DataSetReaders. All ReaderGroups are
 * created within a PubSubConnection and automatically deleted if the connection
 * is removed. All network message related filters are only available in the DataSetReader. */
/* Add ReaderGroup to the created connection */
static UA_StatusCode
addReaderGroupConfig(UA_Server *server, UA_NodeId connectionId,
                     UA_ReaderGroupDataType *readerGroup,
                     UA_NodeId *readerGroupId) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_ReaderGroupConfig readerGroupConfig;
    memset(&readerGroupConfig, 0, sizeof(UA_ReaderGroupConfig));
    readerGroupConfig.name = readerGroup->name;
    return UA_ReaderGroup_create(server, connectionId,
                                 &readerGroupConfig, readerGroupId);
}

/**
 * **SubscribedDataSet**
 *
 * Set SubscribedDataSet type to TargetVariables data type.
 * Add subscribedvariables to the DataSetReader */
static UA_StatusCode
addSubscribedVariables(UA_Server *server, UA_NodeId dataSetReaderId,
                       UA_DataSetReaderDataType *dataSetReader,
                       UA_DataSetMetaDataType *pMetaData) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    UA_ExtensionObject *eoTargetVar = &dataSetReader->subscribedDataSet;
    if(eoTargetVar->encoding != UA_EXTENSIONOBJECT_DECODED ||
       eoTargetVar->content.decoded.type != &UA_TYPES[UA_TYPES_TARGETVARIABLESDATATYPE])
        return UA_STATUSCODE_BADUNEXPECTEDERROR;

    const UA_TargetVariablesDataType *targetVars =
        (UA_TargetVariablesDataType*)eoTargetVar->content.decoded.data;

    UA_NodeId folderId;
    UA_String folderName = pMetaData->name;
    UA_ObjectAttributes oAttr = UA_ObjectAttributes_default;
    UA_QualifiedName folderBrowseName;
    if(folderName.length > 0) {
        oAttr.displayName.locale = UA_STRING("");
        oAttr.displayName.text = folderName;
        folderBrowseName.namespaceIndex = 1;
        folderBrowseName.name = folderName;
    } else {
        oAttr.displayName = UA_LOCALIZEDTEXT("", "Subscribed Variables");
        folderBrowseName = UA_QUALIFIEDNAME(1, "Subscribed Variables");
    }

    addNode(server, UA_NODECLASS_OBJECT, UA_NODEID_NULL,
            UA_NODEID_NUMERIC (0, UA_NS0ID_OBJECTSFOLDER),
            UA_NODEID_NUMERIC (0, UA_NS0ID_ORGANIZES),
            folderBrowseName,
            UA_NODEID_NUMERIC (0, UA_NS0ID_BASEOBJECTTYPE),
            &oAttr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
            NULL, &folderId);

    /* The SubscribedDataSet option TargetVariables defines a list of Variable
     * mappings between received DataSet fields and target Variables in the
     * Subscriber AddressSpace. The values subscribed from the Publisher are
     * updated in the value field of these variables */

    /* Create the TargetVariables with respect to DataSetMetaData fields */
    UA_FieldTargetVariable *targetVarsData = (UA_FieldTargetVariable *)
        UA_calloc(targetVars->targetVariablesSize, sizeof(UA_FieldTargetVariable));
    for(size_t i = 0; i < targetVars->targetVariablesSize; i++) {
        /* Prepare the output structure */
        UA_FieldTargetDataType_init(&targetVarsData[i].targetVariable);
        targetVarsData[i].targetVariable.attributeId  = targetVars->targetVariables[i].attributeId;

        /* Add variable for the field */
        UA_VariableAttributes vAttr = UA_VariableAttributes_default;
        vAttr.description = pMetaData->fields[i].description;
        vAttr.displayName.locale = UA_STRING("");
        vAttr.displayName.text = pMetaData->fields[i].name;
        vAttr.dataType = pMetaData->fields[i].dataType;
        UA_QualifiedName varname = {1, pMetaData->fields[i].name};
        retVal |= addNode(server, UA_NODECLASS_VARIABLE,
                          targetVars->targetVariables[i].targetNodeId,
                          folderId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                          varname, UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
                          &vAttr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],
                          NULL, &targetVarsData[i].targetVariable.targetNodeId);

    }
    UA_DataSetReader *dsr = UA_ReaderGroup_findDSRbyId(server, dataSetReaderId);
    if(dsr) {
        retVal = DataSetReader_createTargetVariables(server, dsr,
                                                     targetVars->targetVariablesSize,
                                                     targetVarsData);
    } else {
        retVal = UA_STATUSCODE_BADINTERNALERROR;
    }
    for(size_t j = 0; j < targetVars->targetVariablesSize; j++)
        UA_FieldTargetDataType_clear(&targetVarsData[j].targetVariable);
    UA_free(targetVarsData);
    return retVal;
}

/**
 * **DataSetReader**
 *
 * DataSetReader can receive NetworkMessages with the DataSetMessage
 * of interest sent by the Publisher. DataSetReader provides
 * the configuration necessary to receive and process DataSetMessages
 * on the Subscriber side. DataSetReader must be linked with a
 * SubscribedDataSet and be contained within a ReaderGroup. */
static UA_StatusCode
addDataSetReaderConfig(UA_Server *server, UA_NodeId readerGroupId,
                       UA_DataSetReaderDataType *dataSetReader,
                       UA_NodeId *dataSetReaderId) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    UA_DataSetReaderConfig readerConfig;
    memset(&readerConfig, 0, sizeof(UA_DataSetReaderConfig));
    readerConfig.name = dataSetReader->name;
    readerConfig.publisherId = dataSetReader->publisherId;
    readerConfig.writerGroupId = dataSetReader->writerGroupId;
    readerConfig.dataSetWriterId = dataSetReader->dataSetWriterId;

    /* Setting up Meta data configuration in DataSetReader */
    UA_DataSetMetaDataType *pMetaData;
    pMetaData = &readerConfig.dataSetMetaData;
    UA_DataSetMetaDataType_init (pMetaData);
    pMetaData->name =  dataSetReader->dataSetMetaData.name;
    pMetaData->fieldsSize = dataSetReader->dataSetMetaData.fieldsSize;
    pMetaData->fields = (UA_FieldMetaData*)UA_Array_new (pMetaData->fieldsSize,
                        &UA_TYPES[UA_TYPES_FIELDMETADATA]);
    for(size_t i = 0; i < pMetaData->fieldsSize; i++){
        UA_FieldMetaData_init (&pMetaData->fields[i]);
        UA_NodeId_copy (&dataSetReader->dataSetMetaData.fields[i].dataType,
                        &pMetaData->fields[i].dataType);
        pMetaData->fields[i].builtInType = dataSetReader->dataSetMetaData.fields[i].builtInType;
        pMetaData->fields[i].name = dataSetReader->dataSetMetaData.fields[i].name;
        pMetaData->fields[i].valueRank = dataSetReader->dataSetMetaData.fields[i].valueRank;
    }

    retVal |= UA_DataSetReader_create(server, readerGroupId,
                                      &readerConfig, dataSetReaderId);
    if(retVal != UA_STATUSCODE_GOOD) {
        UA_free(pMetaData->fields);
        return retVal;
    }

    retVal |= addSubscribedVariables(server, *dataSetReaderId, dataSetReader, pMetaData);
    UA_free(pMetaData->fields);
    return retVal;
}

/*************************************************/
/*            PubSubConnection                   */
/*************************************************/

UA_StatusCode
addPubSubConnectionRepresentation(UA_Server *server, UA_PubSubConnection *connection) {
    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    if(connection->config.name.length > 512)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    char connectionName[513];
    memcpy(connectionName, connection->config.name.data, connection->config.name.length);
    connectionName[connection->config.name.length] = '\0';

    UA_ObjectAttributes attr = UA_ObjectAttributes_default;
    attr.displayName = UA_LOCALIZEDTEXT("", connectionName);
    retVal |= addNode_begin(server, UA_NODECLASS_OBJECT,
                            UA_NODEID_NUMERIC(1, 0), /* Generate a new id */
                            UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASPUBSUBCONNECTION),
                            UA_QUALIFIEDNAME(0, connectionName),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE),
                            (const UA_NodeAttributes*)&attr,
                            &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
                            NULL, &connection->identifier);

    attr.displayName = UA_LOCALIZEDTEXT("", "Address");
    retVal |= addNode(server, UA_NODECLASS_OBJECT, UA_NODEID_NUMERIC(1, 0),
                      connection->identifier, UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                      UA_QUALIFIEDNAME(0, "Address"),
                      UA_NODEID_NUMERIC(0, UA_NS0ID_NETWORKADDRESSURLTYPE),
                      &attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], NULL, NULL);

    retVal |= addNode_finish(server, &server->adminSession, &connection->identifier);

    UA_NodeId addressNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Address"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                            connection->identifier);
    UA_NodeId urlNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Url"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), addressNode);
    UA_NodeId interfaceNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "NetworkInterface"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), addressNode);
    UA_NodeId publisherIdNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublisherId"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), connection->identifier);
    UA_NodeId connectionPropertyNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "ConnectionProperties"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                            connection->identifier);
    UA_NodeId transportProfileUri =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "TransportProfileUri"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                            connection->identifier);

    if(UA_NodeId_isNull(&addressNode) || UA_NodeId_isNull(&urlNode) ||
       UA_NodeId_isNull(&interfaceNode) || UA_NodeId_isNull(&publisherIdNode) ||
       UA_NodeId_isNull(&connectionPropertyNode) ||
       UA_NodeId_isNull(&transportProfileUri)) {
        return UA_STATUSCODE_BADNOTFOUND;
    }

    retVal |= writePubSubNs0VariableArray(server, connectionPropertyNode,
                                          connection->config.connectionProperties.map,
                                          connection->config.connectionProperties.mapSize,
                                          &UA_TYPES[UA_TYPES_KEYVALUEPAIR]);

    UA_NetworkAddressUrlDataType *networkAddressUrl=
        ((UA_NetworkAddressUrlDataType*)connection->config.address.data);
    UA_Variant value;
    UA_Variant_init(&value);

    UA_Variant_setScalar(&value, &networkAddressUrl->url, &UA_TYPES[UA_TYPES_STRING]);
    writeValueAttribute(server, urlNode, &value);

    UA_Variant_setScalar(&value, &networkAddressUrl->networkInterface, &UA_TYPES[UA_TYPES_STRING]);
    writeValueAttribute(server, interfaceNode, &value);

    UA_Variant_setScalar(&value, &connection->config.transportProfileUri, &UA_TYPES[UA_TYPES_STRING]);
    writeValueAttribute(server, transportProfileUri, &value);

    UA_NodePropertyContext *connectionPublisherIdContext =
        (UA_NodePropertyContext *)UA_malloc(sizeof(UA_NodePropertyContext));
    connectionPublisherIdContext->parentNodeId = connection->identifier;
    connectionPublisherIdContext->parentClassifier = UA_NS0ID_PUBSUBCONNECTIONTYPE;
    connectionPublisherIdContext->elementClassiefier =
        UA_NS0ID_PUBSUBCONNECTIONTYPE_PUBLISHERID;
    UA_ValueCallback valueCallback;
    valueCallback.onRead = onRead;
    valueCallback.onWrite = NULL;
    retVal |= addVariableValueSource(server, valueCallback, publisherIdNode,
                                     connectionPublisherIdContext);

    if(server->config.pubSubConfig.enableInformationModelMethods) {
        retVal |= addRef(server, connection->identifier,
                         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                         UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDWRITERGROUP), true);
        retVal |= addRef(server, connection->identifier,
                         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                         UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDREADERGROUP), true);
        retVal |= addRef(server, connection->identifier,
                         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                         UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_REMOVEGROUP), true);
    }
    return retVal;
}

static UA_StatusCode
addPubSubConnectionLocked(UA_Server *server,
                          const UA_NodeId *sessionId, void *sessionContext,
                          const UA_NodeId *methodId, void *methodContext,
                          const UA_NodeId *objectId, void *objectContext,
                          size_t inputSize, const UA_Variant *input,
                          size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    UA_PubSubConnectionDataType *pubSubConnection =
        (UA_PubSubConnectionDataType *) input[0].data;

    //call API function and create the connection
    UA_NodeId connectionId;
    retVal |= addPubSubConnectionConfig(server, pubSubConnection, &connectionId);
    if(retVal != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "addPubSubConnection failed");
        return retVal;
    }

    for(size_t i = 0; i < pubSubConnection->writerGroupsSize; i++) {
        UA_NodeId writerGroupId;
        UA_WriterGroupDataType *writerGroup = &pubSubConnection->writerGroups[i];
        retVal |= addWriterGroupConfig(server, connectionId, writerGroup, &writerGroupId);
        if(retVal != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                         "addWriterGroup failed");
            return retVal;
        }

        for(size_t j = 0; j < writerGroup->dataSetWritersSize; j++) {
            UA_DataSetWriterDataType *dataSetWriter = &writerGroup->dataSetWriters[j];
            retVal |= addDataSetWriterConfig(server, &writerGroupId, dataSetWriter, NULL);
            if(retVal != UA_STATUSCODE_GOOD) {
                UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                             "addDataSetWriter failed");
                return retVal;
            }
        }

        /* TODO: Need to handle the UA_Server_setWriterGroupOperational based on
         * the status variable in information model */
        UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroupId);
        if(!wg)
            continue;
        if(pubSubConnection->enabled) {
            UA_WriterGroup_freezeConfiguration(server, wg);
            UA_WriterGroup_setPubSubState(server, wg, UA_PUBSUBSTATE_OPERATIONAL);
        } else {
            UA_WriterGroup_setPubSubState(server, wg, UA_PUBSUBSTATE_DISABLED);
        }
    }

    for(size_t i = 0; i < pubSubConnection->readerGroupsSize; i++){
        UA_NodeId readerGroupId;
        UA_ReaderGroupDataType *readerGroup = &pubSubConnection->readerGroups[i];
        retVal |= addReaderGroupConfig(server, connectionId, readerGroup, &readerGroupId);
        if(retVal != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                         "addReaderGroup failed");
            return retVal;
        }

        for(size_t j = 0; j < readerGroup->dataSetReadersSize; j++) {
            UA_NodeId dataSetReaderId;
            UA_DataSetReaderDataType *dataSetReader = &readerGroup->dataSetReaders[j];
            retVal |= addDataSetReaderConfig(server, readerGroupId,
                                             dataSetReader, &dataSetReaderId);
            if(retVal != UA_STATUSCODE_GOOD) {
                UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                             "addDataSetReader failed");
                return retVal;
            }

        }

        /* TODO: Need to handle the UA_Server_setReaderGroupOperational based on
         * the status variable in information model */
        UA_ReaderGroup *rg = UA_ReaderGroup_findRGbyId(server, readerGroupId);
        if(!rg)
            continue;
        if(pubSubConnection->enabled) {
            UA_ReaderGroup_freezeConfiguration(server, rg);
            UA_ReaderGroup_setPubSubState(server, rg, UA_PUBSUBSTATE_OPERATIONAL);
        } else {
            UA_ReaderGroup_setPubSubState(server, rg, UA_PUBSUBSTATE_DISABLED);
        }
    }

    /* Set ouput value */
    UA_Variant_setScalarCopy(output, &connectionId, &UA_TYPES[UA_TYPES_NODEID]);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
addPubSubConnectionAction(UA_Server *server,
                          const UA_NodeId *sessionId, void *sessionContext,
                          const UA_NodeId *methodId, void *methodContext,
                          const UA_NodeId *objectId, void *objectContext,
                          size_t inputSize, const UA_Variant *input,
                          size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex, 0);
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = addPubSubConnectionLocked(server, sessionId, sessionContext,
                                                  methodId, methodContext,
                                                  objectId, objectContext,
                                                  inputSize, input, outputSize, output);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

static UA_StatusCode
removeConnectionAction(UA_Server *server,
                       const UA_NodeId *sessionId, void *sessionContext,
                       const UA_NodeId *methodId, void *methodContext,
                       const UA_NodeId *objectId, void *objectContext,
                       size_t inputSize, const UA_Variant *input,
                       size_t outputSize, UA_Variant *output){
    UA_LOCK_ASSERT(&server->serviceMutex, 0);
    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data);
    retVal |= UA_Server_removePubSubConnection(server, nodeToRemove);
    if(retVal == UA_STATUSCODE_BADNOTFOUND)
        retVal = UA_STATUSCODE_BADNODEIDUNKNOWN;
    return retVal;
}

/**********************************************/
/*               DataSetReader                */
/**********************************************/

UA_StatusCode
addDataSetReaderRepresentation(UA_Server *server, UA_DataSetReader *dataSetReader){
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    if(dataSetReader->config.name.length > 512)
        return UA_STATUSCODE_BADCONFIGURATIONERROR;

    char dsrName[513];
    memcpy(dsrName, dataSetReader->config.name.data, dataSetReader->config.name.length);
    dsrName[dataSetReader->config.name.length] = '\0';

    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    UA_NodeId publisherIdNode, writerGroupIdNode, dataSetwriterIdNode, statusIdNode, stateIdNode;

    UA_ObjectAttributes object_attr = UA_ObjectAttributes_default;
    object_attr.displayName = UA_LOCALIZEDTEXT("", dsrName);
    retVal = addNode(server, UA_NODECLASS_OBJECT, UA_NODEID_NUMERIC(1, 0), /* create an id */
                     dataSetReader->linkedReaderGroup->identifier,
                     UA_NODEID_NUMERIC(0, UA_NS0ID_HASDATASETREADER),
                     UA_QUALIFIEDNAME(0, dsrName),
                     UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETREADERTYPE),
                     &object_attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
                     NULL, &dataSetReader->identifier);

    /* Add childNodes such as PublisherId, WriterGroupId and DataSetWriterId in
     * DataSetReader object */
    publisherIdNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublisherId"),
                                          UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                                          dataSetReader->identifier);
    writerGroupIdNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "WriterGroupId"),
                                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                                            dataSetReader->identifier);
    dataSetwriterIdNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetWriterId"),
                                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                                              dataSetReader->identifier);
    statusIdNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Status"),
                                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                                              dataSetReader->identifier);

    if(UA_NodeId_isNull(&statusIdNode)) {
        return UA_STATUSCODE_BADNOTFOUND;
    }

    stateIdNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "State"),
                                              UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                                              statusIdNode);

    if(UA_NodeId_isNull(&publisherIdNode) ||
       UA_NodeId_isNull(&writerGroupIdNode) ||
       UA_NodeId_isNull(&dataSetwriterIdNode) ||
       UA_NodeId_isNull(&stateIdNode)) {
        return UA_STATUSCODE_BADNOTFOUND;
    }

    UA_NodePropertyContext *dataSetReaderPublisherIdContext =
        (UA_NodePropertyContext *) UA_malloc(sizeof(UA_NodePropertyContext));
    dataSetReaderPublisherIdContext->parentNodeId = dataSetReader->identifier;
    dataSetReaderPublisherIdContext->parentClassifier = UA_NS0ID_DATASETREADERTYPE;
    dataSetReaderPublisherIdContext->elementClassiefier = UA_NS0ID_DATASETREADERTYPE_PUBLISHERID;
    UA_ValueCallback valueCallback;
    valueCallback.onRead = onRead;
    valueCallback.onWrite = NULL;
    retVal |= addVariableValueSource(server, valueCallback, publisherIdNode,
                                     dataSetReaderPublisherIdContext);

    UA_NodePropertyContext *dataSetReaderStateContext =
        (UA_NodePropertyContext *) UA_malloc(sizeof(UA_NodePropertyContext));
    UA_CHECK_MEM(dataSetReaderStateContext, return UA_STATUSCODE_BADOUTOFMEMORY);
    dataSetReaderStateContext->parentNodeId = dataSetReader->identifier;
    dataSetReaderStateContext->parentClassifier = UA_NS0ID_DATASETREADERTYPE;
    dataSetReaderStateContext->elementClassiefier = UA_NS0ID_DATASETREADERTYPE_STATUS_STATE;

    retVal |= addVariableValueSource(server, valueCallback, stateIdNode,
                                     dataSetReaderStateContext);

    /* Update childNode with values from Publisher */
    UA_Variant value;
    UA_Variant_init(&value);
    UA_Variant_setScalar(&value, &dataSetReader->config.writerGroupId,
                         &UA_TYPES[UA_TYPES_UINT16]);
    writeValueAttribute(server, writerGroupIdNode, &value);
    UA_Variant_setScalar(&value, &dataSetReader->config.dataSetWriterId,
                         &UA_TYPES[UA_TYPES_UINT16]);
    writeValueAttribute(server, dataSetwriterIdNode, &value);
    return retVal;
}

static UA_StatusCode
addDataSetReaderLocked(UA_Server *server,
                       const UA_NodeId *sessionId, void *sessionContext,
                       const UA_NodeId *methodId, void *methodContext,
                       const UA_NodeId *objectId, void *objectContext,
                       size_t inputSize, const UA_Variant *input,
                       size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    UA_ReaderGroup *rg = UA_ReaderGroup_findRGbyId(server, *objectId);
    if(rg->configurationFrozen) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "AddDataSetReader cannot be done because ReaderGroup config frozen");
        return UA_STATUSCODE_BAD;
    }

    UA_NodeId dataSetReaderId;
    UA_DataSetReaderDataType *dataSetReader= (UA_DataSetReaderDataType *) input[0].data;
    retVal |= addDataSetReaderConfig(server, *objectId, dataSetReader, &dataSetReaderId);
    if(retVal != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "AddDataSetReader failed");
        return retVal;
    }

    UA_Variant_setScalarCopy(output, &dataSetReaderId, &UA_TYPES[UA_TYPES_NODEID]);
    return retVal;
}

static UA_StatusCode
addDataSetReaderAction(UA_Server *server,
                       const UA_NodeId *sessionId, void *sessionContext,
                       const UA_NodeId *methodId, void *methodContext,
                       const UA_NodeId *objectId, void *objectContext,
                       size_t inputSize, const UA_Variant *input,
                       size_t outputSize, UA_Variant *output){
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = addDataSetReaderLocked(server, sessionId, sessionContext,
                                               methodId, methodContext, objectId, objectContext,
                                               inputSize, input, outputSize, output);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

static UA_StatusCode
removeDataSetReaderAction(UA_Server *server,
                          const UA_NodeId *sessionId, void *sessionContext,
                          const UA_NodeId *methodId, void *methodContext,
                          const UA_NodeId *objectId, void *objectContext,
                          size_t inputSize, const UA_Variant *input,
                          size_t outputSize, UA_Variant *output){
    UA_NodeId nodeToRemove = *((UA_NodeId *)input[0].data);
    return UA_Server_removeDataSetReader(server, nodeToRemove);
}

/*************************************************/
/*                PublishedDataSet               */
/*************************************************/
static UA_StatusCode
addDataSetFolderAction(UA_Server *server,
                       const UA_NodeId *sessionId, void *sessionContext,
                       const UA_NodeId *methodId, void *methodContext,
                       const UA_NodeId *objectId, void *objectContext,
                       size_t inputSize, const UA_Variant *input,
                       size_t outputSize, UA_Variant *output){
    UA_LOCK_ASSERT(&server->serviceMutex, 0);

    /* defined in R 1.04 9.1.4.5.7 */
    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    UA_String newFolderName = *((UA_String *) input[0].data);
    UA_NodeId generatedId;
    UA_ObjectAttributes objectAttributes = UA_ObjectAttributes_default;
    UA_LocalizedText name = {UA_STRING(""), newFolderName};
    objectAttributes.displayName = name;
    retVal |= UA_Server_addObjectNode(server, UA_NODEID_NULL, *objectId,
                                      UA_NODEID_NUMERIC(0,UA_NS0ID_ORGANIZES),
                                      UA_QUALIFIEDNAME(0, "DataSetFolder"),
                                      UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE),
                                      objectAttributes, NULL, &generatedId);
    UA_Variant_setScalarCopy(output, &generatedId, &UA_TYPES[UA_TYPES_NODEID]);

    if(server->config.pubSubConfig.enableInformationModelMethods) {
        retVal |= UA_Server_addReference(server, generatedId,
                                         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDPUBLISHEDDATAITEMS), true);
        retVal |= UA_Server_addReference(server, generatedId,
                                         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEPUBLISHEDDATASET), true);
        retVal |= UA_Server_addReference(server, generatedId,
                                         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDDATASETFOLDER), true);
        retVal |= UA_Server_addReference(server, generatedId,
                                         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEDATASETFOLDER), true);
    }
    return retVal;
}

static UA_StatusCode
removeDataSetFolderAction(UA_Server *server,
                          const UA_NodeId *sessionId, void *sessionContext,
                          const UA_NodeId *methodId, void *methodContext,
                          const UA_NodeId *objectId, void *objectContext,
                          size_t inputSize, const UA_Variant *input,
                          size_t outputSize, UA_Variant *output) {
    UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data);
    return UA_Server_deleteNode(server, nodeToRemove, true);
}

UA_StatusCode
addPublishedDataItemsRepresentation(UA_Server *server,
                                    UA_PublishedDataSet *publishedDataSet) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    if(publishedDataSet->config.name.length > 512)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    char pdsName[513];
    memcpy(pdsName, publishedDataSet->config.name.data, publishedDataSet->config.name.length);
    pdsName[publishedDataSet->config.name.length] = '\0';

    UA_ObjectAttributes object_attr = UA_ObjectAttributes_default;
    object_attr.displayName = UA_LOCALIZEDTEXT("", pdsName);
    retVal = addNode(server, UA_NODECLASS_OBJECT, UA_NODEID_NUMERIC(1, 0), /* Create a new id */
                     UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS),
                     UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                     UA_QUALIFIEDNAME(0, pdsName),
                     UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHEDDATAITEMSTYPE),
                     &object_attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
                     NULL, &publishedDataSet->identifier);
    UA_CHECK_STATUS(retVal, return retVal);

    UA_ValueCallback valueCallback;
    valueCallback.onRead = onRead;
    valueCallback.onWrite = NULL;
    //ToDo: Need to move the browse name from namespaceindex 0 to 1
    UA_NodeId configurationVersionNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "ConfigurationVersion"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                            publishedDataSet->identifier);
    if(UA_NodeId_isNull(&configurationVersionNode))
        return UA_STATUSCODE_BADNOTFOUND;

    UA_NodePropertyContext *configurationVersionContext = (UA_NodePropertyContext *)
        UA_malloc(sizeof(UA_NodePropertyContext));
    configurationVersionContext->parentNodeId = publishedDataSet->identifier;
    configurationVersionContext->parentClassifier = UA_NS0ID_PUBLISHEDDATAITEMSTYPE;
    configurationVersionContext->elementClassiefier =
        UA_NS0ID_PUBLISHEDDATASETTYPE_CONFIGURATIONVERSION;
    retVal |= addVariableValueSource(server, valueCallback, configurationVersionNode,
                                     configurationVersionContext);

    UA_NodeId publishedDataNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublishedData"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                            publishedDataSet->identifier);
    if(UA_NodeId_isNull(&publishedDataNode))
        return UA_STATUSCODE_BADNOTFOUND;

    UA_NodePropertyContext * publishingIntervalContext = (UA_NodePropertyContext *)
        UA_malloc(sizeof(UA_NodePropertyContext));
    publishingIntervalContext->parentNodeId = publishedDataSet->identifier;
    publishingIntervalContext->parentClassifier = UA_NS0ID_PUBLISHEDDATAITEMSTYPE;
    publishingIntervalContext->elementClassiefier = UA_NS0ID_PUBLISHEDDATAITEMSTYPE_PUBLISHEDDATA;
    retVal |= addVariableValueSource(server, valueCallback, publishedDataNode,
                                     publishingIntervalContext);

    UA_NodeId dataSetMetaDataNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetMetaData"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                            publishedDataSet->identifier);
    if(UA_NodeId_isNull(&dataSetMetaDataNode))
        return UA_STATUSCODE_BADNOTFOUND;

    UA_NodePropertyContext *metaDataContext = (UA_NodePropertyContext *)
        UA_malloc(sizeof(UA_NodePropertyContext));
    metaDataContext->parentNodeId = publishedDataSet->identifier;
    metaDataContext->parentClassifier = UA_NS0ID_PUBLISHEDDATAITEMSTYPE;
    metaDataContext->elementClassiefier = UA_NS0ID_PUBLISHEDDATASETTYPE_DATASETMETADATA;
    retVal |= addVariableValueSource(server, valueCallback,
                                     dataSetMetaDataNode, metaDataContext);

    if(server->config.pubSubConfig.enableInformationModelMethods) {
        retVal |= addRef(server, publishedDataSet->identifier,
                         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                         UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHEDDATAITEMSTYPE_ADDVARIABLES), true);
        retVal |= addRef(server, publishedDataSet->identifier,
                         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                         UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHEDDATAITEMSTYPE_REMOVEVARIABLES), true);
    }
    return retVal;
}

static UA_StatusCode
addPublishedDataItemsAction(UA_Server *server,
                            const UA_NodeId *sessionId, void *sessionContext,
                            const UA_NodeId *methodId, void *methodContext,
                            const UA_NodeId *objectId, void *objectContext,
                            size_t inputSize, const UA_Variant *input,
                            size_t outputSize, UA_Variant *output){
    UA_LOCK_ASSERT(&server->serviceMutex, 0);
    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    size_t fieldNameAliasesSize = input[1].arrayLength;
    UA_String * fieldNameAliases = (UA_String *) input[1].data;
    size_t fieldFlagsSize = input[2].arrayLength;
    UA_DataSetFieldFlags * fieldFlags = (UA_DataSetFieldFlags *) input[2].data;
    size_t variablesToAddSize = input[3].arrayLength;
    UA_PublishedVariableDataType *eoAddVar =
        (UA_PublishedVariableDataType *)input[3].data;

    if(fieldNameAliasesSize != fieldFlagsSize ||
       fieldFlagsSize != variablesToAddSize)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_PublishedDataSetConfig publishedDataSetConfig;
    memset(&publishedDataSetConfig, 0, sizeof(publishedDataSetConfig));
    publishedDataSetConfig.name = *((UA_String *) input[0].data);
    publishedDataSetConfig.publishedDataSetType = UA_PUBSUB_DATASET_PUBLISHEDITEMS;

    UA_NodeId dataSetItemsNodeId;
    retVal |= UA_Server_addPublishedDataSet(server, &publishedDataSetConfig,
                                            &dataSetItemsNodeId).addResult;
    if(retVal != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "addPublishedDataset failed");
        return retVal;
    }

    UA_DataSetFieldConfig dataSetFieldConfig;
    for(size_t j = 0; j < variablesToAddSize; ++j) {
        /* Prepare the config */
        memset(&dataSetFieldConfig, 0, sizeof(UA_DataSetFieldConfig));
        dataSetFieldConfig.dataSetFieldType = UA_PUBSUB_DATASETFIELD_VARIABLE;
        dataSetFieldConfig.field.variable.fieldNameAlias = fieldNameAliases[j];
        dataSetFieldConfig.field.variable.publishParameters = eoAddVar[j];
        if(fieldFlags[j] == UA_DATASETFIELDFLAGS_PROMOTEDFIELD)
            dataSetFieldConfig.field.variable.promotedField = true;
        retVal |= UA_Server_addDataSetField(server, dataSetItemsNodeId,
                                            &dataSetFieldConfig, NULL).result;
        if(retVal != UA_STATUSCODE_GOOD) {
           UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                        "addDataSetField failed");
           return retVal;
        }
    }

    UA_Variant_setScalarCopy(output, &dataSetItemsNodeId, &UA_TYPES[UA_TYPES_NODEID]);
    return retVal;
}

static UA_StatusCode
addVariablesAction(UA_Server *server,
                   const UA_NodeId *sessionId, void *sessionContext,
                   const UA_NodeId *methodId, void *methodContext,
                   const UA_NodeId *objectId, void *objectContext,
                   size_t inputSize, const UA_Variant *input,
                   size_t outputSize, UA_Variant *output){
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
removeVariablesAction(UA_Server *server,
                      const UA_NodeId *sessionId, void *sessionContext,
                      const UA_NodeId *methodId, void *methodContext,
                      const UA_NodeId *objectId, void *objectContext,
                      size_t inputSize, const UA_Variant *input,
                      size_t outputSize, UA_Variant *output){
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
removePublishedDataSetAction(UA_Server *server,
                             const UA_NodeId *sessionId, void *sessionContext,
                             const UA_NodeId *methodId, void *methodContext,
                             const UA_NodeId *objectId, void *objectContext,
                             size_t inputSize, const UA_Variant *input,
                             size_t outputSize, UA_Variant *output){
    UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data);
    return UA_Server_removePublishedDataSet(server, nodeToRemove);
}

/**********************************************/
/*       StandaloneSubscribedDataSet          */
/**********************************************/

UA_StatusCode
addStandaloneSubscribedDataSetRepresentation(UA_Server *server,
                                             UA_StandaloneSubscribedDataSet *subscribedDataSet) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    if(subscribedDataSet->config.name.length > 512)
        return UA_STATUSCODE_BADCONFIGURATIONERROR;

    UA_STACKARRAY(char, sdsName, sizeof(char) * subscribedDataSet->config.name.length +1);
    memcpy(sdsName, subscribedDataSet->config.name.data, subscribedDataSet->config.name.length);
    sdsName[subscribedDataSet->config.name.length] = '\0';

    UA_ObjectAttributes object_attr = UA_ObjectAttributes_default;
    object_attr.displayName = UA_LOCALIZEDTEXT("", sdsName);
    addNode(server, UA_NODECLASS_OBJECT, UA_NODEID_NUMERIC(1, 0), /* Create a new id */
            UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_SUBSCRIBEDDATASETS),
            UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
            UA_QUALIFIEDNAME(0, sdsName),
            UA_NODEID_NUMERIC(0, UA_NS0ID_STANDALONESUBSCRIBEDDATASETTYPE),
            &object_attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
            NULL, &subscribedDataSet->identifier);
    UA_NodeId sdsObjectNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "SubscribedDataSet"),
                                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                                      subscribedDataSet->identifier);
    UA_NodeId metaDataId = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetMetaData"),
                                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                                      subscribedDataSet->identifier);
    UA_NodeId connectedId = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "IsConnected"),
                                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                                      subscribedDataSet->identifier);

    if(UA_NodeId_equal(&sdsObjectNode, &UA_NODEID_NULL) ||
       UA_NodeId_equal(&metaDataId, &UA_NODEID_NULL) ||
       UA_NodeId_equal(&connectedId, &UA_NODEID_NULL)) {
        return UA_STATUSCODE_BADNOTFOUND;
    }
    if(subscribedDataSet->config.subscribedDataSetType == UA_PUBSUB_SDS_TARGET){
        UA_VariableAttributes attr = UA_VariableAttributes_default;
        UA_NodeId targetVarsId;
        attr.displayName = UA_LOCALIZEDTEXT("", "TargetVariables");
        attr.dataType = UA_TYPES[UA_TYPES_FIELDTARGETDATATYPE].typeId;
        attr.valueRank = UA_VALUERANK_ONE_DIMENSION;
        attr.arrayDimensionsSize = 1;
        UA_UInt32 arrayDimensions[1];
        arrayDimensions[0] = (UA_UInt32)
            subscribedDataSet->config.subscribedDataSet.target.targetVariablesSize;
        attr.arrayDimensions = arrayDimensions;
        attr.accessLevel = UA_ACCESSLEVELMASK_READ;
        UA_Variant_setArray(&attr.value,
                            subscribedDataSet->config.subscribedDataSet.target.targetVariables,
                            subscribedDataSet->config.subscribedDataSet.target.targetVariablesSize,
                            &UA_TYPES[UA_TYPES_FIELDTARGETDATATYPE]);
        ret |= addNode(server, UA_NODECLASS_VARIABLE, UA_NODEID_NULL, sdsObjectNode,
                       UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                       UA_QUALIFIEDNAME(0, "TargetVariables"),
                       UA_NODEID_NUMERIC(0, UA_NS0ID_PROPERTYTYPE),
                       &attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],
                       NULL, &targetVarsId);
    }

    UA_NodePropertyContext *isConnectedNodeContext = (UA_NodePropertyContext *)
        UA_malloc(sizeof(UA_NodePropertyContext));
    isConnectedNodeContext->parentNodeId = subscribedDataSet->identifier;
    isConnectedNodeContext->parentClassifier = UA_NS0ID_STANDALONESUBSCRIBEDDATASETREFDATATYPE;
    isConnectedNodeContext->elementClassiefier = UA_NS0ID_STANDALONESUBSCRIBEDDATASETTYPE_ISCONNECTED;

    UA_ValueCallback valueCallback;
    valueCallback.onRead = onRead;
    valueCallback.onWrite = NULL;
    ret |= addVariableValueSource(server, valueCallback, connectedId, isConnectedNodeContext);

    UA_NodePropertyContext *metaDataContext = (UA_NodePropertyContext *)
        UA_malloc(sizeof(UA_NodePropertyContext));
    metaDataContext->parentNodeId = subscribedDataSet->identifier;
    metaDataContext->parentClassifier = UA_NS0ID_STANDALONESUBSCRIBEDDATASETREFDATATYPE;
    metaDataContext->elementClassiefier = UA_NS0ID_STANDALONESUBSCRIBEDDATASETTYPE_DATASETMETADATA;
    ret |= addVariableValueSource(server, valueCallback, metaDataId, metaDataContext);

    return ret;
}

/**********************************************/
/*               WriterGroup                  */
/**********************************************/

static UA_StatusCode
readContentMask(UA_Server *server, const UA_NodeId *sessionId,
                void *sessionContext, const UA_NodeId *nodeId,
                void *nodeContext, UA_Boolean includeSourceTimeStamp,
                const UA_NumericRange *range, UA_DataValue *value) {
    UA_LOCK_ASSERT(&server->serviceMutex, 0);

    UA_WriterGroup *writerGroup = (UA_WriterGroup*)nodeContext;
    if((writerGroup->config.messageSettings.encoding != UA_EXTENSIONOBJECT_DECODED &&
        writerGroup->config.messageSettings.encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) ||
       writerGroup->config.messageSettings.content.decoded.type !=
       &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE])
        return UA_STATUSCODE_BADINTERNALERROR;
    UA_UadpWriterGroupMessageDataType *wgm = (UA_UadpWriterGroupMessageDataType*)
        writerGroup->config.messageSettings.content.decoded.data;

    UA_Variant_setScalarCopy(&value->value, &wgm->networkMessageContentMask,
                             &UA_TYPES[UA_TYPES_UADPNETWORKMESSAGECONTENTMASK]);
    value->hasValue = true;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
writeContentMask(UA_Server *server, const UA_NodeId *sessionId,
                 void *sessionContext, const UA_NodeId *nodeId,
                 void *nodeContext, const UA_NumericRange *range,
                 const UA_DataValue *value) {
    UA_LOCK_ASSERT(&server->serviceMutex, 0);

    UA_WriterGroup *writerGroup = (UA_WriterGroup*)nodeContext;
    if((writerGroup->config.messageSettings.encoding != UA_EXTENSIONOBJECT_DECODED &&
        writerGroup->config.messageSettings.encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) ||
       writerGroup->config.messageSettings.content.decoded.type !=
       &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE])
        return UA_STATUSCODE_BADINTERNALERROR;
    UA_UadpWriterGroupMessageDataType *wgm = (UA_UadpWriterGroupMessageDataType*)
        writerGroup->config.messageSettings.content.decoded.data;

    if(!value->value.type)
        return UA_STATUSCODE_BADTYPEMISMATCH;
    if(value->value.type->typeKind != UA_DATATYPEKIND_ENUM &&
       value->value.type->typeKind != UA_DATATYPEKIND_INT32)
        return UA_STATUSCODE_BADTYPEMISMATCH;

    wgm->networkMessageContentMask = *(UA_UadpNetworkMessageContentMask*)value->value.data;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
addWriterGroupRepresentation(UA_Server *server, UA_WriterGroup *writerGroup) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    if(writerGroup->config.name.length > 512)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    char wgName[513];
    memcpy(wgName, writerGroup->config.name.data, writerGroup->config.name.length);
    wgName[writerGroup->config.name.length] = '\0';

    UA_ObjectAttributes object_attr = UA_ObjectAttributes_default;
    object_attr.displayName = UA_LOCALIZEDTEXT("", wgName);
    retVal = addNode(server, UA_NODECLASS_OBJECT,
                     UA_NODEID_NUMERIC(1, 0), /* create a new id */
                     writerGroup->linkedConnection->identifier,
                     UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                     UA_QUALIFIEDNAME(0, wgName),
                     UA_NODEID_NUMERIC(0, UA_NS0ID_WRITERGROUPTYPE),
                     &object_attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
                     NULL, &writerGroup->identifier);

    UA_NodeId keepAliveNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "KeepAliveTime"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                            writerGroup->identifier);
    UA_NodeId publishingIntervalNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublishingInterval"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                            writerGroup->identifier);
    UA_NodeId statusIdNode = 
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Status"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                            writerGroup->identifier);

    if(UA_NodeId_isNull(&statusIdNode))
        return UA_STATUSCODE_BADNOTFOUND;

    UA_NodeId stateIdNode = 
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "State"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                            statusIdNode);

    if(UA_NodeId_isNull(&keepAliveNode) ||
       UA_NodeId_isNull(&publishingIntervalNode) ||
       UA_NodeId_isNull(&stateIdNode))
        return UA_STATUSCODE_BADNOTFOUND;

    UA_NodePropertyContext * publishingIntervalContext = (UA_NodePropertyContext *)
        UA_malloc(sizeof(UA_NodePropertyContext));
    publishingIntervalContext->parentNodeId = writerGroup->identifier;
    publishingIntervalContext->parentClassifier = UA_NS0ID_WRITERGROUPTYPE;
    publishingIntervalContext->elementClassiefier = UA_NS0ID_WRITERGROUPTYPE_PUBLISHINGINTERVAL;
    UA_ValueCallback valueCallback;
    valueCallback.onRead = onRead;
    valueCallback.onWrite = onWrite;
    retVal |= addVariableValueSource(server, valueCallback,
                                     publishingIntervalNode, publishingIntervalContext);
    writeAccessLevelAttribute(server, publishingIntervalNode,
                              UA_ACCESSLEVELMASK_READ ^ UA_ACCESSLEVELMASK_WRITE);

    UA_NodePropertyContext * stateContext = (UA_NodePropertyContext *)
        UA_malloc(sizeof(UA_NodePropertyContext));
    UA_CHECK_MEM(stateContext, return UA_STATUSCODE_BADOUTOFMEMORY);
    stateContext->parentNodeId = writerGroup->identifier;
    stateContext->parentClassifier = UA_NS0ID_WRITERGROUPTYPE;
    stateContext->elementClassiefier = UA_NS0ID_PUBSUBGROUPTYPE_STATUS_STATE;
    UA_ValueCallback stateValueCallback;
    stateValueCallback.onRead = onRead;
    stateValueCallback.onWrite = NULL;
    retVal |= addVariableValueSource(server, stateValueCallback,
                                     stateIdNode, stateContext);


    UA_NodeId priorityNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Priority"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                            writerGroup->identifier);
    UA_NodeId writerGroupIdNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "WriterGroupId"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                            writerGroup->identifier);

    UA_Variant value;
    UA_Variant_init(&value);
    UA_Variant_setScalar(&value, &writerGroup->config.publishingInterval, &UA_TYPES[UA_TYPES_DURATION]);
    writeValueAttribute(server, publishingIntervalNode, &value);
    UA_Variant_setScalar(&value, &writerGroup->config.keepAliveTime, &UA_TYPES[UA_TYPES_DURATION]);
    writeValueAttribute(server, keepAliveNode, &value);
    UA_Variant_setScalar(&value, &writerGroup->config.priority, &UA_TYPES[UA_TYPES_BYTE]);
    writeValueAttribute(server, priorityNode, &value);
    UA_Variant_setScalar(&value, &writerGroup->config.writerGroupId, &UA_TYPES[UA_TYPES_UINT16]);
    writeValueAttribute(server, writerGroupIdNode, &value);

    object_attr.displayName = UA_LOCALIZEDTEXT("", "MessageSettings");
    retVal |= addNode(server, UA_NODECLASS_OBJECT,
                      UA_NODEID_NUMERIC(1, 0),
                      writerGroup->identifier,
                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                      UA_QUALIFIEDNAME(0, "MessageSettings"),
                      UA_NODEID_NUMERIC(0, UA_NS0ID_UADPWRITERGROUPMESSAGETYPE),
                      &object_attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
                      NULL, NULL);

    /* Find the variable with the content mask */

    UA_NodeId messageSettingsId =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "MessageSettings"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                            writerGroup->identifier);
    UA_NodeId contentMaskId =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "NetworkMessageContentMask"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), messageSettingsId);
    if(!UA_NodeId_isNull(&contentMaskId)) {
        /* Set the callback */
        UA_DataSource ds;
        ds.read = readContentMask;
        ds.write = writeContentMask;
        setVariableNode_dataSource(server, contentMaskId, ds);
        setNodeContext(server, contentMaskId, writerGroup);

        /* Make writable */
        writeAccessLevelAttribute(server, contentMaskId,
                                  UA_ACCESSLEVELMASK_WRITE | UA_ACCESSLEVELMASK_READ);

    }

    /* Add reference to methods */
    if(server->config.pubSubConfig.enableInformationModelMethods) {
        retVal |= addRef(server, writerGroup->identifier,
                         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                         UA_NODEID_NUMERIC(0, UA_NS0ID_WRITERGROUPTYPE_ADDDATASETWRITER), true);
        retVal |= addRef(server, writerGroup->identifier,
                         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                         UA_NODEID_NUMERIC(0, UA_NS0ID_WRITERGROUPTYPE_REMOVEDATASETWRITER), true);
    }
    return retVal;
}

static UA_StatusCode
addWriterGroupAction(UA_Server *server,
                             const UA_NodeId *sessionId, void *sessionContext,
                             const UA_NodeId *methodId, void *methodContext,
                             const UA_NodeId *objectId, void *objectContext,
                             size_t inputSize, const UA_Variant *input,
                             size_t outputSize, UA_Variant *output){
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    UA_WriterGroupDataType *writerGroup = ((UA_WriterGroupDataType *) input[0].data);
    UA_NodeId writerGroupId;
    retVal |= addWriterGroupConfig(server, *objectId, writerGroup, &writerGroupId);
    if(retVal != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER, "addWriterGroup failed");
        UA_UNLOCK(&server->serviceMutex);
        return retVal;
    }
    // TODO: Need to handle the UA_Server_setWriterGroupOperational based on the
    // status variable in information model

    UA_Variant_setScalarCopy(output, &writerGroupId, &UA_TYPES[UA_TYPES_NODEID]);
    UA_UNLOCK(&server->serviceMutex);
    return retVal;
}

static UA_StatusCode
removeGroupAction(UA_Server *server,
                  const UA_NodeId *sessionId, void *sessionContext,
                  const UA_NodeId *methodId, void *methodContext,
                  const UA_NodeId *objectId, void *objectContext,
                  size_t inputSize, const UA_Variant *input,
                  size_t outputSize, UA_Variant *output){
    UA_LOCK_ASSERT(&server->serviceMutex, 0);

    UA_NodeId nodeToRemove = *((UA_NodeId *)input->data);
    if(UA_WriterGroup_findWGbyId(server, nodeToRemove)) {
        UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, nodeToRemove);
        if(wg->configurationFrozen)
            UA_Server_unfreezeWriterGroupConfiguration(server, nodeToRemove);
        return UA_Server_removeWriterGroup(server, nodeToRemove);
    } else {
        UA_ReaderGroup *rg = UA_ReaderGroup_findRGbyId(server, nodeToRemove);
        if(rg->configurationFrozen)
            UA_Server_unfreezeReaderGroupConfiguration(server, nodeToRemove);
        return UA_Server_removeReaderGroup(server, nodeToRemove);
    }
}

/**********************************************/
/*               ReserveIds                   */
/**********************************************/

static UA_StatusCode
addReserveIdsLocked(UA_Server *server,
                    const UA_NodeId *sessionId, void *sessionContext,
                    const UA_NodeId *methodId, void *methodContext,
                    const UA_NodeId *objectId, void *objectContext,
                    size_t inputSize, const UA_Variant *input,
                    size_t outputSize, UA_Variant *output){
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    UA_String transportProfileUri = *((UA_String *)input[0].data);
    UA_UInt16 numRegWriterGroupIds = *((UA_UInt16 *)input[1].data);
    UA_UInt16 numRegDataSetWriterIds = *((UA_UInt16 *)input[2].data);

    UA_UInt16 *writerGroupIds;
    UA_UInt16 *dataSetWriterIds;

    retVal |= UA_PubSubManager_reserveIds(server, *sessionId, numRegWriterGroupIds,
                                          numRegDataSetWriterIds, transportProfileUri,
                                          &writerGroupIds, &dataSetWriterIds);
    if(retVal != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER, "addReserveIds failed");
        return retVal;
    }

    /* Check the transportProfileUri */
    UA_String profile_1 = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-mqtt-uadp");
    UA_String profile_2 = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-mqtt-json");

    if(UA_String_equal(&transportProfileUri, &profile_1) ||
       UA_String_equal(&transportProfileUri, &profile_2)) {
        UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_SERVER, "ApplicationUri: %.*s",
                    (int)server->config.applicationDescription.applicationUri.length,
                    server->config.applicationDescription.applicationUri.data);
        retVal |= UA_Variant_setScalarCopy(&output[0],
                                           &server->config.applicationDescription.applicationUri,
                                           &UA_TYPES[UA_TYPES_STRING]);
    } else {
        retVal |= UA_Variant_setScalarCopy(&output[0],
                                           &server->pubSubManager.defaultPublisherId,
                                           &UA_TYPES[UA_TYPES_UINT64]);
    }

    UA_Variant_setArray(&output[1], writerGroupIds,
                        numRegWriterGroupIds, &UA_TYPES[UA_TYPES_UINT16]);
    UA_Variant_setArray(&output[2], dataSetWriterIds,
                        numRegDataSetWriterIds, &UA_TYPES[UA_TYPES_UINT16]);

    return retVal;
}

static UA_StatusCode
addReserveIdsAction(UA_Server *server,
                    const UA_NodeId *sessionId, void *sessionContext,
                    const UA_NodeId *methodId, void *methodContext,
                    const UA_NodeId *objectId, void *objectContext,
                    size_t inputSize, const UA_Variant *input,
                    size_t outputSize, UA_Variant *output) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = addReserveIdsLocked(server, sessionId, sessionContext,
                                            methodId, methodContext, objectId, objectContext,
                                            inputSize, input, outputSize, output);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

/**********************************************/
/*               ReaderGroup                  */
/**********************************************/

UA_StatusCode
addReaderGroupRepresentation(UA_Server *server, UA_ReaderGroup *readerGroup) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    if(readerGroup->config.name.length > 512)
        return UA_STATUSCODE_BADCONFIGURATIONERROR;
    char rgName[513];
    memcpy(rgName, readerGroup->config.name.data, readerGroup->config.name.length);
    rgName[readerGroup->config.name.length] = '\0';

    UA_ObjectAttributes object_attr = UA_ObjectAttributes_default;
    object_attr.displayName = UA_LOCALIZEDTEXT("", rgName);
    UA_StatusCode retVal =
        addNode(server, UA_NODECLASS_OBJECT, UA_NODEID_NUMERIC(1, 0), /* create an id */
                readerGroup->linkedConnection->identifier,
                UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                UA_QUALIFIEDNAME(0, rgName), UA_NODEID_NUMERIC(0, UA_NS0ID_READERGROUPTYPE),
                &object_attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
                NULL, &readerGroup->identifier);

    UA_NodeId statusIdNode = 
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Status"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                            readerGroup->identifier);

    if(UA_NodeId_isNull(&statusIdNode))
        return UA_STATUSCODE_BADNOTFOUND;

    UA_NodeId stateIdNode = 
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "State"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                            statusIdNode);

    if(UA_NodeId_isNull(&stateIdNode))
        return UA_STATUSCODE_BADNOTFOUND;

    UA_NodePropertyContext * stateContext = (UA_NodePropertyContext *)
        UA_malloc(sizeof(UA_NodePropertyContext));
    UA_CHECK_MEM(stateContext, return UA_STATUSCODE_BADOUTOFMEMORY);
    stateContext->parentNodeId = readerGroup->identifier;
    stateContext->parentClassifier = UA_NS0ID_READERGROUPTYPE;
    stateContext->elementClassiefier = UA_NS0ID_PUBSUBGROUPTYPE_STATUS_STATE;
    UA_ValueCallback stateValueCallback;
    stateValueCallback.onRead = onRead;
    stateValueCallback.onWrite = NULL;
    retVal |= addVariableValueSource(server, stateValueCallback,
                                     stateIdNode, stateContext);

    if(server->config.pubSubConfig.enableInformationModelMethods) {
        retVal |= addRef(server, readerGroup->identifier,
                         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                         UA_NODEID_NUMERIC(0, UA_NS0ID_READERGROUPTYPE_ADDDATASETREADER), true);
        retVal |= addRef(server, readerGroup->identifier,
                         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                         UA_NODEID_NUMERIC(0, UA_NS0ID_READERGROUPTYPE_REMOVEDATASETREADER), true);
    }
    return retVal;
}

static UA_StatusCode
addReaderGroupAction(UA_Server *server,
                     const UA_NodeId *sessionId, void *sessionContext,
                     const UA_NodeId *methodId, void *methodContext,
                     const UA_NodeId *objectId, void *objectContext,
                     size_t inputSize, const UA_Variant *input,
                     size_t outputSize, UA_Variant *output){
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    UA_ReaderGroupDataType *readerGroup = ((UA_ReaderGroupDataType *) input->data);
    UA_NodeId readerGroupId;
    retVal |= addReaderGroupConfig(server, *objectId, readerGroup, &readerGroupId);
    if(retVal != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER, "addReaderGroup failed");
        UA_UNLOCK(&server->serviceMutex);
        return retVal;
    }
    // TODO: Need to handle the UA_Server_setReaderGroupOperational based on the
    // status variable in information model

    UA_Variant_setScalarCopy(output, &readerGroupId, &UA_TYPES[UA_TYPES_NODEID]);
    UA_UNLOCK(&server->serviceMutex);
    return retVal;
}

#ifdef UA_ENABLE_PUBSUB_SKS
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
static UA_Boolean
isValidParentNode(UA_Server *server, UA_NodeId parentId) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    UA_Boolean retval = true;
    const UA_Node *parentNodeType;
    const UA_NodeId parentNodeTypeId =
        UA_NODEID_NUMERIC(0, UA_NS0ID_SECURITYGROUPFOLDERTYPE);
    const UA_Node *parentNode = UA_NODESTORE_GET(server, &parentId);

    if(parentNode) {
        parentNodeType = getNodeType(server, &parentNode->head);
        if(parentNodeType) {
            retval = UA_NodeId_equal(&parentNodeType->head.nodeId, &parentNodeTypeId);
            UA_NODESTORE_RELEASE(server, parentNodeType);
        }
        UA_NODESTORE_RELEASE(server, parentNode);
    }
    return retval;
}

static UA_StatusCode
updateSecurityGroupProperties(UA_Server *server, UA_NodeId *securityGroupNodeId,
                              UA_SecurityGroupConfig *config) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_StatusCode retval = UA_STATUSCODE_BAD;
    UA_Variant value;
    UA_Variant_init(&value);
    UA_Variant_setScalar(&value, &config->securityGroupName, &UA_TYPES[UA_TYPES_STRING]);
    retval = writeObjectProperty(server, *securityGroupNodeId,
                                 UA_QUALIFIEDNAME(0, "SecurityGroupId"), value);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /*AddValueCallback*/
    UA_Variant_setScalar(&value, &config->securityPolicyUri, &UA_TYPES[UA_TYPES_STRING]);
    retval = writeObjectProperty(server, *securityGroupNodeId,
                                 UA_QUALIFIEDNAME(0, "SecurityPolicyUri"), value);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    UA_Variant_setScalar(&value, &config->keyLifeTime, &UA_TYPES[UA_TYPES_DURATION]);
    retval = writeObjectProperty(server, *securityGroupNodeId,
                                 UA_QUALIFIEDNAME(0, "KeyLifetime"), value);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    UA_Variant_setScalar(&value, &config->maxFutureKeyCount, &UA_TYPES[UA_TYPES_UINT32]);
    retval = writeObjectProperty(server, *securityGroupNodeId,
                                 UA_QUALIFIEDNAME(0, "MaxFutureKeyCount"), value);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    UA_Variant_setScalar(&value, &config->maxPastKeyCount, &UA_TYPES[UA_TYPES_UINT32]);
    retval = writeObjectProperty(server, *securityGroupNodeId,
                                 UA_QUALIFIEDNAME(0, "MaxPastKeyCount"), value);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    return retval;
}

UA_StatusCode
addSecurityGroupRepresentation(UA_Server *server, UA_SecurityGroup *securityGroup) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    UA_StatusCode retval = UA_STATUSCODE_BAD;

    UA_SecurityGroupConfig *securityGroupConfig = &securityGroup->config;
    if(!isValidParentNode(server, securityGroup->securityGroupFolderId))
        return UA_STATUSCODE_BADPARENTNODEIDINVALID;

    if(securityGroupConfig->securityGroupName.length <= 0)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_QualifiedName browseName;
    UA_QualifiedName_init(&browseName);
    browseName.name = securityGroupConfig->securityGroupName;

    UA_ObjectAttributes object_attr = UA_ObjectAttributes_default;
    object_attr.displayName.text = securityGroupConfig->securityGroupName;
    UA_NodeId refType = UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT);
    UA_NodeId nodeType = UA_NODEID_NUMERIC(0, UA_NS0ID_SECURITYGROUPTYPE);
    retval = addNode(server, UA_NODECLASS_OBJECT, UA_NODEID_NULL,
                     securityGroup->securityGroupFolderId, refType,
                     browseName, nodeType, &object_attr,
                     &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES], NULL,
                     &securityGroup->securityGroupNodeId);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Add SecurityGroup failed with error: %s.",
                     UA_StatusCode_name(retval));
        return retval;
    }

    retval = updateSecurityGroupProperties(server,
                                           &securityGroup->securityGroupNodeId,
                                           securityGroupConfig);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Add SecurityGroup failed with error: %s.",
                     UA_StatusCode_name(retval));
        deleteNode(server, securityGroup->securityGroupNodeId, true);
    }
    return retval;
}

#endif /* UA_ENABLE_PUBSUB_INFORMATIONMODEL*/
#endif /* UA_ENABLE_PUBSUB_SKS */

/**********************************************/
/*               DataSetWriter                */
/**********************************************/

UA_StatusCode
addDataSetWriterRepresentation(UA_Server *server, UA_DataSetWriter *dataSetWriter) {

    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    if(dataSetWriter->config.name.length > 512)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    char dswName[513];
    memcpy(dswName, dataSetWriter->config.name.data, dataSetWriter->config.name.length);
    dswName[dataSetWriter->config.name.length] = '\0';

    UA_ObjectAttributes object_attr = UA_ObjectAttributes_default;
    object_attr.displayName = UA_LOCALIZEDTEXT("", dswName);
    retVal = addNode(server, UA_NODECLASS_OBJECT, UA_NODEID_NUMERIC(1, 0), /* create an id */
                     dataSetWriter->linkedWriterGroup->identifier,
                     UA_NODEID_NUMERIC(0, UA_NS0ID_HASDATASETWRITER),
                     UA_QUALIFIEDNAME(0, dswName),
                     UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETWRITERTYPE),
                     &object_attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
                     NULL, &dataSetWriter->identifier);
    //if connected dataset is null this means it's configured for heartbeats
    if(!UA_NodeId_isNull(&dataSetWriter->connectedDataSet)) {
        retVal |= addRef(server, dataSetWriter->connectedDataSet,
                         UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETTOWRITER),
                         dataSetWriter->identifier, true);
    }

    UA_NodeId dataSetWriterIdNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetWriterId"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                            dataSetWriter->identifier);
    UA_NodeId keyFrameNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "KeyFrameCount"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                            dataSetWriter->identifier);
    UA_NodeId dataSetFieldContentMaskNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetFieldContentMask"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                            dataSetWriter->identifier);

    UA_NodeId statusIdNode = 
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Status"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                            dataSetWriter->identifier);
    
    if(UA_NodeId_isNull(&statusIdNode)) {
        return UA_STATUSCODE_BADNOTFOUND;
    }

    UA_NodeId stateIdNode = 
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "State"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                            statusIdNode);

    // TODO: The keyFrameNode is NULL here, should be check
    // does not depend on the pubsub changes
    if(UA_NodeId_isNull(&dataSetWriterIdNode) ||
       UA_NodeId_isNull(&dataSetFieldContentMaskNode) ||
       UA_NodeId_isNull(&stateIdNode)) {
            return UA_STATUSCODE_BADNOTFOUND;
    }

    UA_NodePropertyContext *dataSetWriterIdContext = (UA_NodePropertyContext *)
        UA_malloc(sizeof(UA_NodePropertyContext));
    dataSetWriterIdContext->parentNodeId = dataSetWriter->identifier;
    dataSetWriterIdContext->parentClassifier = UA_NS0ID_DATASETWRITERTYPE;
    dataSetWriterIdContext->elementClassiefier = UA_NS0ID_DATASETWRITERTYPE_DATASETWRITERID;
    UA_ValueCallback valueCallback;
    valueCallback.onRead = onRead;
    valueCallback.onWrite = NULL;
    retVal |= addVariableValueSource(server, valueCallback,
                                     dataSetWriterIdNode, dataSetWriterIdContext);

    UA_NodePropertyContext *dataSetWriterStateContext =
        (UA_NodePropertyContext *) UA_malloc(sizeof(UA_NodePropertyContext));
    UA_CHECK_MEM(dataSetWriterStateContext, return UA_STATUSCODE_BADOUTOFMEMORY);
    dataSetWriterStateContext->parentNodeId = dataSetWriter->identifier;
    dataSetWriterStateContext->parentClassifier = UA_NS0ID_DATASETWRITERTYPE;
    dataSetWriterStateContext->elementClassiefier = UA_NS0ID_DATASETWRITERTYPE_STATUS_STATE;
    retVal |= addVariableValueSource(server, valueCallback,
                                     stateIdNode, dataSetWriterStateContext);

    UA_Variant value;
    UA_Variant_init(&value);
    UA_Variant_setScalar(&value, &dataSetWriter->config.dataSetWriterId,
                         &UA_TYPES[UA_TYPES_UINT16]);
    writeValueAttribute(server, dataSetWriterIdNode, &value);

    UA_Variant_setScalar(&value, &dataSetWriter->config.keyFrameCount,
                         &UA_TYPES[UA_TYPES_UINT32]);
    writeValueAttribute(server, keyFrameNode, &value);

    UA_Variant_setScalar(&value, &dataSetWriter->config.dataSetFieldContentMask,
                         &UA_TYPES[UA_TYPES_DATASETFIELDCONTENTMASK]);
    writeValueAttribute(server, dataSetFieldContentMaskNode, &value);

    object_attr.displayName = UA_LOCALIZEDTEXT("", "MessageSettings");
    retVal |= addNode(server, UA_NODECLASS_OBJECT, UA_NODEID_NUMERIC(1, 0),
                      dataSetWriter->identifier,
                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                      UA_QUALIFIEDNAME(0, "MessageSettings"),
                      UA_NODEID_NUMERIC(0, UA_NS0ID_UADPDATASETWRITERMESSAGETYPE),
                      &object_attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
                      NULL, NULL);

    return retVal;
}

static UA_StatusCode
addDataSetWriterLocked(UA_Server *server,
                       const UA_NodeId *sessionId, void *sessionContext,
                       const UA_NodeId *methodId, void *methodContext,
                       const UA_NodeId *objectId, void *objectContext,
                       size_t inputSize, const UA_Variant *input,
                       size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, *objectId);
    if(!wg) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Not a WriterGroup");
        return UA_STATUSCODE_BAD;
    }
    if(wg->configurationFrozen) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "addDataSetWriter cannot be done because writergroup config frozen");
        return UA_STATUSCODE_BAD;
    }

    UA_NodeId dataSetWriterId;
    UA_DataSetWriterDataType *dataSetWriterData = (UA_DataSetWriterDataType *)input->data;
    retVal |= addDataSetWriterConfig(server, objectId, dataSetWriterData, &dataSetWriterId);
    if(retVal != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "addDataSetWriter failed");
        return retVal;
    }

    UA_Variant_setScalarCopy(output, &dataSetWriterId, &UA_TYPES[UA_TYPES_NODEID]);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
addDataSetWriterAction(UA_Server *server,
                       const UA_NodeId *sessionId, void *sessionContext,
                       const UA_NodeId *methodId, void *methodContext,
                       const UA_NodeId *objectId, void *objectContext,
                       size_t inputSize, const UA_Variant *input,
                       size_t outputSize, UA_Variant *output) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = addDataSetWriterLocked(server, sessionId, sessionContext,
                                               methodId, methodContext, objectId, objectContext,
                                               inputSize, input, outputSize, output);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

static UA_StatusCode
removeDataSetWriterAction(UA_Server *server,
                          const UA_NodeId *sessionId, void *sessionContext,
                          const UA_NodeId *methodId, void *methodContext,
                          const UA_NodeId *objectId, void *objectContext,
                          size_t inputSize, const UA_Variant *input,
                          size_t outputSize, UA_Variant *output){
    UA_LOCK_ASSERT(&server->serviceMutex, 0);
    UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data);
    return UA_Server_removeDataSetWriter(server, nodeToRemove);
}

#ifdef UA_ENABLE_PUBSUB_SKS
/**
 * @note The user credentials and permissions are checked in the AccessControl plugin
 * before this callback is executed.
 */
static UA_StatusCode
setSecurityKeysLocked(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
                      const UA_NodeId *methodId, void *methodContext,
                      const UA_NodeId *objectId, void *objectContext, size_t inputSize,
                      const UA_Variant *input, size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Validate the arguments */
    if(!server || !input)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    if(inputSize < 7)
        return UA_STATUSCODE_BADARGUMENTSMISSING;
    if(inputSize > 7 || outputSize > 0)
        return UA_STATUSCODE_BADTOOMANYARGUMENTS;

    /* Check whether the channel is encrypted according to specification */
    UA_Session *session = getSessionById(server, sessionId);
    if(!session || !session->channel)
        return UA_STATUSCODE_BADINTERNALERROR;
    if(session->channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
        return UA_STATUSCODE_BADSECURITYMODEINSUFFICIENT;

    /*check for types*/
    if(!UA_Variant_hasScalarType(&input[0], &UA_TYPES[UA_TYPES_STRING]) || /*SecurityGroupId*/
        !UA_Variant_hasScalarType(&input[1], &UA_TYPES[UA_TYPES_STRING]) || /*SecurityPolicyUri*/
        !UA_Variant_hasScalarType(&input[2], &UA_TYPES[UA_TYPES_INTEGERID]) || /*CurrentTokenId*/
        !UA_Variant_hasScalarType(&input[3], &UA_TYPES[UA_TYPES_BYTESTRING]) || /*CurrentKey*/
        !UA_Variant_hasArrayType(&input[4], &UA_TYPES[UA_TYPES_BYTESTRING]) || /*FutureKeys*/
        (!UA_Variant_hasScalarType(&input[5], &UA_TYPES[UA_TYPES_DURATION]) &&
        !UA_Variant_hasScalarType(&input[5], &UA_TYPES[UA_TYPES_DOUBLE])) || /*TimeToNextKey*/
        (!UA_Variant_hasScalarType(&input[6], &UA_TYPES[UA_TYPES_DURATION]) &&
        !UA_Variant_hasScalarType(&input[6], &UA_TYPES[UA_TYPES_DOUBLE]))) /*TimeToNextKey*/
        return UA_STATUSCODE_BADTYPEMISMATCH;

    UA_StatusCode retval = UA_STATUSCODE_BAD;
    UA_Duration callbackTime;
    UA_String *securityGroupId = (UA_String *)input[0].data;
    UA_String *securityPolicyUri = (UA_String *)input[1].data;
    UA_UInt32 currentKeyId = *(UA_UInt32 *)input[2].data;
    UA_ByteString *currentKey = (UA_ByteString *)input[3].data;
    UA_ByteString *futureKeys = (UA_ByteString *)input[4].data;
    size_t futureKeySize = input[4].arrayLength;
    UA_Duration msTimeToNextKey = *(UA_Duration *)input[5].data;
    UA_Duration msKeyLifeTime = *(UA_Duration *)input[6].data;

    UA_PubSubKeyStorage *ks =
        UA_PubSubKeyStorage_findKeyStorage(server, *securityGroupId);
    if(!ks)
        return UA_STATUSCODE_BADNOTFOUND;

    if(!UA_String_equal(securityPolicyUri, &ks->policy->policyUri))
        return UA_STATUSCODE_BADSECURITYPOLICYREJECTED;

    if(ks->keyListSize == 0) {
        retval = UA_PubSubKeyStorage_storeSecurityKeys(server, ks, currentKeyId,
                                                       currentKey, futureKeys, futureKeySize,
            msKeyLifeTime);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
    } else {
        retval = UA_PubSubKeyStorage_update(server, ks, currentKey, currentKeyId,
                                            futureKeySize, futureKeys, msKeyLifeTime);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
    }

    retval = UA_PubSubKeyStorage_activateKeyToChannelContext(server, UA_NODEID_NULL,
                                                           ks->securityGroupID);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_INFO(
            server->config.logging, UA_LOGCATEGORY_SERVER,
            "Failed to import Symmetric Keys into PubSub Channel Context with %s \n",
            UA_StatusCode_name(retval));
        return retval;
    }

    callbackTime = msKeyLifeTime;
    if(msTimeToNextKey > 0)
        callbackTime = msTimeToNextKey;

    /*move to setSecurityKeysAction*/
    retval = UA_PubSubKeyStorage_addKeyRolloverCallback(
        server, ks, (UA_ServerCallback)UA_PubSubKeyStorage_keyRolloverCallback, callbackTime,
        &ks->callBackId);
    return retval;
}

static UA_StatusCode
setSecurityKeysAction(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
                      const UA_NodeId *methodId, void *methodContext,
                      const UA_NodeId *objectId, void *objectContext, size_t inputSize,
                      const UA_Variant *input, size_t outputSize, UA_Variant *output) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = setSecurityKeysLocked(server, sessionId, sessionContext,
                                              methodId, methodContext,
                                              objectId, objectContext, inputSize,
                                              input, outputSize, output);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

static UA_StatusCode
getSecurityKeysLocked(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
                      const UA_NodeId *methodId, void *methodContext,
                      const UA_NodeId *objectId, void *objectContext, size_t inputSize,
                      const UA_Variant *input, size_t outputSize, UA_Variant *output) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Validate the arguments */
    if(!server || !input)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    if(inputSize < 3 || outputSize < 5)
        return UA_STATUSCODE_BADARGUMENTSMISSING;
    if(inputSize > 3 || outputSize > 5)
        return UA_STATUSCODE_BADTOOMANYARGUMENTS;

    /* Check whether the channel is encrypted according to specification */
    UA_Session *session = getSessionById(server, sessionId);
    if(!session || !session->channel)
        return UA_STATUSCODE_BADINTERNALERROR;
    if(session->channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
        return UA_STATUSCODE_BADSECURITYMODEINSUFFICIENT;

    /*check for types*/
    if(!UA_Variant_hasScalarType(&input[0],
                                 &UA_TYPES[UA_TYPES_STRING]) || /*SecurityGroupId*/
       !UA_Variant_hasScalarType(&input[1],
                                 &UA_TYPES[UA_TYPES_INTEGERID]) || /*StartingTokenId*/
       !UA_Variant_hasScalarType(&input[2],
                                 &UA_TYPES[UA_TYPES_UINT32])) /*RequestedKeyCount*/
        return UA_STATUSCODE_BADTYPEMISMATCH;

    UA_StatusCode retval = UA_STATUSCODE_BAD;
    UA_UInt32 currentKeyCount = 1;
    /* input */
    UA_String *securityGroupId = (UA_String *)input[0].data;
    UA_UInt32 startingTokenId = *(UA_UInt32 *)input[1].data;
    UA_UInt32 requestedKeyCount = *(UA_UInt32 *)input[2].data;

    UA_PubSubKeyStorage *ks =
        UA_PubSubKeyStorage_findKeyStorage(server, *securityGroupId);
    if(!ks)
        return UA_STATUSCODE_BADNOTFOUND;

    UA_Boolean executable = false;
    UA_SecurityGroup *sg = UA_SecurityGroup_findSGbyName(server, *securityGroupId);
    void *sgNodeCtx;
    getNodeContext(server, sg->securityGroupNodeId, (void **)&sgNodeCtx);
    executable = server->config.accessControl.getUserExecutableOnObject(
        server, &server->config.accessControl, sessionId, sessionContext, methodId,
        methodContext, &sg->securityGroupNodeId, sgNodeCtx);

    if(!executable)
        return UA_STATUSCODE_BADUSERACCESSDENIED;

    /* If the caller requests a number larger than the Security Key Service permits, then
     * the SKS shall return the maximum it allows.*/
    if(requestedKeyCount > sg->config.maxFutureKeyCount)
        requestedKeyCount =(UA_UInt32) sg->keyStorage->keyListSize;
    else
        requestedKeyCount = requestedKeyCount + currentKeyCount; /* Add Current keyCount */

    /*The current token is requested by passing 0.*/
    UA_PubSubKeyListItem *startingItem = NULL;
    if(startingTokenId == 0) {
        /* currentItem is always set by the server when a security group is added */
        UA_assert(sg->keyStorage->currentItem != NULL);
        startingItem = sg->keyStorage->currentItem;
    } else {
        retval = UA_PubSubKeyStorage_getKeyByKeyID(
            startingTokenId, sg->keyStorage, &startingItem);
        /*If the StartingTokenId is unknown, the oldest (firstItem) available tokens are
         * returned. */
        if(retval == UA_STATUSCODE_BADNOTFOUND)
            startingItem =  TAILQ_FIRST(&sg->keyStorage->keyList);
    }

    /*SecurityPolicyUri*/
    retval = UA_Variant_setScalarCopy(&output[0], &(sg->keyStorage->policy->policyUri),
                         &UA_TYPES[UA_TYPES_STRING]);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /*FirstTokenId*/
    retval = UA_Variant_setScalarCopy(&output[1], &startingItem->keyID,
                                      &UA_TYPES[UA_TYPES_INTEGERID]);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /*TimeToNextKey*/
    UA_EventLoop *el = server->config.eventLoop;
    UA_DateTime baseTime = sg->baseTime;
    UA_DateTime currentTime = el->dateTime_nowMonotonic(el);
    UA_Duration interval = sg->config.keyLifeTime;
    UA_Duration timeToNextKey =
        (UA_Duration)((currentTime - baseTime) / UA_DATETIME_MSEC);
    timeToNextKey = interval - timeToNextKey;
    retval = UA_Variant_setScalarCopy(&output[3], &timeToNextKey,
                                      &UA_TYPES[UA_TYPES_DURATION]);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /*KeyLifeTime*/
    retval = UA_Variant_setScalarCopy(&output[4], &sg->config.keyLifeTime,
                         &UA_TYPES[UA_TYPES_DURATION]);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /*Keys*/
    UA_PubSubKeyListItem *iterator = startingItem;
    output[2].data = (UA_ByteString *)UA_calloc(requestedKeyCount, startingItem->key.length);
    if(!output[2].data)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_ByteString *requestedKeys = (UA_ByteString *)output[2].data;
    UA_UInt32 retkeyCount = 0;
    for(size_t i = 0; i < requestedKeyCount; i++) {
        UA_ByteString_copy(&iterator->key, &requestedKeys[i]);
        ++retkeyCount;
        iterator = TAILQ_NEXT(iterator, keyListEntry);
        if(!iterator) {
            requestedKeyCount = retkeyCount;
            break;
        }
    }

    UA_Variant_setArray(&output[2], requestedKeys, requestedKeyCount, &UA_TYPES[UA_TYPES_BYTESTRING]);
    return retval;
}

static UA_StatusCode
getSecurityKeysAction(UA_Server *server, const UA_NodeId *sessionId, void *sessionContext,
                      const UA_NodeId *methodId, void *methodContext,
                      const UA_NodeId *objectId, void *objectContext, size_t inputSize,
                      const UA_Variant *input, size_t outputSize, UA_Variant *output) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = getSecurityKeysLocked(server, sessionId, sessionContext,
                                              methodId, methodContext,
                                              objectId, objectContext, inputSize,
                                              input, outputSize, output);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}
#endif

/**********************************************/
/*                Destructors                 */
/**********************************************/

static void
connectionTypeDestructor(UA_Server *server,
                         const UA_NodeId *sessionId, void *sessionContext,
                         const UA_NodeId *typeId, void *typeContext,
                         const UA_NodeId *nodeId, void **nodeContext) {
    UA_LOCK(&server->serviceMutex);
    UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_USERLAND,
                "Connection destructor called!");
    UA_NodeId publisherIdNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublisherId"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId);
    UA_NodePropertyContext *ctx;
    getNodeContext(server, publisherIdNode, (void **)&ctx);
    if(!UA_NodeId_isNull(&publisherIdNode))
        UA_free(ctx);
    UA_UNLOCK(&server->serviceMutex);
}

static void
writerGroupTypeDestructor(UA_Server *server,
                          const UA_NodeId *sessionId, void *sessionContext,
                          const UA_NodeId *typeId, void *typeContext,
                          const UA_NodeId *nodeId, void **nodeContext) {
    UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_USERLAND,
                "WriterGroup destructor called!");
    UA_LOCK(&server->serviceMutex);
    UA_NodeId intervalNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublishingInterval"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId);

    UA_NodeId statusNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Status"),
                                          UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                                          *nodeId);
    UA_NodeId stateNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "State"),
                                    UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                                    statusNode);
    UA_NodePropertyContext *ctx;
    getNodeContext(server, intervalNode, (void **)&ctx);
    if(!UA_NodeId_isNull(&intervalNode))
        UA_free(ctx);

    getNodeContext(server, stateNode, (void **)&ctx);
    if(!UA_NodeId_isNull(&stateNode))
        UA_free(ctx);
    UA_UNLOCK(&server->serviceMutex);
}

static void
readerGroupTypeDestructor(UA_Server *server,
                          const UA_NodeId *sessionId, void *sessionContext,
                          const UA_NodeId *typeId, void *typeContext,
                          const UA_NodeId *nodeId, void **nodeContext) {
    UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_USERLAND,
                "ReaderGroup destructor called!");
    UA_LOCK(&server->serviceMutex);
    UA_NodeId statusNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Status"),
                                          UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                                          *nodeId);
    UA_NodeId stateNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "State"),
                                    UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                                    statusNode);

    UA_NodePropertyContext *ctx;
    getNodeContext(server, stateNode, (void **)&ctx);
    if(!UA_NodeId_isNull(&stateNode))
        UA_free(ctx);
    UA_UNLOCK(&server->serviceMutex);
}

static void
dataSetWriterTypeDestructor(UA_Server *server,
                            const UA_NodeId *sessionId, void *sessionContext,
                            const UA_NodeId *typeId, void *typeContext,
                            const UA_NodeId *nodeId, void **nodeContext) {
    UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_USERLAND,
                "DataSetWriter destructor called!");
    UA_LOCK(&server->serviceMutex);
    UA_NodeId dataSetWriterIdNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetWriterId"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId);
    UA_NodeId statusNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Status"),
                                          UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                                          *nodeId);
    UA_NodeId stateNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "State"),
                                    UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                                    statusNode);
    UA_NodePropertyContext *ctx;
    getNodeContext(server, dataSetWriterIdNode, (void **)&ctx);
    if(!UA_NodeId_isNull(&dataSetWriterIdNode))
        UA_free(ctx);
    getNodeContext(server, stateNode, (void **)&ctx);
    if(!UA_NodeId_isNull(&stateNode))
        UA_free(ctx);
    UA_UNLOCK(&server->serviceMutex);
}

static void
dataSetReaderTypeDestructor(UA_Server *server,
                            const UA_NodeId *sessionId, void *sessionContext,
                            const UA_NodeId *typeId, void *typeContext,
                            const UA_NodeId *nodeId, void **nodeContext) {
    UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_USERLAND,
                "DataSetReader destructor called!");
    UA_LOCK(&server->serviceMutex);
    UA_NodeId publisherIdNode =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublisherId"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId);
    UA_NodeId statusNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "Status"),
                                          UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                                          *nodeId);
    UA_NodeId stateNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "State"),
                                    UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                                    statusNode);

    UA_NodePropertyContext *ctx;
    getNodeContext(server, publisherIdNode, (void **)&ctx);
    if(!UA_NodeId_isNull(&publisherIdNode))
        UA_free(ctx);

    getNodeContext(server, stateNode, (void **)&ctx);
    if(!UA_NodeId_isNull(&stateNode))
        UA_free(ctx);
    UA_UNLOCK(&server->serviceMutex);
}

static void
publishedDataItemsTypeDestructor(UA_Server *server,
                            const UA_NodeId *sessionId, void *sessionContext,
                            const UA_NodeId *typeId, void *typeContext,
                            const UA_NodeId *nodeId, void **nodeContext) {
    UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_USERLAND,
                "PublishedDataItems destructor called!");
    UA_LOCK(&server->serviceMutex);
    void *childContext;
    UA_NodeId node = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublishedData"),
                                         UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId);
    getNodeContext(server, node, (void**)&childContext);
    if(!UA_NodeId_isNull(&node))
        UA_free(childContext);

    node = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "ConfigurationVersion"),
                               UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                               *nodeId);
    getNodeContext(server, node, (void**)&childContext);
    if(!UA_NodeId_isNull(&node))
        UA_free(childContext);

    node = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetMetaData"),
                               UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId);
    getNodeContext(server, node, (void**)&childContext);
    if(!UA_NodeId_isNull(&node))
        UA_free(childContext);
    UA_UNLOCK(&server->serviceMutex);
}

static void
standaloneSubscribedDataSetTypeDestructor(UA_Server *server,
                            const UA_NodeId *sessionId, void *sessionContext,
                            const UA_NodeId *typeId, void *typeContext,
                            const UA_NodeId *nodeId, void **nodeContext) {
    UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_USERLAND,
                "Standalone SubscribedDataSet destructor called!");
    UA_LOCK(&server->serviceMutex);
    void *childContext;
    UA_NodeId node =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetMetaData"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId);
    getNodeContext(server, node, (void**)&childContext);
    if(!UA_NodeId_equal(&UA_NODEID_NULL , &node))
        UA_free(childContext);
    node = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "IsConnected"),
                               UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                               *nodeId);
    getNodeContext(server, node, (void**)&childContext);
    if(!UA_NodeId_equal(&UA_NODEID_NULL , &node))
        UA_free(childContext);
    UA_UNLOCK(&server->serviceMutex);
}

/*************************************/
/*         PubSub configurator       */
/*************************************/

#ifdef UA_ENABLE_PUBSUB_FILE_CONFIG

/* Callback function that will be executed when the method "PubSub configurator
 * (replace config)" is called. */
static UA_StatusCode
UA_loadPubSubConfigMethodCallback(UA_Server *server,
                                  const UA_NodeId *sessionId, void *sessionContext,
                                  const UA_NodeId *methodId, void *methodContext,
                                  const UA_NodeId *objectId, void *objectContext,
                                  size_t inputSize, const UA_Variant *input,
                                  size_t outputSize, UA_Variant *output) {
    if(inputSize == 1) {
        UA_LOCK(&server->serviceMutex);
        UA_ByteString *inputStr = (UA_ByteString*)input->data;
        UA_StatusCode res = UA_PubSubManager_loadPubSubConfigFromByteString(server, *inputStr);
        UA_UNLOCK(&server->serviceMutex);
        return res;
    } else if(inputSize > 1) {
        return UA_STATUSCODE_BADTOOMANYARGUMENTS;
    } else {
        return UA_STATUSCODE_BADARGUMENTSMISSING;
    }
}

/* Callback function that will be executed when the method "PubSub configurator
 *  (delete config)" is called. */
static UA_StatusCode
UA_deletePubSubConfigMethodCallback(UA_Server *server,
                                    const UA_NodeId *sessionId, void *sessionContext,
                                    const UA_NodeId *methodId, void *methodContext,
                                    const UA_NodeId *objectId, void *objectContext,
                                    size_t inputSize, const UA_Variant *input,
                                    size_t outputSize, UA_Variant *output) {
    UA_LOCK(&server->serviceMutex);
    UA_PubSubManager_delete(server, &server->pubSubManager);
    UA_UNLOCK(&server->serviceMutex);
    return UA_STATUSCODE_GOOD;
}

#endif

UA_StatusCode
initPubSubNS0(UA_Server *server) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
    UA_String profileArray[1];
    profileArray[0] = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp");

    retVal |= writePubSubNs0VariableArray(server,
           UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_SUPPORTEDTRANSPORTPROFILES),
                                          profileArray, 1, &UA_TYPES[UA_TYPES_STRING]);

    if(server->config.pubSubConfig.enableInformationModelMethods) {
        /* Add missing references */
        retVal |= addRef(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS),
                         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                         UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDDATASETFOLDER), true);
        retVal |= addRef(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS),
                         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                         UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDPUBLISHEDDATAITEMS), true);
        retVal |= addRef(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS),
                         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                         UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEPUBLISHEDDATASET), true);
        retVal |= addRef(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS),
                         UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
                         UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEDATASETFOLDER), true);

        /* Set method callbacks */
        retVal |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_ADDCONNECTION), addPubSubConnectionAction);
        retVal |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_REMOVECONNECTION), removeConnectionAction);
        retVal |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDDATASETFOLDER), addDataSetFolderAction);
        retVal |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEDATASETFOLDER), removeDataSetFolderAction);
        retVal |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDPUBLISHEDDATAITEMS), addPublishedDataItemsAction);
        retVal |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEPUBLISHEDDATASET), removePublishedDataSetAction);
        retVal |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHEDDATAITEMSTYPE_ADDVARIABLES), addVariablesAction);
        retVal |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHEDDATAITEMSTYPE_REMOVEVARIABLES), removeVariablesAction);
        retVal |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDWRITERGROUP), addWriterGroupAction);
        retVal |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDREADERGROUP), addReaderGroupAction);
        retVal |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_REMOVEGROUP), removeGroupAction);
        retVal |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_WRITERGROUPTYPE_ADDDATASETWRITER), addDataSetWriterAction);
        retVal |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_WRITERGROUPTYPE_REMOVEDATASETWRITER), removeDataSetWriterAction);
        retVal |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_READERGROUPTYPE_ADDDATASETREADER), addDataSetReaderAction);
        retVal |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_READERGROUPTYPE_REMOVEDATASETREADER), removeDataSetReaderAction);
        retVal |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_PUBSUBCONFIGURATION_RESERVEIDS), addReserveIdsAction);
#ifdef UA_ENABLE_PUBSUB_SKS
        retVal |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_SETSECURITYKEYS), setSecurityKeysAction);
        retVal |= setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_GETSECURITYKEYS), getSecurityKeysAction);
#endif

#ifdef UA_ENABLE_PUBSUB_FILE_CONFIG
        /* Adds method node to server. This method is used to load binary files for
         * PubSub configuration and delete / replace old PubSub configurations. */
        UA_Argument inputArgument;
        UA_Argument_init(&inputArgument);
        inputArgument.description = UA_LOCALIZEDTEXT("", "PubSub config binfile");
        inputArgument.name = UA_STRING("BinFile");
        inputArgument.dataType = UA_TYPES[UA_TYPES_BYTESTRING].typeId;
        inputArgument.valueRank = UA_VALUERANK_SCALAR;

        UA_MethodAttributes configAttr = UA_MethodAttributes_default;
        configAttr.description = UA_LOCALIZEDTEXT("","Load binary configuration file");
        configAttr.displayName = UA_LOCALIZEDTEXT("","LoadPubSubConfigurationFile");
        configAttr.executable = true;
        configAttr.userExecutable = true;
        retVal |= addMethodNode(server, UA_NODEID_NULL,
                                UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE),
                                UA_NODEID_NUMERIC(0, UA_NS0ID_HASORDEREDCOMPONENT),
                                UA_QUALIFIEDNAME(1, "PubSub configuration"),
                                &configAttr, UA_loadPubSubConfigMethodCallback,
                                1, &inputArgument, UA_NODEID_NULL, NULL,
                                0, NULL, UA_NODEID_NULL, NULL,
                                NULL, NULL);

        /* Adds method node to server. This method is used to delete the current
         * PubSub configuration. */
        configAttr.description = UA_LOCALIZEDTEXT("","Delete current PubSub configuration");
        configAttr.displayName = UA_LOCALIZEDTEXT("","DeletePubSubConfiguration");
        configAttr.executable = true;
        configAttr.userExecutable = true;
        retVal |= addMethodNode(server, UA_NODEID_NULL,
                                UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE),
                                UA_NODEID_NUMERIC(0, UA_NS0ID_HASORDEREDCOMPONENT),
                                UA_QUALIFIEDNAME(1, "Delete PubSub config"),
                                &configAttr, UA_deletePubSubConfigMethodCallback,
                                0, NULL, UA_NODEID_NULL, NULL,
                                0, NULL, UA_NODEID_NULL, NULL,
                                NULL, NULL);
#endif
    } else {
        /* Remove methods */
        retVal |= deleteReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE),
                                  UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
                                  UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_ADDCONNECTION),
                                  false);
        retVal |= deleteReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE),
                                  UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
                                  UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_REMOVECONNECTION),
                                  false);
    }

    /* Set the object-type destructors */
    UA_NodeTypeLifecycle lifeCycle;
    lifeCycle.constructor = NULL;

    lifeCycle.destructor = connectionTypeDestructor;
    retVal |= setNodeTypeLifecycle(server,
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE),
                                   lifeCycle);

    lifeCycle.destructor = writerGroupTypeDestructor;
    retVal |= setNodeTypeLifecycle(server,
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_WRITERGROUPTYPE),
                                   lifeCycle);

    lifeCycle.destructor = readerGroupTypeDestructor;
    retVal |= setNodeTypeLifecycle(server,
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_READERGROUPTYPE),
                                   lifeCycle);

    lifeCycle.destructor = dataSetWriterTypeDestructor;
    retVal |= setNodeTypeLifecycle(server,
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETWRITERTYPE),
                                   lifeCycle);

    lifeCycle.destructor = publishedDataItemsTypeDestructor;
    retVal |= setNodeTypeLifecycle(server,
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHEDDATAITEMSTYPE),
                                   lifeCycle);

    lifeCycle.destructor = dataSetReaderTypeDestructor;
    retVal |= setNodeTypeLifecycle(server,
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETREADERTYPE),
                                   lifeCycle);

    lifeCycle.destructor = standaloneSubscribedDataSetTypeDestructor;
    retVal |= setNodeTypeLifecycle(server,
                                   UA_NODEID_NUMERIC(0, UA_NS0ID_STANDALONESUBSCRIBEDDATASETTYPE),
                                   lifeCycle);

    return retVal;
}

UA_StatusCode
connectDataSetReaderToDataSet(UA_Server *server, UA_NodeId dsrId, UA_NodeId standaloneSdsId) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_StatusCode retVal = UA_STATUSCODE_GOOD;

    UA_NodeId dataSetMetaDataOnDsrId =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetMetaData"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), dsrId);
    UA_NodeId subscribedDataSetOnDsrId =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "SubscribedDataSet"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), dsrId);
    UA_NodeId dataSetMetaDataOnSdsId =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "DataSetMetaData"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), standaloneSdsId);
    UA_NodeId subscribedDataSetOnSdsId =
        findSingleChildNode(server, UA_QUALIFIEDNAME(0, "SubscribedDataSet"),
                            UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), standaloneSdsId);

    if(UA_NodeId_isNull(&dataSetMetaDataOnDsrId) ||
       UA_NodeId_isNull(&subscribedDataSetOnDsrId) ||
       UA_NodeId_isNull(&dataSetMetaDataOnSdsId) ||
       UA_NodeId_isNull(&subscribedDataSetOnSdsId))
        return UA_STATUSCODE_BADNOTFOUND;

    UA_NODESTORE_REMOVE(server, &dataSetMetaDataOnDsrId);
    UA_NODESTORE_REMOVE(server, &subscribedDataSetOnDsrId);

    retVal |= addRef(server, dsrId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                     UA_NODEID_NUMERIC(dataSetMetaDataOnSdsId.namespaceIndex,
                                       dataSetMetaDataOnSdsId.identifier.numeric), true);
    retVal |= addRef(server, dsrId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                     UA_NODEID_NUMERIC(subscribedDataSetOnSdsId.namespaceIndex,
                                       subscribedDataSetOnSdsId.identifier.numeric), true);

    return retVal;
}

#endif /* UA_ENABLE_PUBSUB_INFORMATIONMODEL */

/**** amalgamated original file "/src/pubsub/ua_pubsub_keystorage.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2019 ifak e.V. Magdeburg (Holger Zipper)
 * Copyright (c) 2022 Linutronix GmbH (Author: Muddasir Shakil)
 */


#ifdef UA_ENABLE_PUBSUB_SKS /* conditional compilation */

#define UA_REQ_CURRENT_TOKEN 0


UA_PubSubKeyStorage *
UA_PubSubKeyStorage_findKeyStorage(UA_Server *server, UA_String securityGroupId) {
    if(!server || UA_String_isEmpty(&securityGroupId))
        return NULL;

    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_PubSubKeyStorage *outKeyStorage;
    LIST_FOREACH(outKeyStorage, &server->pubSubManager.pubSubKeyList, keyStorageList) {
        if(UA_String_equal(&outKeyStorage->securityGroupID, &securityGroupId))
            return outKeyStorage;
    }
    return NULL;
}

UA_PubSubSecurityPolicy *
findPubSubSecurityPolicy(UA_Server *server, const UA_String *securityPolicyUri) {
    if(!server || !securityPolicyUri)
        return NULL;

    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_ServerConfig *config = &server->config;
    for(size_t i = 0; i < config->pubSubConfig.securityPoliciesSize; i++) {
        if(UA_String_equal(securityPolicyUri,
                           &config->pubSubConfig.securityPolicies[i].policyUri))
            return &config->pubSubConfig.securityPolicies[i];
    }
    return NULL;
}

static void
UA_PubSubKeyStorage_clearKeyList(UA_PubSubKeyStorage *keyStorage) {
    if(TAILQ_EMPTY(&keyStorage->keyList))
        return;

    UA_PubSubKeyListItem *item, *item_tmp;
    TAILQ_FOREACH_SAFE(item, &keyStorage->keyList, keyListEntry, item_tmp) {
        TAILQ_REMOVE(&keyStorage->keyList, item, keyListEntry);
        UA_ByteString_clear(&item->key);
        UA_free(item);
    }
    keyStorage->keyListSize = 0;
}

void
UA_PubSubKeyStorage_delete(UA_Server *server, UA_PubSubKeyStorage *keyStorage) {
    UA_assert(keyStorage != NULL);
    UA_assert(server != NULL);

    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Remove callback */
    if(!keyStorage->callBackId) {
        removeCallback(server, keyStorage->callBackId);
        keyStorage->callBackId = 0;
    }

    UA_PubSubKeyStorage_clearKeyList(keyStorage);
    UA_String_clear(&keyStorage->securityGroupID);
    UA_ClientConfig_clear(&keyStorage->sksConfig.clientConfig);
    UA_free(keyStorage);
}

UA_StatusCode
UA_PubSubKeyStorage_init(UA_Server *server, UA_PubSubKeyStorage *keyStorage,
                         const UA_String *securityGroupId,
                         UA_PubSubSecurityPolicy *policy,
                         UA_UInt32 maxPastKeyCount, UA_UInt32 maxFutureKeyCount) {
    UA_StatusCode res = UA_String_copy(securityGroupId, &keyStorage->securityGroupID);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    UA_UInt32 currentkeyCount = 1;
    keyStorage->maxPastKeyCount = maxPastKeyCount;
    keyStorage->maxFutureKeyCount = maxFutureKeyCount;
    keyStorage->maxKeyListSize = maxPastKeyCount + currentkeyCount + maxFutureKeyCount;
    keyStorage->policy = policy;

    /* Add this keystorage to the server keystoragelist */
    LIST_INSERT_HEAD(&server->pubSubManager.pubSubKeyList, keyStorage, keyStorageList);

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_PubSubKeyStorage_storeSecurityKeys(UA_Server *server, UA_PubSubKeyStorage *keyStorage,
                                      UA_UInt32 currentTokenId, const UA_ByteString *currentKey,
                                      UA_ByteString *futureKeys, size_t futureKeyCount,
                                      UA_Duration msKeyLifeTime) {
    UA_assert(server);
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_StatusCode retval = UA_STATUSCODE_BAD;

    if(futureKeyCount > 0 && !futureKeys) {
        retval = UA_STATUSCODE_BADARGUMENTSMISSING;
        goto error;
    }

    size_t keyNumber = futureKeyCount;

    if(currentKey && keyStorage->keyListSize == 0) {

        keyStorage->keyListSize++;
        UA_PubSubKeyListItem *keyItem =
            (UA_PubSubKeyListItem *)UA_calloc(1, sizeof(UA_PubSubKeyListItem));
        if(!keyItem)
            goto error;
        retval = UA_ByteString_copy(currentKey, &keyItem->key);
        if(UA_StatusCode_isBad(retval))
            goto error;

        keyItem->keyID = currentTokenId;

        TAILQ_INIT(&keyStorage->keyList);
        TAILQ_INSERT_HEAD(&keyStorage->keyList, keyItem, keyListEntry);
    }

    UA_PubSubKeyListItem *keyListIterator = TAILQ_FIRST(&keyStorage->keyList);
    UA_UInt32 startingTokenID = currentTokenId + 1;
    for(size_t i = 0; i < keyNumber; ++i) {
        retval = UA_PubSubKeyStorage_getKeyByKeyID(
            startingTokenID, keyStorage, &keyListIterator);
        /*Skipping key with matching KeyID in existing list*/
        if(retval == UA_STATUSCODE_BADNOTFOUND) {
            keyListIterator = UA_PubSubKeyStorage_push(keyStorage, &futureKeys[i], startingTokenID);
            if(!keyListIterator)
                goto error;

            keyStorage->keyListSize++;
        }
        if(startingTokenID == UA_UINT32_MAX)
            startingTokenID = 1;
        else
            ++startingTokenID;
    }

    /*update keystorage references*/
    retval = UA_PubSubKeyStorage_getKeyByKeyID(currentTokenId, keyStorage, &keyStorage->currentItem);
    if (retval != UA_STATUSCODE_GOOD && !keyStorage->currentItem)
        goto error;

    keyStorage->keyLifeTime = msKeyLifeTime;

    return retval;
error:
    if(keyStorage) {
        UA_PubSubKeyStorage_clearKeyList(keyStorage);
    }
    return retval;
}

UA_StatusCode
UA_PubSubKeyStorage_getKeyByKeyID(const UA_UInt32 keyId, UA_PubSubKeyStorage *keyStorage,
                                  UA_PubSubKeyListItem **keyItem) {

    if(!keyStorage)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_PubSubKeyListItem *item;
    TAILQ_FOREACH(item, &keyStorage->keyList, keyListEntry){
        if(item->keyID == keyId) {
            *keyItem = item;
            return UA_STATUSCODE_GOOD;
        }
    }
    return UA_STATUSCODE_BADNOTFOUND;
}

UA_PubSubKeyListItem *
UA_PubSubKeyStorage_push(UA_PubSubKeyStorage *keyStorage, const UA_ByteString *key,
                         UA_UInt32 keyID) {
    UA_PubSubKeyListItem *newItem = (UA_PubSubKeyListItem *)malloc(sizeof(UA_PubSubKeyListItem));
    if (!newItem)
        return NULL;

    newItem->keyID = keyID;
    UA_ByteString_copy(key, &newItem->key);
    TAILQ_INSERT_TAIL(&keyStorage->keyList, newItem, keyListEntry);

    return TAILQ_LAST(&keyStorage->keyList, keyListItems);
}

UA_StatusCode
UA_PubSubKeyStorage_addKeyRolloverCallback(UA_Server *server,
                                           UA_PubSubKeyStorage *keyStorage,
                                           UA_ServerCallback callback,
                                           UA_Duration timeToNextMs,
                                           UA_UInt64 *callbackID) {
    if(!server || !keyStorage || !callback || timeToNextMs <= 0)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_EventLoop *el = server->config.eventLoop;
    UA_DateTime dateTimeToNextKey = el->dateTime_nowMonotonic(el) +
        (UA_DateTime)(UA_DATETIME_MSEC * timeToNextMs);
    return el->addTimedCallback(el, (UA_Callback)callback, server, keyStorage,
                                dateTimeToNextKey, callbackID);
}

static UA_StatusCode
splitCurrentKeyMaterial(UA_PubSubKeyStorage *keyStorage, UA_ByteString *signingKey,
                        UA_ByteString *encryptingKey, UA_ByteString *keyNonce) {
    if(!keyStorage)
        return UA_STATUSCODE_BADNOTFOUND;

    if(!keyStorage->policy)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_PubSubSecurityPolicy *policy = keyStorage->policy;

    UA_ByteString key = keyStorage->currentItem->key;

    /*Check the main key length is the same according to policy*/
    if(key.length != policy->symmetricModule.secureChannelNonceLength)
        return UA_STATUSCODE_BADINTERNALERROR;

    /*Get Key Length according to policy*/
    size_t signingkeyLength =
        policy->symmetricModule.cryptoModule.signatureAlgorithm.getLocalKeyLength(NULL);
    size_t encryptkeyLength =
        policy->symmetricModule.cryptoModule.encryptionAlgorithm.getLocalKeyLength(NULL);
    /*Rest of the part is the keyNonce*/
    size_t keyNonceLength = key.length - signingkeyLength - encryptkeyLength;

    /*DivideKeys in origin ByteString*/
    signingKey->data = key.data;
    signingKey->length = signingkeyLength;

    encryptingKey->data = key.data + signingkeyLength;
    encryptingKey->length = encryptkeyLength;

    keyNonce->data = key.data + signingkeyLength + encryptkeyLength;
    keyNonce->length = keyNonceLength;

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
setPubSubGroupEncryptingKey(UA_Server *server, UA_NodeId PubSubGroupId, UA_UInt32 securityTokenId,
                            UA_ByteString signingKey, UA_ByteString encryptingKey,
                            UA_ByteString keyNonce) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    UA_StatusCode retval =
        setWriterGroupEncryptionKeys(server, PubSubGroupId, securityTokenId,
                                     signingKey, encryptingKey, keyNonce);
    if(retval == UA_STATUSCODE_BADNOTFOUND)
        retval = setReaderGroupEncryptionKeys(server, PubSubGroupId, securityTokenId,
                                              signingKey, encryptingKey, keyNonce);
    return retval;
}

static UA_StatusCode
setPubSubGroupEncryptingKeyForMatchingSecurityGroupId(UA_Server *server,
                                                      UA_String securityGroupId,
                                                      UA_UInt32 securityTokenId,
                                                      UA_ByteString signingKey,
                                                      UA_ByteString encryptingKey,
                                                      UA_ByteString keyNonce) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    UA_StatusCode retval = UA_STATUSCODE_BAD;
    UA_PubSubConnection *tmpPubSubConnections;

    /* Key storage is the same for all reader / writer groups, channel context isn't
     * => Update channelcontext in all Writergroups / ReaderGroups which have the same
     * securityGroupId*/
    TAILQ_FOREACH(tmpPubSubConnections, &server->pubSubManager.connections, listEntry) {
        /* For each writerGroup in server with matching SecurityGroupId */
        UA_WriterGroup *tmpWriterGroup;
        LIST_FOREACH(tmpWriterGroup, &tmpPubSubConnections->writerGroups, listEntry) {
            if(UA_String_equal(&tmpWriterGroup->config.securityGroupId, &securityGroupId)) {
                retval = setWriterGroupEncryptionKeys(server, tmpWriterGroup->identifier,
                                                      securityTokenId, signingKey,
                                                      encryptingKey, keyNonce);
                if(retval != UA_STATUSCODE_GOOD)
                    return retval;
            }
        }

        /* For each readerGroup in server with matching SecurityGroupId */
        UA_ReaderGroup *tmpReaderGroup;
        LIST_FOREACH(tmpReaderGroup, &tmpPubSubConnections->readerGroups, listEntry) {
            if(UA_String_equal(&tmpReaderGroup->config.securityGroupId, &securityGroupId)) {
                retval = setReaderGroupEncryptionKeys(server, tmpReaderGroup->identifier,
                                                      securityTokenId, signingKey,
                                                      encryptingKey, keyNonce);
                if(retval != UA_STATUSCODE_GOOD)
                    return retval;
            }
        }
    }
    return retval;
}

UA_StatusCode
UA_PubSubKeyStorage_activateKeyToChannelContext(UA_Server *server, UA_NodeId pubSubGroupId,
                                                UA_String securityGroupId) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    if(securityGroupId.data == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_PubSubKeyStorage *keyStorage =
        UA_PubSubKeyStorage_findKeyStorage(server, securityGroupId);
    if(!keyStorage)
        return UA_STATUSCODE_BADNOTFOUND;

    if(!keyStorage->policy && !(keyStorage->keyListSize > 0))
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_UInt32 securityTokenId = keyStorage->currentItem->keyID;

    /*DivideKeys in origin ByteString*/
    UA_ByteString signingKey;
    UA_ByteString encryptKey;
    UA_ByteString keyNonce;
    UA_StatusCode retval = splitCurrentKeyMaterial(keyStorage, &signingKey,
                                                   &encryptKey, &keyNonce);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    if(!UA_NodeId_isNull(&pubSubGroupId))
        retval = setPubSubGroupEncryptingKey(server, pubSubGroupId, securityTokenId,
                                             signingKey, encryptKey, keyNonce);
    else
        retval = setPubSubGroupEncryptingKeyForMatchingSecurityGroupId(
            server, securityGroupId, securityTokenId, signingKey, encryptKey, keyNonce);

    if(retval != UA_STATUSCODE_GOOD)
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Failed to set Encrypting keys with Error: %s",
                     UA_StatusCode_name(retval));

    return retval;
}

static void
nextGetSecuritykeysCallback(UA_Server *server, UA_PubSubKeyStorage *keyStorage) {
    UA_StatusCode retval = UA_STATUSCODE_BAD;
    if(!keyStorage) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "GetSecurityKeysCall Failed with error: KeyStorage does not exist "
                     "in the server");
        return;
    }
    retval = getSecurityKeysAndStoreFetchedKeys(server, keyStorage);
    if(retval != UA_STATUSCODE_GOOD)
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "GetSecurityKeysCall Failed with error: %s ",
                     UA_StatusCode_name(retval));
}

void
UA_PubSubKeyStorage_keyRolloverCallback(UA_Server *server, UA_PubSubKeyStorage *keyStorage) {
    /* Callbacks from the EventLoop are initially unlocked */
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode retval =
        UA_PubSubKeyStorage_addKeyRolloverCallback(server, keyStorage,
                                     (UA_ServerCallback)UA_PubSubKeyStorage_keyRolloverCallback,
                                                   keyStorage->keyLifeTime, &keyStorage->callBackId);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Failed to update keys for security group id '%.*s'. Reason: '%s'.",
                     (int)keyStorage->securityGroupID.length,
                     keyStorage->securityGroupID.data, UA_StatusCode_name(retval));
    }

    if(keyStorage->currentItem != TAILQ_LAST(&keyStorage->keyList, keyListItems)) {
        keyStorage->currentItem = TAILQ_NEXT(keyStorage->currentItem, keyListEntry);
        keyStorage->currentTokenId = keyStorage->currentItem->keyID;
        retval = UA_PubSubKeyStorage_activateKeyToChannelContext(server, UA_NODEID_NULL,
                                                                 keyStorage->securityGroupID);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                         "Failed to update keys for security group id '%.*s'. Reason: '%s'.",
                         (int)keyStorage->securityGroupID.length, keyStorage->securityGroupID.data,
                         UA_StatusCode_name(retval));
        }
    } else if(keyStorage->sksConfig.endpointUrl && keyStorage->sksConfig.reqId == 0) {
        UA_EventLoop *el = server->config.eventLoop;
        UA_DateTime now = el->dateTime_nowMonotonic(el);
        /*Publishers using a central SKS shall call GetSecurityKeys at a period of half the KeyLifetime */
        UA_Duration msTimeToNextGetSecurityKeys = keyStorage->keyLifeTime / 2;
        UA_DateTime dateTimeToNextGetSecurityKeys =
            now + (UA_DateTime)(UA_DATETIME_MSEC * msTimeToNextGetSecurityKeys);
        retval = server->config.eventLoop->addTimedCallback(
            server->config.eventLoop, (UA_Callback)nextGetSecuritykeysCallback, server,
            keyStorage, dateTimeToNextGetSecurityKeys, NULL);
    }
    UA_UNLOCK(&server->serviceMutex);
}

UA_StatusCode
UA_PubSubKeyStorage_update(UA_Server *server, UA_PubSubKeyStorage *keyStorage,
                           const UA_ByteString *currentKey, UA_UInt32 currentKeyID,
                           const size_t futureKeySize, UA_ByteString *futureKeys,
                           UA_Duration msKeyLifeTime) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    if(!keyStorage)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    UA_PubSubKeyListItem *keyListIterator = NULL;

    if(currentKeyID != 0){
        /* If currentKeyId is known then update keystorage currentItem */
        retval = UA_PubSubKeyStorage_getKeyByKeyID(currentKeyID, keyStorage,
                                                   &keyListIterator);
        if(retval == UA_STATUSCODE_GOOD && keyListIterator) {
            keyStorage->currentItem = keyListIterator;
            /* Add new keys at the end of KeyList */
            retval = UA_PubSubKeyStorage_storeSecurityKeys(server, keyStorage, currentKeyID,
                                                           NULL, futureKeys, futureKeySize,
                                                           msKeyLifeTime);
            if(retval != UA_STATUSCODE_GOOD)
                return retval;
        } else if(retval == UA_STATUSCODE_BADNOTFOUND) {
            /* If the CurrentTokenId is unknown, the existing list shall be
             * discarded and replaced by the fetched list */
            UA_PubSubKeyStorage_clearKeyList(keyStorage);
            retval = UA_PubSubKeyStorage_storeSecurityKeys(server, keyStorage,
                                                           currentKeyID, currentKey, futureKeys,
                                                           futureKeySize, msKeyLifeTime);
            if(retval != UA_STATUSCODE_GOOD)
                return retval;
        }
    }
    return retval;
}

void
UA_PubSubKeyStorage_detachKeyStorage(UA_Server *server, UA_PubSubKeyStorage *keyStorage) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    keyStorage->referenceCount--;
    if(keyStorage->referenceCount == 0) {
        LIST_REMOVE(keyStorage, keyStorageList);
        UA_PubSubKeyStorage_delete(server, keyStorage);
    }
}

/**
 * @brief It holds the information required in the async callback to
 * GetSecurityKeys method Call.
 */
typedef struct {
    UA_Server *server;
    UA_PubSubKeyStorage *ks;
    UA_UInt32 startingTokenId;
    UA_UInt32 requestedKeyCount;
    UA_DelayedCallback dc;
} sksClientContext;

static void sksClientCleanupCb(void *client, void *context);

static void
addDelayedSksClientCleanupCb(UA_Client *client, sksClientContext *context) {
    /* Register at most once */
    if(context->dc.application != NULL)
        return;
    context->dc.application = client;
    context->dc.callback = sksClientCleanupCb;
    context->dc.context = context;
    client->config.eventLoop->addDelayedCallback(client->config.eventLoop, &context->dc);
}

static void
sksClientCleanupCb(void *client, void *context) {
    UA_Client *sksClient = (UA_Client *)client;
    sksClientContext *ctx = (sksClientContext*)context;

    /* we do not want to call state change Callback when cleaning up */
    sksClient->config.stateCallback = NULL;

    if(sksClient->sessionState > UA_SESSIONSTATE_CLOSED &&
       sksClient->channel.state < UA_SECURECHANNELSTATE_CLOSED) {
        sksClient->config.eventLoop->
            addDelayedCallback(sksClient->config.eventLoop, &ctx->dc);
        UA_Client_disconnectAsync(sksClient);
        return;
    }

    if(sksClient->channel.state == UA_SECURECHANNELSTATE_CLOSED) {
        /* We cannot make deep copy of the following pointers because these have
         * internal structures, therefore we do not free them here. These will
         * be freed in UA_PubSubKeyStorage_delete. */
        sksClient->config.securityPolicies = NULL;
        sksClient->config.securityPoliciesSize = 0;
        sksClient->config.certificateVerification.context = NULL;
        sksClient->config.logging = NULL;
        sksClient->config.clientContext = NULL;
        UA_Client_delete(sksClient);
        UA_free(context);
    } else {
        sksClient->config.eventLoop->
            addDelayedCallback(sksClient->config.eventLoop, &ctx->dc);
    }
}

static void
storeFetchedKeys(UA_Client *client, void *userdata, UA_UInt32 requestId,
                 UA_CallResponse *response) {

    sksClientContext *ctx = (sksClientContext *)userdata;
    UA_PubSubKeyStorage *ks = ctx->ks;
    UA_Server *server = ctx->server;
    UA_StatusCode retval = response->responseHeader.serviceResult;

    UA_LOCK(&server->serviceMutex);
    /* check if the call to getSecurityKeys was a success */
    if(response->resultsSize != 0)
        retval = response->results->statusCode;
    if(retval != UA_STATUSCODE_GOOD) {
         UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "SKS Client: Failed to call GetSecurityKeys on SKS server with error: %s ",
                     UA_StatusCode_name(retval));
        goto cleanup;
    }

    UA_String *securityPolicyUri = (UA_String *)response->results->outputArguments[0].data;
    UA_UInt32 firstTokenId = *(UA_UInt32 *)response->results->outputArguments[1].data;
    UA_ByteString *keys = (UA_ByteString *)response->results->outputArguments[2].data;
    UA_ByteString *currentKey = &keys[0];
    UA_UInt32 currentKeyCount = 1;
    UA_ByteString *futureKeys = &keys[currentKeyCount];
    size_t futureKeySize = response->results->outputArguments[2].arrayLength - currentKeyCount;
    UA_Duration msKeyLifeTime = *(UA_Duration *)response->results->outputArguments[4].data;

    if(!UA_String_equal(securityPolicyUri, &ks->policy->policyUri)) {
        retval = UA_STATUSCODE_BADSECURITYPOLICYREJECTED;
        goto cleanup;
    }

    if(ks->keyListSize == 0) {
        retval = UA_PubSubKeyStorage_storeSecurityKeys(server, ks, firstTokenId,
                                                       currentKey, futureKeys,
                                                       futureKeySize, msKeyLifeTime);
        if(retval != UA_STATUSCODE_GOOD)
            goto cleanup;
    } else {
        retval = UA_PubSubKeyStorage_update(server, ks, currentKey, firstTokenId,
                                            futureKeySize, futureKeys, msKeyLifeTime);
        if(retval != UA_STATUSCODE_GOOD)
            goto cleanup;
    }

    /**
     * After a new batch of keys is fetched from SKS server, the key storage is updated
     * with new keys and new keylifetime. Also the remaining time for current
     * keyRollover is also returned. When setting a new keyRollover callback, the
     * previous callback must be removed so that the keyRollover does not happen twice
     */
    if(ks->callBackId != 0) {
        server->config.eventLoop->removeCyclicCallback(server->config.eventLoop,
                                                       ks->callBackId);
        ks->callBackId = 0;
    }

    UA_Duration msTimeToNextKey =
        *(UA_Duration *)response->results->outputArguments[3].data;
    if(!(msTimeToNextKey > 0))
        msTimeToNextKey = ks->keyLifeTime;
    retval = UA_PubSubKeyStorage_addKeyRolloverCallback(
        server, ks, (UA_ServerCallback)UA_PubSubKeyStorage_keyRolloverCallback,
        msTimeToNextKey, &ks->callBackId);

cleanup:
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Failed to store the fetched keys from SKS server with error: %s",
                     UA_StatusCode_name(retval));
    }
    /* call user callback to notify about the status */
    UA_UNLOCK(&server->serviceMutex);
    if(ks->sksConfig.userNotifyCallback)
        ks->sksConfig.userNotifyCallback(server, retval, ks->sksConfig.context);
    ks->sksConfig.reqId = 0;
    UA_Client_disconnectAsync(client);
    addDelayedSksClientCleanupCb(client, ctx);
}

static UA_StatusCode
callGetSecurityKeysMethod(UA_Client *client) {

    sksClientContext *ctx = (sksClientContext *)client->config.clientContext;

    UA_Variant inputArguments[3];
    UA_Variant_setScalar(&inputArguments[0], &ctx->ks->securityGroupID,
                         &UA_TYPES[UA_TYPES_STRING]);
    UA_Variant_setScalar(&inputArguments[1], &ctx->startingTokenId,
                         &UA_TYPES[UA_TYPES_UINT32]);
    UA_Variant_setScalar(&inputArguments[2], &ctx->requestedKeyCount,
                         &UA_TYPES[UA_TYPES_UINT32]);

    UA_NodeId objectId = UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE);
    UA_NodeId methodId = UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_GETSECURITYKEYS);
    size_t inputArgumentsSize = 3;

    UA_StatusCode retval = UA_Client_call_async(client, objectId, methodId, inputArgumentsSize,
                                inputArguments, storeFetchedKeys, (void *)ctx, &ctx->ks->sksConfig.reqId);
    return retval;
}

static void
onConnect(UA_Client *client, UA_SecureChannelState channelState,
          UA_SessionState sessionState, UA_StatusCode connectStatus) {
    UA_Boolean triggerSKSCleanup = false;
    if(connectStatus != UA_STATUSCODE_GOOD &&
       connectStatus != UA_STATUSCODE_BADNOTCONNECTED &&
       sessionState != UA_SESSIONSTATE_ACTIVATED) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "SKS Client: Failed to connect SKS server with error: %s ",
                     UA_StatusCode_name(connectStatus));
        triggerSKSCleanup = true;
    }
    if(connectStatus == UA_STATUSCODE_GOOD && sessionState == UA_SESSIONSTATE_ACTIVATED) {
        connectStatus = callGetSecurityKeysMethod(client);
        if(connectStatus != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_SERVER,
                         "SKS Client: Failed to call GetSecurityKeys on SKS server with "
                         "error: %s ",
                         UA_StatusCode_name(connectStatus));
            triggerSKSCleanup = true;
        }
    }
    if(triggerSKSCleanup) {
        /* call user callback to notify about the status */
        sksClientContext *ctx = (sksClientContext *)client->config.clientContext;
        UA_PubSubKeyStorage *ks = ctx->ks;
        if(ks->sksConfig.userNotifyCallback)
            ks->sksConfig.userNotifyCallback(ctx->server, connectStatus,
                                             ks->sksConfig.context);
        UA_Client_disconnectAsync(client);
        addDelayedSksClientCleanupCb(client, ctx);
    }
}

static void
setServerEventloopOnSksClient(UA_ClientConfig *cc, UA_EventLoop *externalEventloop) {
    UA_assert(externalEventloop != NULL);
    cc->eventLoop = externalEventloop;
    cc->externalEventLoop = true;
}

UA_StatusCode
getSecurityKeysAndStoreFetchedKeys(UA_Server *server, UA_PubSubKeyStorage *keyStorage) {
    UA_StatusCode retval = UA_STATUSCODE_BAD;
    UA_UInt32 startingTokenId = UA_REQ_CURRENT_TOKEN;
    UA_UInt32 requestKeyCount = UA_UINT32_MAX;

    if(keyStorage->sksConfig.reqId != 0) {
        UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_SERVER,
                    "SKS Client: SKS Pull request in process ");
        return UA_STATUSCODE_GOOD;
    }

    UA_ClientConfig cc;
    memset(&cc, 0, sizeof(UA_ClientConfig));

    /* over write the client config with user specified SKS config */
    retval = UA_ClientConfig_copy(&keyStorage->sksConfig.clientConfig, &cc);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    setServerEventloopOnSksClient(&cc, server->config.eventLoop);

    /* this is cleanedup in sksClientCleanupCb */
    sksClientContext *ctx   = (sksClientContext *)UA_calloc(1, sizeof(sksClientContext));
    if(!ctx)
         return UA_STATUSCODE_BADOUTOFMEMORY;
    ctx->ks = keyStorage;
    ctx->server = server;
    ctx->startingTokenId = startingTokenId;
    ctx->requestedKeyCount = requestKeyCount;
    cc.clientContext = ctx;

    UA_Client *client = UA_Client_newWithConfig(&cc);
    if(!client)
        return retval;
    /* connect to sks server */
    retval = UA_Client_connectAsync(client, keyStorage->sksConfig.endpointUrl);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "Failed to connect SKS server with error: %s ",
                     UA_StatusCode_name(retval));
        /* Make sure the client channel state is closed and not fresh, otherwise, eventloop will
        keep waiting for the client status to go from Fresh to closed in UA_Client_delete*/
        client->channel.state = UA_SECURECHANNELSTATE_CLOSED;
        /* this client instance will be cleared in the next event loop iteration */
        addDelayedSksClientCleanupCb(client, ctx);
        return retval;
    }

    /* add user specified callback, if the client is properly configured. */
    client->config.stateCallback = onConnect;

    return retval;
}

UA_StatusCode
UA_Server_setSksClient(UA_Server *server, UA_String securityGroupId,
                       UA_ClientConfig *clientConfig, const char *endpointUrl,
                       UA_Server_sksPullRequestCallback callback, void *context) {
    if(!server || !clientConfig || !endpointUrl)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_StatusCode retval = UA_STATUSCODE_BADNOTFOUND;
    UA_LOCK(&server->serviceMutex);
    UA_PubSubKeyStorage *ks = UA_PubSubKeyStorage_findKeyStorage(server, securityGroupId);
    if(!ks) {
        UA_UNLOCK(&server->serviceMutex);
        return retval;
    }

    UA_ClientConfig_copy(clientConfig, &ks->sksConfig.clientConfig);
    /*Clear the content of original config, so that no body can access the original config */
    clientConfig->authSecurityPolicies = NULL;
    clientConfig->certificateVerification.context = NULL;
    clientConfig->eventLoop = NULL;
    clientConfig->logging = NULL;
    clientConfig->securityPolicies = NULL;
    UA_ClientConfig_clear(clientConfig);

    ks->sksConfig.endpointUrl = endpointUrl;
    ks->sksConfig.userNotifyCallback = callback;
    ks->sksConfig.context = context;
    /* if keys are not previously fetched, then first call GetSecurityKeys*/
    if(ks->keyListSize == 0) {
        retval = getSecurityKeysAndStoreFetchedKeys(server, ks);
    }
    UA_UNLOCK(&server->serviceMutex);
    return retval;
}

#endif

/**** amalgamated original file "/src/pubsub/ua_pubsub_securitygroup.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2019 ifak e.V. Magdeburg (Holger Zipper)
 * Copyright (c) 2022 Linutronix GmbH (Author: Muddasir Shakil)
 */



#ifdef UA_ENABLE_PUBSUB_SKS /* conditional compilation */


#define UA_PUBSUB_KEYMATERIAL_NONCELENGTH 32

UA_SecurityGroup *
UA_SecurityGroup_findSGbyName(UA_Server *server, UA_String securityGroupName) {
    UA_SecurityGroup *tmpSG;
    TAILQ_FOREACH(tmpSG, &server->pubSubManager.securityGroups, listEntry) {
        if(UA_String_equal(&securityGroupName, &tmpSG->config.securityGroupName))
            return tmpSG;
    }
    return NULL;
}

UA_StatusCode
UA_SecurityGroupConfig_copy(const UA_SecurityGroupConfig *src,
                            UA_SecurityGroupConfig *dst) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;

    memcpy(dst, src, sizeof(UA_SecurityGroupConfig));
    if(UA_String_copy(&src->securityGroupName, &dst->securityGroupName) !=
       UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BAD;

    if(UA_String_copy(&src->securityPolicyUri, &dst->securityPolicyUri) !=
       UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BAD;
    return retval;
}

static UA_StatusCode
generateKeyData(const UA_PubSubSecurityPolicy *policy, UA_ByteString *key) {
    if(!key || !policy)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_StatusCode retVal;

    /* Can't not found in specification for pubsub key generation, so use the idea of
     * securechannel, see specification 1.0.3 6.7.5 Deriving keys for more details
     In pubsub we do get have OpenSecureChannel request, so we cannot have Client or Server Nonce*/
    UA_Byte secretBytes[UA_PUBSUB_KEYMATERIAL_NONCELENGTH];
    UA_ByteString secret;
    secret.length = UA_PUBSUB_KEYMATERIAL_NONCELENGTH;
    secret.data = secretBytes;

    UA_Byte seedBytes[UA_PUBSUB_KEYMATERIAL_NONCELENGTH];
    UA_ByteString seed;
    seed.data = seedBytes;
    seed.length = UA_PUBSUB_KEYMATERIAL_NONCELENGTH;
    memset(seed.data, 0, seed.length);
    retVal = policy->symmetricModule.generateNonce(policy->policyContext, &secret);
    retVal |= policy->symmetricModule.generateNonce(policy->policyContext, &seed);
    if(retVal != UA_STATUSCODE_GOOD)
        return retVal;

    retVal = policy->symmetricModule.generateKey(policy->policyContext, &secret, &seed, key);
    return retVal;
}

static void
updateSKSKeyStorage(UA_Server *server, UA_SecurityGroup *securityGroup){

    if(!securityGroup) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_PUBSUB,
                       "UpdateSKSKeyStorage callback failed with Error: %s ",
                       UA_StatusCode_name(UA_STATUSCODE_BADINVALIDARGUMENT));
        return;
    }

    UA_PubSubKeyStorage *keyStorage = securityGroup->keyStorage;

    UA_StatusCode retval = UA_STATUSCODE_BAD;
    UA_ByteString newKey;
    size_t keyLength = keyStorage->policy->symmetricModule.secureChannelNonceLength;

    retval = UA_ByteString_allocBuffer(&newKey, keyLength);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_PUBSUB,
                       "UpdateSKSKeyStorage callback failed to allocate memory for new key with Error: %s ",
                       UA_StatusCode_name(retval));
        return;
    }

    generateKeyData(keyStorage->policy, &newKey);
    UA_UInt32 newKeyID = TAILQ_LAST(&keyStorage->keyList, keyListItems)->keyID;

    if(newKeyID >= UA_UINT32_MAX)
        newKeyID = 1;
    else
        ++newKeyID;

    if(keyStorage->keyListSize >= keyStorage->maxKeyListSize) {
        /* reusing the preallocated memory of the oldest key for the new key material */
        UA_PubSubKeyListItem *oldestKey = TAILQ_FIRST(&keyStorage->keyList);
        TAILQ_REMOVE(&keyStorage->keyList, oldestKey, keyListEntry);
        TAILQ_INSERT_TAIL(&keyStorage->keyList, oldestKey, keyListEntry);
        UA_ByteString_clear(&oldestKey->key);
        oldestKey->keyID = newKeyID;
        UA_ByteString_copy(&newKey, &oldestKey->key);
    } else {
        UA_PubSubKeyListItem *newItem =
            UA_PubSubKeyStorage_push(keyStorage, &newKey, newKeyID);
        if(!newItem) {
            UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_PUBSUB,
                           "UpdateSKSKeyStorage callback failed to add new key to the "
                           "sks keystorage for the SecurityGroup %.*s",
                           (int)securityGroup->securityGroupId.length,
                           securityGroup->securityGroupId.data);
            UA_Byte_delete(newKey.data);
            return;
        }
        keyStorage->keyListSize++;
    }

    UA_PubSubKeyListItem *nextCurrentItem = TAILQ_NEXT(keyStorage->currentItem, keyListEntry);
    if(nextCurrentItem)
        keyStorage->currentItem = nextCurrentItem;

    UA_EventLoop *el = server->config.eventLoop;
    securityGroup->baseTime = el->dateTime_nowMonotonic(el);

    /* We allocated memory for data with allocBuffer so now we free it */
    UA_ByteString_clear(&newKey);
}

static UA_StatusCode
initializeKeyStorageWithKeys(UA_Server *server, UA_SecurityGroup *securityGroup) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_PubSubSecurityPolicy *policy =
        findPubSubSecurityPolicy(server, &securityGroup->config.securityPolicyUri);
    if(!policy)
        return UA_STATUSCODE_BADSECURITYPOLICYREJECTED;

    UA_PubSubKeyStorage *ks = (UA_PubSubKeyStorage *)
        UA_calloc(1, sizeof(UA_PubSubKeyStorage));
    if(!ks)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode retval =
        UA_PubSubKeyStorage_init(server, ks, &securityGroup->securityGroupId,
                                 policy, securityGroup->config.maxPastKeyCount,
                                 securityGroup->config.maxFutureKeyCount);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free(ks);
        return retval;
    }

    ks->referenceCount++;
    securityGroup->keyStorage = ks;

    UA_ByteString currentKey;
    size_t keyLength = ks->policy->symmetricModule.secureChannelNonceLength;
    retval = UA_ByteString_allocBuffer(&currentKey, keyLength);
    retval = generateKeyData(ks->policy, &currentKey);

    UA_ByteString *futurekeys = (UA_ByteString *)UA_calloc(securityGroup->config.maxFutureKeyCount, sizeof(UA_ByteString));
    for(size_t i = 0; i < securityGroup->config.maxFutureKeyCount; i++) {
        retval = UA_ByteString_allocBuffer(&futurekeys[i], keyLength);
        retval = generateKeyData(ks->policy, &futurekeys[i]);
    }

    UA_UInt32 startingKeyId = 1;
    retval = UA_PubSubKeyStorage_storeSecurityKeys(server, securityGroup->keyStorage,
                                                   startingKeyId, &currentKey, futurekeys,
                                                   securityGroup->config.maxFutureKeyCount,
                                                   securityGroup->config.keyLifeTime);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    UA_EventLoop *el = server->config.eventLoop;
    securityGroup->baseTime = el->dateTime_nowMonotonic(el);
    retval = addRepeatedCallback(server, (UA_ServerCallback)updateSKSKeyStorage,
                                 securityGroup, securityGroup->config.keyLifeTime,
                                 &securityGroup->callbackId);

cleanup:
    UA_Array_delete(futurekeys, securityGroup->config.maxFutureKeyCount,
                    &UA_TYPES[UA_TYPES_BYTESTRING]);
    UA_ByteString_clear(&currentKey);
    if(retval != UA_STATUSCODE_GOOD)
        UA_PubSubKeyStorage_delete(server, ks);
    return retval;
}

static UA_StatusCode
addSecurityGroup(UA_Server *server, UA_NodeId securityGroupFolderNodeId,
                 const UA_SecurityGroupConfig *securityGroupConfig,
                 UA_NodeId *securityGroupNodeId) {
    if(!securityGroupConfig)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    /*check minimal config parameters*/
    if(!securityGroupConfig->keyLifeTime ||
       UA_String_isEmpty(&securityGroupConfig->securityGroupName) ||
       UA_String_isEmpty(&securityGroupConfig->securityPolicyUri))
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    if(UA_SecurityGroup_findSGbyName(server, securityGroupConfig->securityGroupName))
        return UA_STATUSCODE_BADNODEIDEXISTS;

    UA_PubSubSecurityPolicy *policy =
        findPubSubSecurityPolicy(server, &securityGroupConfig->securityPolicyUri);
    if(!policy)
        return UA_STATUSCODE_BADSECURITYPOLICYREJECTED;

    if(securityGroupConfig->securityGroupName.length > 512)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode retval = UA_STATUSCODE_BAD;

    UA_SecurityGroup *newSecurityGroup =
        (UA_SecurityGroup *)UA_calloc(1, sizeof(UA_SecurityGroup));
    if(!newSecurityGroup)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    memset(newSecurityGroup, 0, sizeof(UA_SecurityGroup));
    UA_SecurityGroupConfig_copy(securityGroupConfig, &newSecurityGroup->config);

#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    retval = UA_NodeId_copy(&securityGroupFolderNodeId,
                            &newSecurityGroup->securityGroupFolderId);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_SecurityGroup_delete(newSecurityGroup);
        return retval;
    }
#endif

    retval = UA_String_copy(&securityGroupConfig->securityGroupName,
                            &newSecurityGroup->securityGroupId);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_SecurityGroup_delete(newSecurityGroup);
        return retval;
    }

    retval = initializeKeyStorageWithKeys(server, newSecurityGroup);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_SecurityGroup_delete(newSecurityGroup);
        return retval;
    }

#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    retval = addSecurityGroupRepresentation(server, newSecurityGroup);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Add SecurityGroup failed with error: %s.",
                     UA_StatusCode_name(retval));
        UA_SecurityGroup_delete(newSecurityGroup);
        return retval;
    }
#else
    UA_PubSubManager_generateUniqueNodeId(&server->pubSubManager,
                                          &newSecurityGroup->securityGroupNodeId);
#endif
    if(securityGroupNodeId)
        UA_NodeId_copy(&newSecurityGroup->securityGroupNodeId, securityGroupNodeId);

    TAILQ_INSERT_TAIL(&server->pubSubManager.securityGroups, newSecurityGroup, listEntry);

    server->pubSubManager.securityGroupsSize++;
    return retval;
}

UA_StatusCode
UA_Server_addSecurityGroup(UA_Server *server, UA_NodeId securityGroupFolderNodeId,
                           const UA_SecurityGroupConfig *securityGroupConfig,
                           UA_NodeId *securityGroupNodeId) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode retval = addSecurityGroup(server, securityGroupFolderNodeId,
                                            securityGroupConfig, securityGroupNodeId);
    UA_UNLOCK(&server->serviceMutex);
    return retval;
}

UA_SecurityGroup *
UA_SecurityGroup_findSGbyId(UA_Server *server, UA_NodeId identifier) {
    UA_SecurityGroup *tmpSG;
    TAILQ_FOREACH(tmpSG, &server->pubSubManager.securityGroups, listEntry) {
        if(UA_NodeId_equal(&identifier, &tmpSG->securityGroupNodeId))
            return tmpSG;
    }
    return NULL;
}

static void
UA_SecurityGroupConfig_clear(UA_SecurityGroupConfig *config) {
    config->keyLifeTime = 0;
    config->maxFutureKeyCount = 0;
    UA_String_clear(&config->securityGroupName);
    UA_String_clear(&config->securityPolicyUri);
}

static void
UA_SecurityGroup_clear(UA_SecurityGroup *securityGroup) {
    UA_SecurityGroupConfig_clear(&securityGroup->config);
    UA_String_clear(&securityGroup->securityGroupId);
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    UA_NodeId_clear(&securityGroup->securityGroupFolderId);
#endif
    UA_NodeId_clear(&securityGroup->securityGroupNodeId);
}

void
UA_SecurityGroup_delete(UA_SecurityGroup *securityGroup) {
    UA_SecurityGroup_clear(securityGroup);
    UA_free(securityGroup);
}

void
removeSecurityGroup(UA_Server *server, UA_SecurityGroup *securityGroup) {
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    deleteNode(server, securityGroup->securityGroupNodeId, true);
#endif

    /* Unlink from the server */
    TAILQ_REMOVE(&server->pubSubManager.securityGroups, securityGroup, listEntry);
    server->pubSubManager.securityGroupsSize--;
    if(securityGroup->callbackId > 0)
        removeCallback(server, securityGroup->callbackId);

    if(securityGroup->keyStorage) {
        UA_PubSubKeyStorage_detachKeyStorage(server, securityGroup->keyStorage);
        securityGroup->keyStorage = NULL;
    }

    UA_SecurityGroup_delete(securityGroup);
}

UA_StatusCode
UA_Server_removeSecurityGroup(UA_Server *server, const UA_NodeId securityGroup) {
    UA_LOCK(&server->serviceMutex);
    UA_SecurityGroup *sg = UA_SecurityGroup_findSGbyId(server, securityGroup);
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(sg) {
        removeSecurityGroup(server, sg);
    } else {
        res = UA_STATUSCODE_BADBOUNDNOTFOUND;
    }
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

#endif

/**** amalgamated original file "/src/pubsub/ua_pubsub_config.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright (c) 2020 Yannick Wallerer, Siemens AG
 * Copyright (c) 2020 Thomas Fischer, Siemens AG
 */


#if defined(UA_ENABLE_PUBSUB) && defined(UA_ENABLE_PUBSUB_FILE_CONFIG)

static UA_StatusCode
createPubSubConnection(UA_Server *server,
                       const UA_PubSubConnectionDataType *connection,
                       UA_UInt32 pdsCount, UA_NodeId *pdsIdent);

static UA_StatusCode
createWriterGroup(UA_Server *server,
                  const UA_WriterGroupDataType *writerGroupParameters,
                  UA_NodeId connectionIdent, UA_UInt32 pdsCount,
                  const UA_NodeId *pdsIdent);

static UA_StatusCode
createDataSetWriter(UA_Server *server,
                    const UA_DataSetWriterDataType *dataSetWriterParameters,
                    UA_NodeId writerGroupIdent, UA_UInt32 pdsCount,
                    const UA_NodeId *pdsIdent);

static UA_StatusCode
createReaderGroup(UA_Server *server,
                  const UA_ReaderGroupDataType *readerGroupParameters,
                  UA_NodeId connectionIdent);

static UA_StatusCode
createDataSetReader(UA_Server *server,
                    const UA_DataSetReaderDataType *dataSetReaderParameters,
                    UA_NodeId readerGroupIdent);

static UA_StatusCode
createPublishedDataSet(UA_Server *server,
                       const UA_PublishedDataSetDataType *publishedDataSetParameters,
                       UA_NodeId *publishedDataSetIdent);

static UA_StatusCode
createDataSetFields(UA_Server *server,
                    const UA_NodeId *publishedDataSetIdent,
                    const UA_PublishedDataSetDataType *publishedDataSetParameters);

static UA_StatusCode
generatePubSubConfigurationDataType(UA_Server *server,
                                    UA_PubSubConfigurationDataType *pubSubConfiguration);

/* Gets PubSub Configuration from an ExtensionObject */
static UA_StatusCode
extractPubSubConfigFromExtensionObject(UA_Server *server,
                                       const UA_ExtensionObject *src,
                                       UA_PubSubConfigurationDataType **dst) {
    if(src->encoding != UA_EXTENSIONOBJECT_DECODED ||
       src->content.decoded.type != &UA_TYPES[UA_TYPES_UABINARYFILEDATATYPE]) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_PubSubManager_extractPubSubConfigFromDecodedObject] "
                     "Reading extensionObject failed");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_UABinaryFileDataType *binFile = (UA_UABinaryFileDataType*)src->content.decoded.data;

    if(binFile->body.arrayLength != 0 || binFile->body.arrayDimensionsSize != 0) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_PubSubManager_extractPubSubConfigFromDecodedObject] "
                     "Loading multiple configurations is not supported");
        return UA_STATUSCODE_BADNOTIMPLEMENTED;
    }

    if(binFile->body.type != &UA_TYPES[UA_TYPES_PUBSUBCONFIGURATIONDATATYPE]) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_PubSubManager_extractPubSubConfigFromDecodedObject] "
                     "Invalid datatype encoded in the binary file");
        return UA_STATUSCODE_BADTYPEMISMATCH;
    }

    *dst = (UA_PubSubConfigurationDataType*)binFile->body.data;
    return UA_STATUSCODE_GOOD;
}

/* Configures a PubSub Server with given PubSubConfigurationDataType object */
static UA_StatusCode
updatePubSubConfig(UA_Server *server,
                   const UA_PubSubConfigurationDataType *configurationParameters) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    if(configurationParameters == NULL) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_PubSubManager_updatePubSubConfig] Invalid argument");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_PubSubManager_delete(server, &server->pubSubManager);

    /* Configuration of Published DataSets: */
    UA_UInt32 pdsCount = (UA_UInt32)configurationParameters->publishedDataSetsSize;
    UA_NodeId *publishedDataSetIdent = (UA_NodeId*)UA_calloc(pdsCount, sizeof(UA_NodeId));
    if(!publishedDataSetIdent)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode res = UA_STATUSCODE_GOOD;

    for(UA_UInt32 i = 0; i < pdsCount; i++) {
        res = createPublishedDataSet(server,
                                     &configurationParameters->publishedDataSets[i],
                                     &publishedDataSetIdent[i]);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                         "[UA_PubSubManager_updatePubSubConfig] PDS creation failed");
            UA_free(publishedDataSetIdent);
            return res;
        }
    }

    /* Configuration of PubSub Connections: */
    if(configurationParameters->connectionsSize < 1) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "[UA_PubSubManager_updatePubSubConfig] no connection in "
                       "UA_PubSubConfigurationDataType");
        UA_free(publishedDataSetIdent);
        return UA_STATUSCODE_GOOD;
    }

    for(size_t i = 0; i < configurationParameters->connectionsSize; i++) {
        res = createPubSubConnection(server,
                                     &configurationParameters->connections[i],
                                     pdsCount, publishedDataSetIdent);
        if(res != UA_STATUSCODE_GOOD)
            break;
    }

    UA_free(publishedDataSetIdent);

    return res;
}

/* Function called by UA_PubSubManager_createPubSubConnection to set the
 * PublisherId of a certain connection. */
static UA_StatusCode
setConnectionPublisherId(UA_Server *server,
                         const UA_PubSubConnectionDataType *src,
                         UA_PubSubConnectionConfig *dst) {
    if(src->publisherId.type == &UA_TYPES[UA_TYPES_STRING]) {
        dst->publisherIdType = UA_PUBLISHERIDTYPE_STRING;
        dst->publisherId.string = *(UA_String*)src->publisherId.data;
    } else if(src->publisherId.type == &UA_TYPES[UA_TYPES_BYTE]) {
        dst->publisherIdType = UA_PUBLISHERIDTYPE_BYTE;
        dst->publisherId.byte = *((UA_Byte*)src->publisherId.data);
    } else if(src->publisherId.type == &UA_TYPES[UA_TYPES_UINT16]) {
        dst->publisherIdType = UA_PUBLISHERIDTYPE_UINT16;
        dst->publisherId.uint16 = *((UA_UInt16*)src->publisherId.data);
    } else if(src->publisherId.type == &UA_TYPES[UA_TYPES_UINT32]) {
        dst->publisherIdType = UA_PUBLISHERIDTYPE_UINT32;
        dst->publisherId.uint32 = *(UA_UInt32*)src->publisherId.data;
    } else if(src->publisherId.type == &UA_TYPES[UA_TYPES_UINT64]) {
        dst->publisherIdType = UA_PUBLISHERIDTYPE_UINT64;
        dst->publisherId.uint64 = *(UA_UInt64*)src->publisherId.data;
    } else {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_PubSubManager_setConnectionPublisherId] PublisherId is not valid.");
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return UA_STATUSCODE_GOOD;
}

/* Function called by UA_PubSubManager_createPubSubConnection to create all WriterGroups
 * and ReaderGroups that belong to a certain connection. */
static UA_StatusCode
createComponentsForConnection(UA_Server *server,
                              const UA_PubSubConnectionDataType *connParams,
                              UA_NodeId connectionIdent, UA_UInt32 pdsCount,
                              const UA_NodeId *pdsIdent) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* WriterGroups configuration */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    for(size_t i = 0; i < connParams->writerGroupsSize; i++) {
        res = createWriterGroup(server, &connParams->writerGroups[i],
                                connectionIdent, pdsCount, pdsIdent);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                         "[UA_PubSubManager_createComponentsForConnection] "
                         "Error occured during %d. WriterGroup Creation", (UA_UInt32)i+1);
            return res;
        }
    }

    /* ReaderGroups configuration */
    for(size_t j = 0; j < connParams->readerGroupsSize; j++) {
        res = createReaderGroup(server, &connParams->readerGroups[j], connectionIdent);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                         "[UA_PubSubManager_createComponentsForConnection] "
                         "Error occured during %d. ReaderGroup Creation", (UA_UInt32)j+1);
            return res;
        }
    }

    return res;
}

/* Creates PubSubConnection configuration from PubSubConnectionDataType object
 *
 * @param server Server object that shall be configured
 * @param connParams PubSub connection configuration
 * @param pdsCount Number of published DataSets
 * @param pdsIdent Array of NodeIds of the published DataSets */
static UA_StatusCode
createPubSubConnection(UA_Server *server, const UA_PubSubConnectionDataType *connParams,
                       UA_UInt32 pdsCount, UA_NodeId *pdsIdent) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_PubSubConnectionConfig config;
    memset(&config, 0, sizeof(UA_PubSubConnectionConfig));

    config.name =                       connParams->name;
    config.enabled =                    connParams->enabled;
    config.transportProfileUri =        connParams->transportProfileUri;
    config.connectionProperties.map =   connParams->connectionProperties;
    config.connectionProperties.mapSize = connParams->connectionPropertiesSize;

    UA_StatusCode res = setConnectionPublisherId(server, connParams, &config);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_PubSubManager_createPubSubConnection] "
                     "Setting PublisherId failed");
        return res;
    }

    if(connParams->address.encoding == UA_EXTENSIONOBJECT_DECODED) {
        UA_Variant_setScalar(&(config.address),
                             connParams->address.content.decoded.data,
                             connParams->address.content.decoded.type);
    } else {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_PubSubManager_createPubSubConnection] "
                     "Reading connection address failed");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    if(connParams->transportSettings.encoding == UA_EXTENSIONOBJECT_DECODED) {
        UA_Variant_setScalar(&(config.connectionTransportSettings),
                             connParams->transportSettings.content.decoded.data,
                             connParams->transportSettings.content.decoded.type);
    } else {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "[UA_PubSubManager_createPubSubConnection] "
                       "TransportSettings can not be read");
    }

    /* Load connection config into server: */
    UA_NodeId connectionIdent;
    res = UA_PubSubConnection_create(server, &config, &connectionIdent);
    if(res == UA_STATUSCODE_GOOD) {
        /* Configuration of all Components that belong to this connection: */
        res = createComponentsForConnection(server, connParams, connectionIdent,
                                            pdsCount, pdsIdent);
    } else {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_PubSubManager_createPubSubConnection] "
                     "Connection creation failed");
    }

    return res;
}

/* Function called by UA_PubSubManager_createWriterGroup to configure the messageSettings
 * of a writerGroup */
static UA_StatusCode
setWriterGroupEncodingType(UA_Server *server,
                           const UA_WriterGroupDataType *writerGroupParameters,
                           UA_WriterGroupConfig *config) {
    if(writerGroupParameters->messageSettings.encoding != UA_EXTENSIONOBJECT_DECODED) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_PubSubManager_setWriterGroupEncodingType] "
                     "getting message type information failed");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    if(writerGroupParameters->messageSettings.content.decoded.type ==
       &UA_TYPES[UA_TYPES_UADPWRITERGROUPMESSAGEDATATYPE]) {
        config->encodingMimeType = UA_PUBSUB_ENCODING_UADP;
    } else if(writerGroupParameters->messageSettings.content.decoded.type ==
              &UA_TYPES[UA_TYPES_JSONWRITERGROUPMESSAGEDATATYPE]) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_PubSubManager_setWriterGroupEncodingType] "
                     "encoding type: JSON (not implemented!)");
        return UA_STATUSCODE_BADNOTIMPLEMENTED;
    } else {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_PubSubManager_setWriterGroupEncodingType] "
                     "invalid message encoding type");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    return UA_STATUSCODE_GOOD;
}

/* WriterGroup configuration from WriterGroup object
 *
 * @param server Server object that shall be configured
 * @param writerGroupParameters WriterGroup configuration
 * @param connectionIdent NodeId of the PubSub connection, the WriterGroup belongs to
 * @param pdsCount Number of published DataSets
 * @param pdsIdent Array of NodeIds of the published DataSets */
static UA_StatusCode
createWriterGroup(UA_Server *server,
                  const UA_WriterGroupDataType *writerGroupParameters,
                  UA_NodeId connectionIdent, UA_UInt32 pdsCount,
                  const UA_NodeId *pdsIdent) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_WriterGroupConfig config;
    memset(&config, 0, sizeof(UA_WriterGroupConfig));
    config.name =                  writerGroupParameters->name;
    config.enabled =               writerGroupParameters->enabled;
    config.writerGroupId =         writerGroupParameters->writerGroupId;
    config.publishingInterval =    writerGroupParameters->publishingInterval;
    config.keepAliveTime =         writerGroupParameters->keepAliveTime;
    config.priority =              writerGroupParameters->priority;
    config.securityMode =          writerGroupParameters->securityMode;
    config.transportSettings =     writerGroupParameters->transportSettings;
    config.messageSettings =       writerGroupParameters->messageSettings;
    config.groupProperties.mapSize =   writerGroupParameters->groupPropertiesSize;
    config.groupProperties.map =   writerGroupParameters->groupProperties;
    config.maxEncapsulatedDataSetMessageCount = 255; /* non std parameter */

    UA_StatusCode res = setWriterGroupEncodingType(server, writerGroupParameters, &config);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_PubSubManager_createWriterGroup] "
                     "Setting message settings failed");
        return res;
    }

    /* Load config into server: */
    UA_NodeId writerGroupIdent;
    res = UA_WriterGroup_create(server, connectionIdent, &config, &writerGroupIdent);
    UA_WriterGroup *wg = UA_WriterGroup_findWGbyId(server, writerGroupIdent);
    if(wg)
        UA_WriterGroup_setPubSubState(server, wg, UA_PUBSUBSTATE_OPERATIONAL);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_PubSubManager_createWriterGroup] "
                     "Adding WriterGroup to server failed: 0x%x", res);
        return res;
    }

    /* Configuration of all DataSetWriters that belong to this WriterGroup */
    for(size_t dsw = 0; dsw < writerGroupParameters->dataSetWritersSize; dsw++) {
        res = createDataSetWriter(server, &writerGroupParameters->dataSetWriters[dsw],
                                  writerGroupIdent, pdsCount, pdsIdent);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                         "[UA_PubSubManager_createWriterGroup] "
                         "DataSetWriter Creation failed.");
            break;
        }
    }
    return res;
}

/* Function called by UA_PubSubManager_createDataSetWriter. It searches for a
 * PublishedDataSet that is referenced by the DataSetWriter. If a related PDS is found,
 * the DSWriter will be added to the server, otherwise, no DSWriter will be added.
 *
 * @param server UA_Server object that shall be configured
 * @param writerGroupIdent NodeId of writerGroup, the DataSetWriter belongs to
 * @param dsWriterConfig WriterGroup configuration
 * @param pdsCount Number of published DataSets
 * @param pdsIdent Array of NodeIds of the published DataSets */
static UA_StatusCode
addDataSetWriterWithPdsReference(UA_Server *server, UA_NodeId writerGroupIdent,
                                 const UA_DataSetWriterConfig *dsWriterConfig,
                                 UA_UInt32 pdsCount, const UA_NodeId *pdsIdent) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_NodeId dataSetWriterIdent;
    UA_PublishedDataSetConfig pdsConfig;
    UA_Boolean pdsFound = false;

    UA_StatusCode res = UA_STATUSCODE_GOOD;
    for(size_t pds = 0; pds < pdsCount && res == UA_STATUSCODE_GOOD; pds++) {
        res = getPublishedDataSetConfig(server, pdsIdent[pds], &pdsConfig);
        /* members of pdsConfig must be deleted manually */
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                         "[UA_PubSubManager_addDataSetWriterWithPdsReference] "
                         "Getting pdsConfig from NodeId failed.");
            return res;
        }

        if(dsWriterConfig->dataSetName.length == pdsConfig.name.length &&
           0 == strncmp((const char *)dsWriterConfig->dataSetName.data,
                        (const char *)pdsConfig.name.data,
                        dsWriterConfig->dataSetName.length)) {
            /* DSWriter will only be created, if a matching PDS is found: */
            res = UA_DataSetWriter_create(server, writerGroupIdent, pdsIdent[pds],
                                          dsWriterConfig, &dataSetWriterIdent);
            if(res != UA_STATUSCODE_GOOD) {
                UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                             "[UA_PubSubManager_addDataSetWriterWithPdsReference] "
                             "Adding DataSetWriter failed");
            } else {
                pdsFound = true;
            }

            UA_PublishedDataSetConfig_clear(&pdsConfig);
            if(pdsFound)
                break; /* break loop if corresponding publishedDataSet was found */
        }
    }

    if(!pdsFound) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_PubSubManager_addDataSetWriterWithPdsReference] "
                     "No matching DataSet found; no DataSetWriter created");
    }

    return res;
}

/* Creates DataSetWriter configuration from DataSetWriter object
 *
 * @param server UA_Server object that shall be configured
 * @param dataSetWriterParameters DataSetWriter Configuration
 * @param writerGroupIdent NodeId of writerGroup, the DataSetWriter belongs to
 * @param pdsCount Number of published DataSets
 * @param pdsIdent Array of NodeIds of the published DataSets */
static UA_StatusCode
createDataSetWriter(UA_Server *server,
                    const UA_DataSetWriterDataType *dataSetWriterParameters,
                    UA_NodeId writerGroupIdent, UA_UInt32 pdsCount,
                    const UA_NodeId *pdsIdent) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_DataSetWriterConfig config;
    memset(&config, 0, sizeof(UA_DataSetWriterConfig));
    config.name = dataSetWriterParameters->name;
    config.dataSetWriterId = dataSetWriterParameters->dataSetWriterId;
    config.keyFrameCount = dataSetWriterParameters->keyFrameCount;
    config.dataSetFieldContentMask = dataSetWriterParameters->dataSetFieldContentMask;
    config.messageSettings = dataSetWriterParameters->messageSettings;
    config.dataSetName = dataSetWriterParameters->dataSetName;
    config.dataSetWriterProperties.mapSize = dataSetWriterParameters->dataSetWriterPropertiesSize;
    config.dataSetWriterProperties.map = dataSetWriterParameters->dataSetWriterProperties;

    UA_StatusCode res = addDataSetWriterWithPdsReference(server, writerGroupIdent,
                                                         &config, pdsCount, pdsIdent);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_PubSubManager_createDataSetWriter] "
                     "Referencing related PDS failed");
    }

    return res;
}

/* Creates ReaderGroup configuration from ReaderGroup object
 *
 * @param server UA_Server object that shall be configured
 * @param readerGroupParameters ReaderGroup configuration
 * @param connectionIdent NodeId of the PubSub connection, the ReaderGroup belongs to */
static UA_StatusCode
createReaderGroup(UA_Server *server,
                  const UA_ReaderGroupDataType *readerGroupParameters,
                  UA_NodeId connectionIdent) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_ReaderGroupConfig config;
    memset(&config, 0, sizeof(UA_ReaderGroupConfig));

    config.name = readerGroupParameters->name;
    config.securityMode = readerGroupParameters->securityMode;

    UA_NodeId readerGroupIdent;
    UA_StatusCode res =
        UA_ReaderGroup_create(server, connectionIdent, &config, &readerGroupIdent);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_PubSubManager_createReaderGroup] Adding ReaderGroup "
                     "to server failed: 0x%x", res);
        return res;
    }

    UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_SERVER,
                "[UA_PubSubManager_createReaderGroup] ReaderGroup successfully added.");
    for(UA_UInt32 i = 0; i < readerGroupParameters->dataSetReadersSize; i++) {
        res = createDataSetReader(server, &readerGroupParameters->dataSetReaders[i],
                                  readerGroupIdent);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                         "[UA_PubSubManager_createReaderGroup] Creating DataSetReader failed");
            break;
        }
    }

    UA_ReaderGroup *rg = UA_ReaderGroup_findRGbyId(server, readerGroupIdent);
    if(res == UA_STATUSCODE_GOOD && rg)
        UA_ReaderGroup_setPubSubState(server, rg, UA_PUBSUBSTATE_OPERATIONAL);

    return res;
}

/* Creates TargetVariables or SubscribedDataSetMirror for a given DataSetReader
 *
 * @param server UA_Server object that shall be configured
 * @param dsReaderIdent NodeId of the DataSetReader the SubscribedDataSet belongs to
 * @param dataSetReaderParameters Configuration Parameters of the DataSetReader */
static UA_StatusCode
addSubscribedDataSet(UA_Server *server, const UA_NodeId dsReaderIdent,
                     const UA_ExtensionObject *subscribedDataSet) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    if(subscribedDataSet->content.decoded.type ==
       &UA_TYPES[UA_TYPES_TARGETVARIABLESDATATYPE]) {
        UA_TargetVariablesDataType *tmpTargetVars = (UA_TargetVariablesDataType*)
            subscribedDataSet->content.decoded.data;
        UA_FieldTargetVariable *targetVars = (UA_FieldTargetVariable *)
            UA_calloc(tmpTargetVars->targetVariablesSize, sizeof(UA_FieldTargetVariable));

        for(size_t index = 0; index < tmpTargetVars->targetVariablesSize; index++) {
            UA_FieldTargetDataType_copy(&tmpTargetVars->targetVariables[index],
                                        &targetVars[index].targetVariable);
        }

        UA_StatusCode res = UA_STATUSCODE_BADINTERNALERROR;
        UA_DataSetReader *dsr = UA_ReaderGroup_findDSRbyId(server, dsReaderIdent);
        if(dsr)
            res = DataSetReader_createTargetVariables(server, dsr,
                                                      tmpTargetVars->targetVariablesSize,
                                                      targetVars);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                         "[UA_PubSubManager_addSubscribedDataSet] "
                         "create TargetVariables failed");
        }

        for(size_t index = 0; index < tmpTargetVars->targetVariablesSize; index++) {
            UA_FieldTargetDataType_clear(&targetVars[index].targetVariable);
        }

        UA_free(targetVars);
        return res;
    }

    if(subscribedDataSet->content.decoded.type ==
       &UA_TYPES[UA_TYPES_SUBSCRIBEDDATASETMIRRORDATATYPE]) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_PubSubManager_addSubscribedDataSet] "
                     "DataSetMirror is currently not supported");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                 "[UA_PubSubManager_addSubscribedDataSet] "
                 "Invalid Type of SubscribedDataSet");
    return UA_STATUSCODE_BADINTERNALERROR;
}

/* Creates DataSetReader configuration from DataSetReader object
 *
 * @param server UA_Server object that shall be configured
 * @param dataSetReaderParameters DataSetReader configuration
 * @param writerGroupIdent NodeId of readerGroupParameters, the DataSetReader belongs to */
static UA_StatusCode
createDataSetReader(UA_Server *server, const UA_DataSetReaderDataType *dsrParams,
                    UA_NodeId readerGroupIdent) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_DataSetReaderConfig config;
    memset(&config, 0, sizeof(UA_DataSetReaderConfig));

    config.name = dsrParams->name;
    config.publisherId = dsrParams->publisherId;
    config.writerGroupId = dsrParams->writerGroupId;
    config.dataSetWriterId = dsrParams->dataSetWriterId;
    config.dataSetMetaData = dsrParams->dataSetMetaData;
    config.dataSetFieldContentMask = dsrParams->dataSetFieldContentMask;
    config.messageReceiveTimeout =  dsrParams->messageReceiveTimeout;
    config.messageSettings = dsrParams->messageSettings;

    UA_NodeId dsReaderIdent;
    UA_StatusCode res = UA_DataSetReader_create(server, readerGroupIdent,
                                                &config, &dsReaderIdent);
    if(res == UA_STATUSCODE_GOOD)
        res = addSubscribedDataSet(server, dsReaderIdent,
                                   &dsrParams->subscribedDataSet);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_PubSubManager_createDataSetReader] "
                     "create subscribedDataSet failed");
    }

    return res;
}

/* Determines whether PublishedDataSet is of type PublishedItems or PublishedEvents.
 * (PublishedEvents are currently not supported!)
 *
 * @param publishedDataSetParameters PublishedDataSet parameters
 * @param config PublishedDataSet configuration object */
static UA_StatusCode
setPublishedDataSetType(UA_Server *server,
                        const UA_PublishedDataSetDataType *pdsParams,
                        UA_PublishedDataSetConfig *config) {
    if(pdsParams->dataSetSource.encoding != UA_EXTENSIONOBJECT_DECODED)
        return UA_STATUSCODE_BADINTERNALERROR;

    const UA_DataType *sourceType = pdsParams->dataSetSource.content.decoded.type;
    if(sourceType == &UA_TYPES[UA_TYPES_PUBLISHEDDATAITEMSDATATYPE]) {
        config->publishedDataSetType = UA_PUBSUB_DATASET_PUBLISHEDITEMS;
        return UA_STATUSCODE_GOOD;
    } else if(sourceType == &UA_TYPES[UA_TYPES_PUBLISHEDEVENTSDATATYPE]) {
        /* config.publishedDataSetType = UA_PUBSUB_DATASET_PUBLISHEDEVENTS; */
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_PubSubManager_setPublishedDataSetType] Published events not supported.");
        return UA_STATUSCODE_BADNOTIMPLEMENTED;
    }

    UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                 "[UA_PubSubManager_setPublishedDataSetType] Invalid DataSetSourceDataType.");
    return UA_STATUSCODE_BADINTERNALERROR;
}

/* Creates PublishedDataSetConfig object from PublishedDataSet object
 *
 * @param server UA_Server object that shall be configured
 * @param pdsParams publishedDataSet configuration
 * @param pdsIdent NodeId of the publishedDataSet */
static UA_StatusCode
createPublishedDataSet(UA_Server *server,
                       const UA_PublishedDataSetDataType *pdsParams,
                       UA_NodeId *pdsIdent) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_PublishedDataSetConfig config;
    memset(&config, 0, sizeof(UA_PublishedDataSetConfig));

    config.name = pdsParams->name;
    UA_StatusCode res = setPublishedDataSetType(server, pdsParams, &config);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    res = UA_PublishedDataSet_create(server, &config, pdsIdent).addResult;
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_PubSubManager_createPublishedDataSet] "
                     "Adding PublishedDataSet failed.");
        return res;
    }

    /* DataSetField configuration for this publishedDataSet: */
    res = createDataSetFields(server, pdsIdent, pdsParams);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_PubSubManager_createPublishedDataSet] "
                     "Creating DataSetFieldConfig failed.");
    }

    return res;
}

/* Adds DataSetField Variables bound to a certain PublishedDataSet. This method does NOT
 * check, whether the PublishedDataSet actually contains Variables instead of Events!
 *
 * @param server UA_Server object that shall be configured
 * @param pdsIdent NodeId of the publishedDataSet, the DataSetField belongs to
 * @param publishedDataSetParameters publishedDataSet configuration */
static UA_StatusCode
addDataSetFieldVariables(UA_Server *server, const UA_NodeId *pdsIdent,
                         const UA_PublishedDataSetDataType *pdsParams) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_PublishedDataItemsDataType *pdItems = (UA_PublishedDataItemsDataType *)
        pdsParams->dataSetSource.content.decoded.data;
    if(pdItems->publishedDataSize != pdsParams->dataSetMetaData.fieldsSize)
        return UA_STATUSCODE_BADINTERNALERROR;

    for(size_t i = 0; i < pdItems->publishedDataSize; i++) {
        UA_DataSetFieldConfig fc;
        memset(&fc, 0, sizeof(UA_DataSetFieldConfig));
        fc.dataSetFieldType = UA_PUBSUB_DATASETFIELD_VARIABLE;
        fc.field.variable.configurationVersion =
            pdsParams->dataSetMetaData.configurationVersion;
        fc.field.variable.fieldNameAlias = pdsParams->dataSetMetaData.fields[i].name;
        fc.field.variable.promotedField = pdsParams->dataSetMetaData.
            fields[i].fieldFlags & 0x0001;
        fc.field.variable.publishParameters = pdItems->publishedData[i];

        UA_NodeId fieldIdent;
        UA_StatusCode res = UA_DataSetField_create(server, *pdsIdent, &fc, &fieldIdent).result;
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                         "[UA_PubSubManager_addDataSetFieldVariables] "
                         "Adding DataSetField Variable failed.");
            return res;
        }
    }

    return UA_STATUSCODE_GOOD;
}

/* Checks if PublishedDataSet contains event or variable fields and calls the
 * corresponding method to add these fields to the server.
 *
 * @param server UA_Server object that shall be configured
 * @param pdsIdent NodeId of the publishedDataSet, the DataSetFields belongs to
 * @param pdsParams publishedDataSet configuration */
static UA_StatusCode
createDataSetFields(UA_Server *server, const UA_NodeId *pdsIdent,
                    const UA_PublishedDataSetDataType *pdsParams) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    if(pdsParams->dataSetSource.encoding != UA_EXTENSIONOBJECT_DECODED)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(pdsParams->dataSetSource.content.decoded.type ==
       &UA_TYPES[UA_TYPES_PUBLISHEDDATAITEMSDATATYPE])
        return addDataSetFieldVariables(server, pdsIdent, pdsParams);

    /* TODO: Implement Routine for adding Event DataSetFields */
    if(pdsParams->dataSetSource.content.decoded.type ==
       &UA_TYPES[UA_TYPES_PUBLISHEDEVENTSDATATYPE]) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_PubSubManager_createDataSetFields] "
                     "Published events not supported.");
        return UA_STATUSCODE_BADNOTIMPLEMENTED;
    }

    UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                 "[UA_PubSubManager_createDataSetFields] "
                 "Invalid DataSetSourceDataType.");
    return UA_STATUSCODE_BADINTERNALERROR;
}

UA_StatusCode
UA_PubSubManager_loadPubSubConfigFromByteString(UA_Server *server,
                                                const UA_ByteString buffer) {
    size_t offset = 0;
    UA_ExtensionObject decodedFile;
    UA_StatusCode res;

    if(server == NULL) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_PubSubManager_loadPubSubConfigFromByteString] Invalid argument");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    res = UA_ExtensionObject_decodeBinary(&buffer, &offset, &decodedFile);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_decodeBinFile] decoding UA_Binary failed");
        goto cleanup;
    }

    UA_PubSubConfigurationDataType *pubSubConfig = NULL;
    res = extractPubSubConfigFromExtensionObject(server, &decodedFile, &pubSubConfig);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_PubSubManager_loadPubSubConfigFromByteString] "
                     "Extracting PubSub Configuration failed");
        goto cleanup;
    }

    res = updatePubSubConfig(server, pubSubConfig);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_PubSubManager_loadPubSubConfigFromByteString] "
                     "Loading PubSub configuration into server failed");
        goto cleanup;
    }

 cleanup:
    UA_ExtensionObject_clear(&decodedFile);
    return res;
}

/* Encodes a PubSubConfigurationDataType object as ByteString using the UA Binary Data
 * Encoding */
static UA_StatusCode
encodePubSubConfiguration(UA_Server *server,
                          UA_PubSubConfigurationDataType *configurationParameters,
                          UA_ByteString *buffer) {
    UA_UABinaryFileDataType binFile;
    memset(&binFile, 0, sizeof(UA_UABinaryFileDataType));
    /*Perhaps, additional initializations of binFile are necessary here.*/

    UA_Variant_setScalar(&binFile.body, configurationParameters,
                         &UA_TYPES[UA_TYPES_PUBSUBCONFIGURATIONDATATYPE]);

    UA_ExtensionObject container;
    memset(&container, 0, sizeof(UA_ExtensionObject));
    container.encoding = UA_EXTENSIONOBJECT_DECODED;
    container.content.decoded.type = &UA_TYPES[UA_TYPES_UABINARYFILEDATATYPE];
    container.content.decoded.data = &binFile;

    size_t fileSize = UA_ExtensionObject_calcSizeBinary(&container);
    buffer->data = (UA_Byte*)UA_calloc(fileSize, sizeof(UA_Byte));
    if(buffer->data == NULL) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_PubSubManager_encodePubSubConfiguration] Allocating buffer failed");
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    buffer->length = fileSize;

    UA_Byte *bufferPos = buffer->data;
    UA_StatusCode res =
        UA_ExtensionObject_encodeBinary(&container, &bufferPos, bufferPos + fileSize);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_PubSubManager_encodePubSubConfiguration] Encoding failed");
    }
    return res;
}

static UA_StatusCode
generatePublishedDataSetDataType(UA_Server* server,
                                 const UA_PublishedDataSet *src,
                                 UA_PublishedDataSetDataType *dst) {
    if(src->config.publishedDataSetType != UA_PUBSUB_DATASET_PUBLISHEDITEMS)
        return UA_STATUSCODE_BADNOTIMPLEMENTED;

    memset(dst, 0, sizeof(UA_PublishedDataSetDataType));

    UA_PublishedDataItemsDataType *tmp = UA_PublishedDataItemsDataType_new();
    UA_String_copy(&src->config.name, &dst->name);
    dst->dataSetMetaData.fieldsSize = src->fieldSize;

    size_t index = 0;
    tmp->publishedDataSize = src->fieldSize;
    tmp->publishedData = (UA_PublishedVariableDataType*)
        UA_Array_new(tmp->publishedDataSize, &UA_TYPES[UA_TYPES_PUBLISHEDVARIABLEDATATYPE]);
    if(tmp->publishedData == NULL) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER, "Allocation memory failed");
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    dst->dataSetMetaData.fields = (UA_FieldMetaData*)
        UA_Array_new(dst->dataSetMetaData.fieldsSize, &UA_TYPES[UA_TYPES_FIELDMETADATA]);
    if(dst->dataSetMetaData.fields == NULL) {
        UA_free(tmp->publishedData);
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER, "Allocation memory failed");
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    UA_DataSetField *dsf, *dsf_tmp = NULL;
    TAILQ_FOREACH_SAFE(dsf ,&src->fields, listEntry, dsf_tmp) {
        UA_String_copy(&dsf->config.field.variable.fieldNameAlias,
                       &dst->dataSetMetaData.fields[index].name);
        UA_PublishedVariableDataType_copy(&dsf->config.field.variable.publishParameters,
                                          &tmp->publishedData[index]);
        UA_ConfigurationVersionDataType_copy(&dsf->config.field.variable.configurationVersion,
                                             &dst->dataSetMetaData.configurationVersion);
        dst->dataSetMetaData.fields[index].fieldFlags =
            dsf->config.field.variable.promotedField;
        index++;
    }
    UA_ExtensionObject_setValue(&dst->dataSetSource, tmp,
                                &UA_TYPES[UA_TYPES_PUBLISHEDDATAITEMSDATATYPE]);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
generateDataSetWriterDataType(const UA_DataSetWriter *src,
                              UA_DataSetWriterDataType *dst) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    memset(dst, 0, sizeof(UA_DataSetWriterDataType));
    res |= UA_String_copy(&src->config.name, &dst->name);
    dst->dataSetWriterId = src->config.dataSetWriterId;
    dst->keyFrameCount = src->config.keyFrameCount;
    dst->dataSetFieldContentMask = src->config.dataSetFieldContentMask;
    res |= UA_ExtensionObject_copy(&src->config.messageSettings, &dst->messageSettings);
    res |= UA_String_copy(&src->config.dataSetName, &dst->dataSetName);
    if(res != UA_STATUSCODE_GOOD) {
        UA_DataSetWriterDataType_clear(dst);
        return res;
    }

    res = UA_Array_copy(src->config.dataSetWriterProperties.map,
                        src->config.dataSetWriterProperties.mapSize,
                        (void**)&dst->dataSetWriterProperties,
                        &UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
    if(res == UA_STATUSCODE_GOOD)
        dst->dataSetWriterPropertiesSize = src->config.dataSetWriterProperties.mapSize;
    else
        UA_DataSetWriterDataType_clear(dst);

    return res;
}

static UA_StatusCode
generateWriterGroupDataType(const UA_WriterGroup *src,
                            UA_WriterGroupDataType *dst) {
    memset(dst, 0, sizeof(UA_WriterGroupDataType));

    UA_String_copy(&src->config.name, &dst->name);
    dst->enabled = src->config.enabled;
    dst->writerGroupId = src->config.writerGroupId;
    dst->publishingInterval = src->config.publishingInterval;
    dst->keepAliveTime = src->config.keepAliveTime;
    dst->priority = src->config.priority;
    dst->securityMode = src->config.securityMode;

    UA_ExtensionObject_copy(&src->config.transportSettings, &dst->transportSettings);
    UA_ExtensionObject_copy(&src->config.messageSettings, &dst->messageSettings);

    UA_StatusCode res =
        UA_Array_copy(src->config.groupProperties.map,
                      src->config.groupProperties.mapSize,
                      (void**)&dst->groupProperties,
                      &UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
    if(res != UA_STATUSCODE_GOOD) {
        UA_WriterGroupDataType_clear(dst);
        return res;
    }
    dst->groupPropertiesSize = src->config.groupProperties.mapSize,

    dst->dataSetWriters = (UA_DataSetWriterDataType*)
        UA_calloc(src->writersCount, sizeof(UA_DataSetWriterDataType));
    if(!dst->dataSetWriters) {
        UA_WriterGroupDataType_clear(dst);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    dst->dataSetWritersSize = src->writersCount;

    UA_DataSetWriter *dsw;
    size_t dsWriterIndex = 0;
    LIST_FOREACH(dsw, &src->writers, listEntry) {
        res |= generateDataSetWriterDataType(dsw, &dst->dataSetWriters[dsWriterIndex]);
        dsWriterIndex++;
    }
    if(res != UA_STATUSCODE_GOOD)
        UA_WriterGroupDataType_clear(dst);
    return res;
}

static UA_StatusCode
generateDataSetReaderDataType(const UA_DataSetReader *src,
                              UA_DataSetReaderDataType *dst) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    memset(dst, 0, sizeof(UA_DataSetReaderDataType));
    dst->writerGroupId = src->config.writerGroupId;
    dst->dataSetWriterId = src->config.dataSetWriterId;
    dst->dataSetFieldContentMask = src->config.dataSetFieldContentMask;
    dst->messageReceiveTimeout = src->config.messageReceiveTimeout;
    res |= UA_String_copy(&src->config.name, &dst->name);
    res |= UA_Variant_copy(&src->config.publisherId, &dst->publisherId);
    res |= UA_DataSetMetaDataType_copy(&src->config.dataSetMetaData,
                                       &dst->dataSetMetaData);
    res |= UA_ExtensionObject_copy(&src->config.messageSettings, &dst->messageSettings);

    UA_TargetVariablesDataType *tmpTarget = UA_TargetVariablesDataType_new();
    if(!tmpTarget)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    UA_ExtensionObject_setValue(&dst->subscribedDataSet, tmpTarget,
                                &UA_TYPES[UA_TYPES_TARGETVARIABLESDATATYPE]);

    const UA_TargetVariables *targets =
        &src->config.subscribedDataSet.subscribedDataSetTarget;
    tmpTarget->targetVariables = (UA_FieldTargetDataType *)
        UA_calloc(targets->targetVariablesSize, sizeof(UA_FieldTargetDataType));
    if(!tmpTarget->targetVariables)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    tmpTarget->targetVariablesSize = targets->targetVariablesSize;

    for(size_t i = 0; i < tmpTarget->targetVariablesSize; i++) {
        res |= UA_FieldTargetDataType_copy(&targets->targetVariables[i].targetVariable,
                                           &tmpTarget->targetVariables[i]);
    }

    return res;
}

static UA_StatusCode
generateReaderGroupDataType(const UA_ReaderGroup *src,
                            UA_ReaderGroupDataType *dst) {
    memset(dst, 0, sizeof(UA_ReaderGroupDataType));

    UA_String_copy(&src->config.name, &dst->name);
    dst->dataSetReaders = (UA_DataSetReaderDataType*)
        UA_calloc(src->readersCount, sizeof(UA_DataSetReaderDataType));
    if(dst->dataSetReaders == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    dst->dataSetReadersSize = src->readersCount;

    size_t i = 0;
    UA_DataSetReader *dsr, *dsr_tmp = NULL;
    LIST_FOREACH_SAFE(dsr, &src->readers, listEntry, dsr_tmp) {
        UA_StatusCode res =
            generateDataSetReaderDataType(dsr, &dst->dataSetReaders[i]);
        if(res != UA_STATUSCODE_GOOD)
            return res;
        i++;
    }

    return UA_STATUSCODE_GOOD;
}

/* Generates a PubSubConnectionDataType object from a PubSubConnection. */
static UA_StatusCode
generatePubSubConnectionDataType(UA_Server* server,
                                 const UA_PubSubConnection *src,
                                 UA_PubSubConnectionDataType *dst) {
    const UA_DataType *publisherIdType;
    memset(dst, 0, sizeof(UA_PubSubConnectionDataType));

    UA_String_copy(&src->config.name, &dst->name);
    UA_String_copy(&src->config.transportProfileUri, &dst->transportProfileUri);
    dst->enabled = src->config.enabled;

    UA_StatusCode res =
        UA_Array_copy(src->config.connectionProperties.map,
                      src->config.connectionProperties.mapSize,
                      (void**)&dst->connectionProperties,
                      &UA_TYPES[UA_TYPES_KEYVALUEPAIR]);
    if(res != UA_STATUSCODE_GOOD) {
        UA_PubSubConnectionDataType_clear(dst);
        return res;
    }
    dst->connectionPropertiesSize = src->config.connectionProperties.mapSize;

    switch (src->config.publisherIdType) {
        case UA_PUBLISHERIDTYPE_BYTE:
            publisherIdType = &UA_TYPES[UA_TYPES_BYTE];
            break;
        case UA_PUBLISHERIDTYPE_UINT16:
            publisherIdType = &UA_TYPES[UA_TYPES_UINT16];
            break;
        case UA_PUBLISHERIDTYPE_UINT32:
            publisherIdType = &UA_TYPES[UA_TYPES_UINT32];
            break;
        case UA_PUBLISHERIDTYPE_UINT64:
            publisherIdType = &UA_TYPES[UA_TYPES_UINT64];
            break;
        case UA_PUBLISHERIDTYPE_STRING:
            publisherIdType = &UA_TYPES[UA_TYPES_STRING];
            break;
        default:
            UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                         "generatePubSubConnectionDataType(): publisher Id type is not supported");
            return UA_STATUSCODE_BADINTERNALERROR;
            break;
    }
    UA_Variant_setScalarCopy(&dst->publisherId,
                             &src->config.publisherId,
                             publisherIdType);

    /* Possibly, array size and dimensions of src->config->address and
     * src->config->connectionTransportSettings should be checked beforehand. */
    dst->address.encoding = UA_EXTENSIONOBJECT_DECODED;
    dst->address.content.decoded.type = src->config.address.type;
    res = UA_Array_copy(src->config.address.data, 1,
                        &dst->address.content.decoded.data,
                        src->config.address.type);
    if(res != UA_STATUSCODE_GOOD) {
        UA_PubSubConnectionDataType_clear(dst);
        return res;
    }

    if(src->config.connectionTransportSettings.data) {
        dst->transportSettings.encoding = UA_EXTENSIONOBJECT_DECODED;
        dst->transportSettings.content.decoded.type =
            src->config.connectionTransportSettings.type;
        res = UA_Array_copy(src->config.connectionTransportSettings.data, 1,
                            &dst->transportSettings.content.decoded.data,
                            src->config.connectionTransportSettings.type);

        if(res != UA_STATUSCODE_GOOD) {
            UA_PubSubConnectionDataType_clear(dst);
            return res;
        }
    }

    dst->writerGroups = (UA_WriterGroupDataType*)
        UA_calloc(src->writerGroupsSize, sizeof(UA_WriterGroupDataType));
    if(!dst->writerGroups) {
        UA_PubSubConnectionDataType_clear(dst);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    dst->writerGroupsSize = src->writerGroupsSize;
    UA_WriterGroup *wg, *wg_tmp = NULL;
    size_t wgIndex = 0;
    LIST_FOREACH_SAFE(wg, &src->writerGroups, listEntry, wg_tmp) {
        res = generateWriterGroupDataType(wg, &dst->writerGroups[wgIndex]);
        if(res != UA_STATUSCODE_GOOD) {
            UA_PubSubConnectionDataType_clear(dst);
            return res;
        }
        wgIndex++;
    }

    dst->readerGroups = (UA_ReaderGroupDataType*)
        UA_calloc(src->readerGroupsSize, sizeof(UA_ReaderGroupDataType));
    if(dst->readerGroups == NULL) {
        UA_PubSubConnectionDataType_clear(dst);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    dst->readerGroupsSize = src->readerGroupsSize;
    UA_ReaderGroup *rg = NULL;
    size_t rgIndex = 0;
    LIST_FOREACH(rg, &src->readerGroups, listEntry) {
        res = generateReaderGroupDataType(rg, &dst->readerGroups[rgIndex]);
        if(res != UA_STATUSCODE_GOOD) {
            UA_PubSubConnectionDataType_clear(dst);
            return res;
        }
        rgIndex++;
    }

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
generatePubSubConfigurationDataType(UA_Server* server,
                                    UA_PubSubConfigurationDataType *configDT) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_StatusCode res = UA_STATUSCODE_GOOD;
    const UA_PubSubManager *manager = &server->pubSubManager;
    memset(configDT, 0, sizeof(UA_PubSubConfigurationDataType));

    configDT->publishedDataSets = (UA_PublishedDataSetDataType*)
        UA_calloc(manager->publishedDataSetsSize,
                  sizeof(UA_PublishedDataSetDataType));
    if(configDT->publishedDataSets == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    configDT->publishedDataSetsSize = manager->publishedDataSetsSize;

    UA_PublishedDataSet *pds;
    UA_UInt32 pdsIndex = 0;
    TAILQ_FOREACH(pds, &manager->publishedDataSets, listEntry) {
        UA_PublishedDataSetDataType *dst = &configDT->publishedDataSets[pdsIndex];
        res = generatePublishedDataSetDataType(server, pds, dst);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                         "[UA_PubSubManager_generatePubSubConfigurationDataType] "
                         "retrieving PublishedDataSet configuration failed");
            return res;
        }
        pdsIndex++;
    }

    configDT->connections = (UA_PubSubConnectionDataType*)
        UA_calloc(manager->connectionsSize, sizeof(UA_PubSubConnectionDataType));
    if(configDT->connections == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    configDT->connectionsSize = manager->connectionsSize;

    UA_UInt32 connectionIndex = 0;
    UA_PubSubConnection *connection;
    TAILQ_FOREACH(connection, &manager->connections, listEntry) {
        UA_PubSubConnectionDataType *cdt = &configDT->connections[connectionIndex];
        res = generatePubSubConnectionDataType(server, connection, cdt);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                         "[UA_PubSubManager_generatePubSubConfigurationDataType] "
                         "retrieving PubSubConnection configuration failed");
            return res;
        }
        connectionIndex++;
    }

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_PubSubManager_getEncodedPubSubConfiguration(UA_Server *server,
                                               UA_ByteString *buffer) {
    UA_PubSubConfigurationDataType config;
    memset(&config, 0, sizeof(UA_PubSubConfigurationDataType));

    if(server == NULL) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "[UA_PubSubManager_getEncodedPubSubConfiguration] Invalid argument");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_StatusCode res = generatePubSubConfigurationDataType(server, &config);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "retrieving PubSub configuration from server failed");
        goto cleanup;
    }

    res = encodePubSubConfiguration(server, &config, buffer);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "encoding PubSub configuration failed");
        goto cleanup;
    }

    UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_SERVER,
                "Saving PubSub config was successful");

 cleanup:
    UA_PubSubConfigurationDataType_clear(&config);
    return res;
}

#endif /* UA_ENABLE_PUBSUB && UA_ENABLE_PUBSUB_FILE_CONFIG */

/**** amalgamated original file "/src/client/ua_client.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2015-2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2015-2016 (c) Chris Iatrou
 *    Copyright 2015 (c) hfaham
 *    Copyright 2015-2017 (c) Florian Palm
 *    Copyright 2017-2018 (c) Thomas Stalder, Blue Time Concept SA
 *    Copyright 2015 (c) Holger Jeromin
 *    Copyright 2015 (c) Oleksiy Vasylyev
 *    Copyright 2016 (c) TorbenD
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2016 (c) Lykurg
 *    Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2018 (c) Kalycito Infotech Private Limited
 *    Copyright 2020 (c) Christian von Arnim, ISW University of Stuttgart
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Jan Hermes)
 *    Copyright 2022 (c) Linutronix GmbH (Author: Muddasir Shakil)
 */



static void
clientHouseKeeping(UA_Client *client, void *_);

/********************/
/* Client Lifecycle */
/********************/

UA_StatusCode
UA_ClientConfig_copy(UA_ClientConfig const *src, UA_ClientConfig *dst){
    UA_StatusCode retval = UA_STATUSCODE_GOOD;

    retval = UA_ApplicationDescription_copy(&src->clientDescription, &dst->clientDescription);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    retval = UA_ExtensionObject_copy(&src->userIdentityToken, &dst->userIdentityToken);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    retval = UA_String_copy(&src->securityPolicyUri, &dst->securityPolicyUri);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    retval = UA_EndpointDescription_copy(&src->endpoint, &dst->endpoint);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    retval = UA_UserTokenPolicy_copy(&src->userTokenPolicy, &dst->userTokenPolicy);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    retval = UA_Array_copy(src->sessionLocaleIds, src->sessionLocaleIdsSize,
                           (void **)&dst->sessionLocaleIds, &UA_TYPES[UA_TYPES_LOCALEID]);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    dst->sessionLocaleIdsSize = src->sessionLocaleIdsSize;
    dst->connectivityCheckInterval = src->connectivityCheckInterval;
    dst->certificateVerification = src->certificateVerification;
    dst->clientContext = src->clientContext;
    dst->customDataTypes = src->customDataTypes;
    dst->eventLoop = src->eventLoop;
    dst->externalEventLoop = src->externalEventLoop;
    dst->inactivityCallback = src->inactivityCallback;
    dst->localConnectionConfig = src->localConnectionConfig;
    dst->logging = src->logging;
    if(src->certificateVerification.logging == NULL)
        dst->certificateVerification.logging = dst->logging;
#ifdef UA_ENABLE_SUBSCRIPTIONS
    dst->outStandingPublishRequests = src->outStandingPublishRequests;
#endif
    dst->requestedSessionTimeout = src->requestedSessionTimeout;
    dst->secureChannelLifeTime = src->secureChannelLifeTime;
    dst->securityMode = src->securityMode;
    dst->stateCallback = src->stateCallback;
#ifdef UA_ENABLE_SUBSCRIPTIONS
    dst->subscriptionInactivityCallback = src->subscriptionInactivityCallback;
#endif
    dst->timeout = src->timeout;
    dst->userTokenPolicy = src->userTokenPolicy;
    dst->securityPolicies = src->securityPolicies;
    dst->securityPoliciesSize = src->securityPoliciesSize;
    dst->authSecurityPolicies = src->authSecurityPolicies;
    dst->authSecurityPoliciesSize = src->authSecurityPoliciesSize;

cleanup:
    if(retval != UA_STATUSCODE_GOOD) {
        /* _clear will free the plugins in dst that are a shallow copy from src. */
        dst->authSecurityPolicies = NULL;
        dst->certificateVerification.context = NULL;
        dst->eventLoop = NULL;
        dst->logging = NULL;
        dst->securityPolicies = NULL;
        UA_ClientConfig_clear(dst);
    }
    return retval;
}

UA_Client *
UA_Client_newWithConfig(const UA_ClientConfig *config) {
    if(!config)
        return NULL;
    UA_Client *client = (UA_Client*)UA_malloc(sizeof(UA_Client));
    if(!client)
        return NULL;
    memset(client, 0, sizeof(UA_Client));
    client->config = *config;

    UA_SecureChannel_init(&client->channel);
    client->channel.config = client->config.localConnectionConfig;
    client->connectStatus = UA_STATUSCODE_GOOD;

#if UA_MULTITHREADING >= 100
    UA_LOCK_INIT(&client->clientMutex);
#endif

    return client;
}

void
UA_ClientConfig_clear(UA_ClientConfig *config) {
    UA_ApplicationDescription_clear(&config->clientDescription);
    UA_String_clear(&config->endpointUrl);
    UA_ExtensionObject_clear(&config->userIdentityToken);

    /* Delete the SecurityPolicies for Authentication */
    if(config->authSecurityPolicies != 0) {
        for(size_t i = 0; i < config->authSecurityPoliciesSize; i++)
            config->authSecurityPolicies[i].clear(&config->authSecurityPolicies[i]);
        UA_free(config->authSecurityPolicies);
        config->authSecurityPolicies = 0;
    }
    UA_String_clear(&config->securityPolicyUri);
    UA_String_clear(&config->authSecurityPolicyUri);

    UA_EndpointDescription_clear(&config->endpoint);
    UA_UserTokenPolicy_clear(&config->userTokenPolicy);

    UA_String_clear(&config->applicationUri);

    if(config->certificateVerification.clear)
        config->certificateVerification.clear(&config->certificateVerification);

    /* Delete the SecurityPolicies */
    if(config->securityPolicies != 0) {
        for(size_t i = 0; i < config->securityPoliciesSize; i++)
            config->securityPolicies[i].clear(&config->securityPolicies[i]);
        UA_free(config->securityPolicies);
        config->securityPolicies = 0;
    }

    /* Stop and delete the EventLoop */
    UA_EventLoop *el = config->eventLoop;
    if(el && !config->externalEventLoop) {
        if(el->state != UA_EVENTLOOPSTATE_FRESH &&
           el->state != UA_EVENTLOOPSTATE_STOPPED) {
            el->stop(el);
            while(el->state != UA_EVENTLOOPSTATE_STOPPED) {
                el->run(el, 100);
            }
        }
        el->free(el);
        config->eventLoop = NULL;
    }

    /* Logging */
    if(config->logging != NULL && config->logging->clear != NULL)
        config->logging->clear(config->logging);
    config->logging = NULL;

    UA_String_clear(&config->sessionName);
    if(config->sessionLocaleIdsSize > 0 && config->sessionLocaleIds) {
        UA_Array_delete(config->sessionLocaleIds,
                        config->sessionLocaleIdsSize, &UA_TYPES[UA_TYPES_LOCALEID]);
    }
    config->sessionLocaleIds = NULL;
    config->sessionLocaleIdsSize = 0;

    /* Custom Data Types */
    UA_cleanupDataTypeWithCustom(config->customDataTypes);

#ifdef UA_ENABLE_ENCRYPTION
    config->privateKeyPasswordCallback = NULL;
#endif
}

void
UA_ClientConfig_delete(UA_ClientConfig *config){
    UA_assert(config != NULL);
    UA_ClientConfig_clear(config);
    UA_free(config);
}

static void
UA_Client_clear(UA_Client *client) {
    /* Prevent new async service calls in UA_Client_AsyncService_removeAll */
    UA_SessionState oldState = client->sessionState;
    client->sessionState = UA_SESSIONSTATE_CLOSING;

    /* Delete the async service calls with BADHSUTDOWN */
    __Client_AsyncService_removeAll(client, UA_STATUSCODE_BADSHUTDOWN);

    /* Reset to the old state to properly close the session */
    client->sessionState = oldState;

    UA_Client_disconnect(client);
    UA_String_clear(&client->discoveryUrl);
    UA_ApplicationDescription_clear(&client->serverDescription);

    UA_String_clear(&client->serverSessionNonce);
    UA_String_clear(&client->clientSessionNonce);

    /* Delete the subscriptions */
#ifdef UA_ENABLE_SUBSCRIPTIONS
    __Client_Subscriptions_clean(client);
#endif

    /* Remove the internal regular callback */
    UA_Client_removeCallback(client, client->houseKeepingCallbackId);
    client->houseKeepingCallbackId = 0;

    UA_SecureChannel_clear(&client->channel);

#if UA_MULTITHREADING >= 100
    UA_LOCK_DESTROY(&client->clientMutex);
#endif
}

void
UA_Client_delete(UA_Client* client) {
    UA_Client_disconnect(client);
    UA_Client_clear(client);
    UA_ClientConfig_clear(&client->config);
    UA_free(client);
}

void
UA_Client_getState(UA_Client *client, UA_SecureChannelState *channelState,
                   UA_SessionState *sessionState, UA_StatusCode *connectStatus) {
    UA_LOCK(&client->clientMutex);
    if(channelState)
        *channelState = client->channel.state;
    if(sessionState)
        *sessionState = client->sessionState;
    if(connectStatus)
        *connectStatus = client->connectStatus;
    UA_UNLOCK(&client->clientMutex);
}

UA_ClientConfig *
UA_Client_getConfig(UA_Client *client) {
    if(!client)
        return NULL;
    return &client->config;
}

#if UA_LOGLEVEL <= 300
static const char *channelStateTexts[14] = {
    "Fresh", "ReverseListening", "Connecting", "Connected", "ReverseConnected", "RHESent", "HELSent", "HELReceived", "ACKSent",
    "AckReceived", "OPNSent", "Open", "Closing", "Closed"};
static const char *sessionStateTexts[6] =
    {"Closed", "CreateRequested", "Created",
     "ActivateRequested", "Activated", "Closing"};
#endif

void
notifyClientState(UA_Client *client) {
    UA_LOCK_ASSERT(&client->clientMutex, 1);

    if(client->connectStatus == client->oldConnectStatus &&
       client->channel.state == client->oldChannelState &&
       client->sessionState == client->oldSessionState)
        return;

#if UA_LOGLEVEL <= 300
    UA_Boolean info = (client->connectStatus != UA_STATUSCODE_GOOD);
    if(client->oldChannelState != client->channel.state)
        info |= (client->channel.state == UA_SECURECHANNELSTATE_OPEN ||
                 client->channel.state == UA_SECURECHANNELSTATE_CLOSED);
    if(client->oldSessionState != client->sessionState)
        info |= (client->sessionState == UA_SESSIONSTATE_CREATED ||
                 client->sessionState == UA_SESSIONSTATE_ACTIVATED ||
                 client->sessionState == UA_SESSIONSTATE_CLOSED);

    const char *channelStateText = channelStateTexts[client->channel.state];
    const char *sessionStateText = sessionStateTexts[client->sessionState];
    const char *connectStatusText = UA_StatusCode_name(client->connectStatus);

    if(info)
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                    "Client Status: ChannelState: %s, SessionState: %s, ConnectStatus: %s",
                    channelStateText, sessionStateText, connectStatusText);
    else
        UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "Client Status: ChannelState: %s, SessionState: %s, ConnectStatus: %s",
                     channelStateText, sessionStateText, connectStatusText);
#endif

    client->oldConnectStatus = client->connectStatus;
    client->oldChannelState = client->channel.state;
    client->oldSessionState = client->sessionState;

    UA_UNLOCK(&client->clientMutex);
    if(client->config.stateCallback)
        client->config.stateCallback(client, client->channel.state,
                                     client->sessionState, client->connectStatus);
    UA_LOCK(&client->clientMutex);
}

/****************/
/* Raw Services */
/****************/

/* For both synchronous and asynchronous service calls */
static UA_StatusCode
sendRequest(UA_Client *client, const void *request,
            const UA_DataType *requestType, UA_UInt32 *requestId) {
    UA_LOCK_ASSERT(&client->clientMutex, 1);

    /* Renew SecureChannel if necessary */
    __Client_renewSecureChannel(client);
    if(client->connectStatus != UA_STATUSCODE_GOOD)
        return client->connectStatus;

    UA_EventLoop *el = client->config.eventLoop;

    /* Adjusting the request header. The const attribute is violated, but we
     * only touch the following members: */
    UA_RequestHeader *rr = (UA_RequestHeader*)(uintptr_t)request;
    UA_NodeId oldToken = rr->authenticationToken; /* Put back in place later */
    rr->authenticationToken = client->authenticationToken;
    rr->timestamp = el->dateTime_now(el);

    /* Create a unique handle >100,000 if not manually defined. The handle is
     * not necessarily unique when manually defined and used to cancel async
     * service requests. */
    if(rr->requestHandle == 0) {
        if(UA_UNLIKELY(client->requestHandle < 100000))
            client->requestHandle = 100000;
        rr->requestHandle = ++client->requestHandle;
    }

    /* Set the timeout hint if not manually defined */
    if(rr->timeoutHint == 0)
        rr->timeoutHint = client->config.timeout;

    /* Generate the request id */
    UA_UInt32 rqId = ++client->requestId;

#ifdef UA_ENABLE_TYPEDESCRIPTION
    UA_LOG_DEBUG_CHANNEL(client->config.logging, &client->channel,
                         "Sending request with RequestId %u of type %s",
                         (unsigned)rqId, requestType->typeName);
#else
    UA_LOG_DEBUG_CHANNEL(client->config.logging, &client->channel,
                         "Sending request with RequestId %u of type %" PRIu32,
                         (unsigned)rqId, requestType->binaryEncodingId.identifier.numeric);
#endif

    /* Send the message */
    UA_StatusCode retval =
        UA_SecureChannel_sendSymmetricMessage(&client->channel, rqId,
                                              UA_MESSAGETYPE_MSG, rr, requestType);

    rr->authenticationToken = oldToken; /* Set back to the original token */

    /* Sending failed. The SecureChannel cannot recover from that. Call
     * closeSecureChannel to a) close from our end and b) set the session to
     * non-activated. */
    if(retval != UA_STATUSCODE_GOOD)
        closeSecureChannel(client);

    /* Return the request id */
    *requestId = rqId;
    return retval;
}

static const UA_NodeId
serviceFaultId = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_SERVICEFAULT_ENCODING_DEFAULTBINARY}};

/* Look for the async callback in the linked list, execute and delete it */
static UA_StatusCode
processMSGResponse(UA_Client *client, UA_UInt32 requestId,
                   const UA_ByteString *msg) {
    /* Find the callback */
    AsyncServiceCall *ac;
    LIST_FOREACH(ac, &client->asyncServiceCalls, pointers) {
        if(ac->requestId == requestId)
            break;
    }

    /* Part 6, 6.7.6: After the security validation is complete the receiver
     * shall verify the RequestId and the SequenceNumber. If these checks fail a
     * Bad_SecurityChecksFailed error is reported. The RequestId only needs to
     * be verified by the Client since only the Client knows if it is valid or
     * not.*/
    if(!ac) {
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "Request with unknown RequestId %u", requestId);
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    }

    UA_Response asyncResponse;
    UA_Response *response = (ac->syncResponse) ? ac->syncResponse : &asyncResponse;
    const UA_DataType *responseType = ac->responseType;

    /* Dequeue ac. We might disconnect the client (remove all ac) in the callback. */
    LIST_REMOVE(ac, pointers);

    /* Decode the response type */
    size_t offset = 0;
    UA_NodeId responseTypeId;
    UA_StatusCode retval = UA_NodeId_decodeBinary(msg, &offset, &responseTypeId);
    if(retval != UA_STATUSCODE_GOOD)
        goto process;

    /* Verify the type of the response */
    if(!UA_NodeId_equal(&responseTypeId, &ac->responseType->binaryEncodingId)) {
        /* Initialize before switching the responseType to ServiceFault.
         * Otherwise the decoding will leave fields from the original response
         * type uninitialized. */
        UA_init(response, ac->responseType);
        if(UA_NodeId_equal(&responseTypeId, &serviceFaultId)) {
            /* Decode as a ServiceFault, i.e. only the response header */
            UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                        "Received a ServiceFault response");
            responseType = &UA_TYPES[UA_TYPES_SERVICEFAULT];
        } else {
            UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                         "Service response type does not match");
            retval = UA_STATUSCODE_BADCOMMUNICATIONERROR;
            goto process; /* Do not decode */
        }
    }

    /* Decode the response */
#ifdef UA_ENABLE_TYPEDESCRIPTION
    UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT,
                 "Decode a message of type %s", responseType->typeName);
#else
    UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT,
                 "Decode a message of type %" PRIu32,
                 responseTypeId.identifier.numeric);
#endif
    retval = UA_decodeBinaryInternal(msg, &offset, response, responseType,
                                     client->config.customDataTypes);

 process:
    /* Process the received MSG response */
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "Could not decode the response with RequestId %u with status %s",
                       (unsigned)requestId, UA_StatusCode_name(retval));
        response->responseHeader.serviceResult = retval;
    }

    /* The Session closed. The current response is processed with the return code.
     * The next request first recreates a session. */
    if(responseType != &UA_TYPES[UA_TYPES_ACTIVATESESSIONRESPONSE] &&
       (response->responseHeader.serviceResult == UA_STATUSCODE_BADSESSIONIDINVALID ||
        response->responseHeader.serviceResult == UA_STATUSCODE_BADSESSIONCLOSED)) {
        /* Clean up the session information and reset the state */
        cleanupSession(client);

        if(client->config.noNewSession) {
            /* Configuration option to not create a new Session. Disconnect the
             * client. */
            client->connectStatus = response->responseHeader.serviceResult;
            UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                         "Session cannot be activated with StatusCode %s. "
                         "The client is configured not to create a new Session.",
                         UA_StatusCode_name(client->connectStatus));
            closeSecureChannel(client);
        } else {
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                           "Session no longer valid. A new Session is created for the next "
                           "Service request but we do not re-send the current request.");
        }
    }

    /* Call the async callback. This is the only thread with access to ac. So we
     * can just unlock for the callback into userland. */
    UA_UNLOCK(&client->clientMutex);
    if(ac->callback)
        ac->callback(client, ac->userdata, requestId, response);
    UA_LOCK(&client->clientMutex);

    /* Clean up */
    UA_NodeId_clear(&responseTypeId);
    if(!ac->syncResponse) {
        UA_clear(response, ac->responseType);
        UA_free(ac);
    } else {
        ac->syncResponse = NULL; /* Indicate that response was received */
    }
    return retval;
}

UA_StatusCode
processServiceResponse(void *application, UA_SecureChannel *channel,
                       UA_MessageType messageType, UA_UInt32 requestId,
                       UA_ByteString *message) {
    UA_Client *client = (UA_Client*)application;

    if(!UA_SecureChannel_isConnected(channel)) {
        if(messageType == UA_MESSAGETYPE_MSG) {
            UA_LOG_DEBUG_CHANNEL(client->config.logging, channel, "Discard MSG message "
                                 "with RequestId %u as the SecureChannel is not connected",
                                 requestId);
        } else {
            UA_LOG_DEBUG_CHANNEL(client->config.logging, channel, "Discard message "
                                 "as the SecureChannel is not connected");
        }
        return UA_STATUSCODE_BADCONNECTIONCLOSED;
    }

    switch(messageType) {
    case UA_MESSAGETYPE_RHE:
        UA_LOG_DEBUG_CHANNEL(client->config.logging, channel, "Process RHE message");
        processRHEMessage(client, message);
        return UA_STATUSCODE_GOOD;
    case UA_MESSAGETYPE_ACK:
        UA_LOG_DEBUG_CHANNEL(client->config.logging, channel, "Process ACK message");
        processACKResponse(client, message);
        return UA_STATUSCODE_GOOD;
    case UA_MESSAGETYPE_OPN:
        UA_LOG_DEBUG_CHANNEL(client->config.logging, channel, "Process OPN message");
        processOPNResponse(client, message);
        return UA_STATUSCODE_GOOD;
    case UA_MESSAGETYPE_ERR:
        UA_LOG_DEBUG_CHANNEL(client->config.logging, channel, "Process ERR message");
        processERRResponse(client, message);
        return UA_STATUSCODE_GOOD;
    case UA_MESSAGETYPE_MSG:
        UA_LOG_DEBUG_CHANNEL(client->config.logging, channel, "Process MSG message "
                             "with RequestId %u", requestId);
        return processMSGResponse(client, requestId, message);
    default:
        UA_LOG_TRACE_CHANNEL(client->config.logging, channel,
                             "Invalid message type");
        channel->state = UA_SECURECHANNELSTATE_CLOSING;
        return UA_STATUSCODE_BADTCPMESSAGETYPEINVALID;
    }
}

void
__Client_Service(UA_Client *client, const void *request,
                 const UA_DataType *requestType, void *response,
                 const UA_DataType *responseType) {
    UA_ResponseHeader *respHeader = (UA_ResponseHeader*)response;

    /* Initialize. Response is valied in case of aborting. */
    UA_init(response, responseType);

    /* Verify that the EventLoop is running */
    UA_EventLoop *el = client->config.eventLoop;
    if(!el || el->state != UA_EVENTLOOPSTATE_STARTED) {
        respHeader->serviceResult = UA_STATUSCODE_BADINTERNALERROR;
		return;
    }

    /* Check that the SecureChannel is open and also a Session active (if we
     * want a Session). Otherwise reopen. */
    if(!isFullyConnected(client)) {
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                    "Re-establish the connction for the synchronous service call");
        connectSync(client);
        if(client->connectStatus != UA_STATUSCODE_GOOD) {
            respHeader->serviceResult = client->connectStatus;
            return;
        }
    }

    /* Store the channelId to detect if the channel was changed by a
     * reconnection within the EventLoop run method. */
    UA_UInt32 channelId = client->channel.securityToken.channelId;

    /* Send the request */
    UA_UInt32 requestId = 0;
    UA_StatusCode retval = sendRequest(client, request, requestType, &requestId);
    if(retval != UA_STATUSCODE_GOOD) {
        /* If sending failed, the status is set to closing. The SecureChannel is
         * the actually closed in the next iteration of the EventLoop. */
        UA_assert(client->channel.state == UA_SECURECHANNELSTATE_CLOSING ||
                  client->channel.state == UA_SECURECHANNELSTATE_CLOSED);
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "Sending the request failed with status %s",
                       UA_StatusCode_name(retval));
        notifyClientState(client);
        respHeader->serviceResult = retval;
        return;
    }

    /* Temporarily insert an AsyncServiceCall */
    const UA_RequestHeader *rh = (const UA_RequestHeader*)request;
    AsyncServiceCall ac;
    ac.callback = NULL;
    ac.userdata = NULL;
    ac.responseType = responseType;
    ac.syncResponse = (UA_Response*)response;
    ac.requestId = requestId;
    ac.start = el->dateTime_nowMonotonic(el); /* Start timeout after sending */
    ac.timeout = rh->timeoutHint;
    ac.requestHandle = rh->requestHandle;
    if(ac.timeout == 0)
        ac.timeout = UA_UINT32_MAX; /* 0 -> unlimited */

    LIST_INSERT_HEAD(&client->asyncServiceCalls, &ac, pointers);

    /* Time until which the request has to be answered */
    UA_DateTime maxDate = ac.start + ((UA_DateTime)ac.timeout * UA_DATETIME_MSEC);

    /* Run the EventLoop until the request was processed, the request has timed
     * out or the client connection fails */
    UA_UInt32 timeout_remaining = ac.timeout;
    while(true) {
        /* Unlock before dropping into the EventLoop. The client lock is
         * re-taken in the network callback if an event occurs. */
        UA_UNLOCK(&client->clientMutex);
        retval = el->run(el, timeout_remaining);
        UA_LOCK(&client->clientMutex);

        /* Was the response received? In that case we can directly return. The
         * ac was already removed from the internal linked list. */
        if(ac.syncResponse == NULL)
            return;

        /* Check the status. Do not try to resend if the connection breaks.
         * Leave this to the application-level user. For example, we do not want
         * to call a method twice is the connection broke after sending the
         * request. */
        if(retval != UA_STATUSCODE_GOOD)
            break;

        /* The connection was lost */
        retval = client->connectStatus;
        if(retval != UA_STATUSCODE_GOOD)
            break;

        /* The channel is no longer the same or was closed */
        if(channelId != client->channel.securityToken.channelId) {
            retval = UA_STATUSCODE_BADSECURECHANNELCLOSED;
            break;
        }

        /* Update the remaining timeout or break */
        UA_DateTime now = ac.start = el->dateTime_nowMonotonic(el);
        if(now > maxDate) {
            retval = UA_STATUSCODE_BADTIMEOUT;
            break;
        }
        timeout_remaining = (UA_UInt32)((maxDate - now) / UA_DATETIME_MSEC);
    }

    /* Detach from the internal async service list */
    LIST_REMOVE(&ac, pointers);

    /* Return the status code */
    respHeader->serviceResult = retval;
}

void
__UA_Client_Service(UA_Client *client, const void *request,
                    const UA_DataType *requestType, void *response,
                    const UA_DataType *responseType) {
    UA_LOCK(&client->clientMutex);
    __Client_Service(client, request, requestType, response, responseType);
    UA_UNLOCK(&client->clientMutex);
}

/***********************************/
/* Handling of Async Service Calls */
/***********************************/

static void
__Client_AsyncService_cancel(UA_Client *client, AsyncServiceCall *ac,
                             UA_StatusCode statusCode) {
    /* Set the status for the synchronous service call. Don't free the ac. */
    if(ac->syncResponse) {
        ac->syncResponse->responseHeader.serviceResult = statusCode;
        ac->syncResponse = NULL; /* Indicate the async service call was processed */
        return;
    }

    if(ac->callback) {
        /* Create an empty response with the statuscode and call the callback */
        UA_Response response;
        UA_init(&response, ac->responseType);
        response.responseHeader.serviceResult = statusCode;
        UA_UNLOCK(&client->clientMutex);
        ac->callback(client, ac->userdata, ac->requestId, &response);
        UA_LOCK(&client->clientMutex);

        /* Clean up the response. The user callback might move data into it. For
         * whatever reasons. */
        UA_clear(&response, ac->responseType);
    }

    UA_free(ac);
}

void
__Client_AsyncService_removeAll(UA_Client *client, UA_StatusCode statusCode) {
    /* Make this function reentrant. One of the async callbacks could indirectly
     * operate on the list. Moving all elements to a local list before iterating
     * that. */
    UA_AsyncServiceList asyncServiceCalls = client->asyncServiceCalls;
    LIST_INIT(&client->asyncServiceCalls);
    if(asyncServiceCalls.lh_first)
        asyncServiceCalls.lh_first->pointers.le_prev = &asyncServiceCalls.lh_first;

    /* Cancel and remove the elements from the local list */
    AsyncServiceCall *ac, *ac_tmp;
    LIST_FOREACH_SAFE(ac, &asyncServiceCalls, pointers, ac_tmp) {
        LIST_REMOVE(ac, pointers);
        __Client_AsyncService_cancel(client, ac, statusCode);
    }
}

UA_StatusCode
UA_Client_modifyAsyncCallback(UA_Client *client, UA_UInt32 requestId,
                              void *userdata, UA_ClientAsyncServiceCallback callback) {
    UA_LOCK(&client->clientMutex);
    AsyncServiceCall *ac;
    UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND;
    LIST_FOREACH(ac, &client->asyncServiceCalls, pointers) {
        if(ac->requestId == requestId) {
            ac->callback = callback;
            ac->userdata = userdata;
            res = UA_STATUSCODE_GOOD;
            break;
        }
    }
    UA_UNLOCK(&client->clientMutex);
    return res;
}

UA_StatusCode
__Client_AsyncService(UA_Client *client, const void *request,
                      const UA_DataType *requestType,
                      UA_ClientAsyncServiceCallback callback,
                      const UA_DataType *responseType,
                      void *userdata, UA_UInt32 *requestId) {
    UA_LOCK_ASSERT(&client->clientMutex, 1);

    /* Is the SecureChannel connected? */
    if(client->channel.state != UA_SECURECHANNELSTATE_OPEN) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "SecureChannel must be connected to send request");
        return UA_STATUSCODE_BADSERVERNOTCONNECTED;
    }

    /* Prepare the entry for the linked list */
    AsyncServiceCall *ac = (AsyncServiceCall*)UA_malloc(sizeof(AsyncServiceCall));
    if(!ac)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Call the service and set the requestId */
    UA_StatusCode retval = sendRequest(client, request, requestType, &ac->requestId);
    if(retval != UA_STATUSCODE_GOOD) {
        /* If sending failed, the status is set to closing. The SecureChannel is
         * the actually closed in the next iteration of the EventLoop. */
        UA_assert(client->channel.state == UA_SECURECHANNELSTATE_CLOSING ||
                  client->channel.state == UA_SECURECHANNELSTATE_CLOSED);
        UA_free(ac);
        notifyClientState(client);
        return retval;
    }

    /* Set up the AsyncServiceCall for processing the response */
    UA_EventLoop *el = client->config.eventLoop;
    const UA_RequestHeader *rh = (const UA_RequestHeader*)request;
    ac->callback = callback;
    ac->responseType = responseType;
    ac->userdata = userdata;
    ac->syncResponse = NULL;
    ac->start = el->dateTime_nowMonotonic(el);
    ac->timeout = rh->timeoutHint;
    ac->requestHandle = rh->requestHandle;
    if(ac->timeout == 0)
        ac->timeout = UA_UINT32_MAX; /* 0 -> unlimited */

    LIST_INSERT_HEAD(&client->asyncServiceCalls, ac, pointers);

    /* Return the generated request id */
    if(requestId)
        *requestId = ac->requestId;

    /* Notify the userland if a change happened */
    notifyClientState(client);

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
__UA_Client_AsyncService(UA_Client *client, const void *request,
                         const UA_DataType *requestType,
                         UA_ClientAsyncServiceCallback callback,
                         const UA_DataType *responseType,
                         void *userdata, UA_UInt32 *requestId) {
    UA_LOCK(&client->clientMutex);
    UA_StatusCode res =
        __Client_AsyncService(client, request, requestType, callback, responseType,
                              userdata, requestId);
    UA_UNLOCK(&client->clientMutex);
    return res;
}

static UA_StatusCode
cancelByRequestHandle(UA_Client *client, UA_UInt32 requestHandle, UA_UInt32 *cancelCount) {
    UA_CancelRequest creq;
    UA_CancelRequest_init(&creq);
    creq.requestHandle = requestHandle;
    UA_CancelResponse cresp;
    UA_CancelResponse_init(&cresp);
    __Client_Service(client, &creq, &UA_TYPES[UA_TYPES_CANCELREQUEST],
                     &cresp, &UA_TYPES[UA_TYPES_CANCELRESPONSE]);
    if(cancelCount)
        *cancelCount = cresp.cancelCount;
    UA_StatusCode res = cresp.responseHeader.serviceResult;
    UA_CancelResponse_clear(&cresp);
    return res;
}

UA_StatusCode
UA_Client_cancelByRequestHandle(UA_Client *client, UA_UInt32 requestHandle,
                                UA_UInt32 *cancelCount) {
    UA_LOCK(&client->clientMutex);
    UA_StatusCode res = cancelByRequestHandle(client, requestHandle, cancelCount);
    UA_UNLOCK(&client->clientMutex);
    return res;
}

UA_StatusCode
UA_Client_cancelByRequestId(UA_Client *client, UA_UInt32 requestId,
                            UA_UInt32 *cancelCount) {
    UA_LOCK(&client->clientMutex);
    UA_StatusCode res = UA_STATUSCODE_BADNOTFOUND;
    AsyncServiceCall *ac;
    LIST_FOREACH(ac, &client->asyncServiceCalls, pointers) {
        if(ac->requestId != requestId)
            continue;
        res = cancelByRequestHandle(client, ac->requestHandle, cancelCount);
        break;
    }
    UA_UNLOCK(&client->clientMutex);
    return res;
}

/*******************/
/* Timed Callbacks */
/*******************/

UA_StatusCode
UA_Client_addTimedCallback(UA_Client *client, UA_ClientCallback callback,
                           void *data, UA_DateTime date, UA_UInt64 *callbackId) {
    if(!client->config.eventLoop)
        return UA_STATUSCODE_BADINTERNALERROR;
    UA_LOCK(&client->clientMutex);
    UA_StatusCode res = client->config.eventLoop->
        addTimedCallback(client->config.eventLoop, (UA_Callback)callback,
                         client, data, date, callbackId);
    UA_UNLOCK(&client->clientMutex);
    return res;
}

UA_StatusCode
UA_Client_addRepeatedCallback(UA_Client *client, UA_ClientCallback callback,
                              void *data, UA_Double interval_ms, UA_UInt64 *callbackId) {
    if(!client->config.eventLoop)
        return UA_STATUSCODE_BADINTERNALERROR;
    UA_LOCK(&client->clientMutex);
    UA_StatusCode res = client->config.eventLoop->
        addCyclicCallback(client->config.eventLoop, (UA_Callback)callback,
                          client, data, interval_ms, NULL,
                          UA_TIMER_HANDLE_CYCLEMISS_WITH_CURRENTTIME, callbackId);
    UA_UNLOCK(&client->clientMutex);
    return res;
}

UA_StatusCode
UA_Client_changeRepeatedCallbackInterval(UA_Client *client, UA_UInt64 callbackId,
                                         UA_Double interval_ms) {
    if(!client->config.eventLoop)
        return UA_STATUSCODE_BADINTERNALERROR;
    UA_LOCK(&client->clientMutex);
    UA_StatusCode res = client->config.eventLoop->
        modifyCyclicCallback(client->config.eventLoop, callbackId, interval_ms,
                             NULL, UA_TIMER_HANDLE_CYCLEMISS_WITH_CURRENTTIME);
    UA_UNLOCK(&client->clientMutex);
    return res;
}

void
UA_Client_removeCallback(UA_Client *client, UA_UInt64 callbackId) {
    if(!client->config.eventLoop)
        return;
    UA_LOCK(&client->clientMutex);
    client->config.eventLoop->
        removeCyclicCallback(client->config.eventLoop, callbackId);
    UA_UNLOCK(&client->clientMutex);
}

/**********************/
/* Housekeeping Tasks */
/**********************/

static void
asyncServiceTimeoutCheck(UA_Client *client) {
    /* Make this function reentrant. One of the async callbacks could indirectly
     * operate on the list. Moving all elements to a local list before iterating
     * that. */
    UA_EventLoop *el = client->config.eventLoop;
    UA_DateTime now = el->dateTime_nowMonotonic(el);
    UA_AsyncServiceList asyncServiceCalls;
    AsyncServiceCall *ac, *ac_tmp;
    LIST_INIT(&asyncServiceCalls);
    LIST_FOREACH_SAFE(ac, &client->asyncServiceCalls, pointers, ac_tmp) {
        if(!ac->timeout)
           continue;
        if(ac->start + (UA_DateTime)(ac->timeout * UA_DATETIME_MSEC) <= now) {
            LIST_REMOVE(ac, pointers);
            LIST_INSERT_HEAD(&asyncServiceCalls, ac, pointers);
        }
    }

    /* Cancel and remove the elements from the local list */
    LIST_FOREACH_SAFE(ac, &asyncServiceCalls, pointers, ac_tmp) {
        LIST_REMOVE(ac, pointers);
        __Client_AsyncService_cancel(client, ac, UA_STATUSCODE_BADTIMEOUT);
    }
}

static void
backgroundConnectivityCallback(UA_Client *client, void *userdata,
                               UA_UInt32 requestId, const UA_ReadResponse *response) {
    UA_LOCK(&client->clientMutex);
    if(response->responseHeader.serviceResult == UA_STATUSCODE_BADTIMEOUT) {
        if(client->config.inactivityCallback) {
            UA_UNLOCK(&client->clientMutex);
            client->config.inactivityCallback(client);
            UA_LOCK(&client->clientMutex);
        }
    }
    UA_EventLoop *el = client->config.eventLoop;
    client->pendingConnectivityCheck = false;
    client->lastConnectivityCheck = el->dateTime_nowMonotonic(el);
    UA_UNLOCK(&client->clientMutex);
}

static void
__Client_backgroundConnectivity(UA_Client *client) {
    if(!client->config.connectivityCheckInterval)
        return;

    if(client->pendingConnectivityCheck)
        return;

    UA_EventLoop *el = client->config.eventLoop;
    UA_DateTime now = el->dateTime_nowMonotonic(el);
    UA_DateTime nextDate = client->lastConnectivityCheck +
        (UA_DateTime)(client->config.connectivityCheckInterval * UA_DATETIME_MSEC);
    if(now <= nextDate)
        return;

    /* Prepare the request */
    UA_ReadValueId rvid;
    UA_ReadValueId_init(&rvid);
    rvid.attributeId = UA_ATTRIBUTEID_VALUE;
    rvid.nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE);
    UA_ReadRequest request;
    UA_ReadRequest_init(&request);
    request.nodesToRead = &rvid;
    request.nodesToReadSize = 1;
    UA_StatusCode retval =
        __Client_AsyncService(client, &request, &UA_TYPES[UA_TYPES_READREQUEST],
                              (UA_ClientAsyncServiceCallback)backgroundConnectivityCallback,
                              &UA_TYPES[UA_TYPES_READRESPONSE], NULL, NULL);
    if(retval == UA_STATUSCODE_GOOD)
        client->pendingConnectivityCheck = true;
}

/* Regular housekeeping activities in the client -- called via a cyclic callback */
static void
clientHouseKeeping(UA_Client *client, void *_) {
    UA_LOCK(&client->clientMutex);

    UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT,
                 "Internally check the the client state and "
                 "required activities");

    /* Renew Secure Channel */
    __Client_renewSecureChannel(client);

    /* Send read requests from time to time to test the connectivity */
    __Client_backgroundConnectivity(client);

#ifdef UA_ENABLE_SUBSCRIPTIONS
    /* Feed the server PublishRequests for the Subscriptions */
    __Client_Subscriptions_backgroundPublish(client);

    /* Check for inactive Subscriptions */
    __Client_Subscriptions_backgroundPublishInactivityCheck(client);
#endif

    /* Did async services time out? Process callbacks with an error code */
    asyncServiceTimeoutCheck(client);

    /* Log and notify user if the client state has changed */
    notifyClientState(client);

    UA_UNLOCK(&client->clientMutex);
}

UA_StatusCode
__UA_Client_startup(UA_Client *client) {
    /* On entry, the client mutex is already locked */
    UA_EventLoop *el = client->config.eventLoop;
    UA_CHECK_ERROR(el != NULL,
                   return UA_STATUSCODE_BADINTERNALERROR,
                   client->config.logging, UA_LOGCATEGORY_CLIENT,
                   "No EventLoop configured");

    /* Set up the regular callback for checking the internal state? */
    UA_StatusCode rv = UA_STATUSCODE_GOOD;
    if(!client->houseKeepingCallbackId) {
        /* As per UA_Client_addRepeatedCallback but without locking mutex */
        rv = el->addCyclicCallback(el, (UA_Callback)clientHouseKeeping,
                                   client, NULL, 1000.0, NULL,
                                   UA_TIMER_HANDLE_CYCLEMISS_WITH_CURRENTTIME,
                                   &client->houseKeepingCallbackId);
        UA_CHECK_STATUS(rv, return rv);
    }

    /* Start the EventLoop? */
    if(el->state == UA_EVENTLOOPSTATE_FRESH) {
        rv = el->start(el);
        UA_CHECK_STATUS(rv, return rv);
    }

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Client_run_iterate(UA_Client *client, UA_UInt32 timeout) {
    UA_StatusCode rv = __UA_Client_startup(client);
    UA_CHECK_STATUS(rv, return rv);

    /* Process timed and network events in the EventLoop */
    UA_EventLoop *el = client->config.eventLoop;
    rv = el->run(el, timeout);
    UA_CHECK_STATUS(rv, return rv);
    return client->connectStatus;
}

const UA_DataType *
UA_Client_findDataType(UA_Client *client, const UA_NodeId *typeId) {
    return UA_findDataTypeWithCustom(typeId, client->config.customDataTypes);
}

/*************************/
/* Connection Attributes */
/*************************/

#define UA_CONNECTIONATTRIBUTESSIZE 3
static const UA_QualifiedName connectionAttributes[UA_CONNECTIONATTRIBUTESSIZE] = {
    {0, UA_STRING_STATIC("serverDescription")},
    {0, UA_STRING_STATIC("securityPolicyUri")},
    {0, UA_STRING_STATIC("securityMode")}
};

static UA_StatusCode
getConnectionttribute(UA_Client *client, const UA_QualifiedName key,
                      UA_Variant *outValue, UA_Boolean copy) {
    if(!outValue)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_Variant localAttr;

    if(UA_QualifiedName_equal(&key, &connectionAttributes[0])) {
        /* ServerDescription */
        UA_Variant_setScalar(&localAttr, &client->serverDescription,
                             &UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION]);
    } else if(UA_QualifiedName_equal(&key, &connectionAttributes[1])) {
        /* SecurityPolicyUri */
        const UA_SecurityPolicy *sp = client->channel.securityPolicy;
        if(!sp)
            return UA_STATUSCODE_BADNOTCONNECTED;
        UA_Variant_setScalar(&localAttr, (void*)(uintptr_t)&sp->policyUri,
                             &UA_TYPES[UA_TYPES_STRING]);
    } else if(UA_QualifiedName_equal(&key, &connectionAttributes[2])) {
        /* SecurityMode */
        UA_Variant_setScalar(&localAttr, &client->channel.securityMode,
                             &UA_TYPES[UA_TYPES_MESSAGESECURITYMODE]);
    } else {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    if(copy)
        return UA_Variant_copy(&localAttr, outValue);

    localAttr.storageType = UA_VARIANT_DATA_NODELETE;
    *outValue = localAttr;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Client_getConnectionAttribute(UA_Client *client, const UA_QualifiedName key,
                                 UA_Variant *outValue) {
    UA_LOCK(&client->clientMutex);
    UA_StatusCode res = getConnectionttribute(client, key, outValue, false);
    UA_UNLOCK(&client->clientMutex);
    return res;
}

UA_StatusCode
UA_Client_getConnectionAttributeCopy(UA_Client *client, const UA_QualifiedName key,
                                     UA_Variant *outValue) {
    UA_LOCK(&client->clientMutex);
    UA_StatusCode res = getConnectionttribute(client, key, outValue, true);
    UA_UNLOCK(&client->clientMutex);
    return res;
}

UA_StatusCode
UA_Client_getConnectionAttribute_scalar(UA_Client *client,
                                        const UA_QualifiedName key,
                                        const UA_DataType *type,
                                        void *outValue) {
    UA_LOCK(&client->clientMutex);

    UA_Variant attr;
    UA_StatusCode res = getConnectionttribute(client, key, &attr, false);
    if(res != UA_STATUSCODE_GOOD) {
        UA_UNLOCK(&client->clientMutex);
        return res;
    }

    if(!UA_Variant_hasScalarType(&attr, type)) {
        UA_UNLOCK(&client->clientMutex);
        return UA_STATUSCODE_BADNOTFOUND;
    }

    memcpy(outValue, attr.data, type->memSize);

    UA_UNLOCK(&client->clientMutex);
    return UA_STATUSCODE_GOOD;
}

/**** amalgamated original file "/src/client/ua_client_connect.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2017-2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2017-2019 (c) Fraunhofer IOSB (Author: Mark Giraud)
 */



/* Some OPC UA servers only return all Endpoints if the EndpointURL used during
 * the HEL/ACK handshake exactly matches -- including the path following the
 * address and port! Hence for the first connection we only call FindServers and
 * reopen a new TCP connection using then EndpointURL found there.
 *
 * The overall process is this:
 * - Connect with the EndpointURL provided by the user (HEL/ACK)
 * - Call FindServers
 *   - If one of the results has an exactly matching EndpointUrl, continue.
 *   - Otherwise select a matching server, update the endpointURL member of
 *     UA_Client and reconnect.
 * - Call GetEndpoints and select an Endpoint
 * - Open a SecureChannel and Session for that Endpoint
 */

#define UA_MINMESSAGESIZE 8192
#define UA_SESSION_LOCALNONCELENGTH 32
#define MAX_DATA_SIZE 4096
#define REVERSE_CONNECT_INDICATOR (void *)(uintptr_t)0xFFFFFFFF

static void initConnect(UA_Client *client);
static UA_StatusCode createSessionAsync(UA_Client *client);

/* Get the EndpointUrl to be used right now.
 * This is adjusted during the discovery process.
 * We fall back if connecting to an EndpointUrl fails. */
static UA_String
getEndpointUrl(UA_Client *client) {
    if(client->config.endpoint.endpointUrl.length > 0) {
        return client->config.endpoint.endpointUrl;
    } else if(client->discoveryUrl.length > 0) {
        return client->discoveryUrl;
    } else {
        return client->config.endpointUrl;
    }
}

/* If an EndpointUrl doesn't work (TCP connection fails), fall back to the
 * initial EndpointUrl */
static UA_StatusCode
fallbackEndpointUrl(UA_Client* client) {
    /* Cannot fallback, the initial EndpointUrl is already in use */
    UA_String currentUrl = getEndpointUrl(client);
    if(UA_String_equal(&currentUrl, &client->config.endpointUrl)) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "Could not open a TCP connection to the Endpoint at %.*s",
                     (int)client->config.endpointUrl.length,
                     client->config.endpointUrl.data);
        return UA_STATUSCODE_BADCONNECTIONREJECTED;
    }

    if(client->config.endpoint.endpointUrl.length > 0) {
        /* Overwrite the EndpointUrl of the Endpoint */
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "Could not open a TCP connection to the Endpoint at %.*s. "
                       "Overriding the endpoint description with the initial "
                       "EndpointUrl at %.*s.",
                       (int)client->config.endpoint.endpointUrl.length,
                       client->config.endpoint.endpointUrl.data,
                       (int)client->config.endpointUrl.length,
                       client->config.endpointUrl.data);
        UA_String_clear(&client->config.endpoint.endpointUrl);
        return UA_String_copy(&client->config.endpointUrl,
                              &client->config.endpoint.endpointUrl);
    } else {
        /* Overwrite the DiscoveryUrl returned by FindServers */
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "The DiscoveryUrl returned by the FindServers service (%.*s) "
                       "could not be connected. Continuing with the initial EndpointUrl "
                       "%.*s for the GetEndpoints service.",
                       (int)client->config.endpointUrl.length,
                       client->config.endpointUrl.data,
                       (int)client->config.endpointUrl.length,
                       client->config.endpointUrl.data);
        UA_String_clear(&client->discoveryUrl);
        return UA_String_copy(&client->config.endpointUrl, &client->discoveryUrl);
    }
}

static UA_SecurityPolicy *
getSecurityPolicy(UA_Client *client, UA_String policyUri) {
    for(size_t i = 0; i < client->config.securityPoliciesSize; i++) {
        if(UA_String_equal(&policyUri, &client->config.securityPolicies[i].policyUri))
            return &client->config.securityPolicies[i];
    }
    return NULL;
}

static UA_SecurityPolicy *
getAuthSecurityPolicy(UA_Client *client, UA_String policyUri) {
    for(size_t i = 0; i < client->config.authSecurityPoliciesSize; i++) {
        if(UA_String_equal(&policyUri, &client->config.authSecurityPolicies[i].policyUri))
            return &client->config.authSecurityPolicies[i];
    }
    return NULL;
}

/* The endpoint is unconfigured if the description is all zeroed-out */
static UA_Boolean
endpointUnconfigured(UA_Client *client) {
    UA_EndpointDescription tmp;
    UA_EndpointDescription_init(&tmp);
    return UA_equal(&tmp, &client->config.endpoint,
                    &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
}

UA_Boolean
isFullyConnected(UA_Client *client) {
    /* No Session, but require one */
    if(client->sessionState != UA_SESSIONSTATE_ACTIVATED && !client->config.noSession)
        return false;

    /* No SecureChannel */
    if(client->channel.state != UA_SECURECHANNELSTATE_OPEN)
        return false;

    /* Handshake ongoing or not yet done */
    if(client->endpointsHandshake || endpointUnconfigured(client) ||
       client->findServersHandshake || client->discoveryUrl.length == 0)
        return false;

    return true;
}

/* Function to create a signature using remote certificate and nonce */
static UA_StatusCode
signActivateSessionRequest(UA_Client *client, UA_SecureChannel *channel,
                           UA_ActivateSessionRequest *request) {
    if(channel->securityMode != UA_MESSAGESECURITYMODE_SIGN &&
       channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
        return UA_STATUSCODE_GOOD;

    const UA_SecurityPolicy *sp = channel->securityPolicy;
    UA_SignatureData *sd = &request->clientSignature;
    const UA_SecurityPolicySignatureAlgorithm *signAlg =
        &sp->asymmetricModule.cryptoModule.signatureAlgorithm;

    /* Copy the signature algorithm identifier */
    UA_StatusCode retval = UA_String_copy(&signAlg->uri, &sd->algorithm);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Allocate memory for the signature */
    size_t signatureSize = signAlg->getLocalSignatureSize(channel->channelContext);
    retval = UA_ByteString_allocBuffer(&sd->signature, signatureSize);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Allocate a temporary buffer */
    UA_ByteString dataToSign;
    size_t dataToSignSize =
        channel->remoteCertificate.length + client->serverSessionNonce.length;
    if(dataToSignSize > MAX_DATA_SIZE)
        return UA_STATUSCODE_BADINTERNALERROR;
    retval = UA_ByteString_allocBuffer(&dataToSign, dataToSignSize);
    if(retval != UA_STATUSCODE_GOOD)
        return retval; /* sd->signature is cleaned up with the response */

    /* Sign the clientSignature */
    memcpy(dataToSign.data, channel->remoteCertificate.data,
           channel->remoteCertificate.length);
    memcpy(dataToSign.data + channel->remoteCertificate.length,
           client->serverSessionNonce.data, client->serverSessionNonce.length);
    retval = signAlg->sign(channel->channelContext, &dataToSign, &sd->signature);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Prepare the userTokenSignature */
    if(client->config.userTokenPolicy.tokenType == UA_USERTOKENTYPE_CERTIFICATE) {
        /* Get the correct securityPolicy for authentication */
        UA_SecurityPolicy *utsp =
            getAuthSecurityPolicy(client, client->config.authSecurityPolicyUri);
        if(!utsp) {
            UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                         "The configured SecurityPolicy for certificate "
                         "authentication could not be found");
            retval = UA_STATUSCODE_BADSECURITYPOLICYREJECTED;
            goto cleanup;
        }

        UA_SignatureData *utsd = &request->userTokenSignature;
        UA_X509IdentityToken *token = (UA_X509IdentityToken *)
            request->userIdentityToken.content.decoded.data;
        UA_SecurityPolicySignatureAlgorithm *utpSignAlg =
            &utsp->asymmetricModule.cryptoModule.signatureAlgorithm;

        /* Check the size of the content for signing */
        UA_ByteString signData = UA_BYTESTRING_NULL;
        size_t signDataSize =
            channel->remoteCertificate.length + client->serverSessionNonce.length;
        if(dataToSignSize > MAX_DATA_SIZE) {
            retval = UA_STATUSCODE_BADINTERNALERROR;
            goto cleanup;
        }

        /* Copy the algorithm identifier */
        retval = UA_String_copy(&utpSignAlg->uri, &utsd->algorithm);
        if(retval != UA_STATUSCODE_GOOD)
            goto cleanup;

        /* We need a channel context with the user certificate in order to reuse
         * the code for signing. */
        void *tmpCtx;
        retval = utsp->channelModule.newContext(utsp, &token->certificateData, &tmpCtx);
        if(retval != UA_STATUSCODE_GOOD)
            goto cleanup;

        /* Allocate memory for the signature */
        retval = UA_ByteString_allocBuffer(&utsd->signature,
                                           utpSignAlg->getLocalSignatureSize(tmpCtx));
        if(retval != UA_STATUSCODE_GOOD)
            goto cleanup_utp;

        /* Allocate a temporary buffer for the data to be signed */
        retval = UA_ByteString_allocBuffer(&signData, signDataSize);
        if(retval != UA_STATUSCODE_GOOD)
            goto cleanup_utp;

        /* Create the userTokenSignature */
        memcpy(signData.data, channel->remoteCertificate.data,
               channel->remoteCertificate.length);
        memcpy(signData.data + channel->remoteCertificate.length,
               client->serverSessionNonce.data, client->serverSessionNonce.length);
        retval = utpSignAlg->sign(tmpCtx, &signData, &utsd->signature);

    cleanup_utp:
        UA_ByteString_clear(&signData);
        utsp->channelModule.deleteContext(tmpCtx);
    }

 cleanup:
    UA_ByteString_clear(&dataToSign);
    return retval;
}

static UA_StatusCode
encryptUserIdentityToken(UA_Client *client, const UA_String *userTokenSecurityPolicy,
                         UA_ExtensionObject *userIdentityToken) {
    UA_IssuedIdentityToken *iit = NULL;
    UA_UserNameIdentityToken *unit = NULL;
    UA_ByteString *tokenData;
    const UA_DataType *tokenType = userIdentityToken->content.decoded.type;
    if(tokenType == &UA_TYPES[UA_TYPES_ISSUEDIDENTITYTOKEN]) {
        iit = (UA_IssuedIdentityToken*)userIdentityToken->content.decoded.data;
        tokenData = &iit->tokenData;
    } else if(tokenType == &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]) {
        unit = (UA_UserNameIdentityToken*)userIdentityToken->content.decoded.data;
        tokenData = &unit->password;
    } else {
        return UA_STATUSCODE_GOOD;
    }

    /* No encryption */
    const UA_String none = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None");
    if(userTokenSecurityPolicy->length == 0 ||
       UA_String_equal(userTokenSecurityPolicy, &none)) {
        return UA_STATUSCODE_GOOD;
    }

    UA_SecurityPolicy *sp = getSecurityPolicy(client, *userTokenSecurityPolicy);
    if(!sp) {
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_NETWORK,
                       "Could not find the required SecurityPolicy for the UserToken");
        return UA_STATUSCODE_BADSECURITYPOLICYREJECTED;
    }

    /* Create a temp channel context */

    void *channelContext;
    UA_StatusCode retval = sp->channelModule.
        newContext(sp, &client->config.endpoint.serverCertificate, &channelContext);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_NETWORK,
                       "Could not instantiate the SecurityPolicy for the UserToken");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Compute the encrypted length (at least one byte padding) */
    size_t plainTextBlockSize = sp->asymmetricModule.cryptoModule.
        encryptionAlgorithm.getRemotePlainTextBlockSize(channelContext);
    size_t encryptedBlockSize = sp->asymmetricModule.cryptoModule.
        encryptionAlgorithm.getRemoteBlockSize(channelContext);
    UA_UInt32 length = (UA_UInt32)(tokenData->length +
                                   client->serverSessionNonce.length);
    UA_UInt32 totalLength = length + 4; /* Including the length field */
    size_t blocks = totalLength / plainTextBlockSize;
    if(totalLength % plainTextBlockSize != 0)
        blocks++;
    size_t encryptedLength = blocks * encryptedBlockSize;

    /* Allocate memory for encryption overhead */
    UA_ByteString encrypted;
    retval = UA_ByteString_allocBuffer(&encrypted, encryptedLength);
    if(retval != UA_STATUSCODE_GOOD) {
        sp->channelModule.deleteContext(channelContext);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    UA_Byte *pos = encrypted.data;
    const UA_Byte *end = &encrypted.data[encrypted.length];
    retval = UA_UInt32_encodeBinary(&length, &pos, end);
    memcpy(pos, tokenData->data, tokenData->length);
    memcpy(&pos[tokenData->length], client->serverSessionNonce.data,
           client->serverSessionNonce.length);
    UA_assert(retval == UA_STATUSCODE_GOOD);

    /* Add padding
     *
     * 7.36.2.2 Legacy Encrypted Token Secret Format: A Client should not add any
     * padding after the secret. If a Client adds padding then all bytes shall
     * be zero. A Server shall check for padding added by Clients and ensure
     * that all padding bytes are zeros. */
    size_t paddedLength = plainTextBlockSize * blocks;
    for(size_t i = totalLength; i < paddedLength; i++)
        encrypted.data[i] = 0;
    encrypted.length = paddedLength;

    retval = sp->asymmetricModule.cryptoModule.encryptionAlgorithm.
        encrypt(channelContext, &encrypted);
    encrypted.length = encryptedLength;

    if(iit) {
        retval |= UA_String_copy(&sp->asymmetricModule.cryptoModule.encryptionAlgorithm.uri,
                                 &iit->encryptionAlgorithm);
    } else {
        retval |= UA_String_copy(&sp->asymmetricModule.cryptoModule.encryptionAlgorithm.uri,
                                 &unit->encryptionAlgorithm);
    }

    UA_ByteString_clear(tokenData);
    *tokenData = encrypted;

    /* Delete the temp channel context */
    sp->channelModule.deleteContext(channelContext);

    return retval;
}

/* Function to verify the signature corresponds to ClientNonce
 * using the local certificate */
static UA_StatusCode
checkCreateSessionSignature(UA_Client *client, const UA_SecureChannel *channel,
                            const UA_CreateSessionResponse *response) {
    if(channel->securityMode != UA_MESSAGESECURITYMODE_SIGN &&
       channel->securityMode != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
        return UA_STATUSCODE_GOOD;

    if(!channel->securityPolicy)
        return UA_STATUSCODE_BADINTERNALERROR;

    const UA_SecurityPolicy *sp = channel->securityPolicy;
    const UA_ByteString *lc = &sp->localCertificate;

    size_t dataToVerifySize = lc->length + client->clientSessionNonce.length;
    UA_ByteString dataToVerify = UA_BYTESTRING_NULL;
    UA_StatusCode retval = UA_ByteString_allocBuffer(&dataToVerify, dataToVerifySize);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    memcpy(dataToVerify.data, lc->data, lc->length);
    memcpy(dataToVerify.data + lc->length, client->clientSessionNonce.data,
           client->clientSessionNonce.length);

    const UA_SecurityPolicySignatureAlgorithm *signAlg =
        &sp->asymmetricModule.cryptoModule.signatureAlgorithm;
    retval = signAlg->verify(channel->channelContext, &dataToVerify,
                             &response->serverSignature.signature);
    UA_ByteString_clear(&dataToVerify);
    return retval;
}

/***********************/
/* Open the Connection */
/***********************/

void
processERRResponse(UA_Client *client, const UA_ByteString *chunk) {
    client->channel.state = UA_SECURECHANNELSTATE_CLOSING;

    size_t offset = 0;
    UA_TcpErrorMessage errMessage;
    client->connectStatus =
        UA_decodeBinaryInternal(chunk, &offset, &errMessage,
                                &UA_TRANSPORT[UA_TRANSPORT_TCPERRORMESSAGE], NULL);
    if(client->connectStatus != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR_CHANNEL(client->config.logging, &client->channel,
                             "Received an ERR response that could not be decoded "
                             "with StatusCode %s",
                             UA_StatusCode_name(client->connectStatus));
        closeSecureChannel(client);
        return;
    }

    UA_LOG_ERROR_CHANNEL(client->config.logging, &client->channel,
                         "Received an ERR response with StatusCode %s and the following "
                         "reason: %.*s", UA_StatusCode_name(errMessage.error),
                         (int)errMessage.reason.length, errMessage.reason.data);
    client->connectStatus = errMessage.error;
    closeSecureChannel(client);
    UA_TcpErrorMessage_clear(&errMessage);
}

void
processACKResponse(UA_Client *client, const UA_ByteString *chunk) {
    UA_SecureChannel *channel = &client->channel;
    if(channel->state != UA_SECURECHANNELSTATE_HEL_SENT) {
        UA_LOG_ERROR_CHANNEL(client->config.logging, channel,
                             "SecureChannel not in the HEL-sent state");
        client->connectStatus = UA_STATUSCODE_BADSECURECHANNELCLOSED;
        closeSecureChannel(client);
        return;
    }

    /* Decode the message */
    size_t offset = 0;
    UA_TcpAcknowledgeMessage ackMessage;
    client->connectStatus =
        UA_decodeBinaryInternal(chunk, &offset, &ackMessage,
                                &UA_TRANSPORT[UA_TRANSPORT_TCPACKNOWLEDGEMESSAGE], NULL);
    if(client->connectStatus != UA_STATUSCODE_GOOD) {
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_NETWORK,
                     "Decoding ACK message failed");
        closeSecureChannel(client);
        return;
    }

    client->connectStatus =
        UA_SecureChannel_processHELACK(channel, &ackMessage);
    if(client->connectStatus != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_NETWORK,
                     "Processing the ACK message failed with StatusCode %s",
                     UA_StatusCode_name(client->connectStatus));
        closeSecureChannel(client);
        return;
    }

    client->channel.state = UA_SECURECHANNELSTATE_ACK_RECEIVED;
}

static UA_StatusCode
sendHELMessage(UA_Client *client) {
    UA_ConnectionManager *cm = client->channel.connectionManager;
    if(!UA_SecureChannel_isConnected(&client->channel))
        return UA_STATUSCODE_BADNOTCONNECTED;

    /* Get a buffer */
    UA_ByteString message;
    UA_StatusCode retval = cm->allocNetworkBuffer(cm, client->channel.connectionId,
                                                  &message, UA_MINMESSAGESIZE);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Prepare the HEL message and encode at offset 8 */
    UA_TcpHelloMessage hello;
    hello.protocolVersion = 0;
    hello.receiveBufferSize = client->config.localConnectionConfig.recvBufferSize;
    hello.sendBufferSize = client->config.localConnectionConfig.sendBufferSize;
    hello.maxMessageSize = client->config.localConnectionConfig.localMaxMessageSize;
    hello.maxChunkCount = client->config.localConnectionConfig.localMaxChunkCount;
    hello.endpointUrl = getEndpointUrl(client);

    UA_Byte *bufPos = &message.data[8]; /* skip the header */
    const UA_Byte *bufEnd = &message.data[message.length];
    client->connectStatus =
        UA_encodeBinaryInternal(&hello, &UA_TRANSPORT[UA_TRANSPORT_TCPHELLOMESSAGE],
                                &bufPos, &bufEnd, NULL, NULL);

    /* Encode the message header at offset 0 */
    UA_TcpMessageHeader messageHeader;
    messageHeader.messageTypeAndChunkType = UA_CHUNKTYPE_FINAL + UA_MESSAGETYPE_HEL;
    messageHeader.messageSize = (UA_UInt32) ((uintptr_t)bufPos - (uintptr_t)message.data);
    bufPos = message.data;
    retval = UA_encodeBinaryInternal(&messageHeader,
                                     &UA_TRANSPORT[UA_TRANSPORT_TCPMESSAGEHEADER],
                                     &bufPos, &bufEnd, NULL, NULL);
    if(retval != UA_STATUSCODE_GOOD) {
        cm->freeNetworkBuffer(cm, client->channel.connectionId, &message);
        return retval;
    }

    /* Send the HEL message */
    message.length = messageHeader.messageSize;
    retval = cm->sendWithConnection(cm, client->channel.connectionId,
                                    &UA_KEYVALUEMAP_NULL, &message);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT, "Sending HEL failed");
        closeSecureChannel(client);
        return retval;
    }

    UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT, "Sent HEL message");
    client->channel.state = UA_SECURECHANNELSTATE_HEL_SENT;
    return UA_STATUSCODE_GOOD;
}

void processRHEMessage(UA_Client *client, const UA_ByteString *chunk) {
    UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT, "RHE received");

    size_t offset = 0; /* Go to the beginning of the TcpHelloMessage */
    UA_TcpReverseHelloMessage rheMessage;
    UA_StatusCode retval =
        UA_decodeBinaryInternal(chunk, &offset, &rheMessage,
                                &UA_TRANSPORT[UA_TRANSPORT_TCPREVERSEHELLOMESSAGE], NULL);

    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_NETWORK,
                     "Decoding RHE message failed");
        closeSecureChannel(client);
        return;
    }

    UA_String_clear(&client->discoveryUrl);
    UA_String_copy(&rheMessage.endpointUrl, &client->discoveryUrl);

    UA_TcpReverseHelloMessage_clear(&rheMessage);

    sendHELMessage(client);
}

void
processOPNResponse(UA_Client *client, const UA_ByteString *message) {
    /* Is the content of the expected type? */
    size_t offset = 0;
    UA_NodeId responseId;
    UA_NodeId expectedId =
        UA_NODEID_NUMERIC(0, UA_NS0ID_OPENSECURECHANNELRESPONSE_ENCODING_DEFAULTBINARY);
    UA_StatusCode retval = UA_NodeId_decodeBinary(message, &offset, &responseId);
    if(retval != UA_STATUSCODE_GOOD) {
        closeSecureChannel(client);
        return;
    }

    if(!UA_NodeId_equal(&responseId, &expectedId)) {
        UA_NodeId_clear(&responseId);
        closeSecureChannel(client);
        return;
    }

    /* Decode the response */
    UA_OpenSecureChannelResponse response;
    retval = UA_decodeBinaryInternal(message, &offset, &response,
                                     &UA_TYPES[UA_TYPES_OPENSECURECHANNELRESPONSE], NULL);
    if(retval != UA_STATUSCODE_GOOD) {
        closeSecureChannel(client);
        return;
    }

    /* Check whether the nonce was reused */
    if(client->channel.securityMode != UA_MESSAGESECURITYMODE_NONE &&
       UA_ByteString_equal(&client->channel.remoteNonce,
                           &response.serverNonce)) {
        UA_LOG_ERROR_CHANNEL(client->config.logging, &client->channel,
                             "The server reused the last nonce");
        client->connectStatus = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        closeSecureChannel(client);
        return;
    }

    /* Response.securityToken.revisedLifetime is UInt32 we need to cast it to
     * DateTime=Int64 we take 75% of lifetime to start renewing as described in
     * standard */
    UA_EventLoop *el = client->config.eventLoop;
    client->nextChannelRenewal = el->dateTime_nowMonotonic(el)
            + (UA_DateTime) (response.securityToken.revisedLifetime
                    * (UA_Double) UA_DATETIME_MSEC * 0.75);

    /* Move the nonce out of the response */
    UA_ByteString_clear(&client->channel.remoteNonce);
    client->channel.remoteNonce = response.serverNonce;
    UA_ByteString_init(&response.serverNonce);
    UA_ResponseHeader_clear(&response.responseHeader);

    /* Replace the token. Keep the current token as the old token. Messages
     * might still arrive for the old token. */
    client->channel.altSecurityToken = client->channel.securityToken;
    client->channel.securityToken = response.securityToken;
    client->channel.renewState = UA_SECURECHANNELRENEWSTATE_NEWTOKEN_CLIENT;

    /* Compute the new local keys. The remote keys are updated when a message
     * with the new SecurityToken is received. */
    retval = UA_SecureChannel_generateLocalKeys(&client->channel);
    if(retval != UA_STATUSCODE_GOOD) {
        closeSecureChannel(client);
        return;
    }

    UA_Float lifetime = (UA_Float)response.securityToken.revisedLifetime / 1000;
    UA_Boolean renew = (client->channel.state == UA_SECURECHANNELSTATE_OPEN);
    if(renew) {
        UA_LOG_INFO_CHANNEL(client->config.logging, &client->channel, "SecureChannel "
                            "renewed with a revised lifetime of %.2fs", lifetime);
    } else {
        UA_LOG_INFO_CHANNEL(client->config.logging, &client->channel,
                            "SecureChannel opened with SecurityPolicy %.*s "
                            "and a revised lifetime of %.2fs",
                            (int)client->channel.securityPolicy->policyUri.length,
                            client->channel.securityPolicy->policyUri.data, lifetime);
    }

    client->channel.state = UA_SECURECHANNELSTATE_OPEN;
}

/* OPN messges to renew the channel are sent asynchronous */
static void
sendOPNAsync(UA_Client *client, UA_Boolean renew) {
    if(!UA_SecureChannel_isConnected(&client->channel)) {
        client->connectStatus = UA_STATUSCODE_BADINTERNALERROR;
        return;
    }

    client->connectStatus =
        UA_SecureChannel_generateLocalNonce(&client->channel);
    if(client->connectStatus != UA_STATUSCODE_GOOD)
        return;

    UA_EventLoop *el = client->config.eventLoop;

    /* Prepare the OpenSecureChannelRequest */
    UA_OpenSecureChannelRequest opnSecRq;
    UA_OpenSecureChannelRequest_init(&opnSecRq);
    opnSecRq.requestHeader.timestamp = el->dateTime_now(el);
    opnSecRq.requestHeader.authenticationToken = client->authenticationToken;
    opnSecRq.securityMode = client->channel.securityMode;
    opnSecRq.clientNonce = client->channel.localNonce;
    opnSecRq.requestedLifetime = client->config.secureChannelLifeTime;
    if(renew) {
        opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_RENEW;
        UA_LOG_DEBUG_CHANNEL(client->config.logging, &client->channel,
                             "Requesting to renew the SecureChannel");
    } else {
        opnSecRq.requestType = UA_SECURITYTOKENREQUESTTYPE_ISSUE;
        UA_LOG_DEBUG_CHANNEL(client->config.logging, &client->channel,
                             "Requesting to open a SecureChannel");
    }

    /* Prepare the entry for the linked list */
    UA_UInt32 requestId = ++client->requestId;

    /* Send the OPN message */
    UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_SECURECHANNEL,
                 "Requesting to open a SecureChannel");
    client->connectStatus =
        UA_SecureChannel_sendAsymmetricOPNMessage(&client->channel, requestId, &opnSecRq,
                                                  &UA_TYPES[UA_TYPES_OPENSECURECHANNELREQUEST]);
    if(client->connectStatus != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_SECURECHANNEL,
                      "Sending OPN message failed with error %s",
                      UA_StatusCode_name(client->connectStatus));
        closeSecureChannel(client);
        return;
    }

    /* Update the state */
    client->channel.renewState = UA_SECURECHANNELRENEWSTATE_SENT;
    if(client->channel.state < UA_SECURECHANNELSTATE_OPN_SENT)
        client->channel.state = UA_SECURECHANNELSTATE_OPN_SENT;

    UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_SECURECHANNEL,
                 "OPN message sent");
}

UA_StatusCode
__Client_renewSecureChannel(UA_Client *client) {
    UA_LOCK_ASSERT(&client->clientMutex, 1);

    UA_EventLoop *el = client->config.eventLoop;
    UA_DateTime now = el->dateTime_nowMonotonic(el);

    /* Check if OPN has been sent or the SecureChannel is still valid */
    if(client->channel.state != UA_SECURECHANNELSTATE_OPEN ||
       client->channel.renewState == UA_SECURECHANNELRENEWSTATE_SENT ||
       client->nextChannelRenewal > now)
        return UA_STATUSCODE_GOODCALLAGAIN;

    sendOPNAsync(client, true);

    return client->connectStatus;
}

UA_StatusCode
UA_Client_renewSecureChannel(UA_Client *client) {
    UA_LOCK(&client->clientMutex);
    UA_StatusCode res = __Client_renewSecureChannel(client);
    UA_UNLOCK(&client->clientMutex);
    return res;
}

static void
responseActivateSession(UA_Client *client, void *userdata,
                        UA_UInt32 requestId, void *response) {
    UA_LOCK(&client->clientMutex);

    UA_ActivateSessionResponse *ar = (UA_ActivateSessionResponse*)response;
    if(ar->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
        /* Activating the Session failed */
        cleanupSession(client);

        /* Configuration option to not create a new Session */
        if(client->config.noNewSession) {
            UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                         "Session cannot be activated with StatusCode %s. "
                         "The client is configured not to create a new Session.",
                         UA_StatusCode_name(ar->responseHeader.serviceResult));
            client->connectStatus = ar->responseHeader.serviceResult;
            closeSecureChannel(client);
            UA_UNLOCK(&client->clientMutex);
            return;
        }

        /* The Session is no longer usable. Create a brand new one. */
        if(ar->responseHeader.serviceResult == UA_STATUSCODE_BADSESSIONIDINVALID ||
           ar->responseHeader.serviceResult == UA_STATUSCODE_BADSESSIONCLOSED) {
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                           "Session to be activated no longer exists. Create a new Session.");
            client->connectStatus = createSessionAsync(client);
            UA_UNLOCK(&client->clientMutex);
            return;
        }

        /* Something else is wrong. Maybe the credentials no longer work. Give up. */
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "Session cannot be activated with StatusCode %s. "
                     "The client cannot recover from this, closing the connection.",
                     UA_StatusCode_name(ar->responseHeader.serviceResult));
        client->connectStatus = ar->responseHeader.serviceResult;
        closeSecureChannel(client);
        UA_UNLOCK(&client->clientMutex);
        return;
    }

    /* Replace the nonce */
    UA_ByteString_clear(&client->serverSessionNonce);
    client->serverSessionNonce = ar->serverNonce;
    UA_ByteString_init(&ar->serverNonce);

    client->sessionState = UA_SESSIONSTATE_ACTIVATED;
    notifyClientState(client);

    /* Immediately check if publish requests are outstanding - for example when
     * an existing Session has been reattached / activated. */
#ifdef UA_ENABLE_SUBSCRIPTIONS
    __Client_Subscriptions_backgroundPublish(client);
#endif

    UA_UNLOCK(&client->clientMutex);
}

static UA_StatusCode
activateSessionAsync(UA_Client *client) {
    UA_LOCK_ASSERT(&client->clientMutex, 1);

    if(client->sessionState != UA_SESSIONSTATE_CREATED &&
       client->sessionState != UA_SESSIONSTATE_ACTIVATED) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "Can not activate session, session neither created nor activated. "
                     "Actual state: '%u'", client->sessionState);
        return UA_STATUSCODE_BADSESSIONCLOSED;
    }

    UA_ActivateSessionRequest request;
    UA_ActivateSessionRequest_init(&request);
    UA_StatusCode retval =
        UA_ExtensionObject_copy(&client->config.userIdentityToken,
                                &request.userIdentityToken);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    if(client->config.sessionLocaleIdsSize && client->config.sessionLocaleIds) {
        retval = UA_Array_copy(client->config.sessionLocaleIds,
                               client->config.sessionLocaleIdsSize,
                               (void **)&request.localeIds, &UA_TYPES[UA_TYPES_LOCALEID]);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
        request.localeIdsSize = client->config.sessionLocaleIdsSize;
    }

    /* If not token is set, use anonymous */
    if(request.userIdentityToken.encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY) {
        UA_AnonymousIdentityToken *t = UA_AnonymousIdentityToken_new();
        if(!t) {
            UA_ActivateSessionRequest_clear(&request);
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }
        request.userIdentityToken.content.decoded.data = t;
        request.userIdentityToken.content.decoded.type =
            &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN];
        request.userIdentityToken.encoding = UA_EXTENSIONOBJECT_DECODED;
    }

    /* Set the correct PolicyId from the endpoint */
    UA_String_clear((UA_String*)request.userIdentityToken.content.decoded.data);
    retval = UA_String_copy(&client->config.userTokenPolicy.policyId,
                            (UA_String*)request.userIdentityToken.content.decoded.data);

    /* Encrypt the UserIdentityToken */
    const UA_String *userTokenPolicy = &client->channel.securityPolicy->policyUri;
    if(client->config.userTokenPolicy.securityPolicyUri.length > 0)
        userTokenPolicy = &client->config.userTokenPolicy.securityPolicyUri;
    retval |= encryptUserIdentityToken(client, userTokenPolicy, &request.userIdentityToken);
    retval |= signActivateSessionRequest(client, &client->channel, &request);

    if(retval == UA_STATUSCODE_GOOD)
        retval = __Client_AsyncService(client, &request,
                                       &UA_TYPES[UA_TYPES_ACTIVATESESSIONREQUEST],
                                       (UA_ClientAsyncServiceCallback)responseActivateSession,
                                       &UA_TYPES[UA_TYPES_ACTIVATESESSIONRESPONSE],
                                       NULL, NULL);

    UA_ActivateSessionRequest_clear(&request);
    if(retval == UA_STATUSCODE_GOOD)
        client->sessionState = UA_SESSIONSTATE_ACTIVATE_REQUESTED;
    else
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "ActivateSession failed when sending the request with error code %s",
                     UA_StatusCode_name(retval));

    return retval;
}

/* Combination of UA_Client_getEndpointsInternal and getEndpoints */
static void
responseGetEndpoints(UA_Client *client, void *userdata,
                     UA_UInt32 requestId, void *response) {
    UA_LOCK(&client->clientMutex);

    client->endpointsHandshake = false;

    UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT,
                 "Received GetEndpointsResponse");

    UA_GetEndpointsResponse *resp = (UA_GetEndpointsResponse*)response;

    /* GetEndpoints not possible. Fail the connection */
    if(resp->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
        /* Fail the connection attempt if the SecureChannel is still connected.
         * If the SecureChannel is (intentionally or unintentionally) closed,
         * the connectStatus should come from there. */
        if(UA_SecureChannel_isConnected(&client->channel)) {
           client->connectStatus = resp->responseHeader.serviceResult;
           closeSecureChannel(client);
           UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                        "GetEndpointRequest failed with error code %s",
                        UA_StatusCode_name(client->connectStatus));
        }

        UA_GetEndpointsResponse_clear(resp);
        UA_UNLOCK(&client->clientMutex);
        return;
    }

    /* Warn if the Endpoints look incomplete / don't match the EndpointUrl */
    Client_warnEndpointsResult(client, resp, &client->discoveryUrl);

    const size_t notFound = (size_t)-1;
    size_t bestEndpointIndex = notFound;
    size_t bestTokenIndex = notFound;
    UA_Byte bestEndpointLevel = 0;
    const UA_String binaryTransport =
        UA_STRING("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary");

    /* Find a matching combination of Endpoint and UserTokenPolicy */
    for(size_t i = 0; i < resp->endpointsSize; ++i) {
        UA_EndpointDescription* endpoint = &resp->endpoints[i];

        /* Do we already have a better candidate? */
        if(endpoint->securityLevel < bestEndpointLevel)
            continue;

        /* Filter by the ApplicationURI if defined */
        if(client->config.applicationUri.length > 0 &&
           !UA_String_equal(&client->config.applicationUri,
                            &endpoint->server.applicationUri))
            continue;

        /* Look out for binary transport endpoints.
         * Note: Siemens returns empty ProfileUrl, we will accept it as binary. */
        if(endpoint->transportProfileUri.length != 0 &&
           !UA_String_equal(&endpoint->transportProfileUri, &binaryTransport))
            continue;

        /* Valid SecurityMode? */
        if(endpoint->securityMode < 1 || endpoint->securityMode > 3) {
            UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                        "Rejecting endpoint %lu: invalid security mode",
                        (long unsigned)i);
            continue;
        }

        /* Selected SecurityMode? */
        if(client->config.securityMode > 0 &&
           client->config.securityMode != endpoint->securityMode) {
            UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                        "Rejecting endpoint %lu: security mode doesn't match",
                        (long unsigned)i);
            continue;
        }

        /* Matching SecurityPolicy? */
        if(client->config.securityPolicyUri.length > 0 &&
           !UA_String_equal(&client->config.securityPolicyUri,
                            &endpoint->securityPolicyUri)) {
            UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                        "Rejecting endpoint %lu: security policy doesn't match",
                        (long unsigned)i);
            continue;
        }

        /* SecurityPolicy available? */
        if(!getSecurityPolicy(client, endpoint->securityPolicyUri)) {
            UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                        "Rejecting endpoint %lu: security policy not available",
                        (long unsigned)i);
            continue;
        }

        /* We have found a matching endpoint.
         * But does it contain a matching user token policy? */
        bestEndpointIndex = i;

        /* Look for a supported user token policy */
        for(size_t j = 0; j < endpoint->userIdentityTokensSize; ++j) {
            UA_UserTokenPolicy* tokenPolicy = &endpoint->userIdentityTokens[j];
            const UA_DataType *tokenType =
                client->config.userIdentityToken.content.decoded.type;

            /* Usertokens also have a security policy... */
            if(tokenPolicy->tokenType != UA_USERTOKENTYPE_ANONYMOUS &&
               tokenPolicy->securityPolicyUri.length > 0 &&
               !getSecurityPolicy(client, tokenPolicy->securityPolicyUri)) {
                UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                            "Rejecting UserTokenPolicy %lu in endpoint %lu: "
                            "security policy '%.*s' not available",
                            (long unsigned)j, (long unsigned)i,
                            (int)tokenPolicy->securityPolicyUri.length,
                            tokenPolicy->securityPolicyUri.data);
                continue;
            }

            if(tokenPolicy->tokenType > 3) {
                UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                            "Rejecting UserTokenPolicy %lu in endpoint %lu: "
                            "invalid token type",
                            (long unsigned)j, (long unsigned)i);
                continue;
            }

            if(tokenPolicy->tokenType == UA_USERTOKENTYPE_ANONYMOUS &&
               tokenType != &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN] &&
               tokenType != NULL) {
                UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                            "Rejecting UserTokenPolicy %lu (anonymous) in endpoint %lu: "
                            "configuration doesn't match",
                            (long unsigned)j, (long unsigned)i);
                continue;
            }
            if(tokenPolicy->tokenType == UA_USERTOKENTYPE_USERNAME &&
               tokenType != &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]) {
                UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                            "Rejecting UserTokenPolicy %lu (username) in endpoint %lu: "
                            "configuration doesn't match",
                            (long unsigned)j, (long unsigned)i);
                continue;
            }
            if(tokenPolicy->tokenType == UA_USERTOKENTYPE_CERTIFICATE &&
               tokenType != &UA_TYPES[UA_TYPES_X509IDENTITYTOKEN]) {
                UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                            "Rejecting UserTokenPolicy %lu (certificate) in endpoint %lu: "
                            "configuration doesn't match",
                            (long unsigned)j, (long unsigned)i);
                continue;
            }
            if(tokenPolicy->tokenType == UA_USERTOKENTYPE_ISSUEDTOKEN &&
               tokenType != &UA_TYPES[UA_TYPES_ISSUEDIDENTITYTOKEN]) {
                UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                            "Rejecting UserTokenPolicy %lu (token) in endpoint %lu: "
                            "configuration doesn't match",
                            (long unsigned)j, (long unsigned)i);
                continue;
            }

            /* Endpoint with matching UserTokenPolicy found */

            /* If not explicit PolicyUri for authentication is configured, use
             * that from the TokenPolicy or (if that is not defined) from the
             * Endpoint SecurityPolicy. */
            UA_String *securityPolicyUri = &tokenPolicy->securityPolicyUri;
            if(securityPolicyUri->length == 0)
                securityPolicyUri = &endpoint->securityPolicyUri;
            if(UA_String_isEmpty(&client->config.authSecurityPolicyUri))
                UA_String_copy(securityPolicyUri, &client->config.authSecurityPolicyUri);

            /* Update tracking */
            bestEndpointLevel = endpoint->securityLevel;
            bestTokenIndex = j;

            /* Move to the client config */
            UA_EndpointDescription_clear(&client->config.endpoint);
            client->config.endpoint = *endpoint;
            UA_EndpointDescription_init(endpoint);
            UA_UserTokenPolicy_clear(&client->config.userTokenPolicy);
            client->config.userTokenPolicy = *tokenPolicy;
            UA_UserTokenPolicy_init(tokenPolicy);

            /* Store the Server Description */
            UA_ApplicationDescription_clear(&client->serverDescription);
            UA_ApplicationDescription_copy(&endpoint->server,
                                           &client->serverDescription);

            break;
        }
    }

    if(bestEndpointIndex == notFound) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "No suitable endpoint found");
        client->connectStatus = UA_STATUSCODE_BADINTERNALERROR;
        closeSecureChannel(client);
        UA_UNLOCK(&client->clientMutex);
        return;
    } else if(bestTokenIndex == notFound) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "No suitable UserTokenPolicy found for the possible endpoints");
        client->connectStatus = UA_STATUSCODE_BADIDENTITYTOKENINVALID;
        closeSecureChannel(client);
        UA_UNLOCK(&client->clientMutex);
        return;
    }

    /* Log the selected Endpoint and UserTokenPolicy */
#if UA_LOGLEVEL <= 300
    UA_EndpointDescription *endpoint = &client->config.endpoint;
    UA_UserTokenPolicy *tokenPolicy = &client->config.userTokenPolicy;
    UA_String *securityPolicyUri = &tokenPolicy->securityPolicyUri;
    const char *securityModeNames[3] = {"None", "Sign", "SignAndEncrypt"};
    const char *userTokenTypeNames[4] =
        {"Anonymous", "UserName", "Certificate", "IssuedToken"};

    UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                "Selected endpoint %lu in URL %.*s with SecurityMode "
                "%s and SecurityPolicy %.*s",
                (long unsigned)bestEndpointIndex, (int)endpoint->endpointUrl.length,
                endpoint->endpointUrl.data, securityModeNames[endpoint->securityMode - 1],
                (int)endpoint->securityPolicyUri.length, endpoint->securityPolicyUri.data);

    UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                "Selected UserTokenPolicy %.*s with UserTokenType %s "
                "and SecurityPolicy %.*s",
                (int)tokenPolicy->policyId.length, tokenPolicy->policyId.data,
                userTokenTypeNames[tokenPolicy->tokenType],
                (int)securityPolicyUri->length, securityPolicyUri->data);
#endif

    /* Close the SecureChannel -- a different SecurityMode or SecurityPolicy is
     * defined by the Endpoint. */
    if(client->config.endpoint.securityMode != client->channel.securityMode ||
       !UA_String_equal(&client->config.endpoint.securityPolicyUri,
                        &client->channel.securityPolicy->policyUri)) {
        closeSecureChannel(client);
        UA_UNLOCK(&client->clientMutex);
        return;
    }

    /* We were using a distinct discovery URL and we are switching away from it.
     * Close the SecureChannel to reopen with the EndpointUrl. If an endpoint
     * was selected, then we use the endpointUrl for the HEL message. */
    if(client->discoveryUrl.length > 0 &&
       !UA_String_equal(&client->discoveryUrl,
                        &client->config.endpoint.endpointUrl)) {
        closeSecureChannel(client);
        UA_UNLOCK(&client->clientMutex);
        return;
    }

    /* Nothing to do. We have selected an endpoint that we can use to open a
     * Session on the current SecureChannel. */
    UA_UNLOCK(&client->clientMutex);
}

static UA_StatusCode
requestGetEndpoints(UA_Client *client) {
    UA_LOCK_ASSERT(&client->clientMutex, 1);

    UA_GetEndpointsRequest request;
    UA_GetEndpointsRequest_init(&request);
    request.endpointUrl = getEndpointUrl(client);

    UA_StatusCode retval =
        __Client_AsyncService(client, &request, &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST],
                              (UA_ClientAsyncServiceCallback) responseGetEndpoints,
                              &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE], NULL, NULL);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "RequestGetEndpoints failed when sending the request with error code %s",
                     UA_StatusCode_name(retval));
        return retval;
    }

    client->endpointsHandshake = true;
    return UA_STATUSCODE_GOOD;
}

static void
responseFindServers(UA_Client *client, void *userdata,
                    UA_UInt32 requestId, void *response) {
    client->findServersHandshake = false;

    UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT,
                 "Received FindServersResponse");

    /* Error handling. Log the error but continue to connect with the current
     * EndpointURL. */
    UA_FindServersResponse *fsr = (UA_FindServersResponse*)response;
    if(fsr->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "FindServers failed with error code %s. Continue with the "
                       "EndpointURL %.*s.",
                       UA_StatusCode_name(fsr->responseHeader.serviceResult),
                       (int)client->config.endpointUrl.length,
                       client->config.endpointUrl.data);
        UA_String_copy(&client->config.endpointUrl, &client->discoveryUrl);
        return;
    }

    /* Check if one of the returned servers matches the EndpointURL already used */
    for(size_t i = 0; i < fsr->serversSize; i++) {
        UA_ApplicationDescription *server = &fsr->servers[i];

        /* Filter by the ApplicationURI if defined */
        if(client->config.applicationUri.length > 0 &&
           !UA_String_equal(&client->config.applicationUri,
                            &server->applicationUri))
            continue;

        for(size_t j = 0; j < server->discoveryUrlsSize; j++) {
            if(UA_String_equal(&client->config.endpointUrl, &server->discoveryUrls[j])) {
                UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                            "The initially defined EndpointURL %.*s "
                            "is valid for the server",
                            (int)client->config.endpointUrl.length,
                            client->config.endpointUrl.data);
                UA_String_copy(&client->config.endpointUrl, &client->discoveryUrl);
                return;
            }
        }
    }

    /* The current EndpointURL is not usable. Pick the first "opc.tcp" DiscoveryUrl of a
     * returned server. */
    for(size_t i = 0; i < fsr->serversSize; i++) {
        UA_ApplicationDescription *server = &fsr->servers[i];
        if(server->applicationType != UA_APPLICATIONTYPE_SERVER &&
            server->applicationType != UA_APPLICATIONTYPE_CLIENTANDSERVER &&
            server->applicationType != UA_APPLICATIONTYPE_DISCOVERYSERVER)
            continue;

        /* Filter by the ApplicationURI if defined */
        if(client->config.applicationUri.length > 0 &&
           !UA_String_equal(&client->config.applicationUri,
                            &server->applicationUri))
            continue;

        for(size_t j = 0; j < server->discoveryUrlsSize; j++) {
            /* Try to parse the DiscoveryUrl. This weeds out http schemas (etc.)
             * and invalid DiscoveryUrls in general. */
            UA_String hostname, path;
            UA_UInt16 port;
            UA_StatusCode res =
                UA_parseEndpointUrl(&server->discoveryUrls[j], &hostname,
                                    &port, &path);
            if(res != UA_STATUSCODE_GOOD)
                continue;

            /* Use this DiscoveryUrl in the client */
            UA_String_clear(&client->discoveryUrl);
            client->discoveryUrl = server->discoveryUrls[j];
            UA_String_init(&server->discoveryUrls[j]);

            UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                        "Use the EndpointURL %.*s returned from FindServers",
                        (int)client->discoveryUrl.length, client->discoveryUrl.data);

            /* Close the SecureChannel to build it up new with the correct
             * EndpointURL in the HEL/ACK handshake */
            closeSecureChannel(client);
            return;
        }
    }

    /* Could not find a suitable server. Try to continue with the
     * original EndpointURL. */
    UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                   "FindServers did not returned a suitable DiscoveryURL. "
                   "Continue with the EndpointURL %.*s.",
                   (int)client->config.endpointUrl.length,
                   client->config.endpointUrl.data);
    UA_String_clear(&client->discoveryUrl);
    UA_String_copy(&client->config.endpointUrl, &client->discoveryUrl);
}

static UA_StatusCode
requestFindServers(UA_Client *client) {
    UA_FindServersRequest request;
    UA_FindServersRequest_init(&request);
    request.requestHeader.timeoutHint = 10000;
    request.endpointUrl = client->config.endpointUrl;
    UA_StatusCode retval =
        __Client_AsyncService(client, &request, &UA_TYPES[UA_TYPES_FINDSERVERSREQUEST],
                              (UA_ClientAsyncServiceCallback) responseFindServers,
                              &UA_TYPES[UA_TYPES_FINDSERVERSRESPONSE], NULL, NULL);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "FindServers failed when sending the request with error code %s",
                     UA_StatusCode_name(retval));
        return retval;
    }

    client->findServersHandshake = true;
    return UA_STATUSCODE_GOOD;
}

static void
createSessionCallback(UA_Client *client, void *userdata,
                      UA_UInt32 requestId, void *response) {
    UA_LOCK(&client->clientMutex);

    UA_CreateSessionResponse *sessionResponse = (UA_CreateSessionResponse*)response;
    UA_StatusCode res = sessionResponse->responseHeader.serviceResult;
    if(res != UA_STATUSCODE_GOOD)
        goto cleanup;

    if(client->channel.securityMode == UA_MESSAGESECURITYMODE_SIGN ||
       client->channel.securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
        /* Verify the session response was created with the same certificate as
         * the SecureChannel */
        if(!UA_ByteString_equal(&sessionResponse->serverCertificate,
                                &client->channel.remoteCertificate)) {
            res = UA_STATUSCODE_BADCERTIFICATEINVALID;
            goto cleanup;
        }

        /* Verify the client signature */
        res = checkCreateSessionSignature(client, &client->channel, sessionResponse);
        if(res != UA_STATUSCODE_GOOD)
            goto cleanup;
    }

    /* Copy nonce and AuthenticationToken */
    UA_ByteString_clear(&client->serverSessionNonce);
    UA_NodeId_clear(&client->authenticationToken);
    res |= UA_ByteString_copy(&sessionResponse->serverNonce,
                              &client->serverSessionNonce);
    res |= UA_NodeId_copy(&sessionResponse->authenticationToken,
                          &client->authenticationToken);
    if(res != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Activate the new Session */
    client->sessionState = UA_SESSIONSTATE_CREATED;

 cleanup:
    client->connectStatus = res;
    if(client->connectStatus != UA_STATUSCODE_GOOD)
        client->sessionState = UA_SESSIONSTATE_CLOSED;

    UA_UNLOCK(&client->clientMutex);
}

static UA_StatusCode
createSessionAsync(UA_Client *client) {
    UA_LOCK_ASSERT(&client->clientMutex, 1);

    /* Generate the local nonce for the session */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(client->channel.securityMode == UA_MESSAGESECURITYMODE_SIGN ||
       client->channel.securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
        if(client->clientSessionNonce.length != UA_SESSION_LOCALNONCELENGTH) {
           UA_ByteString_clear(&client->clientSessionNonce);
            res = UA_ByteString_allocBuffer(&client->clientSessionNonce,
                                            UA_SESSION_LOCALNONCELENGTH);
            if(res != UA_STATUSCODE_GOOD)
                return res;
        }
        res = client->channel.securityPolicy->symmetricModule.
                 generateNonce(client->channel.securityPolicy->policyContext,
                               &client->clientSessionNonce);
        if(res != UA_STATUSCODE_GOOD)
            return res;
    }

    /* Prepare and send the request */
    UA_CreateSessionRequest request;
    UA_CreateSessionRequest_init(&request);
    request.clientNonce = client->clientSessionNonce;
    request.requestedSessionTimeout = client->config.requestedSessionTimeout;
    request.maxResponseMessageSize = UA_INT32_MAX;
    request.endpointUrl = client->config.endpoint.endpointUrl;
    request.clientDescription = client->config.clientDescription;
    request.sessionName = client->config.sessionName;
    if(client->channel.securityMode == UA_MESSAGESECURITYMODE_SIGN ||
       client->channel.securityMode == UA_MESSAGESECURITYMODE_SIGNANDENCRYPT) {
        request.clientCertificate = client->channel.securityPolicy->localCertificate;
    }

    res = __Client_AsyncService(client, &request,
                                &UA_TYPES[UA_TYPES_CREATESESSIONREQUEST],
                                (UA_ClientAsyncServiceCallback)createSessionCallback,
                                &UA_TYPES[UA_TYPES_CREATESESSIONRESPONSE], NULL, NULL);

    if(res == UA_STATUSCODE_GOOD)
        client->sessionState = UA_SESSIONSTATE_CREATE_REQUESTED;
    else
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "CreateSession failed when sending the request with "
                     "error code %s", UA_StatusCode_name(res));

    return res;
}

static UA_StatusCode
initSecurityPolicy(UA_Client *client) {
    /* Find the SecurityPolicy */
    UA_SecurityPolicy *sp = NULL;
    if(client->config.endpoint.securityPolicyUri.length == 0) {
        sp = getSecurityPolicy(client,
                               UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None"));
    } else {
        sp = getSecurityPolicy(client, client->config.endpoint.securityPolicyUri);
    }

    /* Unknown SecurityPolicy -- we would never select such an endpoint */
    if(!sp)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Already initialized -- check we are using the configured SecurityPolicy */
    if(client->channel.securityPolicy)
        return (client->channel.securityPolicy == sp) ?
            UA_STATUSCODE_GOOD : UA_STATUSCODE_BADINTERNALERROR;

    /* Set the SecurityMode -- none if no endpoint is selected so far */
    client->channel.securityMode = client->config.endpoint.securityMode;
    if(client->channel.securityMode == UA_MESSAGESECURITYMODE_INVALID)
        client->channel.securityMode = UA_MESSAGESECURITYMODE_NONE;

    /* Instantiate the SecurityPolicy context with the remote certificate */
    return UA_SecureChannel_setSecurityPolicy(&client->channel, sp,
                                              &client->config.endpoint.serverCertificate);
}

static void
connectActivity(UA_Client *client) {
    UA_LOG_TRACE(client->config.logging, UA_LOGCATEGORY_CLIENT,
                 "Client connect iterate");

    /* Could not connect with an error that canot be recovered from */
    if(client->connectStatus != UA_STATUSCODE_GOOD)
        return;

    /* Already connected */
    if(client->sessionState == UA_SESSIONSTATE_ACTIVATED)
        return;

    /* Switch on the SecureChannel state */
    switch(client->channel.state) {
        /* Nothing to do if the connection has not opened fully */
    case UA_SECURECHANNELSTATE_CONNECTING:
    case UA_SECURECHANNELSTATE_CLOSING:
    case UA_SECURECHANNELSTATE_HEL_SENT:
        return;

        /* Send HEL */
    case UA_SECURECHANNELSTATE_CONNECTED:
        client->connectStatus = sendHELMessage(client);
        return;

        /* ACK receieved. Send OPN. */
    case UA_SECURECHANNELSTATE_ACK_RECEIVED:
        sendOPNAsync(client, false); /* Send OPN */
        return;

        /* The channel is open -> continue with the Session handling */
    case UA_SECURECHANNELSTATE_OPEN:
        break;

        /* The connection is closed. Reset the SecureChannel and open a new TCP
         * connection */
    case UA_SECURECHANNELSTATE_CLOSED:
        if(client->config.noReconnect)
            client->connectStatus = UA_STATUSCODE_BADNOTCONNECTED;
        else
            initConnect(client); /* Sets the connectStatus internally */
        return;

        /* These states should never occur for the client */
    default:
        client->connectStatus = UA_STATUSCODE_BADINTERNALERROR;
        return;
    }

    /* <-- The SecureChannel is open --> */

    /* Ongoing handshake -> Waiting for a response */
    if(client->endpointsHandshake || client->findServersHandshake)
        return;

    /* Call FindServers to see if we should reconnect with another EndpointUrl.
     * This needs to be done before GetEndpoints, as the set of returned
     * endpoints may depend on the EndpointUrl used during the initial HEL/ACK
     * handshake. */
    if(client->discoveryUrl.length == 0) {
        client->connectStatus = requestFindServers(client);
        return;
    }

    /* GetEndpoints to identify the remote side and/or reset the SecureChannel
     * with encryption */
    if(endpointUnconfigured(client)) {
        client->connectStatus = requestGetEndpoints(client);
        return;
    }

    /* Have the final SecureChannel but no session */
    if(client->config.noSession)
        return;

    /* Create and Activate the Session */
    switch(client->sessionState) {
        /* Send a CreateSessionRequest */
    case UA_SESSIONSTATE_CLOSED:
        client->connectStatus = createSessionAsync(client);
        return;

        /* Activate the Session */
    case UA_SESSIONSTATE_CREATED:
        client->connectStatus = activateSessionAsync(client);
        return;

    case UA_SESSIONSTATE_CREATE_REQUESTED:
    case UA_SESSIONSTATE_ACTIVATE_REQUESTED:
    case UA_SESSIONSTATE_ACTIVATED:
    case UA_SESSIONSTATE_CLOSING:
        return; /* Nothing to do */

        /* These states should never occur for the client */
    default:
        client->connectStatus = UA_STATUSCODE_BADINTERNALERROR;
        break;
    }
}

static UA_StatusCode
verifyClientSecureChannelHeader(void *application, UA_SecureChannel *channel,
                                const UA_AsymmetricAlgorithmSecurityHeader *asymHeader) {
    UA_Client *client = (UA_Client*)application;
    const UA_SecurityPolicy *sp = channel->securityPolicy;
    UA_assert(sp != NULL);

    /* Check the SecurityPolicyUri */
    if(asymHeader->securityPolicyUri.length > 0 &&
       !UA_String_equal(&sp->policyUri, &asymHeader->securityPolicyUri)) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "The server uses a different SecurityPolicy from the client");
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    }

    /* If encryption is used, check that the server certificate for the
     * endpoint is used for the SecureChannel */
    UA_ByteString serverCert = getLeafCertificate(asymHeader->senderCertificate);
    if(client->config.endpoint.serverCertificate.length > 0 &&
       !UA_String_equal(&client->config.endpoint.serverCertificate, &serverCert)) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "The server certificate is different from the EndpointDescription");
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    }

    /* Verify the certificate the server assumes on our end */
    UA_StatusCode res = sp->asymmetricModule.
        compareCertificateThumbprint(sp, &asymHeader->receiverCertificateThumbprint);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "The server does not use the client certificate "
                     "used for the selected SecurityPolicy");
        return res;
    }

    return UA_STATUSCODE_GOOD;
}

/* The local ApplicationURI has to match the certificates of the
 * SecurityPolicies */
static void
verifyClientApplicationURI(const UA_Client *client) {
#if UA_LOGLEVEL <= 400
    for(size_t i = 0; i < client->config.securityPoliciesSize; i++) {
        UA_SecurityPolicy *sp = &client->config.securityPolicies[i];
        if(!sp->localCertificate.data) {
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                           "skip verifying ApplicationURI for the SecurityPolicy %.*s",
                           (int)sp->policyUri.length, sp->policyUri.data);
            continue;
        }

        UA_StatusCode retval =
            UA_CertificateUtils_verifyApplicationURI(client->allowAllCertificateUris, &sp->localCertificate,
                                                     &client->config.clientDescription.applicationUri);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                           "The configured ApplicationURI does not match the URI "
                           "specified in the certificate for the SecurityPolicy %.*s",
                           (int)sp->policyUri.length, sp->policyUri.data);
        }
    }
#endif
}

static void
__Client_networkCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
                         void *application, void **connectionContext,
                         UA_ConnectionState state, const UA_KeyValueMap *params,
                         UA_ByteString msg) {
    /* Take the client lock */
    UA_Client *client = (UA_Client*)application;
    UA_LOCK(&client->clientMutex);

    UA_LOG_TRACE(client->config.logging, UA_LOGCATEGORY_CLIENT, "Client network callback");

    /* A new connection with no context pointer attached */
    if(!*connectionContext) {
        /* Inconsistent SecureChannel state. Has to be fresh for a new
         * connection. */
        if(client->channel.state != UA_SECURECHANNELSTATE_CLOSED &&
           client->channel.state != UA_SECURECHANNELSTATE_REVERSE_LISTENING) {
            UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                         "Cannot open a connection, the SecureChannel is already used");
            client->connectStatus = UA_STATUSCODE_BADINTERNALERROR;
            notifyClientState(client);
            UA_UNLOCK(&client->clientMutex);
            return;
        }

        /* Initialize the client connection and attach to the EventLoop connection */
        client->channel.connectionManager = cm;
        client->channel.connectionId = connectionId;
        *connectionContext = &client->channel;
    }

    /* The connection is closing in the EventLoop. This is the last callback
     * from that connection. Clean up the SecureChannel in the client. */
    if(state == UA_CONNECTIONSTATE_CLOSING) {
        UA_LOG_INFO_CHANNEL(client->config.logging, &client->channel,
                            "SecureChannel closed");

        /* Set to closing (could be done already in UA_SecureChannel_shutdown).
         * This impacts the handling of cancelled requests below. */
        UA_SecureChannelState oldState = client->channel.state;
        client->channel.state = UA_SECURECHANNELSTATE_CLOSING;

        /* Set the Session to CREATED if it was ACTIVATED */
        if(client->sessionState == UA_SESSIONSTATE_ACTIVATED)
            client->sessionState = UA_SESSIONSTATE_CREATED;

        /* Delete outstanding async services - the RequestId is no longer valid. Do
         * this after setting the Session state. Otherwise we send out new Publish
         * Requests immediately. */
        __Client_AsyncService_removeAll(client, UA_STATUSCODE_BADSECURECHANNELCLOSED);

        /* Clean up the channel and set the status to CLOSED */
        UA_SecureChannel_clear(&client->channel);

        /* The connection closed before it actually opened. Since we are
         * connecting asynchronously, this happens when the TCP connection
         * fails. Try to fall back on the initial EndpointUrl. */
        if(oldState == UA_SECURECHANNELSTATE_CONNECTING &&
           client->connectStatus == UA_STATUSCODE_GOOD)
            client->connectStatus = fallbackEndpointUrl(client);

        /* Try to reconnect */
        goto continue_connect;
    }

    /* Update the SecureChannel state */
    if(UA_LIKELY(state == UA_CONNECTIONSTATE_ESTABLISHED)) {
        /* The connection is now open on the TCP level. Set the SecureChannel
         * state to reflect this. Otherwise later consistency checks for the
         * received messages fail. */
        if(client->channel.state == UA_SECURECHANNELSTATE_REVERSE_LISTENING)
            client->channel.state = UA_SECURECHANNELSTATE_REVERSE_CONNECTED;
        if(client->channel.state < UA_SECURECHANNELSTATE_CONNECTED)
            client->channel.state = UA_SECURECHANNELSTATE_CONNECTED;
    } else /* state == UA_CONNECTIONSTATE_OPENING */ {
        /* The connection was opened on our end only. Waiting for the TCP handshake
         * to complete. */
        client->channel.state = UA_SECURECHANNELSTATE_CONNECTING;
    }

    /* Received a message. Process the message with the SecureChannel. */
    UA_EventLoop *el = client->config.eventLoop;
    UA_DateTime nowMonotonic = el->dateTime_nowMonotonic(el);
    UA_StatusCode res =
        UA_SecureChannel_processBuffer(&client->channel, client,
                                       processServiceResponse,
                                       &msg, nowMonotonic);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "Processing the message returned the error code %s",
                     UA_StatusCode_name(res));

        /* If processing the buffer fails before the SecureChannel has opened,
         * then the client cannot recover. Set the connectStatus to reflect
         * this. The application is notified when the socket has closed. */
        if(client->channel.state != UA_SECURECHANNELSTATE_OPEN)
            client->connectStatus = res;

        /* Close the SecureChannel, but don't notify the client right away.
         * Return immediately. notifyClientState will be called in the next
         * callback from the ConnectionManager when the connection closes with a
         * StatusCode.
         *
         * If the connectStatus is still good (the SecureChannel was fully
         * opened before), then a reconnect is attempted. */
        closeSecureChannel(client);
        UA_UNLOCK(&client->clientMutex);
        return;
    }

 continue_connect:
    /* Trigger the next action from our end to fully open up the connection */
    if(!isFullyConnected(client))
        connectActivity(client);
    notifyClientState(client);
    UA_UNLOCK(&client->clientMutex);
}

/* Initialize a TCP connection. Writes the result to client->connectStatus. */
static void
initConnect(UA_Client *client) {
    if(client->channel.state != UA_SECURECHANNELSTATE_CLOSED) {
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "Client connection already initiated");
        return;
    }

    /* Start the EventLoop if not already started */
    client->connectStatus = __UA_Client_startup(client);
    UA_CHECK_STATUS(client->connectStatus, return);

    /* Consistency check the client's own ApplicationURI.
     * Problems are only logged. */
    verifyClientApplicationURI(client);

    /* Initialize the SecureChannel */
    UA_SecureChannel_clear(&client->channel);
    client->channel.config = client->config.localConnectionConfig;
    client->channel.certificateVerification = &client->config.certificateVerification;
    client->channel.processOPNHeader = verifyClientSecureChannelHeader;

    /* Initialize the SecurityPolicy */
    client->connectStatus = initSecurityPolicy(client);
    if(client->connectStatus != UA_STATUSCODE_GOOD)
        return;

    /* Extract hostname and port from the URL */
    UA_String hostname = UA_STRING_NULL;
    UA_String path = UA_STRING_NULL;
    UA_UInt16 port = 4840;

    client->connectStatus =
        UA_parseEndpointUrl(&client->config.endpointUrl, &hostname, &port, &path);
    if(client->connectStatus != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_NETWORK,
                       "OPC UA URL is invalid: %.*s",
                       (int)client->config.endpointUrl.length,
                       client->config.endpointUrl.data);
        return;
    }

    /* Initialize the TCP connection */
    UA_String tcpString = UA_STRING("tcp");
    for(UA_EventSource *es = client->config.eventLoop->eventSources;
        es != NULL; es = es->next) {
        /* Is this a usable connection manager? */
        if(es->eventSourceType != UA_EVENTSOURCETYPE_CONNECTIONMANAGER)
            continue;
        UA_ConnectionManager *cm = (UA_ConnectionManager*)es;
        if(!UA_String_equal(&tcpString, &cm->protocol))
            continue;

        /* Set up the parameters */
        UA_KeyValuePair params[2];
        params[0].key = UA_QUALIFIEDNAME(0, "port");
        UA_Variant_setScalar(&params[0].value, &port, &UA_TYPES[UA_TYPES_UINT16]);
        params[1].key = UA_QUALIFIEDNAME(0, "address");
        UA_Variant_setScalar(&params[1].value, &hostname, &UA_TYPES[UA_TYPES_STRING]);

        UA_KeyValueMap paramMap;
        paramMap.map = params;
        paramMap.mapSize = 2;

        /* Open the client TCP connection */
        UA_UNLOCK(&client->clientMutex);
        UA_StatusCode res =
            cm->openConnection(cm, &paramMap, client, NULL, __Client_networkCallback);
        UA_LOCK(&client->clientMutex);
        if(res == UA_STATUSCODE_GOOD)
            break;
    }

    /* The channel has not opened */
    if(client->channel.state == UA_SECURECHANNELSTATE_CLOSED)
        client->connectStatus = UA_STATUSCODE_BADINTERNALERROR;

    /* Opening the TCP connection failed */
    if(client->connectStatus != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "Could not open a TCP connection to %.*s",
                       (int)client->config.endpointUrl.length,
                       client->config.endpointUrl.data);
        client->connectStatus = UA_STATUSCODE_BADCONNECTIONCLOSED;
    }
}

void
connectSync(UA_Client *client) {
    UA_LOCK_ASSERT(&client->clientMutex, 1);

    /* EventLoop is started. Otherwise initConnect would have failed. */
    UA_EventLoop *el = client->config.eventLoop;
    UA_assert(el);

    UA_DateTime now = el->dateTime_nowMonotonic(el);
    UA_DateTime maxDate = now + ((UA_DateTime)client->config.timeout * UA_DATETIME_MSEC);

    /* Initialize the connection */
    initConnect(client);
    notifyClientState(client);
    if(client->connectStatus != UA_STATUSCODE_GOOD)
        return;

    /* Run the EventLoop until connected, connect fail or timeout. Write the
     * iterate result to the connectStatus. So we do not attempt to restore a
     * failed connection during the sync connect. */
    while(client->connectStatus == UA_STATUSCODE_GOOD &&
          !isFullyConnected(client)) {

        /* Timeout -> abort */
        now = el->dateTime_nowMonotonic(el);
        if(maxDate < now) {
            UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                         "The connection has timed out before it could be fully opened");
            client->connectStatus = UA_STATUSCODE_BADTIMEOUT;
            closeSecureChannel(client);
            /* Continue to run. So the SecureChannel is fully closed in the next
             * EventLoop iteration. */
        }

        /* Drop into the EventLoop */
        UA_UNLOCK(&client->clientMutex);
        UA_StatusCode res = el->run(el, (UA_UInt32)((maxDate - now) / UA_DATETIME_MSEC));
        UA_LOCK(&client->clientMutex);
        if(res != UA_STATUSCODE_GOOD) {
            client->connectStatus = res;
            closeSecureChannel(client);
        }

        notifyClientState(client);
    }
}

UA_StatusCode
connectInternal(UA_Client *client, UA_Boolean async) {
    /* Reset the connectStatus. This should be the only place where we can
     * recover from a bad connectStatus. */
    client->connectStatus = UA_STATUSCODE_GOOD;

    if(async)
        initConnect(client);
    else
        connectSync(client);
    notifyClientState(client);
    return client->connectStatus;
}

UA_StatusCode
connectSecureChannel(UA_Client *client, const char *endpointUrl) {
    UA_ClientConfig *cc = UA_Client_getConfig(client);
    cc->noSession = true;
    UA_String_clear(&cc->endpointUrl);
    cc->endpointUrl = UA_STRING_ALLOC(endpointUrl);
    return connectInternal(client, false);
}

UA_StatusCode
__UA_Client_connect(UA_Client *client, UA_Boolean async) {
    UA_LOCK(&client->clientMutex);
    connectInternal(client, async);
    UA_UNLOCK(&client->clientMutex);
    return client->connectStatus;
}

static UA_StatusCode
activateSessionSync(UA_Client *client) {
    UA_LOCK_ASSERT(&client->clientMutex, 1);

    /* EventLoop is started. Otherwise activateSessionAsync would have failed. */
    UA_EventLoop *el = client->config.eventLoop;
    UA_assert(el);

    UA_DateTime now = el->dateTime_nowMonotonic(el);
    UA_DateTime maxDate = now + ((UA_DateTime)client->config.timeout * UA_DATETIME_MSEC);

    /* Try to activate */
    UA_StatusCode res = activateSessionAsync(client);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    while(client->sessionState != UA_SESSIONSTATE_ACTIVATED &&
          client->connectStatus == UA_STATUSCODE_GOOD) {

        /* Timeout -> abort */
        now = el->dateTime_nowMonotonic(el);
        if(maxDate < now) {
            UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                         "The connection has timed out before it could be fully opened");
            client->connectStatus = UA_STATUSCODE_BADTIMEOUT;
            closeSecureChannel(client);
            /* Continue to run. So the SecureChannel is fully closed in the next
             * EventLoop iteration. */
        }

        /* Drop into the EventLoop */
        UA_UNLOCK(&client->clientMutex);
        res = el->run(el, (UA_UInt32)((maxDate - now) / UA_DATETIME_MSEC));
        UA_LOCK(&client->clientMutex);
        if(res != UA_STATUSCODE_GOOD) {
            client->connectStatus = res;
            closeSecureChannel(client);
        }

        notifyClientState(client);
    }

    return client->connectStatus;
}

UA_StatusCode
UA_Client_activateCurrentSession(UA_Client *client) {
    UA_LOCK(&client->clientMutex);
    UA_StatusCode res = activateSessionSync(client);
    notifyClientState(client);
    UA_UNLOCK(&client->clientMutex);
    return res != UA_STATUSCODE_GOOD ? res : client->connectStatus;
}

UA_StatusCode
UA_Client_activateCurrentSessionAsync(UA_Client *client) {
    UA_LOCK(&client->clientMutex);
    UA_StatusCode res = activateSessionAsync(client);
    notifyClientState(client);
    UA_UNLOCK(&client->clientMutex);
    return res != UA_STATUSCODE_GOOD ? res : client->connectStatus;
}

UA_StatusCode
UA_Client_getSessionAuthenticationToken(UA_Client *client, UA_NodeId *authenticationToken,
                                        UA_ByteString *serverNonce) {
    UA_LOCK(&client->clientMutex);
    if(client->sessionState != UA_SESSIONSTATE_CREATED &&
       client->sessionState != UA_SESSIONSTATE_ACTIVATED) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "There is no current session");
        UA_UNLOCK(&client->clientMutex);
        return UA_STATUSCODE_BADSESSIONCLOSED;
    }

    UA_StatusCode res = UA_NodeId_copy(&client->authenticationToken, authenticationToken);
    res |= UA_ByteString_copy(&client->serverSessionNonce, serverNonce);
    UA_UNLOCK(&client->clientMutex);
    return res;
}

static UA_StatusCode
switchSession(UA_Client *client,
              const UA_NodeId authenticationToken,
              const UA_ByteString serverNonce) {
    /* Check that there is no pending session in the client */
    if(client->sessionState != UA_SESSIONSTATE_CLOSED) {
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "Cannot activate a session with a different AuthenticationToken "
                     "when the client already has a Session.");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Replace token and nonce */
    UA_NodeId_clear(&client->authenticationToken);
    UA_ByteString_clear(&client->serverSessionNonce);
    UA_StatusCode res = UA_NodeId_copy(&authenticationToken, &client->authenticationToken);
    res |= UA_ByteString_copy(&serverNonce, &client->serverSessionNonce);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Notify that we have now a created session */
    client->sessionState = UA_SESSIONSTATE_CREATED;
    notifyClientState(client);

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Client_activateSession(UA_Client *client,
                          const UA_NodeId authenticationToken,
                          const UA_ByteString serverNonce) {
    UA_LOCK(&client->clientMutex);
    UA_StatusCode res = switchSession(client, authenticationToken, serverNonce);
    if(res != UA_STATUSCODE_GOOD) {
        UA_UNLOCK(&client->clientMutex);
        return res;
    }
    res = activateSessionSync(client);
    notifyClientState(client);
    UA_UNLOCK(&client->clientMutex);
    return res != UA_STATUSCODE_GOOD ? res : client->connectStatus;
}

UA_StatusCode
UA_Client_activateSessionAsync(UA_Client *client,
                               const UA_NodeId authenticationToken,
                               const UA_ByteString serverNonce) {
    UA_LOCK(&client->clientMutex);
    UA_StatusCode res = switchSession(client, authenticationToken, serverNonce);
    if(res != UA_STATUSCODE_GOOD) {
        UA_UNLOCK(&client->clientMutex);
        return res;
    }
    res = activateSessionAsync(client);
    notifyClientState(client);
    UA_UNLOCK(&client->clientMutex);
    return res != UA_STATUSCODE_GOOD ? res : client->connectStatus;
}

static void
__Client_reverseConnectCallback(UA_ConnectionManager *cm, uintptr_t connectionId,
                         void *application, void **connectionContext,
                         UA_ConnectionState state, const UA_KeyValueMap *params,
                         UA_ByteString msg) {

    UA_Client *client = (UA_Client*)application;

    UA_LOCK(&client->clientMutex);

    /* This is the first call for the listening socket, attach the
     * REVERSE_CONNECT_INDICATOR marker and set the ID to the channel */
    if(!client->channel.connectionId) {
        client->channel.connectionId = connectionId;
        *connectionContext = REVERSE_CONNECT_INDICATOR;
    }

    /* Last call for the listening connection while it is being closed. Only
     * notify a state change if no reverse connection is being or has been
     * established by now */
    if(*connectionContext == REVERSE_CONNECT_INDICATOR &&
       state == UA_CONNECTIONSTATE_CLOSING) {
        if(client->channel.connectionId == connectionId) {
            client->channel.state = UA_SECURECHANNELSTATE_CLOSED;
            notifyClientState(client);
        }
        UA_UNLOCK(&client->clientMutex);
        return;
    }

    /* Second callback for the listening socket, it is now listening for
     * incoming connections */
    if(client->channel.connectionId == connectionId &&
       *connectionContext == REVERSE_CONNECT_INDICATOR) {
        client->channel.state = UA_SECURECHANNELSTATE_REVERSE_LISTENING;
        notifyClientState(client);
    }

    /* This is a connection initiated by a server, disconnect the listener and
     * reset secure channel information */
    if(client->channel.connectionId != connectionId) {
        cm->closeConnection(cm, client->channel.connectionId);
        client->channel.connectionId = 0;
        *connectionContext = NULL;
    }

    /* Forward all calls belonging to the reverse connection estblished by the
     * server to the regular network callback */
    if(*connectionContext != REVERSE_CONNECT_INDICATOR) {
        UA_UNLOCK(&client->clientMutex);
        __Client_networkCallback(cm, connectionId, application,
                                 connectionContext, state, params, msg);
        return;
    }

    UA_UNLOCK(&client->clientMutex);
}

UA_StatusCode
UA_Client_startListeningForReverseConnect(UA_Client *client,
                                          const UA_String *listenHostnames,
                                          size_t listenHostnamesLength,
                                          UA_UInt16 port) {
    UA_LOCK(&client->clientMutex);

    if(client->channel.state != UA_SECURECHANNELSTATE_CLOSED) {
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "Unable to listen for reverse connect while the client "
                       "is connected or already listening");
        UA_UNLOCK(&client->clientMutex);
        return UA_STATUSCODE_BADINVALIDSTATE;
    }

    const UA_String tcpString = UA_STRING_STATIC("tcp");
    UA_StatusCode res = UA_STATUSCODE_BADINTERNALERROR;

    client->connectStatus = UA_STATUSCODE_GOOD;
    client->channel.renewState = UA_SECURECHANNELRENEWSTATE_NORMAL;

    UA_SecureChannel_init(&client->channel);
    client->channel.config = client->config.localConnectionConfig;
    client->channel.certificateVerification = &client->config.certificateVerification;
    client->channel.processOPNHeader = verifyClientSecureChannelHeader;
    client->channel.connectionId = 0;

    client->connectStatus = initSecurityPolicy(client);
    if(client->connectStatus != UA_STATUSCODE_GOOD)
        return client->connectStatus;

    UA_EventLoop *el = client->config.eventLoop;
    if(!el) {
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "No EventLoop configured");
        UA_UNLOCK(&client->clientMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    if(el->state != UA_EVENTLOOPSTATE_STARTED) {
        res = el->start(el);
        UA_CHECK_STATUS(res, UA_UNLOCK(&client->clientMutex); return res);
    }

    UA_ConnectionManager *cm = NULL;
    for(UA_EventSource *es = el->eventSources; es != NULL; es = es->next) {
        if(es->eventSourceType != UA_EVENTSOURCETYPE_CONNECTIONMANAGER)
            continue;
        cm = (UA_ConnectionManager*)es;
        if(UA_String_equal(&tcpString, &cm->protocol))
            break;
        cm = NULL;
    }

    if(!cm) {
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "Could not find a TCP connection manager, unable to "
                       "listen for reverse connect");
        UA_UNLOCK(&client->clientMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    client->channel.connectionManager = cm;

    UA_KeyValuePair params[3];
    bool booleanTrue = true;
    params[0].key = UA_QUALIFIEDNAME(0, "port");
    UA_Variant_setScalar(&params[0].value, &port, &UA_TYPES[UA_TYPES_UINT16]);
    params[1].key = UA_QUALIFIEDNAME(0, "address");
    UA_Variant_setArray(&params[1].value, (void *)(uintptr_t)listenHostnames,
            listenHostnamesLength, &UA_TYPES[UA_TYPES_STRING]);
    params[2].key = UA_QUALIFIEDNAME(0, "listen");
    UA_Variant_setScalar(&params[2].value, &booleanTrue, &UA_TYPES[UA_TYPES_BOOLEAN]);

    UA_KeyValueMap paramMap;
    paramMap.map = params;
    paramMap.mapSize = 3;

    UA_UNLOCK(&client->clientMutex);
    res = cm->openConnection(cm, &paramMap, client, NULL, __Client_reverseConnectCallback);
    UA_LOCK(&client->clientMutex);

    /* Opening the TCP connection failed */
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "Failed to open a listening TCP socket for reverse connect");
        res = UA_STATUSCODE_BADCONNECTIONCLOSED;
    }

    UA_UNLOCK(&client->clientMutex);
    return res;
}

/************************/
/* Close the Connection */
/************************/

void
closeSecureChannel(UA_Client *client) {
    /* If we close SecureChannel when the Session is still active, set to
     * created. Otherwise the Session would remain active until the connection
     * callback is called for the closing connection. */
    if(client->sessionState == UA_SESSIONSTATE_ACTIVATED)
        client->sessionState = UA_SESSIONSTATE_CREATED;

    /* Prevent recursion */
    if(client->channel.state == UA_SECURECHANNELSTATE_CLOSING ||
       client->channel.state == UA_SECURECHANNELSTATE_CLOSED)
        return;

    UA_LOG_DEBUG_CHANNEL(client->config.logging, &client->channel,
                         "Closing the channel");

    /* Send CLO if the SecureChannel is open */
    if(client->channel.state == UA_SECURECHANNELSTATE_OPEN) {
        UA_LOG_DEBUG_CHANNEL(client->config.logging, &client->channel,
                             "Sending the CLO message");

        UA_EventLoop *el = client->config.eventLoop;

        /* Manually set up the header (otherwise done in sendRequest) */
        UA_CloseSecureChannelRequest request;
        UA_CloseSecureChannelRequest_init(&request);
        request.requestHeader.requestHandle = ++client->requestHandle;
        request.requestHeader.timestamp = el->dateTime_now(el);
        request.requestHeader.timeoutHint = client->config.timeout;
        request.requestHeader.authenticationToken = client->authenticationToken;
        UA_SecureChannel_sendSymmetricMessage(&client->channel, ++client->requestId,
                                              UA_MESSAGETYPE_CLO, &request,
                                              &UA_TYPES[UA_TYPES_CLOSESECURECHANNELREQUEST]);
    }

    /* The connection is eventually closed in the next callback from the
     * ConnectionManager with the appropriate status code. Don't set the
     * connection closed right away! */
    UA_SecureChannel_shutdown(&client->channel, UA_SHUTDOWNREASON_CLOSE);
}

static void
sendCloseSession(UA_Client *client) {
    UA_CloseSessionRequest request;
    UA_CloseSessionRequest_init(&request);
    request.deleteSubscriptions = true;
    UA_CloseSessionResponse response;
    __Client_Service(client, &request, &UA_TYPES[UA_TYPES_CLOSESESSIONREQUEST],
                        &response, &UA_TYPES[UA_TYPES_CLOSESESSIONRESPONSE]);
    UA_CloseSessionRequest_clear(&request);
    UA_CloseSessionResponse_clear(&response);

    /* Set after sending the message to prevent immediate reoping during the
     * service call */
    client->sessionState = UA_SESSIONSTATE_CLOSING;
}

void
cleanupSession(UA_Client *client) {
    UA_NodeId_clear(&client->authenticationToken);
    client->requestHandle = 0;

#ifdef UA_ENABLE_SUBSCRIPTIONS
    /* We need to clean up the subscriptions */
    __Client_Subscriptions_clean(client);
#endif

    /* Delete outstanding async services */
    __Client_AsyncService_removeAll(client, UA_STATUSCODE_BADSESSIONCLOSED);

#ifdef UA_ENABLE_SUBSCRIPTIONS
    client->currentlyOutStandingPublishRequests = 0;
#endif

    client->sessionState = UA_SESSIONSTATE_CLOSED;
}

static void
disconnectSecureChannel(UA_Client *client, UA_Boolean sync) {
    /* Clean the DiscoveryUrl when the connection is explicitly closed */
    UA_String_clear(&client->discoveryUrl);

    /* Close the SecureChannel */
    closeSecureChannel(client);

    /* Manually set the status to closed to prevent an automatic reconnection */
    if(client->connectStatus == UA_STATUSCODE_GOOD)
        client->connectStatus = UA_STATUSCODE_BADCONNECTIONCLOSED;

    /* In the synchronous case, loop until the client has actually closed. */
    UA_EventLoop *el = client->config.eventLoop;
    if(sync && el &&
       el->state != UA_EVENTLOOPSTATE_FRESH &&
       el->state != UA_EVENTLOOPSTATE_STOPPED) {
        UA_UNLOCK(&client->clientMutex);
        while(client->channel.state != UA_SECURECHANNELSTATE_CLOSED) {
            el->run(el, 100);
        }
        UA_LOCK(&client->clientMutex);
    }

    notifyClientState(client);
}

UA_StatusCode
UA_Client_disconnectSecureChannel(UA_Client *client) {
    UA_LOCK(&client->clientMutex);
    disconnectSecureChannel(client, true);
    UA_UNLOCK(&client->clientMutex);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Client_disconnectSecureChannelAsync(UA_Client *client) {
    UA_LOCK(&client->clientMutex);
    disconnectSecureChannel(client, false);
    UA_UNLOCK(&client->clientMutex);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Client_disconnect(UA_Client *client) {
    UA_LOCK(&client->clientMutex);
    if(client->sessionState == UA_SESSIONSTATE_ACTIVATED)
        sendCloseSession(client);
    cleanupSession(client);
    disconnectSecureChannel(client, true);
    UA_UNLOCK(&client->clientMutex);
    return UA_STATUSCODE_GOOD;
}

static void
closeSessionCallback(UA_Client *client, void *userdata,
                     UA_UInt32 requestId, void *response) {
    UA_LOCK(&client->clientMutex);
    cleanupSession(client);
    disconnectSecureChannel(client, false);
    notifyClientState(client);
    UA_UNLOCK(&client->clientMutex);
}

UA_StatusCode
UA_Client_disconnectAsync(UA_Client *client) {
    UA_LOCK(&client->clientMutex);

    if(client->sessionState == UA_SESSIONSTATE_CLOSED ||
       client->sessionState == UA_SESSIONSTATE_CLOSING) {
        disconnectSecureChannel(client, false);
        notifyClientState(client);
        UA_UNLOCK(&client->clientMutex);
        return UA_STATUSCODE_GOOD;
    }

    /* Set before sending the message to prevent recursion */
    client->sessionState = UA_SESSIONSTATE_CLOSING;

    UA_CloseSessionRequest request;
    UA_CloseSessionRequest_init(&request);
    request.deleteSubscriptions = true;
    UA_StatusCode res =
        __Client_AsyncService(client, &request, &UA_TYPES[UA_TYPES_CLOSESESSIONREQUEST],
                              (UA_ClientAsyncServiceCallback)closeSessionCallback,
                              &UA_TYPES[UA_TYPES_CLOSESESSIONRESPONSE], NULL, NULL);
    if(res != UA_STATUSCODE_GOOD) {
        /* Sending the close request failed. Continue to close the connection
         * anyway. */
        cleanupSession(client);
        disconnectSecureChannel(client, false);
    }

    notifyClientState(client);
    UA_UNLOCK(&client->clientMutex);
    return res;
}

/**** amalgamated original file "/src/client/ua_client_discovery.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2017 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 */


/* Helper method for additional warnings */
void
Client_warnEndpointsResult(UA_Client *client,
                           const UA_GetEndpointsResponse *response,
                           const UA_String *endpointUrl) {
    if(response->endpointsSize == 0) {
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "The server did not return any endpoints. "
                       "Did you use the correct endpointUrl?");
        return;
    }

    if(!UA_String_equal(endpointUrl, &response->endpoints[0].endpointUrl) ||
       (response->endpoints[0].server.discoveryUrlsSize > 0 &&
        !UA_String_equal(endpointUrl, &response->endpoints[0].server.discoveryUrls[0]))) {
        UA_String *betterUrl = &response->endpoints[0].endpointUrl;
        if(response->endpoints[0].server.discoveryUrlsSize > 0)
            betterUrl = &response->endpoints[0].server.discoveryUrls[0];
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "The server returned Endpoints with a different EndpointUrl %.*s than was "
                       "used to initialize the connection: %.*s. Some servers require a complete "
                       "match of the EndpointUrl/DiscoveryUrl (including the path) "
                       "to return all endpoints.",
                       (int)betterUrl->length, betterUrl->data,
                       (int)endpointUrl->length, endpointUrl->data);
    }
}

/* Gets a list of endpoints. Memory is allocated for endpointDescription array */
static UA_StatusCode
getEndpointsInternal(UA_Client *client, const UA_String endpointUrl,
                     size_t *endpointDescriptionsSize,
                     UA_EndpointDescription **endpointDescriptions) {
    UA_LOCK_ASSERT(&client->clientMutex, 1);

    UA_GetEndpointsRequest request;
    UA_GetEndpointsRequest_init(&request);
    request.requestHeader.timeoutHint = 10000;
    // assume the endpointurl outlives the service call
    request.endpointUrl = endpointUrl;

    UA_GetEndpointsResponse response;
    __Client_Service(client, &request, &UA_TYPES[UA_TYPES_GETENDPOINTSREQUEST],
                     &response, &UA_TYPES[UA_TYPES_GETENDPOINTSRESPONSE]);

    if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
        UA_StatusCode retval = response.responseHeader.serviceResult;
        UA_LOG_ERROR(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "GetEndpointRequest failed with error code %s",
                     UA_StatusCode_name(retval));
        UA_GetEndpointsResponse_clear(&response);
        return retval;
    }

    *endpointDescriptions = response.endpoints;
    *endpointDescriptionsSize = response.endpointsSize;
    response.endpoints = NULL;
    response.endpointsSize = 0;
    UA_GetEndpointsResponse_clear(&response);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Client_getEndpoints(UA_Client *client, const char *serverUrl,
                       size_t *endpointDescriptionsSize,
                       UA_EndpointDescription** endpointDescriptions) {
    UA_LOCK(&client->clientMutex);

    UA_Boolean connected = (client->channel.state == UA_SECURECHANNELSTATE_OPEN);
    /* Client is already connected to a different server */
    if(connected && strncmp((const char*)client->config.endpoint.endpointUrl.data, serverUrl,
                            client->config.endpoint.endpointUrl.length) != 0) {
        UA_UNLOCK(&client->clientMutex);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_StatusCode retval;
    const UA_String url = UA_STRING((char*)(uintptr_t)serverUrl);
    if(!connected) {
        retval = connectSecureChannel(client, serverUrl);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_UNLOCK(&client->clientMutex);
            return retval;
        }
    }
    retval = getEndpointsInternal(client, url, endpointDescriptionsSize,
                                  endpointDescriptions);
    UA_UNLOCK(&client->clientMutex);

    if(!connected)
        UA_Client_disconnect(client);
    return retval;
}

UA_StatusCode
UA_Client_findServers(UA_Client *client, const char *serverUrl,
                      size_t serverUrisSize, UA_String *serverUris,
                      size_t localeIdsSize, UA_String *localeIds,
                      size_t *registeredServersSize,
                      UA_ApplicationDescription **registeredServers) {
    UA_LOCK(&client->clientMutex);
    UA_Boolean connected = (client->channel.state == UA_SECURECHANNELSTATE_OPEN);
    /* Client is already connected to a different server */
    if(connected && strncmp((const char*)client->config.endpoint.endpointUrl.data, serverUrl,
                            client->config.endpoint.endpointUrl.length) != 0) {
        UA_UNLOCK(&client->clientMutex);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_StatusCode retval;
    if(!connected) {
        retval = connectSecureChannel(client, serverUrl);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_UNLOCK(&client->clientMutex);
            return retval;
        }
    }

    /* Prepare the request */
    UA_FindServersRequest request;
    UA_FindServersRequest_init(&request);
    request.serverUrisSize = serverUrisSize;
    request.serverUris = serverUris;
    request.localeIdsSize = localeIdsSize;
    request.localeIds = localeIds;

    /* Send the request */
    UA_FindServersResponse response;
    __Client_Service(client, &request, &UA_TYPES[UA_TYPES_FINDSERVERSREQUEST],
                     &response, &UA_TYPES[UA_TYPES_FINDSERVERSRESPONSE]);

    UA_UNLOCK(&client->clientMutex);

    /* Process the response */
    retval = response.responseHeader.serviceResult;
    if(retval == UA_STATUSCODE_GOOD) {
        *registeredServersSize = response.serversSize;
        *registeredServers = response.servers;
        response.serversSize = 0;
        response.servers = NULL;
    } else {
        *registeredServersSize = 0;
        *registeredServers = NULL;
    }

    /* Clean up */
    UA_FindServersResponse_clear(&response);
    if(!connected)
        UA_Client_disconnect(client);
    return retval;
}

UA_StatusCode
UA_Client_findServersOnNetwork(UA_Client *client, const char *serverUrl,
                               UA_UInt32 startingRecordId, UA_UInt32 maxRecordsToReturn,
                               size_t serverCapabilityFilterSize, UA_String *serverCapabilityFilter,
                               size_t *serverOnNetworkSize, UA_ServerOnNetwork **serverOnNetwork) {
    UA_LOCK(&client->clientMutex);

    UA_Boolean connected = (client->channel.state == UA_SECURECHANNELSTATE_OPEN);
    /* Client is already connected to a different server */
    if(connected && strncmp((const char*)client->config.endpoint.endpointUrl.data, serverUrl,
                            client->config.endpoint.endpointUrl.length) != 0) {
        UA_UNLOCK(&client->clientMutex);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_StatusCode retval;
    if(!connected) {
        retval = connectSecureChannel(client, serverUrl);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOCK(&client->clientMutex);
            return retval;
        }
    }

    /* Prepare the request */
    UA_FindServersOnNetworkRequest request;
    UA_FindServersOnNetworkRequest_init(&request);
    request.startingRecordId = startingRecordId;
    request.maxRecordsToReturn = maxRecordsToReturn;
    request.serverCapabilityFilterSize = serverCapabilityFilterSize;
    request.serverCapabilityFilter = serverCapabilityFilter;

    /* Send the request */
    UA_FindServersOnNetworkResponse response;
    __Client_Service(client, &request, &UA_TYPES[UA_TYPES_FINDSERVERSONNETWORKREQUEST],
                     &response, &UA_TYPES[UA_TYPES_FINDSERVERSONNETWORKRESPONSE]);

    UA_UNLOCK(&client->clientMutex);

    /* Process the response */
    retval = response.responseHeader.serviceResult;
    if(retval == UA_STATUSCODE_GOOD) {
        *serverOnNetworkSize = response.serversSize;
        *serverOnNetwork = response.servers;
        response.serversSize = 0;
        response.servers = NULL;
    } else {
        *serverOnNetworkSize = 0;
        *serverOnNetwork = NULL;
    }

    /* Clean up */
    UA_FindServersOnNetworkResponse_clear(&response);
    if(!connected)
        UA_Client_disconnect(client);
    return retval;
}

/**** amalgamated original file "/src/client/ua_client_highlevel.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2015-2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2015 (c) Oleksiy Vasylyev
 *    Copyright 2017 (c) Florian Palm
 *    Copyright 2016 (c) Chris Iatrou
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2018 (c) Fabian Arndt
 *    Copyright 2018 (c) Peter Rustler, basyskom GmbH
 */


/* The highlevel client API is an "outer onion layer". This file does not
 * include ua_client_internal.h on purpose. */

UA_StatusCode
UA_Client_NamespaceGetIndex(UA_Client *client, UA_String *namespaceUri,
                            UA_UInt16 *namespaceIndex) {
    UA_ReadRequest request;
    UA_ReadRequest_init(&request);
    UA_ReadValueId id;
    UA_ReadValueId_init(&id);
    id.attributeId = UA_ATTRIBUTEID_VALUE;
    id.nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_NAMESPACEARRAY);
    request.nodesToRead = &id;
    request.nodesToReadSize = 1;

    UA_ReadResponse response = UA_Client_Service_read(client, request);

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
        retval = response.responseHeader.serviceResult;
    else if(response.resultsSize != 1 || !response.results[0].hasValue)
        retval = UA_STATUSCODE_BADNODEATTRIBUTESINVALID;
    else if(response.results[0].value.type != &UA_TYPES[UA_TYPES_STRING])
        retval = UA_STATUSCODE_BADTYPEMISMATCH;

    if(retval != UA_STATUSCODE_GOOD) {
        UA_ReadResponse_clear(&response);
        return retval;
    }

    retval = UA_STATUSCODE_BADNOTFOUND;
    UA_String *ns = (UA_String *)response.results[0].value.data;
    for(size_t i = 0; i < response.results[0].value.arrayLength; ++i) {
        if(UA_String_equal(namespaceUri, &ns[i])) {
            *namespaceIndex = (UA_UInt16)i;
            retval = UA_STATUSCODE_GOOD;
            break;
        }
    }

    UA_ReadResponse_clear(&response);
    return retval;
}

UA_StatusCode
UA_Client_forEachChildNodeCall(UA_Client *client, UA_NodeId parentNodeId,
                               UA_NodeIteratorCallback callback, void *handle) {
    UA_BrowseRequest bReq;
    UA_BrowseRequest_init(&bReq);
    bReq.requestedMaxReferencesPerNode = 0;
    bReq.nodesToBrowse = UA_BrowseDescription_new();
    if(!bReq.nodesToBrowse)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    bReq.nodesToBrowseSize = 1;
    UA_NodeId_copy(&parentNodeId, &bReq.nodesToBrowse[0].nodeId);
    bReq.nodesToBrowse[0].resultMask = UA_BROWSERESULTMASK_ALL; //return everything
    bReq.nodesToBrowse[0].browseDirection = UA_BROWSEDIRECTION_BOTH;

    UA_BrowseResponse bResp = UA_Client_Service_browse(client, bReq);

    UA_StatusCode retval = bResp.responseHeader.serviceResult;
    if(retval == UA_STATUSCODE_GOOD) {
        for(size_t i = 0; i < bResp.resultsSize; ++i) {
            for(size_t j = 0; j < bResp.results[i].referencesSize; ++j) {
                UA_ReferenceDescription *ref = &bResp.results[i].references[j];
                retval |= callback(ref->nodeId.nodeId, !ref->isForward,
                                   ref->referenceTypeId, handle);
            }
        }
    }

    UA_BrowseRequest_clear(&bReq);
    UA_BrowseResponse_clear(&bResp);
    return retval;
}

/*******************/
/* Node Management */
/*******************/

UA_StatusCode
UA_Client_addReference(UA_Client *client, const UA_NodeId sourceNodeId,
                       const UA_NodeId referenceTypeId, UA_Boolean isForward,
                       const UA_String targetServerUri,
                       const UA_ExpandedNodeId targetNodeId,
                       UA_NodeClass targetNodeClass) {
    UA_AddReferencesItem item;
    UA_AddReferencesItem_init(&item);
    item.sourceNodeId = sourceNodeId;
    item.referenceTypeId = referenceTypeId;
    item.isForward = isForward;
    item.targetServerUri = targetServerUri;
    item.targetNodeId = targetNodeId;
    item.targetNodeClass = targetNodeClass;
    UA_AddReferencesRequest request;
    UA_AddReferencesRequest_init(&request);
    request.referencesToAdd = &item;
    request.referencesToAddSize = 1;
    UA_AddReferencesResponse response = UA_Client_Service_addReferences(client, request);
    UA_StatusCode retval = response.responseHeader.serviceResult;
    if(retval != UA_STATUSCODE_GOOD) {
        UA_AddReferencesResponse_clear(&response);
        return retval;
    }
    if(response.resultsSize != 1) {
        UA_AddReferencesResponse_clear(&response);
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    }
    retval = response.results[0];
    UA_AddReferencesResponse_clear(&response);
    return retval;
}

UA_StatusCode
UA_Client_deleteReference(UA_Client *client, const UA_NodeId sourceNodeId,
                          const UA_NodeId referenceTypeId, UA_Boolean isForward,
                          const UA_ExpandedNodeId targetNodeId,
                          UA_Boolean deleteBidirectional) {
    UA_DeleteReferencesItem item;
    UA_DeleteReferencesItem_init(&item);
    item.sourceNodeId = sourceNodeId;
    item.referenceTypeId = referenceTypeId;
    item.isForward = isForward;
    item.targetNodeId = targetNodeId;
    item.deleteBidirectional = deleteBidirectional;
    UA_DeleteReferencesRequest request;
    UA_DeleteReferencesRequest_init(&request);
    request.referencesToDelete = &item;
    request.referencesToDeleteSize = 1;
    UA_DeleteReferencesResponse response = UA_Client_Service_deleteReferences(client, request);
    UA_StatusCode retval = response.responseHeader.serviceResult;
    if(retval != UA_STATUSCODE_GOOD) {
        UA_DeleteReferencesResponse_clear(&response);
        return retval;
    }
    if(response.resultsSize != 1) {
        UA_DeleteReferencesResponse_clear(&response);
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    }
    retval = response.results[0];
    UA_DeleteReferencesResponse_clear(&response);
    return retval;
}

UA_StatusCode
UA_Client_deleteNode(UA_Client *client, const UA_NodeId nodeId,
                     UA_Boolean deleteTargetReferences) {
    UA_DeleteNodesItem item;
    UA_DeleteNodesItem_init(&item);
    item.nodeId = nodeId;
    item.deleteTargetReferences = deleteTargetReferences;
    UA_DeleteNodesRequest request;
    UA_DeleteNodesRequest_init(&request);
    request.nodesToDelete = &item;
    request.nodesToDeleteSize = 1;
    UA_DeleteNodesResponse response = UA_Client_Service_deleteNodes(client, request);
    UA_StatusCode retval = response.responseHeader.serviceResult;
    if(retval != UA_STATUSCODE_GOOD) {
        UA_DeleteNodesResponse_clear(&response);
        return retval;
    }
    if(response.resultsSize != 1) {
        UA_DeleteNodesResponse_clear(&response);
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    }
    retval = response.results[0];
    UA_DeleteNodesResponse_clear(&response);
    return retval;
}

UA_StatusCode
__UA_Client_addNode(UA_Client *client, const UA_NodeClass nodeClass,
                    const UA_NodeId requestedNewNodeId, const UA_NodeId parentNodeId,
                    const UA_NodeId referenceTypeId, const UA_QualifiedName browseName,
                    const UA_NodeId typeDefinition, const UA_NodeAttributes *attr,
                    const UA_DataType *attributeType, UA_NodeId *outNewNodeId) {
    UA_AddNodesRequest request;
    UA_AddNodesRequest_init(&request);
    UA_AddNodesItem item;
    UA_AddNodesItem_init(&item);
    item.parentNodeId.nodeId = parentNodeId;
    item.referenceTypeId = referenceTypeId;
    item.requestedNewNodeId.nodeId = requestedNewNodeId;
    item.browseName = browseName;
    item.nodeClass = nodeClass;
    item.typeDefinition.nodeId = typeDefinition;
    item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
    item.nodeAttributes.content.decoded.type = attributeType;
    item.nodeAttributes.content.decoded.data = (void*)(uintptr_t)attr; // hack. is not written into.
    request.nodesToAdd = &item;
    request.nodesToAddSize = 1;
    UA_AddNodesResponse response = UA_Client_Service_addNodes(client, request);

    UA_StatusCode retval = response.responseHeader.serviceResult;
    if(retval != UA_STATUSCODE_GOOD) {
        UA_AddNodesResponse_clear(&response);
        return retval;
    }

    if(response.resultsSize != 1) {
        UA_AddNodesResponse_clear(&response);
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    }

    /* Move the id of the created node */
    retval = response.results[0].statusCode;
    if(retval == UA_STATUSCODE_GOOD && outNewNodeId) {
        *outNewNodeId = response.results[0].addedNodeId;
        UA_NodeId_init(&response.results[0].addedNodeId);
    }

    UA_AddNodesResponse_clear(&response);
    return retval;
}

/********/
/* Call */
/********/

UA_StatusCode
UA_Client_call(UA_Client *client, const UA_NodeId objectId,
               const UA_NodeId methodId, size_t inputSize,
               const UA_Variant *input, size_t *outputSize,
               UA_Variant **output) {
    /* Set up the request */
    UA_CallRequest request;
    UA_CallRequest_init(&request);
    UA_CallMethodRequest item;
    UA_CallMethodRequest_init(&item);
    item.methodId = methodId;
    item.objectId = objectId;
    item.inputArguments = (UA_Variant *)(void*)(uintptr_t)input; // cast const...
    item.inputArgumentsSize = inputSize;
    request.methodsToCall = &item;
    request.methodsToCallSize = 1;

    /* Call the service */
    UA_CallResponse response = UA_Client_Service_call(client, request);
    UA_StatusCode retval = response.responseHeader.serviceResult;
    if(retval == UA_STATUSCODE_GOOD) {
        if(response.resultsSize == 1)
            retval = response.results[0].statusCode;
        else
            retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
    }
    if(UA_StatusCode_isBad(retval)) {
        UA_CallResponse_clear(&response);
        return retval;
    }

    /* Move the output arguments */
    if(output != NULL && outputSize != NULL) {
        *output = response.results[0].outputArguments;
        *outputSize = response.results[0].outputArgumentsSize;
        response.results[0].outputArguments = NULL;
        response.results[0].outputArgumentsSize = 0;
    }
    UA_CallResponse_clear(&response);
    return retval;
}

/********************/
/* Write Attributes */
/********************/

UA_StatusCode
__UA_Client_writeAttribute(UA_Client *client, const UA_NodeId *nodeId,
                           UA_AttributeId attributeId, const void *in,
                           const UA_DataType *inDataType) {
    if(!in || !inDataType)
      return UA_STATUSCODE_BADTYPEMISMATCH;

    UA_WriteValue wValue;
    UA_WriteValue_init(&wValue);
    wValue.nodeId = *nodeId;
    wValue.attributeId = attributeId;
    if(attributeId == UA_ATTRIBUTEID_VALUE &&
       inDataType == &UA_TYPES[UA_TYPES_VARIANT]) {
        wValue.value.value = *(const UA_Variant*)in;
        wValue.value.hasValue = true;
    } else if(attributeId == UA_ATTRIBUTEID_VALUE &&
              inDataType == &UA_TYPES[UA_TYPES_DATAVALUE]) {
        wValue.value = *(const UA_DataValue*)in;
    } else {
        /* Hack to get rid of the const annotation.
         * The value is never written into. */
        UA_Variant_setScalar(&wValue.value.value, (void*)(uintptr_t)in, inDataType);
        wValue.value.hasValue = true;
    }
    UA_WriteRequest wReq;
    UA_WriteRequest_init(&wReq);
    wReq.nodesToWrite = &wValue;
    wReq.nodesToWriteSize = 1;

    UA_WriteResponse wResp = UA_Client_Service_write(client, wReq);

    UA_StatusCode retval = wResp.responseHeader.serviceResult;
    if(retval == UA_STATUSCODE_GOOD) {
        if(wResp.resultsSize == 1)
            retval = wResp.results[0];
        else
            retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
    }

    UA_WriteResponse_clear(&wResp);
    return retval;
}

UA_StatusCode
UA_Client_writeArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId,
                                        size_t newArrayDimensionsSize,
                                        const UA_UInt32 *newArrayDimensions) {
    if(!newArrayDimensions)
      return UA_STATUSCODE_BADTYPEMISMATCH;

    UA_WriteValue wValue;
    UA_WriteValue_init(&wValue);
    wValue.nodeId = nodeId;
    wValue.attributeId = UA_ATTRIBUTEID_ARRAYDIMENSIONS;
    UA_Variant_setArray(&wValue.value.value, (void*)(uintptr_t)newArrayDimensions,
                        newArrayDimensionsSize, &UA_TYPES[UA_TYPES_UINT32]);
    wValue.value.hasValue = true;
    UA_WriteRequest wReq;
    UA_WriteRequest_init(&wReq);
    wReq.nodesToWrite = &wValue;
    wReq.nodesToWriteSize = 1;

    UA_WriteResponse wResp = UA_Client_Service_write(client, wReq);

    UA_StatusCode retval = wResp.responseHeader.serviceResult;
    if(retval == UA_STATUSCODE_GOOD) {
        if(wResp.resultsSize == 1)
            retval = wResp.results[0];
        else
            retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
    }
    UA_WriteResponse_clear(&wResp);
    return retval;
}

/*******************/
/* Read Attributes */
/*******************/

UA_StatusCode
__UA_Client_readAttribute(UA_Client *client, const UA_NodeId *nodeId,
                          UA_AttributeId attributeId, void *out,
                          const UA_DataType *outDataType) {
    UA_ReadValueId item;
    UA_ReadValueId_init(&item);
    item.nodeId = *nodeId;
    item.attributeId = attributeId;
    UA_ReadRequest request;
    UA_ReadRequest_init(&request);
    request.nodesToRead = &item;
    request.nodesToReadSize = 1;
    UA_ReadResponse response = UA_Client_Service_read(client, request);
    UA_StatusCode retval = response.responseHeader.serviceResult;
    if(retval == UA_STATUSCODE_GOOD) {
        if(response.resultsSize == 1)
            retval = response.results[0].status;
        else
            retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
    }
    if(!UA_StatusCode_isEqualTop(retval,UA_STATUSCODE_GOOD)) {
        UA_ReadResponse_clear(&response);
        return retval;
    }

    /* Set the StatusCode */
    UA_DataValue *res = response.results;
    if(res->hasStatus)
        retval = res->status;

    /* Return early of no value is given */
    if(!res->hasValue) {
        retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
        UA_ReadResponse_clear(&response);
        return retval;
    }

    /* Copy value into out */
    if(attributeId == UA_ATTRIBUTEID_VALUE) {
        memcpy(out, &res->value, sizeof(UA_Variant));
        UA_Variant_init(&res->value);
    } else if(attributeId == UA_ATTRIBUTEID_NODECLASS) {
        memcpy(out, (UA_NodeClass*)res->value.data, sizeof(UA_NodeClass));
    } else if(UA_Variant_isScalar(&res->value) &&
              res->value.type == outDataType) {
        memcpy(out, res->value.data, res->value.type->memSize);
        UA_free(res->value.data);
        res->value.data = NULL;
    } else {
        retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
    }

    UA_ReadResponse_clear(&response);
    return retval;
}

static UA_StatusCode
processReadArrayDimensionsResult(UA_ReadResponse *response,
                                 UA_UInt32 **outArrayDimensions,
                                 size_t *outArrayDimensionsSize) {
    UA_StatusCode retval = response->responseHeader.serviceResult;
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    if(response->resultsSize != 1)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;

    retval = response->results[0].status;
    if(!UA_StatusCode_isEqualTop(retval,UA_STATUSCODE_GOOD))
        return retval;

    UA_DataValue *res = &response->results[0];
    if(!res->hasValue ||
       UA_Variant_isScalar(&res->value) ||
       res->value.type != &UA_TYPES[UA_TYPES_UINT32])
        return UA_STATUSCODE_BADUNEXPECTEDERROR;

    /* Move results */
    *outArrayDimensions = (UA_UInt32*)res->value.data;
    *outArrayDimensionsSize = res->value.arrayLength;
    res->value.data = NULL;
    res->value.arrayLength = 0;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Client_readArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId,
                                       size_t *outArrayDimensionsSize,
                                       UA_UInt32 **outArrayDimensions) {
    UA_ReadValueId item;
    UA_ReadValueId_init(&item);
    item.nodeId = nodeId;
    item.attributeId = UA_ATTRIBUTEID_ARRAYDIMENSIONS;
    UA_ReadRequest request;
    UA_ReadRequest_init(&request);
    request.nodesToRead = &item;
    request.nodesToReadSize = 1;

    UA_ReadResponse response = UA_Client_Service_read(client, request);
    UA_StatusCode retval = processReadArrayDimensionsResult(&response, outArrayDimensions,
                                                            outArrayDimensionsSize);
    UA_ReadResponse_clear(&response);
    return retval;
}

/*********************/
/* Historical Access */
/*********************/

static UA_HistoryReadResponse
__UA_Client_HistoryRead(UA_Client *client, const UA_NodeId *nodeId,
                        UA_ExtensionObject* details, UA_String indexRange,
                        UA_TimestampsToReturn timestampsToReturn,
                        UA_ByteString continuationPoint, UA_Boolean releaseConti) {

    UA_HistoryReadValueId item;
    UA_HistoryReadValueId_init(&item);

    item.nodeId = *nodeId;
    item.indexRange = indexRange;
    item.continuationPoint = continuationPoint;
    item.dataEncoding = UA_QUALIFIEDNAME(0, "");

    UA_HistoryReadRequest request;
    UA_HistoryReadRequest_init(&request);

    request.nodesToRead = &item;
    request.nodesToReadSize = 1;
    request.timestampsToReturn = timestampsToReturn; // Defaults to Source
    request.releaseContinuationPoints = releaseConti; // No values are returned, if true

    /* Build ReadDetails */
    request.historyReadDetails = *details;

    return UA_Client_Service_historyRead(client, request);
}

static UA_StatusCode
__UA_Client_HistoryRead_service(UA_Client *client, const UA_NodeId *nodeId,
                                   const UA_HistoricalIteratorCallback callback,
                                   UA_ExtensionObject *details, UA_String indexRange,
                                   UA_TimestampsToReturn timestampsToReturn,
                                   void *callbackContext) {

    UA_ByteString continuationPoint = UA_BYTESTRING_NULL;
    UA_Boolean continuationAvail = false;
    UA_Boolean fetchMore = false;
    UA_StatusCode retval = UA_STATUSCODE_GOOD;

    do {
        /* We release the continuation point, if no more data is requested by the user */
        UA_Boolean cleanup = !fetchMore && continuationAvail;
        UA_HistoryReadResponse response =
            __UA_Client_HistoryRead(client, nodeId, details, indexRange, timestampsToReturn, continuationPoint, cleanup);

        if(cleanup) {
            retval = response.responseHeader.serviceResult;
cleanup:    UA_HistoryReadResponse_clear(&response);
            UA_ByteString_clear(&continuationPoint);
            return retval;
        }

        retval = response.responseHeader.serviceResult;
        if(retval == UA_STATUSCODE_GOOD) {
            if(response.resultsSize == 1)
                retval = response.results[0].statusCode;
            else
                retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
        }
        if(!UA_StatusCode_isEqualTop(retval,UA_STATUSCODE_GOOD))
            goto cleanup;

        UA_HistoryReadResult *res = response.results;

        /* Clear old and check / store new continuation point */
        UA_ByteString_clear(&continuationPoint);
        UA_ByteString_copy(&res->continuationPoint, &continuationPoint);
        continuationAvail = !UA_ByteString_equal(&continuationPoint, &UA_BYTESTRING_NULL);

        /* Client callback with possibility to request further values */
        fetchMore = callback(client, nodeId, continuationAvail, &res->historyData, callbackContext);

        /* Regular cleanup */
        UA_HistoryReadResponse_clear(&response);
    } while(continuationAvail);

    return retval;
}

UA_StatusCode
UA_Client_HistoryRead_events(UA_Client *client, const UA_NodeId *nodeId,
                                const UA_HistoricalIteratorCallback callback,
                                UA_DateTime startTime, UA_DateTime endTime,
                                UA_String indexRange, const UA_EventFilter filter, UA_UInt32 numValuesPerNode,
                                UA_TimestampsToReturn timestampsToReturn, void *callbackContext) {

    UA_ReadEventDetails details;
    UA_ReadEventDetails_init(&details);
    details.filter = filter;

    // At least two of the following parameters must be set
    details.numValuesPerNode = numValuesPerNode; // 0 = return all / max server is capable of
    details.startTime = startTime;
    details.endTime = endTime;

    UA_ExtensionObject detailsExtensionObject;
    UA_ExtensionObject_init(&detailsExtensionObject);
    detailsExtensionObject.content.decoded.type = &UA_TYPES[UA_TYPES_READEVENTDETAILS];
    detailsExtensionObject.content.decoded.data = &details;
    detailsExtensionObject.encoding = UA_EXTENSIONOBJECT_DECODED;

    return __UA_Client_HistoryRead_service(client, nodeId, callback, &detailsExtensionObject,
                                              indexRange, timestampsToReturn, callbackContext);
}

static UA_StatusCode
__UA_Client_HistoryRead_service_rawMod(UA_Client *client, const UA_NodeId *nodeId,
                                          const UA_HistoricalIteratorCallback callback,
                                          UA_DateTime startTime,UA_DateTime endTime,
                                          UA_String indexRange, UA_Boolean returnBounds, UA_UInt32 numValuesPerNode,
                                          UA_Boolean readModified, UA_TimestampsToReturn timestampsToReturn,
                                          void *callbackContext) {

    UA_ReadRawModifiedDetails details;
    UA_ReadRawModifiedDetails_init(&details);
    details.isReadModified = readModified; // Return only modified values
    details.returnBounds = returnBounds;   // Return values pre / post given range

    // At least two of the following parameters must be set
    details.numValuesPerNode = numValuesPerNode;   // 0 = return all / max server is capable of
    details.startTime = startTime;
    details.endTime = endTime;

    UA_ExtensionObject detailsExtensionObject;
    UA_ExtensionObject_init(&detailsExtensionObject);
    detailsExtensionObject.content.decoded.type = &UA_TYPES[UA_TYPES_READRAWMODIFIEDDETAILS];
    detailsExtensionObject.content.decoded.data = &details;
    detailsExtensionObject.encoding = UA_EXTENSIONOBJECT_DECODED;

    return __UA_Client_HistoryRead_service(client, nodeId, callback,
                                              &detailsExtensionObject, indexRange,
                                              timestampsToReturn, callbackContext);
}

UA_StatusCode
UA_Client_HistoryRead_raw(UA_Client *client, const UA_NodeId *nodeId,
                             const UA_HistoricalIteratorCallback callback,
                             UA_DateTime startTime, UA_DateTime endTime,
                             UA_String indexRange, UA_Boolean returnBounds, UA_UInt32 numValuesPerNode,
                             UA_TimestampsToReturn timestampsToReturn, void *callbackContext) {

    return __UA_Client_HistoryRead_service_rawMod(client, nodeId, callback, startTime, endTime, indexRange, returnBounds,
                                                     numValuesPerNode, false, timestampsToReturn, callbackContext);
}

UA_StatusCode
UA_Client_HistoryRead_modified(UA_Client *client, const UA_NodeId *nodeId,
                                  const UA_HistoricalIteratorCallback callback,
                                  UA_DateTime startTime, UA_DateTime endTime,
                                  UA_String indexRange, UA_Boolean returnBounds, UA_UInt32 maxItems,
                                  UA_TimestampsToReturn timestampsToReturn, void *callbackContext) {
    return __UA_Client_HistoryRead_service_rawMod(client, nodeId, callback, startTime,
                                                  endTime, indexRange, returnBounds, maxItems,
                                                  true, timestampsToReturn, callbackContext);
}

static UA_HistoryUpdateResponse
__UA_Client_HistoryUpdate(UA_Client *client, void *details, size_t typeId) {
    UA_HistoryUpdateRequest request;
    UA_HistoryUpdateRequest_init(&request);

    UA_ExtensionObject extension;
    UA_ExtensionObject_init(&extension);
    request.historyUpdateDetailsSize = 1;
    request.historyUpdateDetails = &extension;

    extension.encoding = UA_EXTENSIONOBJECT_DECODED;
    extension.content.decoded.type = &UA_TYPES[typeId];
    extension.content.decoded.data = details;

    UA_HistoryUpdateResponse response;
    response = UA_Client_Service_historyUpdate(client, request);
    return response;
}

static UA_StatusCode
__UA_Client_HistoryUpdate_updateData(UA_Client *client, const UA_NodeId *nodeId,
                                     UA_PerformUpdateType type, UA_DataValue *value) {
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    UA_UpdateDataDetails details;
    UA_UpdateDataDetails_init(&details);

    details.performInsertReplace = type;
    details.updateValuesSize = 1;
    details.updateValues = value;
    UA_NodeId_copy(nodeId, &details.nodeId);

    UA_HistoryUpdateResponse response;
    response = __UA_Client_HistoryUpdate(client, &details, UA_TYPES_UPDATEDATADETAILS);
    if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
        ret = response.responseHeader.serviceResult;
        goto cleanup;
    }
    if(response.resultsSize != 1 || response.results[0].operationResultsSize != 1) {
        ret = UA_STATUSCODE_BADUNEXPECTEDERROR;
        goto cleanup;
    }
    if(response.results[0].statusCode != UA_STATUSCODE_GOOD) {
        ret = response.results[0].statusCode;
        goto cleanup;
    }
    ret = response.results[0].operationResults[0];
cleanup:
    UA_HistoryUpdateResponse_clear(&response);
    UA_NodeId_clear(&details.nodeId);
    return ret;
}

UA_StatusCode
UA_Client_HistoryUpdate_insert(UA_Client *client, const UA_NodeId *nodeId,
                               UA_DataValue *value) {
    return __UA_Client_HistoryUpdate_updateData(client, nodeId,
                                                UA_PERFORMUPDATETYPE_INSERT,
                                                value);
}

UA_StatusCode
UA_Client_HistoryUpdate_replace(UA_Client *client, const UA_NodeId *nodeId,
                                UA_DataValue *value) {
    return __UA_Client_HistoryUpdate_updateData(client, nodeId,
                                                UA_PERFORMUPDATETYPE_REPLACE,
                                                value);
}

UA_StatusCode
UA_Client_HistoryUpdate_update(UA_Client *client, const UA_NodeId *nodeId,
                               UA_DataValue *value) {
    return __UA_Client_HistoryUpdate_updateData(client, nodeId,
                                                UA_PERFORMUPDATETYPE_UPDATE,
                                                value);
}

UA_StatusCode
UA_Client_HistoryUpdate_deleteRaw(UA_Client *client, const UA_NodeId *nodeId,
                                  UA_DateTime startTimestamp, UA_DateTime endTimestamp) {
    UA_DeleteRawModifiedDetails details;
    UA_DeleteRawModifiedDetails_init(&details);
    details.isDeleteModified = false;
    details.startTime = startTimestamp;
    details.endTime = endTimestamp;
    UA_NodeId_copy(nodeId, &details.nodeId);

    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    UA_HistoryUpdateResponse response;
    response = __UA_Client_HistoryUpdate(client, &details, UA_TYPES_DELETERAWMODIFIEDDETAILS);
    if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
        ret = response.responseHeader.serviceResult;
        goto cleanup;
    }
    if(response.resultsSize != 1) {
        ret = UA_STATUSCODE_BADUNEXPECTEDERROR;
        goto cleanup;
    }

    ret = response.results[0].statusCode;

cleanup:
    UA_HistoryUpdateResponse_clear(&response);
    UA_NodeId_clear(&details.nodeId);
    return ret;
}

/*******************/
/* Async Functions */
/*******************/

UA_StatusCode
__UA_Client_writeAttribute_async(UA_Client *client, const UA_NodeId *nodeId,
                                 UA_AttributeId attributeId, const void *in,
                                 const UA_DataType *inDataType, UA_ClientAsyncServiceCallback callback,
                                 void *userdata, UA_UInt32 *reqId) {
    if(!in)
        return UA_STATUSCODE_BADTYPEMISMATCH;

    UA_WriteValue wValue;
    UA_WriteValue_init(&wValue);
    wValue.nodeId = *nodeId;
    wValue.attributeId = attributeId;
    if(attributeId == UA_ATTRIBUTEID_VALUE)
        wValue.value.value = *(const UA_Variant*) in;
    else
        /* hack. is never written into. */
        UA_Variant_setScalar(&wValue.value.value, (void*) (uintptr_t) in,
                inDataType);
    wValue.value.hasValue = true;
    UA_WriteRequest wReq;
    UA_WriteRequest_init(&wReq);
    wReq.nodesToWrite = &wValue;
    wReq.nodesToWriteSize = 1;

    return __UA_Client_AsyncService(client, &wReq,
            &UA_TYPES[UA_TYPES_WRITEREQUEST], callback,
            &UA_TYPES[UA_TYPES_WRITERESPONSE], userdata, reqId);
}

UA_StatusCode
__UA_Client_addNode_async(UA_Client *client, const UA_NodeClass nodeClass,
                          const UA_NodeId requestedNewNodeId, const UA_NodeId parentNodeId,
                          const UA_NodeId referenceTypeId, const UA_QualifiedName browseName,
                          const UA_NodeId typeDefinition, const UA_NodeAttributes *attr,
                          const UA_DataType *attributeType, UA_NodeId *outNewNodeId,
                          UA_ClientAsyncServiceCallback callback, void *userdata,
                          UA_UInt32 *reqId) {
    UA_AddNodesRequest request;
    UA_AddNodesRequest_init(&request);
    UA_AddNodesItem item;
    UA_AddNodesItem_init(&item);
    item.parentNodeId.nodeId = parentNodeId;
    item.referenceTypeId = referenceTypeId;
    item.requestedNewNodeId.nodeId = requestedNewNodeId;
    item.browseName = browseName;
    item.nodeClass = nodeClass;
    item.typeDefinition.nodeId = typeDefinition;
    item.nodeAttributes.encoding = UA_EXTENSIONOBJECT_DECODED_NODELETE;
    item.nodeAttributes.content.decoded.type = attributeType;
    item.nodeAttributes.content.decoded.data = (void*) (uintptr_t) attr; // hack. is not written into.
    request.nodesToAdd = &item;
    request.nodesToAddSize = 1;

    return __UA_Client_AsyncService(client, &request,
            &UA_TYPES[UA_TYPES_ADDNODESREQUEST], callback,
            &UA_TYPES[UA_TYPES_ADDNODESRESPONSE], userdata, reqId);

}

UA_StatusCode
__UA_Client_call_async(UA_Client *client, const UA_NodeId objectId,
                       const UA_NodeId methodId, size_t inputSize,
                       const UA_Variant *input, UA_ClientAsyncServiceCallback callback,
                       void *userdata, UA_UInt32 *reqId) {
    UA_CallRequest request;
    UA_CallRequest_init(&request);
    UA_CallMethodRequest item;
    UA_CallMethodRequest_init(&item);
    item.methodId = methodId;
    item.objectId = objectId;
    item.inputArguments = (UA_Variant *) (void*) (uintptr_t) input; // cast const...
    item.inputArgumentsSize = inputSize;
    request.methodsToCall = &item;
    request.methodsToCallSize = 1;

    return __UA_Client_AsyncService(client, &request,
            &UA_TYPES[UA_TYPES_CALLREQUEST], callback,
            &UA_TYPES[UA_TYPES_CALLRESPONSE], userdata, reqId);
}

/* UA_StatusCode */
/* UA_Cient_translateBrowsePathsToNodeIds_async(UA_Client *client, char **paths, */
/*                                              UA_UInt32 *ids, size_t pathSize, */
/*                                              UA_ClientAsyncTranslateCallback callback, */
/*                                              void *userdata, UA_UInt32 *reqId) { */
/*     return UA_STATUSCODE_BADNOTIMPLEMENTED; */
/* } */

/*************************/
/* Read Single Attribute */
/*************************/

typedef struct {
    UA_ClientAsyncOperationCallback userCallback;
    void *userContext;
    const UA_DataType *resultType; /* DataValue -> Value attribute,
                                    * Variant -> ArrayDimensions attribute */
} UA_AttributeReadContext;

static void
AttributeReadCallback(UA_Client *client, void *userdata,
                      UA_UInt32 requestId, UA_ReadResponse *rr) {
    UA_AttributeReadContext *ctx = (UA_AttributeReadContext*)userdata;
    UA_LOG_DEBUG(UA_Client_getConfig(client)->logging, UA_LOGCATEGORY_CLIENT,
                "Async read response for request %" PRIu32, requestId);

    UA_DataValue *dv = NULL;

    /* Check the ServiceResult */
    UA_StatusCode res = rr->responseHeader.serviceResult;
    if(res != UA_STATUSCODE_GOOD)
        goto finish;

    /* Check result array size */
    if(rr->resultsSize != 1) {
        res = UA_STATUSCODE_BADINTERNALERROR;
        goto finish;
    }

    /* A Value attribute */
    dv = &rr->results[0];
    if(ctx->resultType == &UA_TYPES[UA_TYPES_DATAVALUE]) {
        ctx->userCallback(client, ctx->userContext, requestId,
                          UA_STATUSCODE_GOOD, dv);
        goto finish;
    }

    /* An ArrayDimensions attribute. Has to be an array of UInt32. */
    if(ctx->resultType == &UA_TYPES[UA_TYPES_VARIANT]) {
        if(dv->hasValue &&
           UA_Variant_hasArrayType(&dv->value, &UA_TYPES[UA_TYPES_UINT32])) {
            ctx->userCallback(client, ctx->userContext, requestId,
                              UA_STATUSCODE_GOOD, &dv->value);
        } else {
            res = UA_STATUSCODE_BADINTERNALERROR;
        }
        goto finish;
    }

    /* Check we have a scalar value of the right datatype */
    if(!dv->hasValue ||
       !UA_Variant_hasScalarType(&dv->value, ctx->resultType)) {
        res = UA_STATUSCODE_BADINTERNALERROR;
        goto finish;
    }

    /* Callback into userland */
    ctx->userCallback(client, ctx->userContext, requestId,
                      UA_STATUSCODE_GOOD, dv->value.data);

 finish:
    if(res != UA_STATUSCODE_GOOD)
        ctx->userCallback(client, ctx->userContext, requestId, res, NULL);
    UA_free(ctx);
}

static UA_StatusCode
readAttribute_async(UA_Client *client, const UA_ReadValueId *rvi,
                    UA_TimestampsToReturn timestampsToReturn,
                    const UA_DataType *resultType, /* For the specialized reads */
                    UA_ClientAsyncOperationCallback callback,
                    void *userdata, UA_UInt32 *requestId) {
    UA_AttributeReadContext *ctx = (UA_AttributeReadContext*)
        UA_malloc(sizeof(UA_AttributeReadContext));
    if(!ctx)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    ctx->userCallback = callback;
    ctx->userContext = userdata;
    ctx->resultType = resultType;

    UA_ReadRequest request;
    UA_ReadRequest_init(&request);
    request.nodesToRead = (UA_ReadValueId*)(uintptr_t)rvi; /* hack, treated as const */
    request.nodesToReadSize = 1;
    request.timestampsToReturn = timestampsToReturn;

    UA_StatusCode res =
        __UA_Client_AsyncService(client, &request, &UA_TYPES[UA_TYPES_READREQUEST],
                                 (UA_ClientAsyncServiceCallback)AttributeReadCallback,
                                 &UA_TYPES[UA_TYPES_READRESPONSE], ctx, requestId);
    if(res != UA_STATUSCODE_GOOD)
        UA_free(ctx);
    return res;
}

UA_StatusCode
UA_Client_readAttribute_async(UA_Client *client, const UA_ReadValueId *rvi,
                              UA_TimestampsToReturn timestampsToReturn,
                              UA_ClientAsyncReadAttributeCallback callback,
                              void *userdata, UA_UInt32 *requestId) {
    return readAttribute_async(client, rvi, timestampsToReturn,
                               &UA_TYPES[UA_TYPES_DATAVALUE], /* special handling */
                               (UA_ClientAsyncOperationCallback)callback,
                               userdata, requestId);
}

/* Helper to keep the code short */
static UA_StatusCode
readAttribute_simpleAsync(UA_Client *client, const UA_NodeId *nodeId,
                          UA_AttributeId attributeId, const UA_DataType *resultType,
                          UA_ClientAsyncOperationCallback callback,
                          void *userdata, UA_UInt32 *requestId) {
    UA_ReadValueId rvi;
    UA_ReadValueId_init(&rvi);
    rvi.nodeId = *nodeId;
    rvi.attributeId = attributeId;
    return readAttribute_async(client, &rvi, UA_TIMESTAMPSTORETURN_NEITHER,
                               resultType, callback, userdata, requestId);
}

UA_StatusCode
UA_Client_readValueAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                   UA_ClientAsyncReadValueAttributeCallback callback,
                                   void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_VALUE,
                                     &UA_TYPES[UA_TYPES_DATAVALUE], /* special hndling */
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readDataTypeAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                      UA_ClientAsyncReadDataTypeAttributeCallback callback,
                                      void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_DATATYPE,
                                     &UA_TYPES[UA_TYPES_NODEID],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readArrayDimensionsAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                             UA_ClientReadArrayDimensionsAttributeCallback callback,
                                             void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_ARRAYDIMENSIONS,
                                     &UA_TYPES[UA_TYPES_VARIANT], /* special handling */
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readNodeClassAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                       UA_ClientAsyncReadNodeClassAttributeCallback callback,
                                       void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_NODECLASS,
                                     &UA_TYPES[UA_TYPES_NODECLASS],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readBrowseNameAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                        UA_ClientAsyncReadBrowseNameAttributeCallback callback,
                                        void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_BROWSENAME,
                                     &UA_TYPES[UA_TYPES_QUALIFIEDNAME],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readDisplayNameAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                         UA_ClientAsyncReadDisplayNameAttributeCallback callback,
                                         void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_DISPLAYNAME,
                                     &UA_TYPES[UA_TYPES_LOCALIZEDTEXT],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readDescriptionAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                         UA_ClientAsyncReadDescriptionAttributeCallback callback,
                                         void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_DESCRIPTION,
                                     &UA_TYPES[UA_TYPES_LOCALIZEDTEXT],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readWriteMaskAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                       UA_ClientAsyncReadWriteMaskAttributeCallback callback,
                                       void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_WRITEMASK,
                                     &UA_TYPES[UA_TYPES_UINT32],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode UA_EXPORT
UA_Client_readUserWriteMaskAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                           UA_ClientAsyncReadUserWriteMaskAttributeCallback callback,
                                           void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_USERWRITEMASK,
                                     &UA_TYPES[UA_TYPES_UINT32],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readIsAbstractAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                        UA_ClientAsyncReadIsAbstractAttributeCallback callback,
                                        void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_ISABSTRACT,
                                     &UA_TYPES[UA_TYPES_BOOLEAN],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readSymmetricAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                       UA_ClientAsyncReadSymmetricAttributeCallback callback,
                                       void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_SYMMETRIC,
                                     &UA_TYPES[UA_TYPES_BOOLEAN],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readInverseNameAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                         UA_ClientAsyncReadInverseNameAttributeCallback callback,
                                         void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_INVERSENAME,
                                     &UA_TYPES[UA_TYPES_LOCALIZEDTEXT],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readContainsNoLoopsAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                             UA_ClientAsyncReadContainsNoLoopsAttributeCallback callback,
                                             void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_CONTAINSNOLOOPS,
                                     &UA_TYPES[UA_TYPES_BOOLEAN],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readEventNotifierAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                           UA_ClientAsyncReadEventNotifierAttributeCallback callback,
                                           void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_EVENTNOTIFIER,
                                     &UA_TYPES[UA_TYPES_BYTE],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readValueRankAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                       UA_ClientAsyncReadValueRankAttributeCallback callback,
                                       void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_VALUERANK,
                                     &UA_TYPES[UA_TYPES_INT32],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readAccessLevelAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                         UA_ClientAsyncReadAccessLevelAttributeCallback callback,
                                         void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_ACCESSLEVEL,
                                     &UA_TYPES[UA_TYPES_BYTE],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readAccessLevelExAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                           UA_ClientAsyncReadAccessLevelExAttributeCallback callback,
                                           void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_ACCESSLEVELEX,
                                     &UA_TYPES[UA_TYPES_UINT32],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readUserAccessLevelAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                             UA_ClientAsyncReadUserAccessLevelAttributeCallback callback,
                                             void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_USERACCESSLEVEL,
                                     &UA_TYPES[UA_TYPES_BYTE],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readMinimumSamplingIntervalAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                                     UA_ClientAsyncReadMinimumSamplingIntervalAttributeCallback callback,
                                                     void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_MINIMUMSAMPLINGINTERVAL,
                                     &UA_TYPES[UA_TYPES_DOUBLE],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readHistorizingAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                         UA_ClientAsyncReadHistorizingAttributeCallback callback,
                                         void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_HISTORIZING,
                                     &UA_TYPES[UA_TYPES_BOOLEAN],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readExecutableAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                        UA_ClientAsyncReadExecutableAttributeCallback callback,
                                        void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_EXECUTABLE,
                                     &UA_TYPES[UA_TYPES_BOOLEAN],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

UA_StatusCode
UA_Client_readUserExecutableAttribute_async(UA_Client *client, const UA_NodeId nodeId,
                                            UA_ClientAsyncReadUserExecutableAttributeCallback callback,
                                            void *userdata, UA_UInt32 *requestId) {
    return readAttribute_simpleAsync(client, &nodeId, UA_ATTRIBUTEID_USEREXECUTABLE,
                                     &UA_TYPES[UA_TYPES_BOOLEAN],
                                     (UA_ClientAsyncOperationCallback)callback,
                                     userdata, requestId);
}

/**** amalgamated original file "/src/client/ua_client_subscriptions.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2015-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2015 (c) Oleksiy Vasylyev
 *    Copyright 2016 (c) Sten Grüner
 *    Copyright 2017-2018 (c) Thomas Stalder, Blue Time Concept SA
 *    Copyright 2016-2017 (c) Florian Palm
 *    Copyright 2017 (c) Frank Meerkötter
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 */



struct UA_Client_MonitoredItem_ForDelete {
    UA_Client *client;
    UA_Client_Subscription *sub;
    UA_UInt32 *monitoredItemId;
};

/*****************/
/* Subscriptions */
/*****************/

static enum ZIP_CMP
/* For ZIP_TREE we use clientHandle comparison */
UA_ClientHandle_cmp(const void *a, const void *b) {
    const UA_Client_MonitoredItem *aa = (const UA_Client_MonitoredItem *)a;
    const UA_Client_MonitoredItem *bb = (const UA_Client_MonitoredItem *)b;

    /* Compare  clientHandle */
    if(aa->clientHandle < bb->clientHandle) {
        return ZIP_CMP_LESS;
    }
    if(aa->clientHandle > bb->clientHandle) {
        return ZIP_CMP_MORE;
    }

    return ZIP_CMP_EQ;
}

ZIP_FUNCTIONS(MonitorItemsTree, UA_Client_MonitoredItem, zipfields,
              UA_Client_MonitoredItem, zipfields, UA_ClientHandle_cmp)

static void
MonitoredItem_delete(UA_Client *client, UA_Client_Subscription *sub,
                     UA_Client_MonitoredItem *mon);

static void
ua_Subscriptions_create(UA_Client *client, UA_Client_Subscription *newSub,
                        UA_CreateSubscriptionResponse *response) {
    UA_LOCK_ASSERT(&client->clientMutex, 1);

    UA_EventLoop *el = client->config.eventLoop;

    newSub->subscriptionId = response->subscriptionId;
    newSub->sequenceNumber = 0;
    newSub->lastActivity = el->dateTime_nowMonotonic(el);
    newSub->publishingInterval = response->revisedPublishingInterval;
    newSub->maxKeepAliveCount = response->revisedMaxKeepAliveCount;
    ZIP_INIT(&newSub->monitoredItems);
    LIST_INSERT_HEAD(&client->subscriptions, newSub, listEntry);

    /* Immediately send the first publish requests if there are none
     * outstanding */
    __Client_Subscriptions_backgroundPublish(client);
}

static void
ua_Subscriptions_create_handler(UA_Client *client, void *data,
                                UA_UInt32 requestId, void *r) {
    UA_LOCK_ASSERT(&client->clientMutex, 0);

    UA_CreateSubscriptionResponse *response = (UA_CreateSubscriptionResponse *)r;
    CustomCallback *cc = (CustomCallback *)data;
    UA_Client_Subscription *newSub = (UA_Client_Subscription *)cc->clientData;
    if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
        UA_free(newSub);
        goto cleanup;
    }

    /* Prepare the internal representation */
    UA_LOCK(&client->clientMutex);
    ua_Subscriptions_create(client, newSub, response);
    UA_UNLOCK(&client->clientMutex);

cleanup:
    if(cc->userCallback)
        cc->userCallback(client, cc->userData, requestId, response);
    UA_free(cc);
}

UA_CreateSubscriptionResponse
UA_Client_Subscriptions_create(UA_Client *client,
                               const UA_CreateSubscriptionRequest request,
                               void *subscriptionContext,
                               UA_Client_StatusChangeNotificationCallback statusChangeCallback,
                               UA_Client_DeleteSubscriptionCallback deleteCallback) {
    UA_CreateSubscriptionResponse response;
    UA_Client_Subscription *sub = (UA_Client_Subscription *)
        UA_malloc(sizeof(UA_Client_Subscription));
    if(!sub) {
        UA_CreateSubscriptionResponse_init(&response);
        response.responseHeader.serviceResult = UA_STATUSCODE_BADOUTOFMEMORY;
        return response;
    }
    sub->context = subscriptionContext;
    sub->statusChangeCallback = statusChangeCallback;
    sub->deleteCallback = deleteCallback;

    /* Send the request as a synchronous service call */
    __UA_Client_Service(client,
                        &request, &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONREQUEST],
                        &response, &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONRESPONSE]);
    if (response.responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
        UA_free (sub);
        return response;
    }

    UA_LOCK(&client->clientMutex);
    ua_Subscriptions_create(client, sub, &response);
    UA_UNLOCK(&client->clientMutex);

    return response;
}

UA_StatusCode
UA_Client_Subscriptions_create_async(UA_Client *client,
                                     const UA_CreateSubscriptionRequest request,
                                     void *subscriptionContext,
                                     UA_Client_StatusChangeNotificationCallback statusChangeCallback,
                                     UA_Client_DeleteSubscriptionCallback deleteCallback,
                                     UA_ClientAsyncServiceCallback createCallback,
                                     void *userdata,
                                     UA_UInt32 *requestId) {
    CustomCallback *cc = (CustomCallback *)UA_calloc(1, sizeof(CustomCallback));
    if(!cc)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_Client_Subscription *sub = (UA_Client_Subscription *)
        UA_malloc(sizeof(UA_Client_Subscription));
    if(!sub) {
        UA_free(cc);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    sub->context = subscriptionContext;
    sub->statusChangeCallback = statusChangeCallback;
    sub->deleteCallback = deleteCallback;

    cc->userCallback = createCallback;
    cc->userData = userdata;
    cc->clientData = sub;

    /* Send the request as asynchronous service call */
    return __UA_Client_AsyncService(client, &request, &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONREQUEST],
                                    ua_Subscriptions_create_handler, &UA_TYPES[UA_TYPES_CREATESUBSCRIPTIONRESPONSE],
                                    cc, requestId);
}

static UA_Client_Subscription *
findSubscription(const UA_Client *client, UA_UInt32 subscriptionId) {
    UA_Client_Subscription *sub = NULL;
    LIST_FOREACH(sub, &client->subscriptions, listEntry) {
        if(sub->subscriptionId == subscriptionId)
            break;
    }
    return sub;
}

static void
ua_Subscriptions_modify(UA_Client *client, UA_Client_Subscription *sub,
                        const UA_ModifySubscriptionResponse *response) {
    sub->publishingInterval = response->revisedPublishingInterval;
    sub->maxKeepAliveCount = response->revisedMaxKeepAliveCount;
}

static void
ua_Subscriptions_modify_handler(UA_Client *client, void *data, UA_UInt32 requestId,
                                void *r) {
    UA_ModifySubscriptionResponse *response = (UA_ModifySubscriptionResponse *)r;
    CustomCallback *cc = (CustomCallback *)data;
    UA_LOCK(&client->clientMutex);
    UA_Client_Subscription *sub =
        findSubscription(client, (UA_UInt32)(uintptr_t)cc->clientData);
    if(sub) {
        ua_Subscriptions_modify(client, sub, response);
    } else {
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                    "No internal representation of subscription %" PRIu32,
                    (UA_UInt32)(uintptr_t)cc->clientData);
    }
    UA_UNLOCK(&client->clientMutex);

    if(cc->userCallback)
        cc->userCallback(client, cc->userData, requestId, response);
    UA_free(cc);
}

UA_ModifySubscriptionResponse
UA_Client_Subscriptions_modify(UA_Client *client,
                               const UA_ModifySubscriptionRequest request) {
    UA_ModifySubscriptionResponse response;
    UA_ModifySubscriptionResponse_init(&response);

    /* Find the internal representation */
    UA_LOCK(&client->clientMutex);
    UA_Client_Subscription *sub = findSubscription(client, request.subscriptionId);
    UA_UNLOCK(&client->clientMutex);
    if(!sub) {
        response.responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
        return response;
    }

    /* Call the service */
    __UA_Client_Service(client,
                        &request, &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONREQUEST],
                        &response, &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONRESPONSE]);

    /* Adjust the internal representation. Lookup again for thread-safety. */
    UA_LOCK(&client->clientMutex);
    sub = findSubscription(client, request.subscriptionId);
    if(!sub) {
        response.responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
        UA_UNLOCK(&client->clientMutex);
        return response;
    }
    ua_Subscriptions_modify(client, sub, &response);
    UA_UNLOCK(&client->clientMutex);
    return response;
}

UA_StatusCode
UA_Client_Subscriptions_modify_async(UA_Client *client,
                                     const UA_ModifySubscriptionRequest request,
                                     UA_ClientAsyncServiceCallback callback,
                                     void *userdata, UA_UInt32 *requestId) {
    /* Find the internal representation */
    UA_LOCK(&client->clientMutex);
    UA_Client_Subscription *sub = findSubscription(client, request.subscriptionId);
    UA_UNLOCK(&client->clientMutex);
    if(!sub)
        return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;

    CustomCallback *cc = (CustomCallback *)UA_calloc(1, sizeof(CustomCallback));
    if(!cc)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    cc->clientData = (void *)(uintptr_t)request.subscriptionId;
    cc->userData = userdata;
    cc->userCallback = callback;

    return __UA_Client_AsyncService(client, &request, &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONREQUEST],
                                    ua_Subscriptions_modify_handler, &UA_TYPES[UA_TYPES_MODIFYSUBSCRIPTIONRESPONSE],
                                    cc, requestId);
}

static void *
UA_MonitoredItem_delete_wrapper(void *data, UA_Client_MonitoredItem *mon) {
    struct UA_Client_MonitoredItem_ForDelete *deleteMonitoredItem =
        (struct UA_Client_MonitoredItem_ForDelete *)data;
    if(deleteMonitoredItem != NULL) {
        if(deleteMonitoredItem->monitoredItemId != NULL &&
           (mon->monitoredItemId != *deleteMonitoredItem->monitoredItemId)) {
            return NULL;
        }
        MonitoredItem_delete(deleteMonitoredItem->client, deleteMonitoredItem->sub, mon);
    }
    return NULL;
}

static void
__Client_Subscription_deleteInternal(UA_Client *client,
                                     UA_Client_Subscription *sub) {
    /* Remove the MonitoredItems */
    struct UA_Client_MonitoredItem_ForDelete deleteMonitoredItem;
    memset(&deleteMonitoredItem, 0, sizeof(struct UA_Client_MonitoredItem_ForDelete));
    deleteMonitoredItem.client = client;
    deleteMonitoredItem.sub = sub;
    ZIP_ITER(MonitorItemsTree, &sub->monitoredItems,
             UA_MonitoredItem_delete_wrapper, &deleteMonitoredItem);

    /* Call the delete callback */
    if(sub->deleteCallback) {
        void *subC = sub->context;
        UA_UInt32 subId = sub->subscriptionId;
        UA_UNLOCK(&client->clientMutex);
        sub->deleteCallback(client, subId, subC);
        UA_LOCK(&client->clientMutex);
    }

    /* Remove */
    LIST_REMOVE(sub, listEntry);
    UA_free(sub);
}

static void
__Client_Subscription_processDelete(UA_Client *client,
                                    const UA_DeleteSubscriptionsRequest *request,
                                    const UA_DeleteSubscriptionsResponse *response)  {
    if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
        return;

    /* Check that the request and response size -- use the same index for both */
    if(request->subscriptionIdsSize != response->resultsSize)
        return;

    for(size_t i = 0; i < request->subscriptionIdsSize; i++) {
        if(response->results[i] != UA_STATUSCODE_GOOD &&
           response->results[i] != UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID)
            continue;

        /* Get the Subscription */
        UA_Client_Subscription *sub =
            findSubscription(client, request->subscriptionIds[i]);
        if(!sub) {
            UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                        "No internal representation of subscription %" PRIu32,
                        request->subscriptionIds[i]);
            continue;
        }

        /* Delete the Subscription */
        __Client_Subscription_deleteInternal(client, sub);
    }
}

typedef struct {
    UA_DeleteSubscriptionsRequest request;
    UA_ClientAsyncServiceCallback userCallback;
    void *userData;
} DeleteSubscriptionCallback;

static void
ua_Subscriptions_delete_handler(UA_Client *client, void *data,
                                UA_UInt32 requestId, void *r) {
    UA_DeleteSubscriptionsResponse *response =
        (UA_DeleteSubscriptionsResponse *)r;
    DeleteSubscriptionCallback *dsc =
        (DeleteSubscriptionCallback*)data;

    /* Delete */
    UA_LOCK(&client->clientMutex);
    __Client_Subscription_processDelete(client, &dsc->request, response);
    UA_UNLOCK(&client->clientMutex);

    /* Userland Callback */
    dsc->userCallback(client, dsc->userData, requestId, response);

    /* Cleanup */
    UA_DeleteSubscriptionsRequest_clear(&dsc->request);
    UA_free(dsc);
}

UA_StatusCode
UA_Client_Subscriptions_delete_async(UA_Client *client,
                                     const UA_DeleteSubscriptionsRequest request,
                                     UA_ClientAsyncServiceCallback callback,
                                     void *userdata, UA_UInt32 *requestId) {
    /* Make a copy of the request that persists into the async callback */
    DeleteSubscriptionCallback *dsc = (DeleteSubscriptionCallback*)
        UA_malloc(sizeof(DeleteSubscriptionCallback));
    if(!dsc)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    dsc->userCallback = callback;
    dsc->userData = userdata;
    UA_StatusCode res = UA_DeleteSubscriptionsRequest_copy(&request, &dsc->request);
    if(res != UA_STATUSCODE_GOOD) {
        UA_free(dsc);
        return res;
    }

    /* Make the async call */
    return __UA_Client_AsyncService(client, &request, &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSREQUEST],
                                    ua_Subscriptions_delete_handler, &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSRESPONSE],
                                    dsc, requestId);
}

UA_DeleteSubscriptionsResponse
UA_Client_Subscriptions_delete(UA_Client *client,
                               const UA_DeleteSubscriptionsRequest request) {
    /* Send the request */
    UA_DeleteSubscriptionsResponse response;
    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSREQUEST],
                        &response, &UA_TYPES[UA_TYPES_DELETESUBSCRIPTIONSRESPONSE]);

    /* Process */
    UA_LOCK(&client->clientMutex);
    __Client_Subscription_processDelete(client, &request, &response);
    UA_UNLOCK(&client->clientMutex);
    return response;
}

UA_StatusCode
UA_Client_Subscriptions_deleteSingle(UA_Client *client, UA_UInt32 subscriptionId) {
    UA_DeleteSubscriptionsRequest request;
    UA_DeleteSubscriptionsRequest_init(&request);
    request.subscriptionIds = &subscriptionId;
    request.subscriptionIdsSize = 1;

    UA_DeleteSubscriptionsResponse response =
        UA_Client_Subscriptions_delete(client, request);

    UA_StatusCode retval = response.responseHeader.serviceResult;
    if(retval != UA_STATUSCODE_GOOD) {
        UA_DeleteSubscriptionsResponse_clear(&response);
        return retval;
    }

    if(response.resultsSize != 1) {
        UA_DeleteSubscriptionsResponse_clear(&response);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    retval = response.results[0];
    UA_DeleteSubscriptionsResponse_clear(&response);
    return retval;
}

/******************/
/* MonitoredItems */
/******************/

static void
MonitoredItem_delete(UA_Client *client, UA_Client_Subscription *sub,
                     UA_Client_MonitoredItem *mon) {
    UA_LOCK_ASSERT(&client->clientMutex, 1);

    ZIP_REMOVE(MonitorItemsTree, &sub->monitoredItems, mon);
    if(mon->deleteCallback) {
        void *subC = sub->context;
        void *monC = mon->context;
        UA_UInt32 subId = sub->subscriptionId;
        UA_UInt32 monId = mon->monitoredItemId;
        UA_UNLOCK(&client->clientMutex);
        mon->deleteCallback(client, subId, subC, monId, monC);
        UA_LOCK(&client->clientMutex);
    }
    UA_free(mon);
}

typedef struct {
    void **contexts;
    UA_Client_DeleteMonitoredItemCallback *deleteCallbacks;
    void **handlingCallbacks;
    UA_CreateMonitoredItemsRequest request;

    /* Notify the user that the async callback was processed */
    UA_ClientAsyncServiceCallback userCallback;
    void *userData;
} MonitoredItems_CreateData;

static void
MonitoredItems_CreateData_clear(UA_Client *client, MonitoredItems_CreateData *data) {
    UA_free(data->contexts);
    UA_free(data->deleteCallbacks);
    UA_free(data->handlingCallbacks);
    UA_CreateMonitoredItemsRequest_clear(&data->request);
}

static void
ua_MonitoredItems_create(UA_Client *client, MonitoredItems_CreateData *data,
                         UA_CreateMonitoredItemsResponse *response) {
    UA_CreateMonitoredItemsRequest *request = &data->request;
    UA_Client_DeleteMonitoredItemCallback *deleteCallbacks = data->deleteCallbacks;

    UA_Client_Subscription *sub = findSubscription(client, data->request.subscriptionId);
    if(!sub)
        goto cleanup;

    if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
        goto cleanup;

    if(response->resultsSize != request->itemsToCreateSize) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    /* Add internally */
    for(size_t i = 0; i < request->itemsToCreateSize; i++) {
        if(response->results[i].statusCode != UA_STATUSCODE_GOOD) {
            void *subC = sub->context;
            UA_UInt32 subId = sub->subscriptionId;
            UA_UNLOCK(&client->clientMutex);
            if(deleteCallbacks[i])
                deleteCallbacks[i](client, subId, subC, 0, data->contexts[i]);
            UA_LOCK(&client->clientMutex);
            continue;
        }

        UA_Client_MonitoredItem *newMon = (UA_Client_MonitoredItem *)
            UA_malloc(sizeof(UA_Client_MonitoredItem));
        if(!newMon) {
            void *subC = sub->context;
            UA_UInt32 subId = sub->subscriptionId;
            UA_UNLOCK(&client->clientMutex);
            if(deleteCallbacks[i])
                deleteCallbacks[i](client, subId, subC, 0, data->contexts[i]);
            UA_LOCK(&client->clientMutex);
            continue;
        }

        newMon->monitoredItemId = response->results[i].monitoredItemId;
        newMon->clientHandle = request->itemsToCreate[i].requestedParameters.clientHandle;
        newMon->context = data->contexts[i];
        newMon->deleteCallback = deleteCallbacks[i];
        newMon->handler.dataChangeCallback =
            (UA_Client_DataChangeNotificationCallback)(uintptr_t)
                data->handlingCallbacks[i];
        newMon->isEventMonitoredItem =
            (request->itemsToCreate[i].itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER);
        ZIP_INSERT(MonitorItemsTree, &sub->monitoredItems, newMon);

        UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT,
                     "Subscription %" PRIu32 " | Added a MonitoredItem with handle %" PRIu32,
                     sub->subscriptionId, newMon->clientHandle);
    }
    return;

    /* Adding failed */
 cleanup:
    for(size_t i = 0; i < request->itemsToCreateSize; i++) {
        void *subC = sub ? sub->context : NULL;
        UA_UNLOCK(&client->clientMutex);
        if(deleteCallbacks[i])
            deleteCallbacks[i](client, data->request.subscriptionId,
                               subC, 0, data->contexts[i]);
        UA_LOCK(&client->clientMutex);
    }
}

static void
ua_MonitoredItems_create_async_handler(UA_Client *client, void *d, UA_UInt32 requestId,
                                       void *r) {
    UA_CreateMonitoredItemsResponse *response = (UA_CreateMonitoredItemsResponse *)r;
    MonitoredItems_CreateData *data = (MonitoredItems_CreateData *)d;

    UA_LOCK(&client->clientMutex);
    ua_MonitoredItems_create(client, data, response);
    MonitoredItems_CreateData_clear(client, data);
    UA_UNLOCK(&client->clientMutex);

    if(data->userCallback)
        data->userCallback(client, data->userData, requestId, response);

    UA_free(data);
}

static UA_StatusCode
MonitoredItems_CreateData_prepare(UA_Client *client,
                                  const UA_CreateMonitoredItemsRequest *request,
                                  void **contexts, void **handlingCallbacks,
                                  UA_Client_DeleteMonitoredItemCallback *deleteCallbacks,
                                  MonitoredItems_CreateData *data) {
    /* Align arrays and copy over */
    UA_StatusCode retval = UA_STATUSCODE_BADOUTOFMEMORY;
    data->contexts = (void **)UA_calloc(request->itemsToCreateSize, sizeof(void *));
    if(!data->contexts)
        goto cleanup;
    if(contexts)
        memcpy(data->contexts, contexts, request->itemsToCreateSize * sizeof(void *));

    data->deleteCallbacks = (UA_Client_DeleteMonitoredItemCallback *)
        UA_calloc(request->itemsToCreateSize, sizeof(UA_Client_DeleteMonitoredItemCallback));
    if(!data->deleteCallbacks)
        goto cleanup;
    if(deleteCallbacks)
        memcpy(data->deleteCallbacks, deleteCallbacks,
               request->itemsToCreateSize * sizeof(UA_Client_DeleteMonitoredItemCallback));

    data->handlingCallbacks = (void **)
        UA_calloc(request->itemsToCreateSize, sizeof(void *));
    if(!data->handlingCallbacks)
        goto cleanup;
    if(handlingCallbacks)
        memcpy(data->handlingCallbacks, handlingCallbacks,
               request->itemsToCreateSize * sizeof(void *));

    retval = UA_CreateMonitoredItemsRequest_copy(request, &data->request);
    if(retval != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Set the clientHandle */
    for(size_t i = 0; i < data->request.itemsToCreateSize; i++)
        data->request.itemsToCreate[i].requestedParameters.clientHandle =
            ++client->monitoredItemHandles;

    return UA_STATUSCODE_GOOD;

cleanup:
    MonitoredItems_CreateData_clear(client, data);
    return retval;
}

static void
ua_Client_MonitoredItems_create(UA_Client *client,
                                const UA_CreateMonitoredItemsRequest *request,
                                void **contexts, void **handlingCallbacks,
                                UA_Client_DeleteMonitoredItemCallback *deleteCallbacks,
                                UA_CreateMonitoredItemsResponse *response) {
    UA_CreateMonitoredItemsResponse_init(response);

    if(!request->itemsToCreateSize) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR;
        return;
    }

    /* Test if the subscription is valid */
    UA_Client_Subscription *sub = findSubscription(client, request->subscriptionId);
    if(!sub) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
        return;
    }

    MonitoredItems_CreateData data;
    memset(&data, 0, sizeof(MonitoredItems_CreateData));

    UA_StatusCode res =
        MonitoredItems_CreateData_prepare(client, request, contexts, handlingCallbacks,
                                          deleteCallbacks, &data);
    if(res != UA_STATUSCODE_GOOD) {
        response->responseHeader.serviceResult = res;
        return;
    }

    /* Call the service. Use data->request as it contains the client handle
     * information. */
    __Client_Service(client, &data.request,
                     &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSREQUEST],
                     response, &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSRESPONSE]);

    /* Add internal representation */
    ua_MonitoredItems_create(client, &data, response);

    MonitoredItems_CreateData_clear(client, &data);
}

static UA_StatusCode
createDataChanges_async(UA_Client *client, const UA_CreateMonitoredItemsRequest request,
                        void **contexts, void **callbacks,
                        UA_Client_DeleteMonitoredItemCallback *deleteCallbacks,
                        UA_ClientAsyncServiceCallback createCallback, void *userdata,
                        UA_UInt32 *requestId) {
    UA_LOCK_ASSERT(&client->clientMutex, 1);

    UA_Client_Subscription *sub = findSubscription(client, request.subscriptionId);
    if(!sub)
        return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;

    MonitoredItems_CreateData *data = (MonitoredItems_CreateData *)
        UA_calloc(1, sizeof(MonitoredItems_CreateData));
    if(!data)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    data->userCallback = createCallback;
    data->userData = userdata;

    UA_StatusCode res =
        MonitoredItems_CreateData_prepare(client, &request, contexts,
                                          callbacks, deleteCallbacks, data);
    if(res != UA_STATUSCODE_GOOD) {
        UA_free(data);
        return res;
    }

    return __Client_AsyncService(client, &data->request,
                                 &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSREQUEST],
                                 ua_MonitoredItems_create_async_handler,
                                 &UA_TYPES[UA_TYPES_CREATEMONITOREDITEMSRESPONSE],
                                 data, requestId);
}

UA_CreateMonitoredItemsResponse
UA_Client_MonitoredItems_createDataChanges(UA_Client *client,
                                           const UA_CreateMonitoredItemsRequest request,
                                           void **contexts,
                                           UA_Client_DataChangeNotificationCallback *callbacks,
                                           UA_Client_DeleteMonitoredItemCallback *deleteCallbacks) {
    UA_CreateMonitoredItemsResponse response;
    UA_LOCK(&client->clientMutex);
    ua_Client_MonitoredItems_create(client, &request, contexts, (void **)callbacks,
                                    deleteCallbacks, &response);
    UA_UNLOCK(&client->clientMutex);
    return response;
}

UA_StatusCode
UA_Client_MonitoredItems_createDataChanges_async(UA_Client *client,
                                                 const UA_CreateMonitoredItemsRequest request,
                                                 void **contexts,
                                                 UA_Client_DataChangeNotificationCallback *callbacks,
                                                 UA_Client_DeleteMonitoredItemCallback *deleteCallbacks,
                                                 UA_ClientAsyncServiceCallback createCallback,
                                                 void *userdata, UA_UInt32 *requestId) {
    UA_LOCK(&client->clientMutex);
    UA_StatusCode res =
        createDataChanges_async(client, request, contexts, (void **)callbacks,
                                deleteCallbacks, createCallback, userdata, requestId);
    UA_UNLOCK(&client->clientMutex);
    return res;
}

UA_MonitoredItemCreateResult
UA_Client_MonitoredItems_createDataChange(UA_Client *client, UA_UInt32 subscriptionId,
                                          UA_TimestampsToReturn timestampsToReturn,
                                          const UA_MonitoredItemCreateRequest item,
                                          void *context,
                                          UA_Client_DataChangeNotificationCallback callback,
                                          UA_Client_DeleteMonitoredItemCallback deleteCallback) {
    UA_CreateMonitoredItemsRequest request;
    UA_CreateMonitoredItemsRequest_init(&request);
    request.subscriptionId = subscriptionId;
    request.timestampsToReturn = timestampsToReturn;
    request.itemsToCreate = (UA_MonitoredItemCreateRequest*)(uintptr_t)&item;
    request.itemsToCreateSize = 1;
    UA_CreateMonitoredItemsResponse response =
       UA_Client_MonitoredItems_createDataChanges(client, request, &context,
                                                   &callback, &deleteCallback);
    UA_MonitoredItemCreateResult result;
    UA_MonitoredItemCreateResult_init(&result);
    if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
        result.statusCode = response.responseHeader.serviceResult;

    if(result.statusCode == UA_STATUSCODE_GOOD &&
       response.resultsSize != 1)
        result.statusCode = UA_STATUSCODE_BADINTERNALERROR;

    if(result.statusCode == UA_STATUSCODE_GOOD)
       UA_MonitoredItemCreateResult_copy(&response.results[0] , &result);
    UA_CreateMonitoredItemsResponse_clear(&response);
    return result;
}

UA_CreateMonitoredItemsResponse
UA_Client_MonitoredItems_createEvents(UA_Client *client,
                                      const UA_CreateMonitoredItemsRequest request,
                                      void **contexts,
                                      UA_Client_EventNotificationCallback *callback,
                                      UA_Client_DeleteMonitoredItemCallback *deleteCallback) {
    UA_CreateMonitoredItemsResponse response;
    UA_LOCK(&client->clientMutex);
    ua_Client_MonitoredItems_create(client, &request, contexts, (void **)callback,
                                    deleteCallback, &response);
    UA_UNLOCK(&client->clientMutex);
    return response;
}

/* Monitor the EventNotifier attribute only */
UA_StatusCode
UA_Client_MonitoredItems_createEvents_async(UA_Client *client,
                                            const UA_CreateMonitoredItemsRequest request,
                                            void **contexts,
                                            UA_Client_EventNotificationCallback *callbacks,
                                            UA_Client_DeleteMonitoredItemCallback *deleteCallbacks,
                                            UA_ClientAsyncServiceCallback createCallback,
                                            void *userdata, UA_UInt32 *requestId) {
    UA_LOCK(&client->clientMutex);
    UA_StatusCode res =
        createDataChanges_async(client, request, contexts, (void **)callbacks, deleteCallbacks,
                                createCallback, userdata, requestId);
    UA_UNLOCK(&client->clientMutex);
    return res;
}

UA_MonitoredItemCreateResult
UA_Client_MonitoredItems_createEvent(UA_Client *client, UA_UInt32 subscriptionId,
                                     UA_TimestampsToReturn timestampsToReturn,
                                     const UA_MonitoredItemCreateRequest item, void *context,
                                     UA_Client_EventNotificationCallback callback,
                                     UA_Client_DeleteMonitoredItemCallback deleteCallback) {
    UA_CreateMonitoredItemsRequest request;
    UA_CreateMonitoredItemsRequest_init(&request);
    request.subscriptionId = subscriptionId;
    request.timestampsToReturn = timestampsToReturn;
    request.itemsToCreate = (UA_MonitoredItemCreateRequest*)(uintptr_t)&item;
    request.itemsToCreateSize = 1;
    UA_CreateMonitoredItemsResponse response =
       UA_Client_MonitoredItems_createEvents(client, request, &context,
                                             &callback, &deleteCallback);
    UA_StatusCode retval = response.responseHeader.serviceResult;
    UA_MonitoredItemCreateResult result;
    UA_MonitoredItemCreateResult_init(&result);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_CreateMonitoredItemsResponse_clear(&response);
        result.statusCode = retval;
        return result;
    }
    UA_MonitoredItemCreateResult_copy(response.results , &result);
    UA_CreateMonitoredItemsResponse_clear(&response);
    return result;
}

static void
ua_MonitoredItems_delete(UA_Client *client, UA_Client_Subscription *sub,
                         const UA_DeleteMonitoredItemsRequest *request,
                         const UA_DeleteMonitoredItemsResponse *response) {
#ifdef __clang_analyzer__
    return;
#endif

    /* Loop over deleted MonitoredItems */
    struct UA_Client_MonitoredItem_ForDelete deleteMonitoredItem;
    memset(&deleteMonitoredItem, 0, sizeof(struct UA_Client_MonitoredItem_ForDelete));
    deleteMonitoredItem.client = client;
    deleteMonitoredItem.sub = sub;

    for(size_t i = 0; i < response->resultsSize; i++) {
        if(response->results[i] != UA_STATUSCODE_GOOD &&
           response->results[i] != UA_STATUSCODE_BADMONITOREDITEMIDINVALID) {
            continue;
        }
        deleteMonitoredItem.monitoredItemId = &request->monitoredItemIds[i];
        /* Delete the internal representation */
        ZIP_ITER(MonitorItemsTree,&sub->monitoredItems,
                 UA_MonitoredItem_delete_wrapper, &deleteMonitoredItem);
    }
}

static void
ua_MonitoredItems_delete_handler(UA_Client *client, void *d, UA_UInt32 requestId, void *r) {
    UA_Client_Subscription *sub = NULL;
    CustomCallback *cc = (CustomCallback *)d;
    UA_DeleteMonitoredItemsResponse *response = (UA_DeleteMonitoredItemsResponse *)r;
    UA_DeleteMonitoredItemsRequest *request =
        (UA_DeleteMonitoredItemsRequest *)cc->clientData;

    UA_LOCK(&client->clientMutex);

    if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD)
        goto cleanup;

    sub = findSubscription(client, request->subscriptionId);
    if(!sub) {
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                    "No internal representation of subscription %" PRIu32,
                    request->subscriptionId);
        goto cleanup;
    }

    /* Delete MonitoredItems from the internal representation */
    ua_MonitoredItems_delete(client, sub, request, response);

cleanup:
    UA_UNLOCK(&client->clientMutex);
    if(cc->userCallback)
        cc->userCallback(client, cc->userData, requestId, response);
    UA_DeleteMonitoredItemsRequest_delete(request);
    UA_free(cc);
}

UA_DeleteMonitoredItemsResponse
UA_Client_MonitoredItems_delete(UA_Client *client,
                                const UA_DeleteMonitoredItemsRequest request) {
    /* Send the request */
    UA_DeleteMonitoredItemsResponse response;
    __UA_Client_Service(client, &request, &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSREQUEST],
                        &response, &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSRESPONSE]);

    /* A problem occured remote? */
    if(response.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
        return response;

    UA_LOCK(&client->clientMutex);

    /* Find the internal subscription representation */
    UA_Client_Subscription *sub = findSubscription(client, request.subscriptionId);
    if(!sub) {
        UA_LOG_INFO(client->config.logging, UA_LOGCATEGORY_CLIENT,
                    "No internal representation of subscription %" PRIu32,
                    request.subscriptionId);
        UA_UNLOCK(&client->clientMutex);
        return response;
    }

    /* Remove MonitoredItems in the internal representation */
    ua_MonitoredItems_delete(client, sub, &request, &response);

    UA_UNLOCK(&client->clientMutex);

    return response;
}

UA_StatusCode
UA_Client_MonitoredItems_delete_async(UA_Client *client,
                                      const UA_DeleteMonitoredItemsRequest request,
                                      UA_ClientAsyncServiceCallback callback,
                                      void *userdata, UA_UInt32 *requestId) {
    /* Send the request */
    CustomCallback *cc = (CustomCallback *)UA_calloc(1, sizeof(CustomCallback));
    if(!cc)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_DeleteMonitoredItemsRequest *req_copy = UA_DeleteMonitoredItemsRequest_new();
    if(!req_copy) {
        UA_free(cc);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    UA_DeleteMonitoredItemsRequest_copy(&request, req_copy);
    cc->clientData = req_copy;
    cc->userCallback = callback;
    cc->userData = userdata;

    return __UA_Client_AsyncService(client, &request, &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSREQUEST],
                                    ua_MonitoredItems_delete_handler,
                                    &UA_TYPES[UA_TYPES_DELETEMONITOREDITEMSRESPONSE], cc, requestId);
}

UA_StatusCode
UA_Client_MonitoredItems_deleteSingle(UA_Client *client, UA_UInt32 subscriptionId,
                                      UA_UInt32 monitoredItemId) {
    UA_DeleteMonitoredItemsRequest request;
    UA_DeleteMonitoredItemsRequest_init(&request);
    request.subscriptionId = subscriptionId;
    request.monitoredItemIds = &monitoredItemId;
    request.monitoredItemIdsSize = 1;

    UA_DeleteMonitoredItemsResponse response =
        UA_Client_MonitoredItems_delete(client, request);

    UA_StatusCode retval = response.responseHeader.serviceResult;
    if(retval != UA_STATUSCODE_GOOD) {
        UA_DeleteMonitoredItemsResponse_clear(&response);
        return retval;
    }

    if(response.resultsSize != 1) {
        UA_DeleteMonitoredItemsResponse_clear(&response);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    retval = response.results[0];
    UA_DeleteMonitoredItemsResponse_clear(&response);
    return retval;
}

static void *
UA_MonitoredItem_change_clientHandle_wrapper(void *data, UA_Client_MonitoredItem *mon) {
    UA_MonitoredItemModifyRequest *monitoredItemModifyRequest =
        (UA_MonitoredItemModifyRequest *)data;
    if(monitoredItemModifyRequest &&
       mon->monitoredItemId == monitoredItemModifyRequest->monitoredItemId)
        monitoredItemModifyRequest->requestedParameters.clientHandle = mon->clientHandle;
    return NULL;
}

static void
UA_MonitoredItem_change_clientHandle(UA_Client_Subscription *sub,
                                     UA_ModifyMonitoredItemsRequest *request) {
    for(size_t i = 0; i < request->itemsToModifySize; ++i) {
        ZIP_ITER(MonitorItemsTree, &sub->monitoredItems,
                 UA_MonitoredItem_change_clientHandle_wrapper,
                 &request->itemsToModify[i]);
    }
}

UA_ModifyMonitoredItemsResponse
UA_Client_MonitoredItems_modify(UA_Client *client,
                                const UA_ModifyMonitoredItemsRequest request) {
    UA_ModifyMonitoredItemsResponse response;
    UA_ModifyMonitoredItemsResponse_init(&response);

    UA_LOCK(&client->clientMutex);
    UA_Client_Subscription *sub = findSubscription(client, request.subscriptionId);
    if(!sub) {
        UA_UNLOCK(&client->clientMutex);
        response.responseHeader.serviceResult = UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
        return response;
    }

    UA_ModifyMonitoredItemsRequest modifiedRequest;
    UA_ModifyMonitoredItemsRequest_copy(&request, &modifiedRequest);
    UA_MonitoredItem_change_clientHandle(sub, &modifiedRequest);

    __Client_Service(client, &modifiedRequest,
                     &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSREQUEST], &response,
                     &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSRESPONSE]);

    UA_UNLOCK(&client->clientMutex);
    UA_ModifyMonitoredItemsRequest_clear(&modifiedRequest);
    return response;
}

UA_StatusCode
UA_Client_MonitoredItems_modify_async(UA_Client *client,
                                      const UA_ModifyMonitoredItemsRequest request,
                                      UA_ClientAsyncServiceCallback callback,
                                      void *userdata, UA_UInt32 *requestId) {
    UA_LOCK(&client->clientMutex);
    UA_Client_Subscription *sub = findSubscription(client, request.subscriptionId);
    if(!sub) {
        UA_UNLOCK(&client->clientMutex);
        return UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID;
    }

    UA_ModifyMonitoredItemsRequest modifiedRequest;
    UA_ModifyMonitoredItemsRequest_copy(&request, &modifiedRequest);
    UA_MonitoredItem_change_clientHandle(sub, &modifiedRequest);

    UA_StatusCode statusCode = __Client_AsyncService(
        client, &modifiedRequest, &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSREQUEST],
        callback, &UA_TYPES[UA_TYPES_MODIFYMONITOREDITEMSRESPONSE], userdata, requestId);

    UA_UNLOCK(&client->clientMutex);
    UA_ModifyMonitoredItemsRequest_clear(&modifiedRequest);
    return statusCode;
}

/*************************************/
/* Async Processing of Notifications */
/*************************************/

/* Assume the request is already initialized */
UA_StatusCode
__Client_preparePublishRequest(UA_Client *client, UA_PublishRequest *request) {
    UA_LOCK_ASSERT(&client->clientMutex, 1);

    /* Count acks */
    UA_Client_NotificationsAckNumber *ack;
    LIST_FOREACH(ack, &client->pendingNotificationsAcks, listEntry)
        ++request->subscriptionAcknowledgementsSize;

    /* Create the array. Returns a sentinel pointer if the length is zero. */
    request->subscriptionAcknowledgements = (UA_SubscriptionAcknowledgement*)
        UA_Array_new(request->subscriptionAcknowledgementsSize,
                     &UA_TYPES[UA_TYPES_SUBSCRIPTIONACKNOWLEDGEMENT]);
    if(!request->subscriptionAcknowledgements) {
        request->subscriptionAcknowledgementsSize = 0;
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    size_t i = 0;
    UA_Client_NotificationsAckNumber *ack_tmp;
    LIST_FOREACH_SAFE(ack, &client->pendingNotificationsAcks, listEntry, ack_tmp) {
        request->subscriptionAcknowledgements[i].sequenceNumber = ack->subAck.sequenceNumber;
        request->subscriptionAcknowledgements[i].subscriptionId = ack->subAck.subscriptionId;
        ++i;
        LIST_REMOVE(ack, listEntry);
        UA_free(ack);
    }
    return UA_STATUSCODE_GOOD;
}

/* According to OPC Unified Architecture, Part 4 5.13.1.1 i) */
/* The value 0 is never used for the sequence number         */
static UA_UInt32
__nextSequenceNumber(UA_UInt32 sequenceNumber) {
    UA_UInt32 nextSequenceNumber = sequenceNumber + 1;
    if(nextSequenceNumber == 0)
        nextSequenceNumber = 1;
    return nextSequenceNumber;
}

static void
processDataChangeNotification(UA_Client *client, UA_Client_Subscription *sub,
                              UA_DataChangeNotification *dataChangeNotification) {
    UA_LOCK_ASSERT(&client->clientMutex, 1);

    for(size_t j = 0; j < dataChangeNotification->monitoredItemsSize; ++j) {
        UA_MonitoredItemNotification *min = &dataChangeNotification->monitoredItems[j];

        /* Find the MonitoredItem */
        UA_Client_MonitoredItem *mon;
        UA_Client_MonitoredItem dummy;
        dummy.clientHandle = min->clientHandle;
        mon = ZIP_FIND(MonitorItemsTree, &sub->monitoredItems, &dummy);

        if(!mon) {
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                           "Could not process a notification with clienthandle %" PRIu32
                           " on subscription %" PRIu32, min->clientHandle, sub->subscriptionId);
            continue;
        }

        if(mon->isEventMonitoredItem) {
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                           "MonitoredItem is configured for Events. But received a "
                           "DataChangeNotification.");
            continue;
        }

        if(mon->handler.dataChangeCallback) {
            void *subC = sub->context;
            void *monC = mon->context;
            UA_UInt32 subId = sub->subscriptionId;
            UA_UInt32 monId = mon->monitoredItemId;
            UA_UNLOCK(&client->clientMutex);
            mon->handler.dataChangeCallback(client, subId, subC, monId, monC, &min->value);
            UA_LOCK(&client->clientMutex);
        }
    }
}

static void
processEventNotification(UA_Client *client, UA_Client_Subscription *sub,
                         UA_EventNotificationList *eventNotificationList) {
    UA_LOCK_ASSERT(&client->clientMutex, 1);

    for(size_t j = 0; j < eventNotificationList->eventsSize; ++j) {
        UA_EventFieldList *eventFieldList = &eventNotificationList->events[j];

        /* Find the MonitoredItem */
        UA_Client_MonitoredItem *mon;
        UA_Client_MonitoredItem dummy;
        dummy.clientHandle = eventFieldList->clientHandle;
        mon = ZIP_FIND(MonitorItemsTree, &sub->monitoredItems, &dummy);

        if(!mon) {
            UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT,
                         "Could not process a notification with clienthandle %" PRIu32
                         " on subscription %" PRIu32, eventFieldList->clientHandle,
                         sub->subscriptionId);
            continue;
        }

        if(!mon->isEventMonitoredItem) {
            UA_LOG_DEBUG(client->config.logging, UA_LOGCATEGORY_CLIENT,
                         "MonitoredItem is configured for DataChanges. But received a "
                         "EventNotification.");
            continue;
        }

        void *subC = sub->context;
        void *monC = mon->context;
        UA_UInt32 subId = sub->subscriptionId;
        UA_UInt32 monId = mon->monitoredItemId;
        UA_UNLOCK(&client->clientMutex);
        mon->handler.eventCallback(client, subId, subC, monId, monC,
                                   eventFieldList->eventFieldsSize,
                                   eventFieldList->eventFields);
        UA_LOCK(&client->clientMutex);
    }
}

static void
processNotificationMessage(UA_Client *client, UA_Client_Subscription *sub,
                           UA_ExtensionObject *msg) {
    UA_LOCK_ASSERT(&client->clientMutex, 1);

    if(msg->encoding != UA_EXTENSIONOBJECT_DECODED)
        return;

    /* Handle DataChangeNotification */
    if(msg->content.decoded.type == &UA_TYPES[UA_TYPES_DATACHANGENOTIFICATION]) {
        UA_DataChangeNotification *dataChangeNotification =
            (UA_DataChangeNotification *)msg->content.decoded.data;
        processDataChangeNotification(client, sub, dataChangeNotification);
        return;
    }

    /* Handle EventNotification */
    if(msg->content.decoded.type == &UA_TYPES[UA_TYPES_EVENTNOTIFICATIONLIST]) {
        UA_EventNotificationList *eventNotificationList =
            (UA_EventNotificationList *)msg->content.decoded.data;
        processEventNotification(client, sub, eventNotificationList);
        return;
    }

    /* Handle StatusChangeNotification */
    if(msg->content.decoded.type == &UA_TYPES[UA_TYPES_STATUSCHANGENOTIFICATION]) {
        if(sub->statusChangeCallback) {
            void *subC = sub->context;
            UA_UInt32 subId = sub->subscriptionId;
            UA_UNLOCK(&client->clientMutex);
            sub->statusChangeCallback(client, subId, subC,
                                      (UA_StatusChangeNotification*)msg->content.decoded.data);
            UA_LOCK(&client->clientMutex);
        } else {
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                           "Dropped a StatusChangeNotification since no "
                           "callback is registered");
        }
        return;
    }

    UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                   "Unknown notification message type");
}

static void
__Client_Subscriptions_processPublishResponse(UA_Client *client, UA_PublishRequest *request,
                                              UA_PublishResponse *response) {
    UA_LOCK_ASSERT(&client->clientMutex, 1);

    UA_NotificationMessage *msg = &response->notificationMessage;

    client->currentlyOutStandingPublishRequests--;

    if(response->responseHeader.serviceResult == UA_STATUSCODE_BADTOOMANYPUBLISHREQUESTS) {
        if(client->config.outStandingPublishRequests > 1) {
            client->config.outStandingPublishRequests--;
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                           "Too many publishrequest, reduce outStandingPublishRequests "
                           "to %" PRId16, client->config.outStandingPublishRequests);
        } else {
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                           "Too many publishrequest when outStandingPublishRequests = 1");
            UA_Client_Subscriptions_deleteSingle(client, response->subscriptionId);
        }
        return;
    }

    if(response->responseHeader.serviceResult == UA_STATUSCODE_BADSHUTDOWN)
        return;

    if(response->responseHeader.serviceResult == UA_STATUSCODE_BADNOSUBSCRIPTION) 
    {
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "Received BadNoSubscription, delete internal information about subscription");
        UA_Client_Subscription *sub = findSubscription(client, response->subscriptionId);
        if(sub != NULL)
            __Client_Subscription_deleteInternal(client, sub);
        return;
    }

    if(!LIST_FIRST(&client->subscriptions)) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADNOSUBSCRIPTION;
        return;
    }

    UA_Client_Subscription *sub = findSubscription(client, response->subscriptionId);
    if(!sub) {
        response->responseHeader.serviceResult = UA_STATUSCODE_BADINTERNALERROR;
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "Received Publish Response for a non-existant subscription");
        return;
    }

    if(response->responseHeader.serviceResult == UA_STATUSCODE_BADSESSIONCLOSED) {
        if(client->sessionState != UA_SESSIONSTATE_ACTIVATED) {
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                           "Received Publish Response with code %s",
                           UA_StatusCode_name(response->responseHeader.serviceResult));
            __Client_Subscription_deleteInternal(client, sub);
        }
        return;
    }

    if(response->responseHeader.serviceResult == UA_STATUSCODE_BADTIMEOUT) {
        if(client->config.subscriptionInactivityCallback) {
            void *subC = sub->context;
            UA_UInt32 subId = sub->subscriptionId;
            UA_UNLOCK(&client->clientMutex);
            client->config.subscriptionInactivityCallback(client, subId, subC);
            UA_LOCK(&client->clientMutex);
        }
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "Received Timeout for Publish Response");
        return;
    }

    if(response->responseHeader.serviceResult != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "Received Publish Response with code %s",
                       UA_StatusCode_name(response->responseHeader.serviceResult));
        return;
    }

    UA_EventLoop *el = client->config.eventLoop;
    sub->lastActivity = el->dateTime_nowMonotonic(el);

    /* Detect missing message - OPC Unified Architecture, Part 4 5.13.1.1 e) */
    if(__nextSequenceNumber(sub->sequenceNumber) != msg->sequenceNumber) {
        UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                       "Invalid subscription sequence number: expected %" PRIu32
                       " but got %" PRIu32, __nextSequenceNumber(sub->sequenceNumber),
                       msg->sequenceNumber);
        /* This is an error. But we do not abort the connection. Some server
         * SDKs misbehave from time to time and send out-of-order sequence
         * numbers. (Probably some multi-threading synchronization issue.) */
        /* UA_Client_disconnect(client);
           return; */
    }
    /* According to f), a keep-alive message contains no notifications and has
     * the sequence number of the next NotificationMessage that is to be sent =>
     * More than one consecutive keep-alive message or a NotificationMessage
     * following a keep-alive message will share the same sequence number. */
    if (msg->notificationDataSize)
        sub->sequenceNumber = msg->sequenceNumber;

    /* Process the notification messages */
    for(size_t k = 0; k < msg->notificationDataSize; ++k)
        processNotificationMessage(client, sub, &msg->notificationData[k]);

    /* Add to the list of pending acks */
    for(size_t i = 0; i < response->availableSequenceNumbersSize; i++) {
        if(response->availableSequenceNumbers[i] != msg->sequenceNumber)
            continue;
        UA_Client_NotificationsAckNumber *tmpAck = (UA_Client_NotificationsAckNumber*)
            UA_malloc(sizeof(UA_Client_NotificationsAckNumber));
        if(!tmpAck) {
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                           "Not enough memory to store the acknowledgement for a publish "
                           "message on subscription %" PRIu32, sub->subscriptionId);
            break;
        }
        tmpAck->subAck.sequenceNumber = msg->sequenceNumber;
        tmpAck->subAck.subscriptionId = sub->subscriptionId;
        LIST_INSERT_HEAD(&client->pendingNotificationsAcks, tmpAck, listEntry);
        break;
    }
}

static void
processPublishResponseAsync(UA_Client *client, void *userdata,
                            UA_UInt32 requestId, void *response) {
    UA_PublishRequest *req = (UA_PublishRequest*)userdata;
    UA_PublishResponse *res = (UA_PublishResponse*)response;

    UA_LOCK(&client->clientMutex);

    /* Process the response */
    __Client_Subscriptions_processPublishResponse(client, req, res);

    /* Delete the cached request */
    UA_PublishRequest_delete(req);

    /* Fill up the outstanding publish requests */
    __Client_Subscriptions_backgroundPublish(client);

    UA_UNLOCK(&client->clientMutex);
}

void
__Client_Subscriptions_clean(UA_Client *client) {
    UA_Client_NotificationsAckNumber *n;
    UA_Client_NotificationsAckNumber *tmp;
    LIST_FOREACH_SAFE(n, &client->pendingNotificationsAcks, listEntry, tmp) {
        LIST_REMOVE(n, listEntry);
        UA_free(n);
    }

    UA_Client_Subscription *sub;
    UA_Client_Subscription *tmps;
    LIST_FOREACH_SAFE(sub, &client->subscriptions, listEntry, tmps)
        __Client_Subscription_deleteInternal(client, sub); /* force local removal */

    client->monitoredItemHandles = 0;
}

void
__Client_Subscriptions_backgroundPublishInactivityCheck(UA_Client *client) {
    UA_LOCK_ASSERT(&client->clientMutex, 1);

    if(client->sessionState < UA_SESSIONSTATE_ACTIVATED)
        return;

    /* Is the lack of responses the client's fault? */
    if(client->currentlyOutStandingPublishRequests == 0)
        return;

    UA_EventLoop *el = client->config.eventLoop;
    UA_DateTime nowm = el->dateTime_nowMonotonic(el);

    UA_Client_Subscription *sub;
    LIST_FOREACH(sub, &client->subscriptions, listEntry) {
        UA_DateTime maxSilence = (UA_DateTime)
            ((sub->publishingInterval * sub->maxKeepAliveCount) +
             client->config.timeout) * UA_DATETIME_MSEC;
        if(maxSilence + sub->lastActivity < nowm) {
            /* Reset activity */
            sub->lastActivity = nowm;

            if(client->config.subscriptionInactivityCallback) {
                void *subC = sub->context;
                UA_UInt32 subId = sub->subscriptionId;
                UA_UNLOCK(&client->clientMutex);
                client->config.subscriptionInactivityCallback(client, subId, subC);
                UA_LOCK(&client->clientMutex);
            }
            UA_LOG_WARNING(client->config.logging, UA_LOGCATEGORY_CLIENT,
                           "Inactivity for Subscription %" PRIu32 ".", sub->subscriptionId);
        }
    }
}

void
__Client_Subscriptions_backgroundPublish(UA_Client *client) {
    UA_LOCK_ASSERT(&client->clientMutex, 1);

    if(client->sessionState != UA_SESSIONSTATE_ACTIVATED)
        return;

    /* The session must have at least one subscription */
    if(!LIST_FIRST(&client->subscriptions))
        return;

    while(client->currentlyOutStandingPublishRequests < client->config.outStandingPublishRequests) {
        UA_PublishRequest *request = UA_PublishRequest_new();
        if(!request)
            return;

        /* Publish requests are valid for 10 minutes */
        request->requestHeader.timeoutHint = 10 * 60 * 1000;

        UA_StatusCode retval = __Client_preparePublishRequest(client, request);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_PublishRequest_delete(request);
            return;
        }

        retval = __Client_AsyncService(client, request,
                                         &UA_TYPES[UA_TYPES_PUBLISHREQUEST],
                                         processPublishResponseAsync,
                                         &UA_TYPES[UA_TYPES_PUBLISHRESPONSE],
                                         (void*)request, NULL);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_PublishRequest_delete(request);
            return;
        }

        client->currentlyOutStandingPublishRequests++;
    }
}

/**** amalgamated original file "/deps/libc_time.c" ****/

/* Originally released by the musl project (http://www.musl-libc.org/) under the
 * MIT license. Taken from the file /src/time/__secs_to_tm.c */

#include <limits.h>

/* 2000-03-01 (mod 400 year, immediately after feb29 */
#define LEAPOCH (946684800LL + 86400*(31+29))

#define DAYS_PER_400Y (365*400 + 97)
#define DAYS_PER_100Y (365*100 + 24)
#define DAYS_PER_4Y   (365*4   + 1)

int __secs_to_tm(long long t, struct mytm *tm) {
    long long days, secs, years;
    int remdays, remsecs, remyears;
    int qc_cycles, c_cycles, q_cycles;
    int months;
    static const char days_in_month[] = {31,30,31,30,31,31,30,31,30,31,31,29};

    /* Reject time_t values whose year would overflow int */
    if (t < INT_MIN * 31622400LL || t > INT_MAX * 31622400LL)
        return -1;

    secs = t - LEAPOCH;
    days = secs / 86400LL;
    remsecs = (int)(secs % 86400);
    if (remsecs < 0) {
        remsecs += 86400;
        --days;
    }

    qc_cycles = (int)(days / DAYS_PER_400Y);
    remdays = (int)(days % DAYS_PER_400Y);
    if (remdays < 0) {
        remdays += DAYS_PER_400Y;
        --qc_cycles;
    }

    c_cycles = remdays / DAYS_PER_100Y;
    if (c_cycles == 4) --c_cycles;
    remdays -= c_cycles * DAYS_PER_100Y;

    q_cycles = remdays / DAYS_PER_4Y;
    if (q_cycles == 25) --q_cycles;
    remdays -= q_cycles * DAYS_PER_4Y;

    remyears = remdays / 365;
    if (remyears == 4) --remyears;
    remdays -= remyears * 365;

    years = remyears + 4*q_cycles + 100*c_cycles + 400LL*qc_cycles;

    for (months=0; days_in_month[months] <= remdays; ++months)
        remdays -= days_in_month[months];

    if (years+100 > INT_MAX || years+100 < INT_MIN)
        return -1;

    tm->tm_year = (int)(years + 100);
    tm->tm_mon = months + 2;
    if (tm->tm_mon >= 12) {
        tm->tm_mon -=12;
        ++tm->tm_year;
    }
    tm->tm_mday = remdays + 1;
    tm->tm_hour = remsecs / 3600;
    tm->tm_min = remsecs / 60 % 60;
    tm->tm_sec = remsecs % 60;

    return 0;
}

static const int secs_through_month[] =
    {0, 31*86400, 59*86400, 90*86400,
     120*86400, 151*86400, 181*86400, 212*86400,
     243*86400, 273*86400, 304*86400, 334*86400 };

static int
__month_to_secs(int month, int is_leap) {
    int t = secs_through_month[month];
    if (is_leap && month >= 2)
        t+=86400;
    return t;
}

static long long
__year_to_secs(const long long year, int *is_leap) {
    int cycles, centuries, leaps, rem;
    int is_leap_val = 0;
    if (!is_leap) {
        is_leap = &is_leap_val;
    }
    cycles = (int)((year-100) / 400);
    rem = (int)((year-100) % 400);
    if (rem < 0) {
        cycles--;
        rem += 400;
    }
    if (!rem) {
        *is_leap = 1;
        centuries = 0;
        leaps = 0;
    } else {
        if (rem >= 200) {
            if (rem >= 300) centuries = 3, rem -= 300;
            else centuries = 2, rem -= 200;
        } else {
            if (rem >= 100) centuries = 1, rem -= 100;
            else centuries = 0;
        }
        if (!rem) {
            *is_leap = 0;
            leaps = 0;
        } else {
            leaps = (rem / (int)4U);
            rem %= (int)4U;
            *is_leap = !rem;
        }
    }

    leaps += 97*cycles + 24*centuries - *is_leap;

    return (year-100) * 31536000LL + leaps * 86400LL + 946684800 + 86400;
}

long long __tm_to_secs(const struct mytm *tm) {
    int is_leap;
    long long year = tm->tm_year;
    int month = tm->tm_mon;
    if (month >= 12 || month < 0) {
        int adj = month / 12;
        month %= 12;
        if (month < 0) {
            adj--;
            month += 12;
        }
        year += adj;
    }
    long long t = __year_to_secs(year, &is_leap);
    t += __month_to_secs(month, is_leap);
    t += 86400LL * (tm->tm_mday-1);
    t += 3600LL * tm->tm_hour;
    t += 60LL * tm->tm_min;
    t += tm->tm_sec;
    return t;
}

/**** amalgamated original file "/deps/pcg_basic.c" ****/

/*
 * PCG Random Number Generation for C.
 *
 * Copyright 2014 Melissa O'Neill <oneill@pcg-random.org>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * For additional information about the PCG random number generation scheme,
 * including its license and other licensing options, visit
 *
 *       http://www.pcg-random.org
 */


void pcg32_srandom_r(pcg32_random_t* rng, uint64_t initial_state, uint64_t initseq) {
    rng->state = 0U;
    rng->inc = (initseq << 1u) | 1u;
    pcg32_random_r(rng);
    rng->state += initial_state;
    pcg32_random_r(rng);
}

uint32_t pcg32_random_r(pcg32_random_t* rng) {
    uint64_t oldstate = rng->state;
    rng->state = oldstate * 6364136223846793005ULL + rng->inc;
    uint32_t xorshifted = (uint32_t)(((oldstate >> 18u) ^ oldstate) >> 27u);
    uint32_t rot = (uint32_t)(oldstate >> 59u);
    return (xorshifted >> rot) | (xorshifted << ((~rot + 1u) & 31)); /* was (xorshifted >> rot) | (xorshifted << ((-rot) & 31)) */
}

/**** amalgamated original file "/deps/base64.c" ****/

/*
 * Base64 encoding: Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>
 * This software may be distributed under the terms of the BSD license.
 *
 * Base64 decoding: Copyright (c) 2016, polfosol
 * Posted at https://stackoverflow.com/a/37109258 under the CC-BY-SA Creative
 * Commons license.
 */


static const unsigned char base64_table[65] =
	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

unsigned char *
UA_base64(const unsigned char *src, size_t len, size_t *out_len) {
    if(len == 0) {
        *out_len = 0;
        return (unsigned char*)UA_EMPTY_ARRAY_SENTINEL;
    }

	size_t olen = 4*((len + 2) / 3); /* 3-byte blocks to 4-byte */
	if(olen < len)
		return NULL; /* integer overflow */

	unsigned char *out = (unsigned char*)UA_malloc(olen);
	if(!out)
		return NULL;

    *out_len = UA_base64_buf(src, len, out);
    return out;
}

size_t
UA_base64_buf(const unsigned char *src, size_t len, unsigned char *out) {
	const unsigned char *end = src + len;
	const unsigned char *in = src;
	unsigned char *pos = out;
	while(end - in >= 3) {
		*pos++ = base64_table[in[0] >> 2];
		*pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
		*pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
		*pos++ = base64_table[in[2] & 0x3f];
		in += 3;
	}

	if(end - in) {
		*pos++ = base64_table[in[0] >> 2];
		if(end - in == 1) {
			*pos++ = base64_table[(in[0] & 0x03) << 4];
			*pos++ = '=';
		} else {
			*pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
			*pos++ = base64_table[(in[1] & 0x0f) << 2];
		}
		*pos++ = '=';
	}

    return (size_t)(pos - out);
}

static const uint32_t from_b64[256] = {
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  62, 63, 62, 62, 63,
    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0,  0,  0,  0,  0,  0,
    0,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14,
    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0,  0,  0,  0,  63,
    0,  26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51};

unsigned char *
UA_unbase64(const unsigned char *src, size_t len, size_t *out_len) {
    // we need a minimum length
    if(len <= 2) {
        *out_len = 0;
        return (unsigned char*)UA_EMPTY_ARRAY_SENTINEL;
    }

    const unsigned char *p = src;
    size_t pad1 = len % 4 || p[len - 1] == '=';
    size_t pad2 = pad1 && (len % 4 > 2 || p[len - 2] != '=');
    const size_t last = (len - pad1) / 4 << 2;

    unsigned char *str = (unsigned char*)UA_malloc(last / 4 * 3 + pad1 + pad2);
    if(!str)
        return NULL;

    unsigned char *pos = str;
    for(size_t i = 0; i < last; i += 4) {
        uint32_t n = from_b64[p[i]] << 18 | from_b64[p[i + 1]] << 12 |
                     from_b64[p[i + 2]] << 6 | from_b64[p[i + 3]];
        *pos++ = (unsigned char)(n >> 16);
        *pos++ = (unsigned char)(n >> 8 & 0xFF);
        *pos++ = (unsigned char)(n & 0xFF);
    }

    if(pad1) {
        if (last + 1 >= len) {
            UA_free(str);
            *out_len = 0;
            return (unsigned char*)UA_EMPTY_ARRAY_SENTINEL;
        }
        uint32_t n = from_b64[p[last]] << 18 | from_b64[p[last + 1]] << 12;
        *pos++ = (unsigned char)(n >> 16);
        if(pad2) {
            if (last + 2 >= len) {
                UA_free(str);
                *out_len = 0;
                return (unsigned char*)UA_EMPTY_ARRAY_SENTINEL;
            }
            n |= from_b64[p[last + 2]] << 6;
            *pos++ = (unsigned char)(n >> 8 & 0xFF);
        }
    }

    *out_len = (uintptr_t)(pos - str);
    return str;
}

/**** amalgamated original file "/deps/dtoa.c" ****/

// Copyright 2013, Andreas Samoljuk
// Copyright 2023, Julius Pfrommer
//
// Boost Software License - Version 1.0 - August 17th, 2003
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

#include <stdint.h>
#include <stdbool.h>
#include <string.h>

#define mantissa_bits 52
#define exponent_bits 11
#define fracmask  0x000FFFFFFFFFFFFFU
#define expmask   0x7FF0000000000000U
#define hiddenbit 0x0010000000000000U
#define signmask  0x8000000000000000U
#define expbias   (1023 + 52)

#define absv(n) ((n) < 0 ? -(n) : (n))
#define minv(a, b) ((a) < (b) ? (a) : (b))

static uint64_t tens[] = {
    10000000000000000000U, 1000000000000000000U, 100000000000000000U,
    10000000000000000U, 1000000000000000U, 100000000000000U,
    10000000000000U, 1000000000000U, 100000000000U,
    10000000000U, 1000000000U, 100000000U,
    10000000U, 1000000U, 100000U,
    10000U, 1000U, 100U,
    10U, 1U
};

#define npowers     87
#define steppowers  8
#define firstpower -348 /* 10 ^ -348 */
#define expmax     -32
#define expmin     -60

typedef struct Fp {
    uint64_t frac;
    int exp;
} Fp;

static Fp powers_ten[] = {
    { 18054884314459144840U, -1220 }, { 13451937075301367670U, -1193 },
    { 10022474136428063862U, -1166 }, { 14934650266808366570U, -1140 },
    { 11127181549972568877U, -1113 }, { 16580792590934885855U, -1087 },
    { 12353653155963782858U, -1060 }, { 18408377700990114895U, -1034 },
    { 13715310171984221708U, -1007 }, { 10218702384817765436U, -980 },
    { 15227053142812498563U, -954 },  { 11345038669416679861U, -927 },
    { 16905424996341287883U, -901 },  { 12595523146049147757U, -874 },
    { 9384396036005875287U,  -847 },  { 13983839803942852151U, -821 },
    { 10418772551374772303U, -794 },  { 15525180923007089351U, -768 },
    { 11567161174868858868U, -741 },  { 17236413322193710309U, -715 },
    { 12842128665889583758U, -688 },  { 9568131466127621947U,  -661 },
    { 14257626930069360058U, -635 },  { 10622759856335341974U, -608 },
    { 15829145694278690180U, -582 },  { 11793632577567316726U, -555 },
    { 17573882009934360870U, -529 },  { 13093562431584567480U, -502 },
    { 9755464219737475723U,  -475 },  { 14536774485912137811U, -449 },
    { 10830740992659433045U, -422 },  { 16139061738043178685U, -396 },
    { 12024538023802026127U, -369 },  { 17917957937422433684U, -343 },
    { 13349918974505688015U, -316 },  { 9946464728195732843U,  -289 },
    { 14821387422376473014U, -263 },  { 11042794154864902060U, -236 },
    { 16455045573212060422U, -210 },  { 12259964326927110867U, -183 },
    { 18268770466636286478U, -157 },  { 13611294676837538539U, -130 },
    { 10141204801825835212U, -103 },  { 15111572745182864684U, -77 },
    { 11258999068426240000U, -50 },   { 16777216000000000000U, -24 },
    { 12500000000000000000U,   3 },   { 9313225746154785156U,   30 },
    { 13877787807814456755U,  56 },   { 10339757656912845936U,  83 },
    { 15407439555097886824U, 109 },   { 11479437019748901445U, 136 },
    { 17105694144590052135U, 162 },   { 12744735289059618216U, 189 },
    { 9495567745759798747U,  216 },   { 14149498560666738074U, 242 },
    { 10542197943230523224U, 269 },   { 15709099088952724970U, 295 },
    { 11704190886730495818U, 322 },   { 17440603504673385349U, 348 },
    { 12994262207056124023U, 375 },   { 9681479787123295682U,  402 },
    { 14426529090290212157U, 428 },   { 10748601772107342003U, 455 },
    { 16016664761464807395U, 481 },   { 11933345169920330789U, 508 },
    { 17782069995880619868U, 534 },   { 13248674568444952270U, 561 },
    { 9871031767461413346U,  588 },   { 14708983551653345445U, 614 },
    { 10959046745042015199U, 641 },   { 16330252207878254650U, 667 },
    { 12166986024289022870U, 694 },   { 18130221999122236476U, 720 },
    { 13508068024458167312U, 747 },   { 10064294952495520794U, 774 },
    { 14996968138956309548U, 800 },   { 11173611982879273257U, 827 },
    { 16649979327439178909U, 853 },   { 12405201291620119593U, 880 },
    { 9242595204427927429U,  907 },   { 13772540099066387757U, 933 },
    { 10261342003245940623U, 960 },   { 15290591125556738113U, 986 },
    { 11392378155556871081U, 1013 },  { 16975966327722178521U, 1039 },
    { 12648080533535911531U, 1066 }
};

static Fp
find_cachedpow10(int exp, int* k) {
    const double one_log_ten = 0.30102999566398114;
    int approx = (int)(-(exp + npowers) * one_log_ten);
    int idx = (approx - firstpower) / steppowers;
    while(1) {
        int current = exp + powers_ten[idx].exp + 64;
        if(current < expmin) {
            idx++;
            continue;
        }
        if(current > expmax) {
            idx--;
            continue;
        }
        *k = (firstpower + idx * steppowers);
        return powers_ten[idx];
    }
}

static Fp build_fp(uint64_t bits) {
    Fp fp;
    fp.frac = bits & fracmask;
    fp.exp = (bits & expmask) >> 52;
    if(fp.exp) {
        fp.frac += hiddenbit;
        fp.exp -= expbias;
    } else {
        fp.exp = -expbias + 1;
    }
    return fp;
}

static void normalize(Fp* fp) {
    while((fp->frac & hiddenbit) == 0) {
        fp->frac <<= 1;
        fp->exp--;
    }
    int shift = 64 - 52 - 1;
    fp->frac <<= shift;
    fp->exp -= shift;
}

static void get_normalized_boundaries(Fp* fp, Fp* lower, Fp* upper) {
    upper->frac = (fp->frac << 1) + 1;
    upper->exp  = fp->exp - 1;
    while ((upper->frac & (hiddenbit << 1)) == 0) {
        upper->frac <<= 1;
        upper->exp--;
    }

    int u_shift = 64 - 52 - 2;
    upper->frac <<= u_shift;
    upper->exp = upper->exp - u_shift;

    int l_shift = fp->frac == hiddenbit ? 2 : 1;
    lower->frac = (fp->frac << l_shift) - 1;
    lower->exp = fp->exp - l_shift;
    lower->frac <<= lower->exp - upper->exp;
    lower->exp = upper->exp;
}

static Fp multiply(Fp* a, Fp* b) {
    const uint64_t lomask = 0x00000000FFFFFFFF;
    uint64_t ah_bl = (a->frac >> 32)    * (b->frac & lomask);
    uint64_t al_bh = (a->frac & lomask) * (b->frac >> 32);
    uint64_t al_bl = (a->frac & lomask) * (b->frac & lomask);
    uint64_t ah_bh = (a->frac >> 32)    * (b->frac >> 32);
    uint64_t tmp = (ah_bl & lomask) + (al_bh & lomask) + (al_bl >> 32); 
    /* round up */
    tmp += 1U << 31;
    Fp fp;
    fp.frac = ah_bh + (ah_bl >> 32) + (al_bh >> 32) + (tmp >> 32);
    fp.exp = a->exp + b->exp + 64;
    return fp;
}

static void round_digit(char* digits, unsigned ndigits, uint64_t delta,
                        uint64_t rem, uint64_t kappa, uint64_t frac) {
    while(rem < frac && delta - rem >= kappa &&
          (rem + kappa < frac || frac - rem > rem + kappa - frac)) {
        digits[ndigits - 1]--;
        rem += kappa;
    }
}

static unsigned generate_digits(Fp* fp, Fp* upper, Fp* lower, char* digits, int* K) {
    uint64_t wfrac = upper->frac - fp->frac;
    uint64_t delta = upper->frac - lower->frac;

    Fp one;
    one.frac = 1ULL << -upper->exp;
    one.exp  = upper->exp;

    uint64_t part1 = upper->frac >> -one.exp;
    uint64_t part2 = upper->frac & (one.frac - 1);

    unsigned idx = 0;
    int kappa = 10;
    uint64_t* divp;

    /* 1000000000 */
    for(divp = tens + 10; kappa > 0; divp++) {
        uint64_t div = *divp;
        uint64_t digit = part1 / div;
        if(digit || idx) {
            digits[idx++] = (char)(digit + '0');
        }

        part1 -= digit * div;
        kappa--;

        uint64_t tmp = (part1 <<-one.exp) + part2;
        if(tmp <= delta) {
            *K += kappa;
            round_digit(digits, idx, delta, tmp, div << -one.exp, wfrac);
            return idx;
        }
    }

    /* 10 */
    uint64_t* unit = tens + 18;
    while(true) {
        part2 *= 10;
        delta *= 10;
        kappa--;

        uint64_t digit = part2 >> -one.exp;
        if(digit || idx) {
            digits[idx++] = (char)(digit + '0');
        }

        part2 &= one.frac - 1;
        if(part2 < delta) {
            *K += kappa;
            round_digit(digits, idx, delta, part2, one.frac, wfrac * *unit);
            break;
        }
        unit--;
    }
    return idx;
}

static unsigned grisu2(uint64_t bits, char* digits, int* K) {
    Fp w = build_fp(bits);
    Fp lower, upper;
    get_normalized_boundaries(&w, &lower, &upper);
    normalize(&w);
    int k;
    Fp cp = find_cachedpow10(upper.exp, &k);
    w     = multiply(&w,     &cp);
    upper = multiply(&upper, &cp);
    lower = multiply(&lower, &cp);
    lower.frac++;
    upper.frac--;
    *K = -k;
    return generate_digits(&w, &upper, &lower, digits, K);
}

static unsigned
emit_digits(char* digits, unsigned ndigits, char* dest, int K, bool neg) {
    int exp = absv(K + (int)ndigits - 1);

    /* write plain integer */
    if(K >= 0 && (exp < (int)ndigits + 7)) {
        memcpy(dest, digits, ndigits);
        memset(dest + ndigits, '0', (unsigned)K);
        memcpy(dest + ndigits + (unsigned)K, ".0", 2); /* always append .0 for naked integers */
        return (unsigned)(ndigits + (unsigned)K + 2);
    }

    /* write decimal w/o scientific notation */
    if(K < 0 && (K > -7 || exp < 4)) {
        int offset = (int)ndigits - absv(K);
        if(offset <= 0) {
            /* fp < 1.0 -> write leading zero */
            offset = -offset;
            dest[0] = '0';
            dest[1] = '.';
            memset(dest + 2, '0', (size_t)offset);
            memcpy(dest + offset + 2, digits, ndigits);
            return ndigits + 2 + (unsigned)offset;
        } else {
            /* fp > 1.0 */
            memcpy(dest, digits, (size_t)offset);
            dest[offset] = '.';
            memcpy(dest + offset + 1, digits + offset, ndigits - (unsigned)offset);
            return ndigits + 1;
        }
    }

    /* write decimal w/ scientific notation */
    ndigits = minv(ndigits, (unsigned)(18 - neg));
    unsigned idx = 0;
    dest[idx++] = digits[0];
    if(ndigits > 1) {
        dest[idx++] = '.';
        memcpy(dest + idx, digits + 1, ndigits - 1);
        idx += ndigits - 1;
    }

    dest[idx++] = 'e';

    char sign = K + (int)ndigits - 1 < 0 ? '-' : '+';
    dest[idx++] = sign;

    int cent = 0;
    if(exp > 99) {
        cent = exp / 100;
        dest[idx++] = (char)(cent + '0');
        exp -= cent * 100;
    }
    if(exp > 9) {
        int dec = exp / 10;
        dest[idx++] = (char)(dec + '0');
        exp -= dec * 10;

    } else if(cent) {
        dest[idx++] = '0';
    }
    dest[idx++] = (char)(exp % 10 + '0');
    return idx;
}

unsigned dtoa(double d, char* buffer) {
    uint64_t bits = 0;
    memcpy(&bits, &d, sizeof(double));

    uint64_t mantissa = bits & ((1ull << mantissa_bits) - 1);
    uint32_t exponent = (uint32_t)
        ((bits >> mantissa_bits) & ((1u << exponent_bits) - 1));

    if(exponent == 0 && mantissa == 0) {
        memcpy(buffer, "0.0", 3);
        return 3;
    }

    bool sign = ((bits >> (mantissa_bits + exponent_bits)) & 1) != 0;
    unsigned pos = 0;
    if(sign) {
        buffer[0] = '-';
        pos++;
        buffer++;
    }

    if(exponent == ((1u << exponent_bits) - 1u)) {
        if(mantissa != 0) {
            memcpy(buffer, "nan", 3);
            return 3;
        } else {
            memcpy(&buffer[pos], "inf", 3);
            return pos + 3;
        }
    }

    int K = 0;
    char digits[18];
    memset(digits, 0, 18);
    unsigned ndigits = grisu2(bits, digits, &K);
    return pos + emit_digits(digits, ndigits, buffer, K, sign);
}

/**** amalgamated original file "/deps/mp_printf.c" ****/

/**
 * @author (c) Julius Pfrommer
 *             2023, Fraunhofer IOSB, Germany
 * @author (c) Eyal Rozenberg <eyalroz1@gmx.com>
 *             2021-2023, Haifa, Palestine/Israel
 * @author (c) Marco Paland (info@paland.com)
 *             2014-2019, PALANDesign Hannover, Germany
 *
 * @note Others have made smaller contributions to this file: see the
 * contributors page at https://github.com/eyalroz/printf/graphs/contributors
 * or ask one of the authors. The original code for exponential specifiers was
 * contributed by Martijn Jasperse <m.jasperse@gmail.com>.
 *
 * @brief Small stand-alone implementation of the printf family of functions
 * (`(v)printf`, `(v)s(n)printf` etc., geared towards use on embedded systems with
 * limited resources.
 *
 * @note the implementations are thread-safe; re-entrant; use no functions from
 * the standard library; and do not dynamically allocate any memory.
 *
 * @license The MIT License (MIT)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */


#include <stdint.h>
#include <stdbool.h>

// 'ntoa' conversion buffer size, this must be big enough to hold one converted
// numeric number including padded zeros (dynamically created on stack)
#define PRINTF_INTEGER_BUFFER_SIZE    32

// size of the fixed (on-stack) buffer for printing individual decimal numbers.
// this must be big enough to hold one converted floating-point value including
// padded zeros.
#define PRINTF_DECIMAL_BUFFER_SIZE    32

// Default precision for the floating point conversion specifiers (the C
// standard sets this at 6)
#define PRINTF_DEFAULT_FLOAT_PRECISION  6

// internal flag definitions
#define FLAGS_ZEROPAD   (1U <<  0U)
#define FLAGS_LEFT      (1U <<  1U)
#define FLAGS_PLUS      (1U <<  2U)
#define FLAGS_SPACE     (1U <<  3U)
#define FLAGS_HASH      (1U <<  4U)
#define FLAGS_UPPERCASE (1U <<  5U)
#define FLAGS_CHAR      (1U <<  6U)
#define FLAGS_SHORT     (1U <<  7U)
  // Only used with PRINTF_SUPPORT_MSVC_STYLE_INTEGER_SPECIFIERS
#define FLAGS_LONG      (1U <<  9U)
#define FLAGS_LONG_LONG (1U << 10U)
#define FLAGS_PRECISION (1U << 11U)
#define FLAGS_ADAPT_EXP (1U << 12U)
#define FLAGS_POINTER   (1U << 13U)
  // Note: Similar, but not identical, effect as FLAGS_HASH
#define FLAGS_SIGNED    (1U << 14U)

#define BASE_BINARY    2
#define BASE_OCTAL     8
#define BASE_DECIMAL  10
#define BASE_HEX      16

typedef unsigned int printf_flags_t;
typedef uint8_t numeric_base_t;
typedef unsigned long long printf_unsigned_value_t;
typedef long long printf_signed_value_t;

// Note in particular the behavior here on LONG_MIN or LLONG_MIN; it is valid
// and well-defined, but if you're not careful you can easily trigger undefined
// behavior with -LONG_MIN or -LLONG_MIN
#define ABS_FOR_PRINTING(_x)                                            \
    ((printf_unsigned_value_t)((_x) > 0 ? (_x) : -((printf_signed_value_t)_x)))

// internal secure strlen @return The length of the string (excluding the
// terminating 0) limited by 'maxsize' @note strlen uses size_t, but wes only
// use this function with size_t variables - hence the signature.
static size_t
strnlen_s_(const char *str, size_t maxsize) {
    for(size_t i = 0; i < maxsize; i++) {
        if(!str[i])
            return i;
    }
    return maxsize;
}

// internal test if char is a digit (0-9)
// @return true if char is a digit
static bool is_digit_(char ch) { return (ch >= '0') && (ch <= '9'); }

// internal ASCII string to size_t conversion
static size_t
atou_(const char **str) {
    size_t i = 0U;
    while(is_digit_(**str)) {
        i = i * 10U + (size_t)(*((*str)++) - '0');
    }
    return i;
}

// Output buffer
typedef struct {
    char *buffer;
    size_t pos;
    size_t max_chars;
} output_t;

static void
putchar_(output_t *out, char c) {
    size_t write_pos = out->pos++;
    // We're _always_ increasing pos, so as to count how may characters
    // _would_ have been written if not for the max_chars limitation
    if(write_pos >= out->max_chars)
        return;
    // it must be the case that out->buffer != NULL , due to the constraint
    // on output_t ; and note we're relying on write_pos being non-negative.
    out->buffer[write_pos] = c;
}

static void
out_(output_t *out, const char *buf, size_t len) {
    if(out->pos < out->max_chars) {
        size_t write_len = len;
        if(out->pos + len > out->max_chars)
            write_len = out->max_chars - out->pos;
        for(size_t i = 0; i < write_len; i++)
            out->buffer[out->pos + i] = buf[i];
    }
    out->pos += len; // Always increase pos by len
}

// output the specified string in reverse, taking care of any zero-padding
static void
out_rev_(output_t *output, const char *buf, size_t len, size_t width,
         printf_flags_t flags) {
    const size_t start_pos = output->pos;

    // pad spaces up to given width
    if(!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) {
        for(size_t i = len; i < width; i++) {
            putchar_(output, ' ');
        }
    }

    // reverse string
    while(len) {
        putchar_(output, buf[--len]);
    }

    // append pad spaces up to given width
    if(flags & FLAGS_LEFT) {
        while(output->pos - start_pos < width) {
            putchar_(output, ' ');
        }
    }
}

// Invoked by print_integer after the actual number has been printed, performing
// necessary work on the number's prefix (as the number is initially printed in
// reverse order)
static void
print_integer_finalization(output_t *output, char *buf, size_t len, bool negative,
                           numeric_base_t base, size_t precision, size_t width,
                           printf_flags_t flags) {
    size_t unpadded_len = len;

    // pad with leading zeros
    if(!(flags & FLAGS_LEFT)) {
        if(width && (flags & FLAGS_ZEROPAD) &&
           (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) {
            width--;
        }
        while((flags & FLAGS_ZEROPAD) && (len < width) &&
              (len < PRINTF_INTEGER_BUFFER_SIZE)) {
            buf[len++] = '0';
        }
    }

    while((len < precision) && (len < PRINTF_INTEGER_BUFFER_SIZE)) {
        buf[len++] = '0';
    }

    if(base == BASE_OCTAL && (len > unpadded_len)) {
        // Since we've written some zeros, we've satisfied the alternative format
        // leading space requirement
        flags &= ~FLAGS_HASH;
    }

    // handle hash
    if(flags & (FLAGS_HASH | FLAGS_POINTER)) {
        if(!(flags & FLAGS_PRECISION) && len && ((len == precision) || (len == width))) {
            // Let's take back some padding digits to fit in what will eventually be
            // the format-specific prefix
            if(unpadded_len < len) {
                len--;  // This should suffice for BASE_OCTAL
            }
            if(len && (base == BASE_HEX || base == BASE_BINARY) && (unpadded_len < len)) {
                len--;  // ... and an extra one for 0x or 0b
            }
        }
        if((base == BASE_HEX) && !(flags & FLAGS_UPPERCASE) &&
           (len < PRINTF_INTEGER_BUFFER_SIZE)) {
            buf[len++] = 'x';
        } else if((base == BASE_HEX) && (flags & FLAGS_UPPERCASE) &&
                  (len < PRINTF_INTEGER_BUFFER_SIZE)) {
            buf[len++] = 'X';
        } else if((base == BASE_BINARY) && (len < PRINTF_INTEGER_BUFFER_SIZE)) {
            buf[len++] = 'b';
        }
        if(len < PRINTF_INTEGER_BUFFER_SIZE) {
            buf[len++] = '0';
        }
    }

    if(len < PRINTF_INTEGER_BUFFER_SIZE) {
        if(negative) {
            buf[len++] = '-';
        } else if(flags & FLAGS_PLUS) {
            buf[len++] = '+';  // ignore the space if the '+' exists
        } else if(flags & FLAGS_SPACE) {
            buf[len++] = ' ';
        }
    }

    out_rev_(output, buf, len, width, flags);
}

// An internal itoa-like function
static void
print_integer(output_t *output, printf_unsigned_value_t value, bool negative,
              numeric_base_t base, size_t precision, size_t width, printf_flags_t flags) {
    char buf[PRINTF_INTEGER_BUFFER_SIZE];
    size_t len = 0U;

    if(!value) {
        if(!(flags & FLAGS_PRECISION)) {
            buf[len++] = '0';
            flags &= ~FLAGS_HASH;
            // We drop this flag this since either the alternative and regular modes
            // of the specifier don't differ on 0 values, or (in the case of octal)
            // we've already provided the special handling for this mode.
        } else if(base == BASE_HEX) {
            flags &= ~FLAGS_HASH;
            // We drop this flag this since either the alternative and regular modes
            // of the specifier don't differ on 0 values
        }
    } else {
        do {
            const char digit = (char)(value % base);
            buf[len++] =
                (char)(digit < 10 ? '0' + digit
                                  : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10);
            value /= base;
        } while(value && (len < PRINTF_INTEGER_BUFFER_SIZE));
    }

    print_integer_finalization(output, buf, len, negative, base, precision, width, flags);
}

static void
print_floating_point(output_t *output, double value, size_t precision,
                     size_t width, printf_flags_t flags) {
    if((flags & FLAGS_PLUS) && value > 0.0)
        putchar_(output, '+');

    // set default precision, if not set explicitly
    //if(!(flags & FLAGS_PRECISION) || precision > PRINTF_DECIMAL_BUFFER_SIZE - 5)
    //    precision = PRINTF_DEFAULT_FLOAT_PRECISION;

    char buf[PRINTF_DECIMAL_BUFFER_SIZE];
    unsigned len = dtoa(value, buf); // Fill the buffer (TODO: Consider precision)
    out_(output, buf, len); // Print the buffer
}

// Advances the format pointer past the flags, and returns the parsed flags
// due to the characters passed
static printf_flags_t
parse_flags(const char **format) {
    printf_flags_t flags = 0U;
    do {
        switch(**format) {
        case '0': flags |= FLAGS_ZEROPAD; break;
        case '-': flags |= FLAGS_LEFT; break;
        case '+': flags |= FLAGS_PLUS; break;
        case ' ': flags |= FLAGS_SPACE; break;
        case '#': flags |= FLAGS_HASH; break;
        default: return flags;
        }
        (*format)++;
    } while(true);
}

#define ADVANCE_IN_FORMAT_STRING(cptr_)                                 \
    do {                                                                \
        (cptr_)++;                                                      \
        if(!*(cptr_))                                                   \
            return;                                                     \
    } while(0)

static void
format_string_loop(output_t *output, const char *format, va_list args) {
    while(*format) {
        if(*format != '%') {
            // A regular content character
            putchar_(output, *format);
            format++;
            continue;
        }
        // We're parsing a format specifier: %[flags][width][.precision][length]
        ADVANCE_IN_FORMAT_STRING(format);

        printf_flags_t flags = parse_flags(&format);

        // evaluate width field
        size_t width = 0U;
        if(is_digit_(*format)) {
            width = atou_(&format);
        } else if(*format == '*') {
            const int w = va_arg(args, int);
            if(w < 0) {
                flags |= FLAGS_LEFT;  // reverse padding
                width = (size_t)-w;
            } else {
                width = (size_t)w;
            }
            ADVANCE_IN_FORMAT_STRING(format);
        }

        // evaluate precision field
        size_t precision = 0U;
        if(*format == '.') {
            flags |= FLAGS_PRECISION;
            ADVANCE_IN_FORMAT_STRING(format);
            if(is_digit_(*format)) {
                precision = atou_(&format);
            } else if(*format == '*') {
                const int precision_ = va_arg(args, int);
                precision = precision_ > 0 ? (size_t)precision_ : 0U;
                ADVANCE_IN_FORMAT_STRING(format);
            }
        }

        // evaluate length field
        switch(*format) {
            case 'l':
                flags |= FLAGS_LONG;
                ADVANCE_IN_FORMAT_STRING(format);
                if(*format == 'l') {
                    flags |= FLAGS_LONG_LONG;
                    ADVANCE_IN_FORMAT_STRING(format);
                }
                break;
            case 'h':
                flags |= FLAGS_SHORT;
                ADVANCE_IN_FORMAT_STRING(format);
                if(*format == 'h') {
                    flags |= FLAGS_CHAR;
                    ADVANCE_IN_FORMAT_STRING(format);
                }
                break;
            case 't':
                flags |=
                    (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
                ADVANCE_IN_FORMAT_STRING(format);
                break;
            case 'j':
                flags |=
                    (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
                ADVANCE_IN_FORMAT_STRING(format);
                break;
            case 'z':
                flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG);
                ADVANCE_IN_FORMAT_STRING(format);
                break;
            default:
                break;
        }

        // evaluate specifier
        switch(*format) {
            case 'd':
            case 'i':
            case 'u':
            case 'x':
            case 'X':
            case 'o':
            case 'b': {
                if(*format == 'd' || *format == 'i') {
                    flags |= FLAGS_SIGNED;
                }

                numeric_base_t base;
                if(*format == 'x' || *format == 'X') {
                    base = BASE_HEX;
                } else if(*format == 'o') {
                    base = BASE_OCTAL;
                } else if(*format == 'b') {
                    base = BASE_BINARY;
                } else {
                    base = BASE_DECIMAL;
                    flags &=
                        ~FLAGS_HASH;  // decimal integers have no alternative presentation
                }

                if(*format == 'X') {
                    flags |= FLAGS_UPPERCASE;
                }

                format++;
                // ignore '0' flag when precision is given
                if(flags & FLAGS_PRECISION) {
                    flags &= ~FLAGS_ZEROPAD;
                }

                if(flags & FLAGS_SIGNED) {
                    // A signed specifier: d, i or possibly I + bit size if enabled
                    if(flags & FLAGS_LONG_LONG) {
                        const long long value = va_arg(args, long long);
                        print_integer(output, ABS_FOR_PRINTING(value), value < 0, base,
                                      precision, width, flags);
                    } else if(flags & FLAGS_LONG) {
                        const long value = va_arg(args, long);
                        print_integer(output, ABS_FOR_PRINTING(value), value < 0, base,
                                      precision, width, flags);
                    } else {
                        // We never try to interpret the argument as something
                        // potentially-smaller than int, due to integer promotion rules:
                        // Even if the user passed a short int, short unsigned etc. -
                        // these will come in after promotion, as int's (or unsigned for
                        // the case of short unsigned when it has the same size as int)
                        const int value =
                            (flags & FLAGS_CHAR)    ? (signed char)va_arg(args, int)
                            : (flags & FLAGS_SHORT) ? (short int)va_arg(args, int)
                                                    : va_arg(args, int);
                        print_integer(output, ABS_FOR_PRINTING(value), value < 0, base,
                                      precision, width, flags);
                    }
                } else {
                    // An unsigned specifier: u, x, X, o, b
                    flags &= ~(FLAGS_PLUS | FLAGS_SPACE);

                    if(flags & FLAGS_LONG_LONG) {
                        print_integer(output, (printf_unsigned_value_t)
                                      va_arg(args, unsigned long long),
                                      false, base, precision, width, flags);
                    } else if(flags & FLAGS_LONG) {
                        print_integer(output, (printf_unsigned_value_t)
                                      va_arg(args, unsigned long),
                                      false, base, precision, width, flags);
                    } else {
                        const unsigned int value = (flags & FLAGS_CHAR)
                            ? (unsigned char)va_arg(args, unsigned int)
                            : (flags & FLAGS_SHORT)
                            ? (unsigned short int)va_arg(args, unsigned int)
                            : va_arg(args, unsigned int);
                        print_integer(output, (printf_unsigned_value_t)value, false, base,
                                      precision, width, flags);
                    }
                }
                break;
            }

            case 'f':
            case 'F':
                if(*format == 'F')
                    flags |= FLAGS_UPPERCASE;
                print_floating_point(output, (double)va_arg(args, double),
                                     precision, width, flags);
                format++;
                break;

            case 'c': {
                size_t l = 1U;
                // pre padding
                if(!(flags & FLAGS_LEFT)) {
                    while(l++ < width) {
                        putchar_(output, ' ');
                    }
                }
                // char output
                putchar_(output, (char)va_arg(args, int));
                // post padding
                if(flags & FLAGS_LEFT) {
                    while(l++ < width) {
                        putchar_(output, ' ');
                    }
                }
                format++;
                break;
            }

            case 's': {
                const char *p = va_arg(args, char *);
                if(p == NULL) {
                    out_rev_(output, ")llun(", 6, width, flags);
                } else {
                    // string length
                    size_t l = strnlen_s_(p, precision ? precision : INT32_MAX);
                    if(flags & FLAGS_PRECISION) {
                        l = (l < precision ? l : precision);
                    }

                    // pre padding
                    if(!(flags & FLAGS_LEFT)) {
                        for(size_t i = 0; l + i < width; i++) {
                            putchar_(output, ' ');
                        }
                    }

                    // string output
                    out_(output, p, l);

                    // post padding
                    if(flags & FLAGS_LEFT) {
                        for(size_t i = 0; l + i < width; i++) {
                            putchar_(output, ' ');
                        }
                    }
                }
                format++;
                break;
            }

            case 'p': {
                width =
                    sizeof(void *) * 2U + 2;  // 2 hex chars per byte + the "0x" prefix
                flags |= FLAGS_ZEROPAD | FLAGS_POINTER;
                uintptr_t value = (uintptr_t)va_arg(args, void *);
                (value == (uintptr_t)NULL)
                    ? out_rev_(output, ")lin(", 5, width, flags)
                    : print_integer(output, (printf_unsigned_value_t)value, false,
                                    BASE_HEX, precision, width, flags);
                format++;
                break;
            }

            case '%':
                putchar_(output, '%');
                format++;
                break;

            default:
                putchar_(output, *format);
                format++;
                break;
        }
    }
}

int
mp_vsnprintf(char *s, size_t n, const char *format, va_list arg) {
    // Check that the inputs are sane
    if(!s || n < 1)
        return -1;

    // Format the string
    output_t out = {s, 0, n};
    format_string_loop(&out, format, arg);

    // Write the string-terminating '\0' character
    size_t null_char_pos = out.pos < out.max_chars ? out.pos : out.max_chars - 1;
    out.buffer[null_char_pos] = '\0';

    // Return written chars without terminating \0
    return (int)out.pos;
}

int
mp_snprintf(char *s, size_t n, const char *format, ...) {
    va_list args;
    va_start(args, format);
    const int ret = mp_vsnprintf(s, n, format, args);
    va_end(args);
    return ret;
}

/**** amalgamated original file "/deps/itoa.c" ****/

/*
 * Copyright 2017 Techie Delight
 * Permission is hereby granted, free of charge, to any person obtaining a copy 
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights 
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
 * copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included 
 * in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 
 * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/* Originally released by techiedelight.com 
 * (http://www.techiedelight.com/implement-itoa-function-in-c/) under the
 * MIT license. */


static void swap(char *x, char *y) {
    char t = *x;
    *x = *y;
    *y = t;
}

/* function to reverse buffer */
static char* reverse(char *buffer, UA_UInt16 i, UA_UInt16 j) {
    while (i < j)
        swap(&buffer[i++], &buffer[j--]);

    return buffer;
}

/* adapted from http://www.techiedelight.com/implement-itoa-function-in-c/ to use UA_... types */
UA_UInt16 itoaUnsigned(UA_UInt64 value, char* buffer, UA_Byte base) {
    /* consider absolute value of number */
    UA_UInt64 n = value;

    UA_UInt16 i = 0;
    while (n) {
        UA_UInt64 r = n % base;

        if (r >= 10)
            buffer[i++] = (char)(65 + (r - 10));
        else
            buffer[i++] = (char)(48 + r);

        n = n / base;
    }
    /* if number is 0 */
    if (i == 0)
        buffer[i++] = '0';

    buffer[i] = '\0'; /* null terminate string */
    i--;
    /* reverse the string */
    reverse(buffer, 0, i);
    i++;
    return i;
}

/* adapted from http://www.techiedelight.com/implement-itoa-function-in-c/ */
UA_UInt16 itoaSigned(UA_Int64 value, char* buffer) {
    /* Special case for UA_INT64_MIN which can not simply be negated */
    /* it will cause a signed integer overflow */
    UA_UInt64 n;
    if(value == UA_INT64_MIN) {
        n = (UA_UInt64)UA_INT64_MAX + 1;
    } else {
        n = (UA_UInt64)value;
        if(value < 0){
            n = (UA_UInt64)-value;
        }
    }

    UA_UInt16 i = 0;
    while(n) {
        UA_UInt64 r = n % 10;
        buffer[i++] = (char)('0' + r);
        n = n / 10;
    }

    if(i == 0)
        buffer[i++] = '0'; /* if number is 0 */
    if(value < 0)
        buffer[i++] = '-';
    buffer[i] = '\0'; /* null terminate string */
    i--;
    reverse(buffer, 0, i); /* reverse the string and return it */
    i++;
    return i;
}


/**** amalgamated original file "/deps/ziptree.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
 *
 *    Copyright 2021-2022 (c) Julius Pfrommer
 */


/* Dummy types */
struct zip_elem;
typedef struct zip_elem zip_elem;
typedef ZIP_ENTRY(zip_elem) zip_entry;
typedef ZIP_HEAD(, zip_elem) zip_head;

/* Access macros */
#define ZIP_ENTRY_PTR(x) ((zip_entry*)((char*)x + fieldoffset))
#define ZIP_KEY_PTR(x) (const void*)((const char*)x + keyoffset)

/* Hash pointers to keep the tie-breeaking of equal keys (mostly) uncorrelated
 * from the rank (pointer order). Hashing code taken from sdbm-hash
 * (http://www.cse.yorku.ca/~oz/hash.html). */
static unsigned int
__ZIP_PTR_HASH(const void *p) {
    unsigned int h = 0;
    const unsigned char *data = (const unsigned char*)&p;
    for(size_t i = 0; i < (sizeof(void*) / sizeof(char)); i++)
        h = data[i] + (h << 6) + (h << 16) - h;
    return h;
}

static ZIP_INLINE enum ZIP_CMP
__ZIP_RANK_CMP(const void *p1, const void *p2) {
    /* assert(p1 != p2); */
    unsigned int h1 = __ZIP_PTR_HASH(p1);
    unsigned int h2 = __ZIP_PTR_HASH(p2);
    if(h1 == h2)
        return (p1 < p2) ? ZIP_CMP_LESS : ZIP_CMP_MORE;
    return (h1 < h2) ? ZIP_CMP_LESS : ZIP_CMP_MORE;
}

static ZIP_INLINE enum ZIP_CMP
__ZIP_UNIQUE_CMP(zip_cmp_cb cmp, const void *p1, const void *p2) {
    if(p1 == p2)
        return ZIP_CMP_EQ;
    enum ZIP_CMP order = cmp(p1, p2);
    if(order == ZIP_CMP_EQ)
        return (p1 < p2) ? ZIP_CMP_LESS : ZIP_CMP_MORE;
    return order;
}

#if 0
#include <assert.h>
ZIP_UNUSED static ZIP_INLINE void
__ZIP_VALIDATE(zip_cmp_cb cmp, unsigned short fieldoffset,
               unsigned short keyoffset, void *elm,
               void *min_elm, void *max_elm) {
    if(!elm)
        return;
    enum ZIP_CMP c1 = __ZIP_UNIQUE_CMP(cmp, ZIP_KEY_PTR(min_elm), ZIP_KEY_PTR(elm));
    assert((elm == min_elm && c1 == ZIP_CMP_EQ) || c1 == ZIP_CMP_LESS);

    enum ZIP_CMP c2 = __ZIP_UNIQUE_CMP(cmp, ZIP_KEY_PTR(max_elm), ZIP_KEY_PTR(elm));
    assert((elm == max_elm && c2 == ZIP_CMP_EQ) || c2 == ZIP_CMP_MORE);

    assert(!ZIP_ENTRY_PTR(elm)->right ||
           __ZIP_RANK_CMP(elm, ZIP_ENTRY_PTR(elm)->right) == ZIP_CMP_MORE);
    assert(!ZIP_ENTRY_PTR(elm)->left ||
           __ZIP_RANK_CMP(elm, ZIP_ENTRY_PTR(elm)->left) == ZIP_CMP_MORE);

    __ZIP_VALIDATE(cmp, fieldoffset, keyoffset, ZIP_ENTRY_PTR(elm)->right, elm, max_elm);
    __ZIP_VALIDATE(cmp, fieldoffset, keyoffset, ZIP_ENTRY_PTR(elm)->left, min_elm, elm);
}
#endif

/* Walk down the right-side spine of cur. Elements that are larger than x_key
 * are moved under x->right. */
static void
__ZIP_INSERT_MOVE_RIGHT(zip_cmp_cb cmp, unsigned short fieldoffset,
                        unsigned short keyoffset, const void *x_key,
                        zip_elem **fix_edge, zip_elem *cur) {
    while(ZIP_ENTRY_PTR(cur)->right) {
        zip_elem *move_candidate = ZIP_ENTRY_PTR(cur)->right;
        if(__ZIP_UNIQUE_CMP(cmp, x_key, ZIP_KEY_PTR(move_candidate)) == ZIP_CMP_MORE) {
            cur = ZIP_ENTRY_PTR(cur)->right;
            continue;
        }
        ZIP_ENTRY_PTR(cur)->right = ZIP_ENTRY_PTR(move_candidate)->left;
        ZIP_ENTRY_PTR(move_candidate)->left = NULL;
        *fix_edge = move_candidate;
        fix_edge = &ZIP_ENTRY_PTR(move_candidate)->left;
    }
}

static void
__ZIP_INSERT_MOVE_LEFT(zip_cmp_cb cmp, unsigned short fieldoffset,
                       unsigned short keyoffset, const void *x_key,
                       zip_elem **fix_edge, zip_elem *cur) {
    while(ZIP_ENTRY_PTR(cur)->left) {
        zip_elem *move_candidate = ZIP_ENTRY_PTR(cur)->left;
        if(__ZIP_UNIQUE_CMP(cmp, x_key, ZIP_KEY_PTR(move_candidate)) == ZIP_CMP_LESS) {
            cur = ZIP_ENTRY_PTR(cur)->left;
            continue;
        }
        ZIP_ENTRY_PTR(cur)->left = ZIP_ENTRY_PTR(move_candidate)->right;
        ZIP_ENTRY_PTR(move_candidate)->right = NULL;
        *fix_edge = move_candidate;
        fix_edge = &ZIP_ENTRY_PTR(move_candidate)->right;
    }
}

void
__ZIP_INSERT(void *h, zip_cmp_cb cmp, unsigned short fieldoffset,
             unsigned short keyoffset, void *elm) {
    zip_elem *x = (zip_elem*)elm;
    ZIP_ENTRY_PTR(x)->left = NULL;
    ZIP_ENTRY_PTR(x)->right = NULL;

    const void *x_key = ZIP_KEY_PTR(x);
    zip_head *head = (zip_head*)h;
    if(!head->root) {
        head->root = x;
        return;
    }

    /* Go down the tree to find the top element "cur" that has a rank smaller
     * than "x" */
    zip_elem *prev = NULL;
    zip_elem *cur = head->root;
    enum ZIP_CMP cur_order, prev_order;
    do {
        cur_order = __ZIP_UNIQUE_CMP(cmp, x_key, ZIP_KEY_PTR(cur));
        if(cur_order == ZIP_CMP_EQ)
            return; /* x is already inserted */
        if(__ZIP_RANK_CMP(cur, x) == ZIP_CMP_LESS)
            break;
        prev = cur;
        prev_order = cur_order;
        cur = (cur_order == ZIP_CMP_MORE) ?
            ZIP_ENTRY_PTR(cur)->right : ZIP_ENTRY_PTR(cur)->left;
    } while(cur);

    /* Insert "x" instead of "cur" under its parent "prev" */
    if(cur == head->root) {
        head->root = x;
    } else {
        if(prev_order == ZIP_CMP_MORE)
            ZIP_ENTRY_PTR(prev)->right = x;
        else
            ZIP_ENTRY_PTR(prev)->left = x;
    }

    if(!cur)
        return;

    /* Re-insert "cur" under "x". Repair by moving elements that ended up on the
     * wrong side of "x". */
    if(cur_order == ZIP_CMP_MORE) {
        ZIP_ENTRY_PTR(x)->left = cur;
        __ZIP_INSERT_MOVE_RIGHT(cmp, fieldoffset, keyoffset,
                                x_key, &ZIP_ENTRY_PTR(x)->right, cur);
    } else {
        ZIP_ENTRY_PTR(x)->right = cur;
        __ZIP_INSERT_MOVE_LEFT(cmp, fieldoffset, keyoffset,
                               x_key, &ZIP_ENTRY_PTR(x)->left, cur);
    }
}

void *
__ZIP_REMOVE(void *h, zip_cmp_cb cmp, unsigned short fieldoffset,
             unsigned short keyoffset, void *elm) {
    zip_head *head = (zip_head*)h;
    zip_elem *x = (zip_elem*)elm;
    zip_elem *cur = head->root;
    if(!cur)
        return NULL;

    const void *x_key = ZIP_KEY_PTR(x);
    zip_elem **prev_edge = &head->root;
    enum ZIP_CMP cur_order = __ZIP_UNIQUE_CMP(cmp, x_key, ZIP_KEY_PTR(cur));
    while(cur_order != ZIP_CMP_EQ) {
        prev_edge = (cur_order == ZIP_CMP_LESS) ?
            &ZIP_ENTRY_PTR(cur)->left : &ZIP_ENTRY_PTR(cur)->right;
        cur = *prev_edge;
        if(!cur)
            return NULL;
        cur_order = __ZIP_UNIQUE_CMP(cmp, x_key, ZIP_KEY_PTR(cur));
    }
    *prev_edge = (zip_elem*)__ZIP_ZIP(fieldoffset,
                                      ZIP_ENTRY_PTR(cur)->left,
                                      ZIP_ENTRY_PTR(cur)->right);
    return cur;
}

void *
__ZIP_ITER(unsigned short fieldoffset, zip_iter_cb cb,
           void *context, void *elm) {
    if(!elm)
        return NULL;
    zip_elem *left = ZIP_ENTRY_PTR(elm)->left;
    zip_elem *right = ZIP_ENTRY_PTR(elm)->right;
    void *res = __ZIP_ITER(fieldoffset, cb, context, left);
    if(res)
        return res;
    res = cb(context, elm);
    if(res)
        return res;
    return __ZIP_ITER(fieldoffset, cb, context, right);
}

void *
__ZIP_ITER_KEY(zip_cmp_cb cmp, unsigned short fieldoffset,
               unsigned short keyoffset, const void *key,
               zip_iter_cb cb, void *context, void *elm) {
    if(!elm)
        return NULL;

    void *res;
    enum ZIP_CMP eq = cmp(key, ZIP_KEY_PTR(elm));
    if(eq != ZIP_CMP_MORE) {
        res = __ZIP_ITER_KEY(cmp, fieldoffset, keyoffset, key,
                             cb, context, ZIP_ENTRY_PTR(elm)->left);
        if(res)
            return res;
    }

    if(eq == ZIP_CMP_EQ) {
        res = cb(context, elm);
        if(res)
            return res;
    }

    if(eq != ZIP_CMP_LESS) {
        res = __ZIP_ITER_KEY(cmp, fieldoffset, keyoffset, key,
                             cb, context, ZIP_ENTRY_PTR(elm)->right);
        if(res)
            return res;
    }

    return NULL;
}

void *
__ZIP_ZIP(unsigned short fieldoffset, void *left, void *right) {
    if(!left)
        return right;
    if(!right)
        return left;
    zip_elem *l = (zip_elem*)left;
    zip_elem *r = (zip_elem*)right;
    zip_elem *root = NULL;
    zip_elem **prev_edge = &root;
    while(l && r) {
        if(__ZIP_RANK_CMP(l, r) == ZIP_CMP_LESS) {
            *prev_edge = r;
            prev_edge = &ZIP_ENTRY_PTR(r)->left;
            r = ZIP_ENTRY_PTR(r)->left;
        } else {
            *prev_edge = l;
            prev_edge = &ZIP_ENTRY_PTR(l)->right;
            l = ZIP_ENTRY_PTR(l)->right;
        }
    }
    *prev_edge = (l) ? l : r;
    return root;
}

/* Walk down from cur and move all elements <= split-key to the left side. All
 * elements that are moved over have to be below left_rightmost. Returns the
 * hierarchy of elements that remain on the right side. */
static void
__ZIP_UNZIP_MOVE_LEFT(zip_cmp_cb cmp, unsigned short fieldoffset,
                      unsigned short keyoffset, const void *key,
                      zip_elem **fix_edge, zip_elem *cur) {
    while(ZIP_ENTRY_PTR(cur)->left) {
        zip_elem *next = ZIP_ENTRY_PTR(cur)->left;
        if(cmp(key, ZIP_KEY_PTR(next)) == ZIP_CMP_LESS) {
            cur = next;
            continue;
        }
        *fix_edge = next;
        ZIP_ENTRY_PTR(cur)->left = ZIP_ENTRY_PTR(next)->right;
        ZIP_ENTRY_PTR(next)->right = NULL;
        fix_edge = &ZIP_ENTRY_PTR(next)->right;
    }
}

static void
__ZIP_UNZIP_MOVE_RIGHT(zip_cmp_cb cmp, unsigned short fieldoffset,
                       unsigned short keyoffset, const void *key,
                       zip_elem **fix_edge, zip_elem *cur) {
    while(ZIP_ENTRY_PTR(cur)->right) {
        zip_elem *next = ZIP_ENTRY_PTR(cur)->right;
        if(cmp(key, ZIP_KEY_PTR(next)) != ZIP_CMP_LESS) {
            cur = next;
            continue;
        }
        *fix_edge = next;
        ZIP_ENTRY_PTR(cur)->right = ZIP_ENTRY_PTR(next)->left;
        ZIP_ENTRY_PTR(next)->left = NULL;
        fix_edge = &ZIP_ENTRY_PTR(next)->left;
    }
}

/* Split the tree into a left side with keys <= split-key and a right side with
 * key > split-key. */
void
__ZIP_UNZIP(zip_cmp_cb cmp, unsigned short fieldoffset,
            unsigned short keyoffset, const void *key,
            void *h, void *l, void *r) {
    zip_elem *prev;
    zip_head *head = (zip_head*)h;
    zip_head *left = (zip_head*)l;
    zip_head *right = (zip_head*)r;
    if(!head->root) {
        left->root = NULL;
        right->root = NULL;
        return;
    }
    zip_elem *cur = head->root;
    if(cmp(key, ZIP_KEY_PTR(cur)) != ZIP_CMP_LESS) {
        left->root = cur;
        do {
            prev = cur;
            cur = ZIP_ENTRY_PTR(cur)->right;
            if(!cur) {
                right->root = NULL;
                return;
            }
        } while(cmp(key, ZIP_KEY_PTR(cur)) != ZIP_CMP_LESS);
        ZIP_ENTRY_PTR(prev)->right = NULL;
        right->root = cur;
        __ZIP_UNZIP_MOVE_LEFT(cmp, fieldoffset, keyoffset, key,
                              &ZIP_ENTRY_PTR(prev)->right, cur);
    } else {
        right->root = cur;
        do {
            prev = cur;
            cur = ZIP_ENTRY_PTR(cur)->left;
            if(!cur) {
                left->root = NULL;
                return;
            }
        } while(cmp(key, ZIP_KEY_PTR(cur)) == ZIP_CMP_LESS);
        ZIP_ENTRY_PTR(prev)->left = NULL;
        left->root = cur;
        __ZIP_UNZIP_MOVE_RIGHT(cmp, fieldoffset, keyoffset, key,
                               &ZIP_ENTRY_PTR(prev)->left, cur);
    }
}

/**** amalgamated original file "/build/src_generated/open62541/namespace0_generated.c" ****/

/* WARNING: This is a generated file.
 * Any manual changes will be overwritten. */



/* HasAddIn - ns=0;i=17604 */

static UA_StatusCode function_namespace0_generated_0_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default;
attr.inverseName  = UA_LOCALIZEDTEXT("", "AddInOf");
attr.displayName = UA_LOCALIZEDTEXT("", "HasAddIn");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE,UA_NODEID_NUMERIC(ns[0], 17604LU),UA_NODEID_NUMERIC(ns[0], 32LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "HasAddIn"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_0_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 17604LU));
}

/* HasHistoricalConfiguration - ns=0;i=56 */

static UA_StatusCode function_namespace0_generated_1_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default;
attr.inverseName  = UA_LOCALIZEDTEXT("", "HistoricalConfigurationOf");
attr.displayName = UA_LOCALIZEDTEXT("", "HasHistoricalConfiguration");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE,UA_NODEID_NUMERIC(ns[0], 56LU),UA_NODEID_NUMERIC(ns[0], 44LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "HasHistoricalConfiguration"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_1_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 56LU));
}

/* HasEffect - ns=0;i=54 */

static UA_StatusCode function_namespace0_generated_2_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default;
attr.inverseName  = UA_LOCALIZEDTEXT("", "MayBeEffectedBy");
attr.displayName = UA_LOCALIZEDTEXT("", "HasEffect");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE,UA_NODEID_NUMERIC(ns[0], 54LU),UA_NODEID_NUMERIC(ns[0], 32LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "HasEffect"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_2_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 54LU));
}

/* HasCause - ns=0;i=53 */

static UA_StatusCode function_namespace0_generated_3_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default;
attr.inverseName  = UA_LOCALIZEDTEXT("", "MayBeCausedBy");
attr.displayName = UA_LOCALIZEDTEXT("", "HasCause");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE,UA_NODEID_NUMERIC(ns[0], 53LU),UA_NODEID_NUMERIC(ns[0], 32LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "HasCause"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_3_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 53LU));
}

/* ToState - ns=0;i=52 */

static UA_StatusCode function_namespace0_generated_4_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default;
attr.inverseName  = UA_LOCALIZEDTEXT("", "FromTransition");
attr.displayName = UA_LOCALIZEDTEXT("", "ToState");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE,UA_NODEID_NUMERIC(ns[0], 52LU),UA_NODEID_NUMERIC(ns[0], 32LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "ToState"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_4_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 52LU));
}

/* FromState - ns=0;i=51 */

static UA_StatusCode function_namespace0_generated_5_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default;
attr.inverseName  = UA_LOCALIZEDTEXT("", "ToTransition");
attr.displayName = UA_LOCALIZEDTEXT("", "FromState");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_REFERENCETYPE,UA_NODEID_NUMERIC(ns[0], 51LU),UA_NODEID_NUMERIC(ns[0], 32LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "FromState"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_REFERENCETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_5_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 51LU));
}

/* DiagnosticInfo - ns=0;i=25 */

static UA_StatusCode function_namespace0_generated_6_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "DiagnosticInfo");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 25LU),UA_NODEID_NUMERIC(ns[0], 24LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "DiagnosticInfo"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_6_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 25LU));
}

/* DataValue - ns=0;i=23 */

static UA_StatusCode function_namespace0_generated_7_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "DataValue");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 23LU),UA_NODEID_NUMERIC(ns[0], 24LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "DataValue"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_7_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 23LU));
}

/* Structure - ns=0;i=22 */

static UA_StatusCode function_namespace0_generated_8_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "Structure");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 22LU),UA_NODEID_NUMERIC(ns[0], 24LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "Structure"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_8_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 22LU));
}

/* TimeZoneDataType - ns=0;i=8912 */

static UA_StatusCode function_namespace0_generated_9_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "TimeZoneDataType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 8912LU),UA_NODEID_NUMERIC(ns[0], 22LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "TimeZoneDataType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_9_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 8912LU));
}

/* EUInformation - ns=0;i=887 */

static UA_StatusCode function_namespace0_generated_10_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "EUInformation");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 887LU),UA_NODEID_NUMERIC(ns[0], 22LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "EUInformation"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_10_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 887LU));
}

/* Range - ns=0;i=884 */

static UA_StatusCode function_namespace0_generated_11_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Range");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 884LU),UA_NODEID_NUMERIC(ns[0], 22LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "Range"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_11_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 884LU));
}

/* SubscriptionDiagnosticsDataType - ns=0;i=874 */

static UA_StatusCode function_namespace0_generated_12_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "SubscriptionDiagnosticsDataType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 874LU),UA_NODEID_NUMERIC(ns[0], 22LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "SubscriptionDiagnosticsDataType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_12_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 874LU));
}

/* ServiceCounterDataType - ns=0;i=871 */

static UA_StatusCode function_namespace0_generated_13_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ServiceCounterDataType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 871LU),UA_NODEID_NUMERIC(ns[0], 22LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "ServiceCounterDataType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_13_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 871LU));
}

/* SessionSecurityDiagnosticsDataType - ns=0;i=868 */

static UA_StatusCode function_namespace0_generated_14_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "SessionSecurityDiagnosticsDataType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 868LU),UA_NODEID_NUMERIC(ns[0], 22LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "SessionSecurityDiagnosticsDataType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_14_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 868LU));
}

/* SessionDiagnosticsDataType - ns=0;i=865 */

static UA_StatusCode function_namespace0_generated_15_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "SessionDiagnosticsDataType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 865LU),UA_NODEID_NUMERIC(ns[0], 22LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "SessionDiagnosticsDataType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_15_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 865LU));
}

/* ServerStatusDataType - ns=0;i=862 */

static UA_StatusCode function_namespace0_generated_16_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ServerStatusDataType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 862LU),UA_NODEID_NUMERIC(ns[0], 22LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "ServerStatusDataType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_16_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 862LU));
}

/* ServerDiagnosticsSummaryDataType - ns=0;i=859 */

static UA_StatusCode function_namespace0_generated_17_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ServerDiagnosticsSummaryDataType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 859LU),UA_NODEID_NUMERIC(ns[0], 22LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "ServerDiagnosticsSummaryDataType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_17_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 859LU));
}

/* SamplingIntervalDiagnosticsDataType - ns=0;i=856 */

static UA_StatusCode function_namespace0_generated_18_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "SamplingIntervalDiagnosticsDataType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 856LU),UA_NODEID_NUMERIC(ns[0], 22LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "SamplingIntervalDiagnosticsDataType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_18_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 856LU));
}

/* EnumValueType - ns=0;i=7594 */

static UA_StatusCode function_namespace0_generated_19_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "EnumValueType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 7594LU),UA_NODEID_NUMERIC(ns[0], 22LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "EnumValueType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_19_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 7594LU));
}

/* SignedSoftwareCertificate - ns=0;i=344 */

static UA_StatusCode function_namespace0_generated_20_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "SignedSoftwareCertificate");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 344LU),UA_NODEID_NUMERIC(ns[0], 22LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "SignedSoftwareCertificate"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_20_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 344LU));
}

/* BuildInfo - ns=0;i=338 */

static UA_StatusCode function_namespace0_generated_21_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "BuildInfo");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 338LU),UA_NODEID_NUMERIC(ns[0], 22LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "BuildInfo"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_21_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 338LU));
}

/* ApplicationDescription - ns=0;i=308 */

static UA_StatusCode function_namespace0_generated_22_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ApplicationDescription");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 308LU),UA_NODEID_NUMERIC(ns[0], 22LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "ApplicationDescription"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_22_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 308LU));
}

/* Argument - ns=0;i=296 */

static UA_StatusCode function_namespace0_generated_23_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Argument");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 296LU),UA_NODEID_NUMERIC(ns[0], 22LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "Argument"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_23_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 296LU));
}

/* Union - ns=0;i=12756 */

static UA_StatusCode function_namespace0_generated_24_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "Union");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 12756LU),UA_NODEID_NUMERIC(ns[0], 22LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "Union"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_24_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12756LU));
}

/* TrustListDataType - ns=0;i=12554 */

static UA_StatusCode function_namespace0_generated_25_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "TrustListDataType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 12554LU),UA_NODEID_NUMERIC(ns[0], 22LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "TrustListDataType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_25_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12554LU));
}

/* LocalizedText - ns=0;i=21 */

static UA_StatusCode function_namespace0_generated_26_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "LocalizedText");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 21LU),UA_NODEID_NUMERIC(ns[0], 24LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "LocalizedText"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_26_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 21LU));
}

/* QualifiedName - ns=0;i=20 */

static UA_StatusCode function_namespace0_generated_27_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "QualifiedName");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 20LU),UA_NODEID_NUMERIC(ns[0], 24LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "QualifiedName"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_27_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 20LU));
}

/* StatusCode - ns=0;i=19 */

static UA_StatusCode function_namespace0_generated_28_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "StatusCode");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 19LU),UA_NODEID_NUMERIC(ns[0], 24LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "StatusCode"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_28_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 19LU));
}

/* ExpandedNodeId - ns=0;i=18 */

static UA_StatusCode function_namespace0_generated_29_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ExpandedNodeId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 18LU),UA_NODEID_NUMERIC(ns[0], 24LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "ExpandedNodeId"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_29_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 18LU));
}

/* NodeId - ns=0;i=17 */

static UA_StatusCode function_namespace0_generated_30_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "NodeId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 17LU),UA_NODEID_NUMERIC(ns[0], 24LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "NodeId"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_30_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 17LU));
}

/* XmlElement - ns=0;i=16 */

static UA_StatusCode function_namespace0_generated_31_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "XmlElement");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 16LU),UA_NODEID_NUMERIC(ns[0], 24LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "XmlElement"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_31_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 16LU));
}

/* ByteString - ns=0;i=15 */

static UA_StatusCode function_namespace0_generated_32_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ByteString");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 15LU),UA_NODEID_NUMERIC(ns[0], 24LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "ByteString"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_32_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 15LU));
}

/* Image - ns=0;i=30 */

static UA_StatusCode function_namespace0_generated_33_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "Image");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 30LU),UA_NODEID_NUMERIC(ns[0], 15LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "Image"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_33_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 30LU));
}

/* Guid - ns=0;i=14 */

static UA_StatusCode function_namespace0_generated_34_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Guid");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 14LU),UA_NODEID_NUMERIC(ns[0], 24LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "Guid"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_34_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 14LU));
}

/* DateTime - ns=0;i=13 */

static UA_StatusCode function_namespace0_generated_35_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "DateTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 13LU),UA_NODEID_NUMERIC(ns[0], 24LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "DateTime"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_35_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 13LU));
}

/* UtcTime - ns=0;i=294 */

static UA_StatusCode function_namespace0_generated_36_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "UtcTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 294LU),UA_NODEID_NUMERIC(ns[0], 13LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "UtcTime"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_36_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 294LU));
}

/* String - ns=0;i=12 */

static UA_StatusCode function_namespace0_generated_37_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "String");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 12LU),UA_NODEID_NUMERIC(ns[0], 24LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "String"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_37_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12LU));
}

/* LocaleId - ns=0;i=295 */

static UA_StatusCode function_namespace0_generated_38_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "LocaleId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 295LU),UA_NODEID_NUMERIC(ns[0], 12LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "LocaleId"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_38_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 295LU));
}

/* Boolean - ns=0;i=1 */

static UA_StatusCode function_namespace0_generated_39_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Boolean");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 1LU),UA_NODEID_NUMERIC(ns[0], 24LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "Boolean"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_39_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 1LU));
}

/* Enumeration - ns=0;i=29 */

static UA_StatusCode function_namespace0_generated_40_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "Enumeration");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 29LU),UA_NODEID_NUMERIC(ns[0], 24LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "Enumeration"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_40_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 29LU));
}

/* ServerState - ns=0;i=852 */

static UA_StatusCode function_namespace0_generated_41_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ServerState");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 852LU),UA_NODEID_NUMERIC(ns[0], 29LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "ServerState"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_41_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 852LU));
}

/* RedundancySupport - ns=0;i=851 */

static UA_StatusCode function_namespace0_generated_42_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "RedundancySupport");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 851LU),UA_NODEID_NUMERIC(ns[0], 29LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "RedundancySupport"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_42_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 851LU));
}

/* EnumStrings - ns=0;i=7611 */

static UA_StatusCode function_namespace0_generated_43_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 21LU);
UA_LocalizedText variablenode_ns_0_i_7611_variant_DataContents[6];
variablenode_ns_0_i_7611_variant_DataContents[0] = UA_LOCALIZEDTEXT("", "None");
variablenode_ns_0_i_7611_variant_DataContents[1] = UA_LOCALIZEDTEXT("", "Cold");
variablenode_ns_0_i_7611_variant_DataContents[2] = UA_LOCALIZEDTEXT("", "Warm");
variablenode_ns_0_i_7611_variant_DataContents[3] = UA_LOCALIZEDTEXT("", "Hot");
variablenode_ns_0_i_7611_variant_DataContents[4] = UA_LOCALIZEDTEXT("", "Transparent");
variablenode_ns_0_i_7611_variant_DataContents[5] = UA_LOCALIZEDTEXT("", "HotAndMirrored");
UA_Variant_setArray(&attr.value, &variablenode_ns_0_i_7611_variant_DataContents, (UA_Int32) 6, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
attr.displayName = UA_LOCALIZEDTEXT("", "EnumStrings");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 7611LU),UA_NODEID_NUMERIC(ns[0], 851LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "EnumStrings"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_43_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 7611LU));
}

/* ApplicationType - ns=0;i=307 */

static UA_StatusCode function_namespace0_generated_44_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ApplicationType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 307LU),UA_NODEID_NUMERIC(ns[0], 29LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "ApplicationType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_44_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 307LU));
}

/* EnumStrings - ns=0;i=7597 */

static UA_StatusCode function_namespace0_generated_45_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 21LU);
UA_LocalizedText variablenode_ns_0_i_7597_variant_DataContents[4];
variablenode_ns_0_i_7597_variant_DataContents[0] = UA_LOCALIZEDTEXT("", "Server");
variablenode_ns_0_i_7597_variant_DataContents[1] = UA_LOCALIZEDTEXT("", "Client");
variablenode_ns_0_i_7597_variant_DataContents[2] = UA_LOCALIZEDTEXT("", "ClientAndServer");
variablenode_ns_0_i_7597_variant_DataContents[3] = UA_LOCALIZEDTEXT("", "DiscoveryServer");
UA_Variant_setArray(&attr.value, &variablenode_ns_0_i_7597_variant_DataContents, (UA_Int32) 4, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
attr.displayName = UA_LOCALIZEDTEXT("", "EnumStrings");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 7597LU),UA_NODEID_NUMERIC(ns[0], 307LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "EnumStrings"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_45_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 7597LU));
}

/* MessageSecurityMode - ns=0;i=302 */

static UA_StatusCode function_namespace0_generated_46_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "MessageSecurityMode");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 302LU),UA_NODEID_NUMERIC(ns[0], 29LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "MessageSecurityMode"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_46_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 302LU));
}

/* EnumStrings - ns=0;i=7595 */

static UA_StatusCode function_namespace0_generated_47_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 21LU);
UA_LocalizedText variablenode_ns_0_i_7595_variant_DataContents[4];
variablenode_ns_0_i_7595_variant_DataContents[0] = UA_LOCALIZEDTEXT("", "Invalid");
variablenode_ns_0_i_7595_variant_DataContents[1] = UA_LOCALIZEDTEXT("", "None");
variablenode_ns_0_i_7595_variant_DataContents[2] = UA_LOCALIZEDTEXT("", "Sign");
variablenode_ns_0_i_7595_variant_DataContents[3] = UA_LOCALIZEDTEXT("", "SignAndEncrypt");
UA_Variant_setArray(&attr.value, &variablenode_ns_0_i_7595_variant_DataContents, (UA_Int32) 4, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
attr.displayName = UA_LOCALIZEDTEXT("", "EnumStrings");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 7595LU),UA_NODEID_NUMERIC(ns[0], 302LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "EnumStrings"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_47_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 7595LU));
}

/* AxisScaleEnumeration - ns=0;i=12077 */

static UA_StatusCode function_namespace0_generated_48_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "AxisScaleEnumeration");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 12077LU),UA_NODEID_NUMERIC(ns[0], 29LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "AxisScaleEnumeration"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_48_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12077LU));
}

/* EnumStrings - ns=0;i=12078 */

static UA_StatusCode function_namespace0_generated_49_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 21LU);
UA_LocalizedText variablenode_ns_0_i_12078_variant_DataContents[3];
variablenode_ns_0_i_12078_variant_DataContents[0] = UA_LOCALIZEDTEXT("", "Linear");
variablenode_ns_0_i_12078_variant_DataContents[1] = UA_LOCALIZEDTEXT("", "Log");
variablenode_ns_0_i_12078_variant_DataContents[2] = UA_LOCALIZEDTEXT("", "Ln");
UA_Variant_setArray(&attr.value, &variablenode_ns_0_i_12078_variant_DataContents, (UA_Int32) 3, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
attr.displayName = UA_LOCALIZEDTEXT("", "EnumStrings");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12078LU),UA_NODEID_NUMERIC(ns[0], 12077LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "EnumStrings"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_49_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12078LU));
}

/* NamingRuleType - ns=0;i=120 */

static UA_StatusCode function_namespace0_generated_50_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "NamingRuleType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 120LU),UA_NODEID_NUMERIC(ns[0], 29LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "NamingRuleType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_50_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 120LU));
}

/* EnumValues - ns=0;i=12169 */

static UA_StatusCode function_namespace0_generated_51_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7594LU);
UA_EnumValueType variablenode_ns_0_i_12169_variant_DataContents[3];

UA_init(&variablenode_ns_0_i_12169_variant_DataContents[0], &UA_TYPES[UA_TYPES_ENUMVALUETYPE]);
variablenode_ns_0_i_12169_variant_DataContents[0].value = (UA_Int64) 1;
variablenode_ns_0_i_12169_variant_DataContents[0].displayName = UA_LOCALIZEDTEXT("", "Mandatory");
variablenode_ns_0_i_12169_variant_DataContents[0].description = UA_LOCALIZEDTEXT("", "The BrowseName must appear in all instances of the type.");

UA_init(&variablenode_ns_0_i_12169_variant_DataContents[1], &UA_TYPES[UA_TYPES_ENUMVALUETYPE]);
variablenode_ns_0_i_12169_variant_DataContents[1].value = (UA_Int64) 2;
variablenode_ns_0_i_12169_variant_DataContents[1].displayName = UA_LOCALIZEDTEXT("", "Optional");
variablenode_ns_0_i_12169_variant_DataContents[1].description = UA_LOCALIZEDTEXT("", "The BrowseName may appear in an instance of the type.");

UA_init(&variablenode_ns_0_i_12169_variant_DataContents[2], &UA_TYPES[UA_TYPES_ENUMVALUETYPE]);
variablenode_ns_0_i_12169_variant_DataContents[2].value = (UA_Int64) 3;
variablenode_ns_0_i_12169_variant_DataContents[2].displayName = UA_LOCALIZEDTEXT("", "Constraint");
variablenode_ns_0_i_12169_variant_DataContents[2].description = UA_LOCALIZEDTEXT("", "The modelling rule defines a constraint and the BrowseName is not used in an instance of the type.");
UA_Variant_setArray(&attr.value, &variablenode_ns_0_i_12169_variant_DataContents, (UA_Int32) 3, &UA_TYPES[UA_TYPES_ENUMVALUETYPE]);
attr.displayName = UA_LOCALIZEDTEXT("", "EnumValues");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12169LU),UA_NODEID_NUMERIC(ns[0], 120LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "EnumValues"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);



return retVal;
}

static UA_StatusCode function_namespace0_generated_51_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12169LU));
}

/* Number - ns=0;i=26 */

static UA_StatusCode function_namespace0_generated_52_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "Number");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 26LU),UA_NODEID_NUMERIC(ns[0], 24LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "Number"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_52_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 26LU));
}

/* Decimal - ns=0;i=50 */

static UA_StatusCode function_namespace0_generated_53_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Decimal");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 50LU),UA_NODEID_NUMERIC(ns[0], 26LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "Decimal"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_53_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 50LU));
}

/* UInteger - ns=0;i=28 */

static UA_StatusCode function_namespace0_generated_54_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "UInteger");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 28LU),UA_NODEID_NUMERIC(ns[0], 26LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "UInteger"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_54_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 28LU));
}

/* UInt64 - ns=0;i=9 */

static UA_StatusCode function_namespace0_generated_55_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "UInt64");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 9LU),UA_NODEID_NUMERIC(ns[0], 28LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "UInt64"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_55_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 9LU));
}

/* UInt32 - ns=0;i=7 */

static UA_StatusCode function_namespace0_generated_56_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "UInt32");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 7LU),UA_NODEID_NUMERIC(ns[0], 28LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "UInt32"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_56_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 7LU));
}

/* UInt16 - ns=0;i=5 */

static UA_StatusCode function_namespace0_generated_57_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "UInt16");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 5LU),UA_NODEID_NUMERIC(ns[0], 28LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "UInt16"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_57_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 5LU));
}

/* Byte - ns=0;i=3 */

static UA_StatusCode function_namespace0_generated_58_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Byte");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 3LU),UA_NODEID_NUMERIC(ns[0], 28LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "Byte"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_58_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3LU));
}

/* Integer - ns=0;i=27 */

static UA_StatusCode function_namespace0_generated_59_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "Integer");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 27LU),UA_NODEID_NUMERIC(ns[0], 26LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "Integer"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_59_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 27LU));
}

/* Int64 - ns=0;i=8 */

static UA_StatusCode function_namespace0_generated_60_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Int64");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 8LU),UA_NODEID_NUMERIC(ns[0], 27LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "Int64"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_60_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 8LU));
}

/* Int32 - ns=0;i=6 */

static UA_StatusCode function_namespace0_generated_61_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Int32");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 6LU),UA_NODEID_NUMERIC(ns[0], 27LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "Int32"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_61_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 6LU));
}

/* Int16 - ns=0;i=4 */

static UA_StatusCode function_namespace0_generated_62_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Int16");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 4LU),UA_NODEID_NUMERIC(ns[0], 27LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "Int16"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_62_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 4LU));
}

/* SByte - ns=0;i=2 */

static UA_StatusCode function_namespace0_generated_63_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "SByte");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 2LU),UA_NODEID_NUMERIC(ns[0], 27LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "SByte"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_63_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2LU));
}

/* Double - ns=0;i=11 */

static UA_StatusCode function_namespace0_generated_64_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Double");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 11LU),UA_NODEID_NUMERIC(ns[0], 26LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "Double"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_64_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11LU));
}

/* Duration - ns=0;i=290 */

static UA_StatusCode function_namespace0_generated_65_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Duration");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 290LU),UA_NODEID_NUMERIC(ns[0], 11LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "Duration"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_65_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 290LU));
}

/* Float - ns=0;i=10 */

static UA_StatusCode function_namespace0_generated_66_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Float");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_DATATYPE,UA_NODEID_NUMERIC(ns[0], 10LU),UA_NODEID_NUMERIC(ns[0], 26LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "Float"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_DATATYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_66_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 10LU));
}

/* DataItemType - ns=0;i=2365 */

static UA_StatusCode function_namespace0_generated_67_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
attr.valueRank = -2;
/* DataType inherited */
attr.dataType = UA_NODEID_NUMERIC(ns[0], 24LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DataItemType");

#ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS

attr.description = UA_LOCALIZEDTEXT("", "A variable that contains live automation data.");

#endif

retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(ns[0], 2365LU),UA_NODEID_NUMERIC(ns[0], 63LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "DataItemType"),UA_NODEID_NUMERIC(ns[0], 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_67_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2365LU));
}

/* DiscreteItemType - ns=0;i=2372 */

static UA_StatusCode function_namespace0_generated_68_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
attr.isAbstract = true;
attr.valueRank = -2;
/* DataType inherited */
attr.dataType = UA_NODEID_NUMERIC(ns[0], 24LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DiscreteItemType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(ns[0], 2372LU),UA_NODEID_NUMERIC(ns[0], 2365LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "DiscreteItemType"),UA_NODEID_NUMERIC(ns[0], 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_68_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2372LU));
}

/* MultiStateDiscreteType - ns=0;i=2376 */

static UA_StatusCode function_namespace0_generated_69_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 28LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MultiStateDiscreteType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(ns[0], 2376LU),UA_NODEID_NUMERIC(ns[0], 2372LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "MultiStateDiscreteType"),UA_NODEID_NUMERIC(ns[0], 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_69_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2376LU));
}

/* EnumStrings - ns=0;i=2377 */

static UA_StatusCode function_namespace0_generated_70_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 21LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EnumStrings");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2377LU),UA_NODEID_NUMERIC(ns[0], 2376LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "EnumStrings"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_70_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2377LU));
}

/* TwoStateDiscreteType - ns=0;i=2373 */

static UA_StatusCode function_namespace0_generated_71_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TwoStateDiscreteType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(ns[0], 2373LU),UA_NODEID_NUMERIC(ns[0], 2372LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "TwoStateDiscreteType"),UA_NODEID_NUMERIC(ns[0], 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_71_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2373LU));
}

/* TrueState - ns=0;i=2375 */

static UA_StatusCode function_namespace0_generated_72_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 21LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TrueState");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2375LU),UA_NODEID_NUMERIC(ns[0], 2373LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "TrueState"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_72_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2375LU));
}

/* FalseState - ns=0;i=2374 */

static UA_StatusCode function_namespace0_generated_73_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 21LU);
attr.displayName = UA_LOCALIZEDTEXT("", "FalseState");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2374LU),UA_NODEID_NUMERIC(ns[0], 2373LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "FalseState"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_73_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2374LU));
}

/* MultiStateValueDiscreteType - ns=0;i=11238 */

static UA_StatusCode function_namespace0_generated_74_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 26LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MultiStateValueDiscreteType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(ns[0], 11238LU),UA_NODEID_NUMERIC(ns[0], 2372LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "MultiStateValueDiscreteType"),UA_NODEID_NUMERIC(ns[0], 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_74_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11238LU));
}

/* ValueAsText - ns=0;i=11461 */

static UA_StatusCode function_namespace0_generated_75_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 21LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ValueAsText");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11461LU),UA_NODEID_NUMERIC(ns[0], 11238LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "ValueAsText"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_75_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11461LU));
}

/* EnumValues - ns=0;i=11241 */

static UA_StatusCode function_namespace0_generated_76_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7594LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EnumValues");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11241LU),UA_NODEID_NUMERIC(ns[0], 11238LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "EnumValues"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_76_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11241LU));
}

/* AnalogItemType - ns=0;i=2368 */

static UA_StatusCode function_namespace0_generated_77_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 26LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AnalogItemType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(ns[0], 2368LU),UA_NODEID_NUMERIC(ns[0], 2365LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "AnalogItemType"),UA_NODEID_NUMERIC(ns[0], 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_77_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2368LU));
}

/* EngineeringUnits - ns=0;i=2371 */

static UA_StatusCode function_namespace0_generated_78_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 887LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EngineeringUnits");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2371LU),UA_NODEID_NUMERIC(ns[0], 2368LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "EngineeringUnits"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_78_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2371LU));
}

/* InstrumentRange - ns=0;i=2370 */

static UA_StatusCode function_namespace0_generated_79_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 884LU);
attr.displayName = UA_LOCALIZEDTEXT("", "InstrumentRange");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2370LU),UA_NODEID_NUMERIC(ns[0], 2368LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "InstrumentRange"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_79_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2370LU));
}

/* EURange - ns=0;i=2369 */

static UA_StatusCode function_namespace0_generated_80_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 3;
attr.accessLevel = 3;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 884LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EURange");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2369LU),UA_NODEID_NUMERIC(ns[0], 2368LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "EURange"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_80_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2369LU));
}

/* ValuePrecision - ns=0;i=2367 */

static UA_StatusCode function_namespace0_generated_81_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 11LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ValuePrecision");

#ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS

attr.description = UA_LOCALIZEDTEXT("", "The maximum precision that the server can maintain for the item based on restrictions in the target environment.");

#endif

retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2367LU),UA_NODEID_NUMERIC(ns[0], 2365LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "ValuePrecision"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_81_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2367LU));
}

/* Definition - ns=0;i=2366 */

static UA_StatusCode function_namespace0_generated_82_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Definition");

#ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS

attr.description = UA_LOCALIZEDTEXT("", "A vendor-specific, human readable string that specifies how the value of this DataItem is calculated.");

#endif

retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2366LU),UA_NODEID_NUMERIC(ns[0], 2365LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "Definition"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_82_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2366LU));
}

/* HistoryServerCapabilitiesType - ns=0;i=2330 */

static UA_StatusCode function_namespace0_generated_83_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "HistoryServerCapabilitiesType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(ns[0], 2330LU),UA_NODEID_NUMERIC(ns[0], 58LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "HistoryServerCapabilitiesType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_83_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2330LU));
}

/* EventQueueOverflowEventType - ns=0;i=3035 */

static UA_StatusCode function_namespace0_generated_84_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "EventQueueOverflowEventType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(ns[0], 3035LU),UA_NODEID_NUMERIC(ns[0], 2041LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "EventQueueOverflowEventType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_84_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3035LU));
}

/* Severity - ns=0;i=2051 */

static UA_StatusCode function_namespace0_generated_85_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 5LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Severity");

#ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS

attr.description = UA_LOCALIZEDTEXT("", "Indicates how urgent an event is.");

#endif

retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2051LU),UA_NODEID_NUMERIC(ns[0], 2041LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "Severity"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_85_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2051LU));
}

/* Message - ns=0;i=2050 */

static UA_StatusCode function_namespace0_generated_86_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 21LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Message");

#ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS

attr.description = UA_LOCALIZEDTEXT("", "A localized description of the event.");

#endif

retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2050LU),UA_NODEID_NUMERIC(ns[0], 2041LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "Message"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_86_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2050LU));
}

/* LocalTime - ns=0;i=3190 */

static UA_StatusCode function_namespace0_generated_87_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 8912LU);
attr.displayName = UA_LOCALIZEDTEXT("", "LocalTime");

#ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS

attr.description = UA_LOCALIZEDTEXT("", "Information about the local time where the event originated.");

#endif

retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3190LU),UA_NODEID_NUMERIC(ns[0], 2041LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "LocalTime"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_87_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3190LU));
}

/* ReceiveTime - ns=0;i=2047 */

static UA_StatusCode function_namespace0_generated_88_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ReceiveTime");

#ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS

attr.description = UA_LOCALIZEDTEXT("", "When the server received the event from the underlying system.");

#endif

retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2047LU),UA_NODEID_NUMERIC(ns[0], 2041LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "ReceiveTime"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_88_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2047LU));
}

/* Time - ns=0;i=2046 */

static UA_StatusCode function_namespace0_generated_89_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Time");

#ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS

attr.description = UA_LOCALIZEDTEXT("", "When the event occurred.");

#endif

retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2046LU),UA_NODEID_NUMERIC(ns[0], 2041LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "Time"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_89_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2046LU));
}

/* SourceName - ns=0;i=2045 */

static UA_StatusCode function_namespace0_generated_90_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SourceName");

#ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS

attr.description = UA_LOCALIZEDTEXT("", "A description of the source of the event.");

#endif

retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2045LU),UA_NODEID_NUMERIC(ns[0], 2041LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "SourceName"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_90_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2045LU));
}

/* SourceNode - ns=0;i=2044 */

static UA_StatusCode function_namespace0_generated_91_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 17LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SourceNode");

#ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS

attr.description = UA_LOCALIZEDTEXT("", "The source of the event.");

#endif

retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2044LU),UA_NODEID_NUMERIC(ns[0], 2041LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "SourceNode"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_91_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2044LU));
}

/* EventType - ns=0;i=2043 */

static UA_StatusCode function_namespace0_generated_92_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 17LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EventType");

#ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS

attr.description = UA_LOCALIZEDTEXT("", "The identifier for the event type.");

#endif

retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2043LU),UA_NODEID_NUMERIC(ns[0], 2041LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "EventType"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_92_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2043LU));
}

/* EventId - ns=0;i=2042 */

static UA_StatusCode function_namespace0_generated_93_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 15LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EventId");

#ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS

attr.description = UA_LOCALIZEDTEXT("", "A globally unique identifier for the event.");

#endif

retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2042LU),UA_NODEID_NUMERIC(ns[0], 2041LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "EventId"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_93_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2042LU));
}

/* SessionDiagnosticsVariableType - ns=0;i=2197 */

static UA_StatusCode function_namespace0_generated_94_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 865LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionDiagnosticsVariableType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 63LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "SessionDiagnosticsVariableType"),UA_NODEID_NUMERIC(ns[0], 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_94_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2197LU));
}

/* TotalRequestCount - ns=0;i=8900 */

static UA_StatusCode function_namespace0_generated_95_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TotalRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 8900LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "TotalRequestCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_95_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 8900LU));
}

/* MaxResponseMessageSize - ns=0;i=3050 */

static UA_StatusCode function_namespace0_generated_96_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxResponseMessageSize");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3050LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "MaxResponseMessageSize"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_96_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3050LU));
}

/* UnregisterNodesCount - ns=0;i=2731 */

static UA_StatusCode function_namespace0_generated_97_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "UnregisterNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2731LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "UnregisterNodesCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_97_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2731LU));
}

/* RegisterNodesCount - ns=0;i=2730 */

static UA_StatusCode function_namespace0_generated_98_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RegisterNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2730LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "RegisterNodesCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_98_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2730LU));
}

/* QueryNextCount - ns=0;i=2242 */

static UA_StatusCode function_namespace0_generated_99_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "QueryNextCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2242LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "QueryNextCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_99_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2242LU));
}

/* QueryFirstCount - ns=0;i=2241 */

static UA_StatusCode function_namespace0_generated_100_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "QueryFirstCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2241LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "QueryFirstCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_100_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2241LU));
}

/* TranslateBrowsePathsToNodeIdsCount - ns=0;i=2240 */

static UA_StatusCode function_namespace0_generated_101_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TranslateBrowsePathsToNodeIdsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2240LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "TranslateBrowsePathsToNodeIdsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_101_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2240LU));
}

/* BrowseNextCount - ns=0;i=2239 */

static UA_StatusCode function_namespace0_generated_102_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "BrowseNextCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2239LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "BrowseNextCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_102_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2239LU));
}

/* BrowseCount - ns=0;i=2238 */

static UA_StatusCode function_namespace0_generated_103_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "BrowseCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2238LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "BrowseCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_103_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2238LU));
}

/* DeleteReferencesCount - ns=0;i=2237 */

static UA_StatusCode function_namespace0_generated_104_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteReferencesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2237LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "DeleteReferencesCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_104_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2237LU));
}

/* DeleteNodesCount - ns=0;i=2236 */

static UA_StatusCode function_namespace0_generated_105_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2236LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "DeleteNodesCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_105_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2236LU));
}

/* AddReferencesCount - ns=0;i=2235 */

static UA_StatusCode function_namespace0_generated_106_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AddReferencesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2235LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "AddReferencesCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_106_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2235LU));
}

/* AddNodesCount - ns=0;i=2234 */

static UA_StatusCode function_namespace0_generated_107_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AddNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2234LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "AddNodesCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_107_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2234LU));
}

/* DeleteSubscriptionsCount - ns=0;i=2233 */

static UA_StatusCode function_namespace0_generated_108_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteSubscriptionsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2233LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "DeleteSubscriptionsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_108_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2233LU));
}

/* TransferSubscriptionsCount - ns=0;i=2232 */

static UA_StatusCode function_namespace0_generated_109_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransferSubscriptionsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2232LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "TransferSubscriptionsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_109_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2232LU));
}

/* RepublishCount - ns=0;i=2231 */

static UA_StatusCode function_namespace0_generated_110_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RepublishCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2231LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "RepublishCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_110_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2231LU));
}

/* PublishCount - ns=0;i=2230 */

static UA_StatusCode function_namespace0_generated_111_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublishCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2230LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "PublishCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_111_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2230LU));
}

/* SetPublishingModeCount - ns=0;i=2229 */

static UA_StatusCode function_namespace0_generated_112_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SetPublishingModeCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2229LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SetPublishingModeCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_112_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2229LU));
}

/* ModifySubscriptionCount - ns=0;i=2228 */

static UA_StatusCode function_namespace0_generated_113_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ModifySubscriptionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2228LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ModifySubscriptionCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_113_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2228LU));
}

/* CreateSubscriptionCount - ns=0;i=2227 */

static UA_StatusCode function_namespace0_generated_114_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CreateSubscriptionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2227LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CreateSubscriptionCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_114_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2227LU));
}

/* DeleteMonitoredItemsCount - ns=0;i=2226 */

static UA_StatusCode function_namespace0_generated_115_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2226LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "DeleteMonitoredItemsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_115_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2226LU));
}

/* SetTriggeringCount - ns=0;i=2225 */

static UA_StatusCode function_namespace0_generated_116_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SetTriggeringCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2225LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SetTriggeringCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_116_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2225LU));
}

/* SetMonitoringModeCount - ns=0;i=2224 */

static UA_StatusCode function_namespace0_generated_117_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SetMonitoringModeCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2224LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SetMonitoringModeCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_117_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2224LU));
}

/* ModifyMonitoredItemsCount - ns=0;i=2223 */

static UA_StatusCode function_namespace0_generated_118_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ModifyMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2223LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ModifyMonitoredItemsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_118_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2223LU));
}

/* CreateMonitoredItemsCount - ns=0;i=2222 */

static UA_StatusCode function_namespace0_generated_119_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CreateMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2222LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CreateMonitoredItemsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_119_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2222LU));
}

/* CallCount - ns=0;i=2221 */

static UA_StatusCode function_namespace0_generated_120_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CallCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2221LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CallCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_120_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2221LU));
}

/* HistoryUpdateCount - ns=0;i=2220 */

static UA_StatusCode function_namespace0_generated_121_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "HistoryUpdateCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2220LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "HistoryUpdateCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_121_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2220LU));
}

/* WriteCount - ns=0;i=2219 */

static UA_StatusCode function_namespace0_generated_122_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "WriteCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2219LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "WriteCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_122_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2219LU));
}

/* HistoryReadCount - ns=0;i=2218 */

static UA_StatusCode function_namespace0_generated_123_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "HistoryReadCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2218LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "HistoryReadCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_123_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2218LU));
}

/* ReadCount - ns=0;i=2217 */

static UA_StatusCode function_namespace0_generated_124_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ReadCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2217LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ReadCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_124_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2217LU));
}

/* CurrentPublishRequestsInQueue - ns=0;i=2209 */

static UA_StatusCode function_namespace0_generated_125_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentPublishRequestsInQueue");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2209LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CurrentPublishRequestsInQueue"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_125_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2209LU));
}

/* CurrentMonitoredItemsCount - ns=0;i=2208 */

static UA_StatusCode function_namespace0_generated_126_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2208LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CurrentMonitoredItemsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_126_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2208LU));
}

/* CurrentSubscriptionsCount - ns=0;i=2207 */

static UA_StatusCode function_namespace0_generated_127_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentSubscriptionsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2207LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CurrentSubscriptionsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_127_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2207LU));
}

/* ClientLastContactTime - ns=0;i=2206 */

static UA_StatusCode function_namespace0_generated_128_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientLastContactTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2206LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ClientLastContactTime"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_128_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2206LU));
}

/* ClientConnectionTime - ns=0;i=2205 */

static UA_StatusCode function_namespace0_generated_129_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientConnectionTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2205LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ClientConnectionTime"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_129_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2205LU));
}

/* ActualSessionTimeout - ns=0;i=2204 */

static UA_StatusCode function_namespace0_generated_130_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 290LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ActualSessionTimeout");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2204LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ActualSessionTimeout"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_130_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2204LU));
}

/* LocaleIds - ns=0;i=2203 */

static UA_StatusCode function_namespace0_generated_131_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 295LU);
attr.displayName = UA_LOCALIZEDTEXT("", "LocaleIds");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2203LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "LocaleIds"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_131_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2203LU));
}

/* EndpointUrl - ns=0;i=2202 */

static UA_StatusCode function_namespace0_generated_132_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EndpointUrl");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2202LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "EndpointUrl"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_132_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2202LU));
}

/* ServerUri - ns=0;i=2201 */

static UA_StatusCode function_namespace0_generated_133_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServerUri");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2201LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ServerUri"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_133_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2201LU));
}

/* ClientDescription - ns=0;i=2200 */

static UA_StatusCode function_namespace0_generated_134_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 308LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientDescription");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2200LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ClientDescription"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_134_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2200LU));
}

/* SessionName - ns=0;i=2199 */

static UA_StatusCode function_namespace0_generated_135_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionName");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2199LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionName"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_135_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2199LU));
}

/* SessionId - ns=0;i=2198 */

static UA_StatusCode function_namespace0_generated_136_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 17LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2198LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionId"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_136_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2198LU));
}

/* UnauthorizedRequestCount - ns=0;i=11892 */

static UA_StatusCode function_namespace0_generated_137_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "UnauthorizedRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11892LU),UA_NODEID_NUMERIC(ns[0], 2197LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "UnauthorizedRequestCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_137_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11892LU));
}

/* SubscriptionDiagnosticsType - ns=0;i=2172 */

static UA_StatusCode function_namespace0_generated_138_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 874LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SubscriptionDiagnosticsType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 63LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "SubscriptionDiagnosticsType"),UA_NODEID_NUMERIC(ns[0], 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_138_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2172LU));
}

/* EventQueueOverflowCount - ns=0;i=8902 */

static UA_StatusCode function_namespace0_generated_139_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EventQueueOverflowCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 8902LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "EventQueueOverflowCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_139_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 8902LU));
}

/* NextSequenceNumber - ns=0;i=8897 */

static UA_StatusCode function_namespace0_generated_140_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "NextSequenceNumber");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 8897LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "NextSequenceNumber"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_140_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 8897LU));
}

/* MonitoringQueueOverflowCount - ns=0;i=8896 */

static UA_StatusCode function_namespace0_generated_141_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MonitoringQueueOverflowCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 8896LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "MonitoringQueueOverflowCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_141_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 8896LU));
}

/* DisabledMonitoredItemCount - ns=0;i=8895 */

static UA_StatusCode function_namespace0_generated_142_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DisabledMonitoredItemCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 8895LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "DisabledMonitoredItemCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_142_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 8895LU));
}

/* MonitoredItemCount - ns=0;i=8894 */

static UA_StatusCode function_namespace0_generated_143_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MonitoredItemCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 8894LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "MonitoredItemCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_143_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 8894LU));
}

/* DiscardedMessageCount - ns=0;i=8893 */

static UA_StatusCode function_namespace0_generated_144_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DiscardedMessageCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 8893LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "DiscardedMessageCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_144_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 8893LU));
}

/* UnacknowledgedMessageCount - ns=0;i=8892 */

static UA_StatusCode function_namespace0_generated_145_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "UnacknowledgedMessageCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 8892LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "UnacknowledgedMessageCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_145_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 8892LU));
}

/* CurrentLifetimeCount - ns=0;i=8891 */

static UA_StatusCode function_namespace0_generated_146_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentLifetimeCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 8891LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CurrentLifetimeCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_146_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 8891LU));
}

/* CurrentKeepAliveCount - ns=0;i=8890 */

static UA_StatusCode function_namespace0_generated_147_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentKeepAliveCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 8890LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CurrentKeepAliveCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_147_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 8890LU));
}

/* LatePublishRequestCount - ns=0;i=8889 */

static UA_StatusCode function_namespace0_generated_148_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "LatePublishRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 8889LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "LatePublishRequestCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_148_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 8889LU));
}

/* MaxLifetimeCount - ns=0;i=8888 */

static UA_StatusCode function_namespace0_generated_149_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxLifetimeCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 8888LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "MaxLifetimeCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_149_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 8888LU));
}

/* EventNotificationsCount - ns=0;i=2998 */

static UA_StatusCode function_namespace0_generated_150_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EventNotificationsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2998LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "EventNotificationsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_150_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2998LU));
}

/* NotificationsCount - ns=0;i=2193 */

static UA_StatusCode function_namespace0_generated_151_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "NotificationsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2193LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "NotificationsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_151_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2193LU));
}

/* DataChangeNotificationsCount - ns=0;i=2191 */

static UA_StatusCode function_namespace0_generated_152_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DataChangeNotificationsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2191LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "DataChangeNotificationsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_152_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2191LU));
}

/* PublishRequestCount - ns=0;i=2190 */

static UA_StatusCode function_namespace0_generated_153_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublishRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2190LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "PublishRequestCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_153_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2190LU));
}

/* TransferredToSameClientCount - ns=0;i=2189 */

static UA_StatusCode function_namespace0_generated_154_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransferredToSameClientCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2189LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "TransferredToSameClientCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_154_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2189LU));
}

/* TransferredToAltClientCount - ns=0;i=2188 */

static UA_StatusCode function_namespace0_generated_155_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransferredToAltClientCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2188LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "TransferredToAltClientCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_155_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2188LU));
}

/* TransferRequestCount - ns=0;i=2187 */

static UA_StatusCode function_namespace0_generated_156_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransferRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2187LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "TransferRequestCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_156_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2187LU));
}

/* RepublishMessageCount - ns=0;i=2186 */

static UA_StatusCode function_namespace0_generated_157_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RepublishMessageCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2186LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "RepublishMessageCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_157_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2186LU));
}

/* RepublishMessageRequestCount - ns=0;i=2185 */

static UA_StatusCode function_namespace0_generated_158_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RepublishMessageRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2185LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "RepublishMessageRequestCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_158_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2185LU));
}

/* RepublishRequestCount - ns=0;i=2184 */

static UA_StatusCode function_namespace0_generated_159_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RepublishRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2184LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "RepublishRequestCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_159_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2184LU));
}

/* DisableCount - ns=0;i=2183 */

static UA_StatusCode function_namespace0_generated_160_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DisableCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2183LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "DisableCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_160_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2183LU));
}

/* EnableCount - ns=0;i=2182 */

static UA_StatusCode function_namespace0_generated_161_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EnableCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2182LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "EnableCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_161_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2182LU));
}

/* ModifyCount - ns=0;i=2181 */

static UA_StatusCode function_namespace0_generated_162_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ModifyCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2181LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ModifyCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_162_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2181LU));
}

/* PublishingEnabled - ns=0;i=2180 */

static UA_StatusCode function_namespace0_generated_163_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublishingEnabled");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2180LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "PublishingEnabled"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_163_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2180LU));
}

/* MaxNotificationsPerPublish - ns=0;i=2179 */

static UA_StatusCode function_namespace0_generated_164_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNotificationsPerPublish");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2179LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "MaxNotificationsPerPublish"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_164_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2179LU));
}

/* MaxKeepAliveCount - ns=0;i=2177 */

static UA_StatusCode function_namespace0_generated_165_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxKeepAliveCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2177LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "MaxKeepAliveCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_165_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2177LU));
}

/* PublishingInterval - ns=0;i=2176 */

static UA_StatusCode function_namespace0_generated_166_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 290LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublishingInterval");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2176LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "PublishingInterval"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_166_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2176LU));
}

/* Priority - ns=0;i=2175 */

static UA_StatusCode function_namespace0_generated_167_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 3LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Priority");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2175LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "Priority"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_167_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2175LU));
}

/* SubscriptionId - ns=0;i=2174 */

static UA_StatusCode function_namespace0_generated_168_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SubscriptionId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2174LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SubscriptionId"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_168_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2174LU));
}

/* SessionId - ns=0;i=2173 */

static UA_StatusCode function_namespace0_generated_169_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 17LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2173LU),UA_NODEID_NUMERIC(ns[0], 2172LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionId"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_169_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2173LU));
}

/* SubscriptionDiagnosticsArrayType - ns=0;i=2171 */

static UA_StatusCode function_namespace0_generated_170_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 874LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SubscriptionDiagnosticsArrayType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(ns[0], 2171LU),UA_NODEID_NUMERIC(ns[0], 63LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "SubscriptionDiagnosticsArrayType"),UA_NODEID_NUMERIC(ns[0], 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_170_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2171LU));
}

/* SubscriptionDiagnostics - ns=0;i=12784 */

static UA_StatusCode function_namespace0_generated_171_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 874LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SubscriptionDiagnostics");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 2171LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SubscriptionDiagnostics"),UA_NODEID_NUMERIC(ns[0], 2172LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_171_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12784LU));
}

/* EventQueueOverflowCount - ns=0;i=12815 */

static UA_StatusCode function_namespace0_generated_172_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EventQueueOverflowCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12815LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "EventQueueOverflowCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_172_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12815LU));
}

/* NextSequenceNumber - ns=0;i=12814 */

static UA_StatusCode function_namespace0_generated_173_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "NextSequenceNumber");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12814LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "NextSequenceNumber"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_173_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12814LU));
}

/* MonitoringQueueOverflowCount - ns=0;i=12813 */

static UA_StatusCode function_namespace0_generated_174_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MonitoringQueueOverflowCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12813LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "MonitoringQueueOverflowCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_174_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12813LU));
}

/* DisabledMonitoredItemCount - ns=0;i=12812 */

static UA_StatusCode function_namespace0_generated_175_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DisabledMonitoredItemCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12812LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "DisabledMonitoredItemCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_175_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12812LU));
}

/* MonitoredItemCount - ns=0;i=12811 */

static UA_StatusCode function_namespace0_generated_176_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MonitoredItemCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12811LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "MonitoredItemCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_176_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12811LU));
}

/* DiscardedMessageCount - ns=0;i=12810 */

static UA_StatusCode function_namespace0_generated_177_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DiscardedMessageCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12810LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "DiscardedMessageCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_177_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12810LU));
}

/* UnacknowledgedMessageCount - ns=0;i=12809 */

static UA_StatusCode function_namespace0_generated_178_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "UnacknowledgedMessageCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12809LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "UnacknowledgedMessageCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_178_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12809LU));
}

/* CurrentLifetimeCount - ns=0;i=12808 */

static UA_StatusCode function_namespace0_generated_179_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentLifetimeCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12808LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CurrentLifetimeCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_179_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12808LU));
}

/* CurrentKeepAliveCount - ns=0;i=12807 */

static UA_StatusCode function_namespace0_generated_180_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentKeepAliveCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12807LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CurrentKeepAliveCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_180_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12807LU));
}

/* LatePublishRequestCount - ns=0;i=12806 */

static UA_StatusCode function_namespace0_generated_181_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "LatePublishRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12806LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "LatePublishRequestCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_181_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12806LU));
}

/* NotificationsCount - ns=0;i=12805 */

static UA_StatusCode function_namespace0_generated_182_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "NotificationsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12805LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "NotificationsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_182_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12805LU));
}

/* EventNotificationsCount - ns=0;i=12804 */

static UA_StatusCode function_namespace0_generated_183_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EventNotificationsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12804LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "EventNotificationsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_183_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12804LU));
}

/* DataChangeNotificationsCount - ns=0;i=12803 */

static UA_StatusCode function_namespace0_generated_184_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DataChangeNotificationsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12803LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "DataChangeNotificationsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_184_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12803LU));
}

/* PublishRequestCount - ns=0;i=12802 */

static UA_StatusCode function_namespace0_generated_185_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublishRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12802LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "PublishRequestCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_185_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12802LU));
}

/* TransferredToSameClientCount - ns=0;i=12801 */

static UA_StatusCode function_namespace0_generated_186_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransferredToSameClientCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12801LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "TransferredToSameClientCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_186_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12801LU));
}

/* TransferredToAltClientCount - ns=0;i=12800 */

static UA_StatusCode function_namespace0_generated_187_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransferredToAltClientCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12800LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "TransferredToAltClientCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_187_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12800LU));
}

/* TransferRequestCount - ns=0;i=12799 */

static UA_StatusCode function_namespace0_generated_188_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransferRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12799LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "TransferRequestCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_188_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12799LU));
}

/* RepublishMessageCount - ns=0;i=12798 */

static UA_StatusCode function_namespace0_generated_189_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RepublishMessageCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12798LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "RepublishMessageCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_189_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12798LU));
}

/* RepublishMessageRequestCount - ns=0;i=12797 */

static UA_StatusCode function_namespace0_generated_190_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RepublishMessageRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12797LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "RepublishMessageRequestCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_190_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12797LU));
}

/* RepublishRequestCount - ns=0;i=12796 */

static UA_StatusCode function_namespace0_generated_191_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RepublishRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12796LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "RepublishRequestCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_191_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12796LU));
}

/* DisableCount - ns=0;i=12795 */

static UA_StatusCode function_namespace0_generated_192_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DisableCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12795LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "DisableCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_192_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12795LU));
}

/* EnableCount - ns=0;i=12794 */

static UA_StatusCode function_namespace0_generated_193_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EnableCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12794LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "EnableCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_193_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12794LU));
}

/* ModifyCount - ns=0;i=12793 */

static UA_StatusCode function_namespace0_generated_194_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ModifyCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12793LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ModifyCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_194_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12793LU));
}

/* PublishingEnabled - ns=0;i=12792 */

static UA_StatusCode function_namespace0_generated_195_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublishingEnabled");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12792LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "PublishingEnabled"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_195_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12792LU));
}

/* MaxNotificationsPerPublish - ns=0;i=12791 */

static UA_StatusCode function_namespace0_generated_196_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNotificationsPerPublish");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12791LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "MaxNotificationsPerPublish"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_196_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12791LU));
}

/* MaxLifetimeCount - ns=0;i=12790 */

static UA_StatusCode function_namespace0_generated_197_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxLifetimeCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12790LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "MaxLifetimeCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_197_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12790LU));
}

/* MaxKeepAliveCount - ns=0;i=12789 */

static UA_StatusCode function_namespace0_generated_198_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxKeepAliveCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12789LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "MaxKeepAliveCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_198_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12789LU));
}

/* PublishingInterval - ns=0;i=12788 */

static UA_StatusCode function_namespace0_generated_199_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 290LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublishingInterval");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12788LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "PublishingInterval"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_199_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12788LU));
}

/* Priority - ns=0;i=12787 */

static UA_StatusCode function_namespace0_generated_200_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 3LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Priority");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12787LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "Priority"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_200_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12787LU));
}

/* SubscriptionId - ns=0;i=12786 */

static UA_StatusCode function_namespace0_generated_201_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SubscriptionId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12786LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SubscriptionId"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_201_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12786LU));
}

/* SessionId - ns=0;i=12785 */

static UA_StatusCode function_namespace0_generated_202_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 17LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12785LU),UA_NODEID_NUMERIC(ns[0], 12784LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionId"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_202_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12785LU));
}

/* SessionSecurityDiagnosticsType - ns=0;i=2244 */

static UA_StatusCode function_namespace0_generated_203_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 868LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionSecurityDiagnosticsType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(ns[0], 2244LU),UA_NODEID_NUMERIC(ns[0], 63LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "SessionSecurityDiagnosticsType"),UA_NODEID_NUMERIC(ns[0], 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_203_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2244LU));
}

/* ClientCertificate - ns=0;i=3058 */

static UA_StatusCode function_namespace0_generated_204_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 15LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientCertificate");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3058LU),UA_NODEID_NUMERIC(ns[0], 2244LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ClientCertificate"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_204_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3058LU));
}

/* SecurityPolicyUri - ns=0;i=2252 */

static UA_StatusCode function_namespace0_generated_205_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecurityPolicyUri");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2252LU),UA_NODEID_NUMERIC(ns[0], 2244LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SecurityPolicyUri"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_205_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2252LU));
}

/* SecurityMode - ns=0;i=2251 */

static UA_StatusCode function_namespace0_generated_206_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 302LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecurityMode");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2251LU),UA_NODEID_NUMERIC(ns[0], 2244LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SecurityMode"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_206_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2251LU));
}

/* TransportProtocol - ns=0;i=2250 */

static UA_StatusCode function_namespace0_generated_207_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransportProtocol");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2250LU),UA_NODEID_NUMERIC(ns[0], 2244LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "TransportProtocol"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_207_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2250LU));
}

/* Encoding - ns=0;i=2249 */

static UA_StatusCode function_namespace0_generated_208_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Encoding");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2249LU),UA_NODEID_NUMERIC(ns[0], 2244LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "Encoding"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_208_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2249LU));
}

/* AuthenticationMechanism - ns=0;i=2248 */

static UA_StatusCode function_namespace0_generated_209_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AuthenticationMechanism");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2248LU),UA_NODEID_NUMERIC(ns[0], 2244LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "AuthenticationMechanism"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_209_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2248LU));
}

/* ClientUserIdHistory - ns=0;i=2247 */

static UA_StatusCode function_namespace0_generated_210_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientUserIdHistory");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2247LU),UA_NODEID_NUMERIC(ns[0], 2244LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ClientUserIdHistory"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_210_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2247LU));
}

/* ClientUserIdOfSession - ns=0;i=2246 */

static UA_StatusCode function_namespace0_generated_211_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientUserIdOfSession");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2246LU),UA_NODEID_NUMERIC(ns[0], 2244LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ClientUserIdOfSession"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_211_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2246LU));
}

/* SessionId - ns=0;i=2245 */

static UA_StatusCode function_namespace0_generated_212_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 17LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2245LU),UA_NODEID_NUMERIC(ns[0], 2244LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionId"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_212_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2245LU));
}

/* SessionDiagnosticsObjectType - ns=0;i=2029 */

static UA_StatusCode function_namespace0_generated_213_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "SessionDiagnosticsObjectType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(ns[0], 2029LU),UA_NODEID_NUMERIC(ns[0], 58LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "SessionDiagnosticsObjectType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_213_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2029LU));
}

/* SubscriptionDiagnosticsArray - ns=0;i=2032 */

static UA_StatusCode function_namespace0_generated_214_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 874LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SubscriptionDiagnosticsArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2032LU),UA_NODEID_NUMERIC(ns[0], 2029LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SubscriptionDiagnosticsArray"),UA_NODEID_NUMERIC(ns[0], 2171LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_214_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2032LU));
}

/* SessionSecurityDiagnostics - ns=0;i=2031 */

static UA_StatusCode function_namespace0_generated_215_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 868LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionSecurityDiagnostics");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2031LU),UA_NODEID_NUMERIC(ns[0], 2029LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionSecurityDiagnostics"),UA_NODEID_NUMERIC(ns[0], 2244LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_215_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2031LU));
}

/* ClientCertificate - ns=0;i=3187 */

static UA_StatusCode function_namespace0_generated_216_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 15LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientCertificate");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3187LU),UA_NODEID_NUMERIC(ns[0], 2031LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ClientCertificate"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_216_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3187LU));
}

/* SecurityPolicyUri - ns=0;i=3186 */

static UA_StatusCode function_namespace0_generated_217_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecurityPolicyUri");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3186LU),UA_NODEID_NUMERIC(ns[0], 2031LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SecurityPolicyUri"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_217_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3186LU));
}

/* SecurityMode - ns=0;i=3185 */

static UA_StatusCode function_namespace0_generated_218_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 302LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecurityMode");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3185LU),UA_NODEID_NUMERIC(ns[0], 2031LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SecurityMode"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_218_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3185LU));
}

/* TransportProtocol - ns=0;i=3184 */

static UA_StatusCode function_namespace0_generated_219_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransportProtocol");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3184LU),UA_NODEID_NUMERIC(ns[0], 2031LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "TransportProtocol"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_219_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3184LU));
}

/* Encoding - ns=0;i=3183 */

static UA_StatusCode function_namespace0_generated_220_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Encoding");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3183LU),UA_NODEID_NUMERIC(ns[0], 2031LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "Encoding"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_220_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3183LU));
}

/* AuthenticationMechanism - ns=0;i=3182 */

static UA_StatusCode function_namespace0_generated_221_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AuthenticationMechanism");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3182LU),UA_NODEID_NUMERIC(ns[0], 2031LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "AuthenticationMechanism"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_221_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3182LU));
}

/* ClientUserIdHistory - ns=0;i=3181 */

static UA_StatusCode function_namespace0_generated_222_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientUserIdHistory");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3181LU),UA_NODEID_NUMERIC(ns[0], 2031LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ClientUserIdHistory"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_222_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3181LU));
}

/* ClientUserIdOfSession - ns=0;i=3180 */

static UA_StatusCode function_namespace0_generated_223_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientUserIdOfSession");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3180LU),UA_NODEID_NUMERIC(ns[0], 2031LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ClientUserIdOfSession"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_223_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3180LU));
}

/* SessionId - ns=0;i=3179 */

static UA_StatusCode function_namespace0_generated_224_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 17LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3179LU),UA_NODEID_NUMERIC(ns[0], 2031LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionId"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_224_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3179LU));
}

/* SessionDiagnostics - ns=0;i=2030 */

static UA_StatusCode function_namespace0_generated_225_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 865LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionDiagnostics");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 2029LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionDiagnostics"),UA_NODEID_NUMERIC(ns[0], 2197LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_225_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2030LU));
}

/* TotalRequestCount - ns=0;i=8898 */

static UA_StatusCode function_namespace0_generated_226_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TotalRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 8898LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "TotalRequestCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_226_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 8898LU));
}

/* UnregisterNodesCount - ns=0;i=3178 */

static UA_StatusCode function_namespace0_generated_227_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "UnregisterNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3178LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "UnregisterNodesCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_227_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3178LU));
}

/* RegisterNodesCount - ns=0;i=3177 */

static UA_StatusCode function_namespace0_generated_228_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RegisterNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3177LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "RegisterNodesCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_228_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3177LU));
}

/* QueryNextCount - ns=0;i=3176 */

static UA_StatusCode function_namespace0_generated_229_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "QueryNextCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3176LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "QueryNextCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_229_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3176LU));
}

/* QueryFirstCount - ns=0;i=3175 */

static UA_StatusCode function_namespace0_generated_230_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "QueryFirstCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3175LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "QueryFirstCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_230_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3175LU));
}

/* TranslateBrowsePathsToNodeIdsCount - ns=0;i=3174 */

static UA_StatusCode function_namespace0_generated_231_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TranslateBrowsePathsToNodeIdsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3174LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "TranslateBrowsePathsToNodeIdsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_231_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3174LU));
}

/* BrowseNextCount - ns=0;i=3173 */

static UA_StatusCode function_namespace0_generated_232_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "BrowseNextCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3173LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "BrowseNextCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_232_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3173LU));
}

/* BrowseCount - ns=0;i=3172 */

static UA_StatusCode function_namespace0_generated_233_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "BrowseCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3172LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "BrowseCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_233_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3172LU));
}

/* DeleteReferencesCount - ns=0;i=3171 */

static UA_StatusCode function_namespace0_generated_234_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteReferencesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3171LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "DeleteReferencesCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_234_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3171LU));
}

/* DeleteNodesCount - ns=0;i=3170 */

static UA_StatusCode function_namespace0_generated_235_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3170LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "DeleteNodesCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_235_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3170LU));
}

/* AddReferencesCount - ns=0;i=3169 */

static UA_StatusCode function_namespace0_generated_236_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AddReferencesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3169LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "AddReferencesCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_236_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3169LU));
}

/* AddNodesCount - ns=0;i=3168 */

static UA_StatusCode function_namespace0_generated_237_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AddNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3168LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "AddNodesCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_237_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3168LU));
}

/* DeleteSubscriptionsCount - ns=0;i=3167 */

static UA_StatusCode function_namespace0_generated_238_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteSubscriptionsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3167LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "DeleteSubscriptionsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_238_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3167LU));
}

/* TransferSubscriptionsCount - ns=0;i=3166 */

static UA_StatusCode function_namespace0_generated_239_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransferSubscriptionsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3166LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "TransferSubscriptionsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_239_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3166LU));
}

/* RepublishCount - ns=0;i=3165 */

static UA_StatusCode function_namespace0_generated_240_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RepublishCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3165LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "RepublishCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_240_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3165LU));
}

/* PublishCount - ns=0;i=3164 */

static UA_StatusCode function_namespace0_generated_241_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublishCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3164LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "PublishCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_241_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3164LU));
}

/* SetPublishingModeCount - ns=0;i=3163 */

static UA_StatusCode function_namespace0_generated_242_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SetPublishingModeCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3163LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SetPublishingModeCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_242_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3163LU));
}

/* ModifySubscriptionCount - ns=0;i=3162 */

static UA_StatusCode function_namespace0_generated_243_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ModifySubscriptionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3162LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ModifySubscriptionCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_243_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3162LU));
}

/* CreateSubscriptionCount - ns=0;i=3161 */

static UA_StatusCode function_namespace0_generated_244_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CreateSubscriptionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3161LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CreateSubscriptionCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_244_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3161LU));
}

/* DeleteMonitoredItemsCount - ns=0;i=3160 */

static UA_StatusCode function_namespace0_generated_245_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3160LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "DeleteMonitoredItemsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_245_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3160LU));
}

/* SetTriggeringCount - ns=0;i=3159 */

static UA_StatusCode function_namespace0_generated_246_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SetTriggeringCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3159LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SetTriggeringCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_246_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3159LU));
}

/* SetMonitoringModeCount - ns=0;i=3158 */

static UA_StatusCode function_namespace0_generated_247_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SetMonitoringModeCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3158LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SetMonitoringModeCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_247_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3158LU));
}

/* ModifyMonitoredItemsCount - ns=0;i=3157 */

static UA_StatusCode function_namespace0_generated_248_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ModifyMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3157LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ModifyMonitoredItemsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_248_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3157LU));
}

/* CreateMonitoredItemsCount - ns=0;i=3156 */

static UA_StatusCode function_namespace0_generated_249_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CreateMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3156LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CreateMonitoredItemsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_249_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3156LU));
}

/* CallCount - ns=0;i=3155 */

static UA_StatusCode function_namespace0_generated_250_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CallCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3155LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CallCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_250_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3155LU));
}

/* HistoryUpdateCount - ns=0;i=3154 */

static UA_StatusCode function_namespace0_generated_251_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "HistoryUpdateCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3154LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "HistoryUpdateCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_251_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3154LU));
}

/* WriteCount - ns=0;i=3153 */

static UA_StatusCode function_namespace0_generated_252_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "WriteCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3153LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "WriteCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_252_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3153LU));
}

/* HistoryReadCount - ns=0;i=3152 */

static UA_StatusCode function_namespace0_generated_253_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "HistoryReadCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3152LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "HistoryReadCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_253_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3152LU));
}

/* ReadCount - ns=0;i=3151 */

static UA_StatusCode function_namespace0_generated_254_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ReadCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3151LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ReadCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_254_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3151LU));
}

/* CurrentPublishRequestsInQueue - ns=0;i=3143 */

static UA_StatusCode function_namespace0_generated_255_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentPublishRequestsInQueue");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3143LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CurrentPublishRequestsInQueue"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_255_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3143LU));
}

/* CurrentMonitoredItemsCount - ns=0;i=3142 */

static UA_StatusCode function_namespace0_generated_256_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3142LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CurrentMonitoredItemsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_256_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3142LU));
}

/* CurrentSubscriptionsCount - ns=0;i=3141 */

static UA_StatusCode function_namespace0_generated_257_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentSubscriptionsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3141LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CurrentSubscriptionsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_257_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3141LU));
}

/* ClientLastContactTime - ns=0;i=3140 */

static UA_StatusCode function_namespace0_generated_258_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientLastContactTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3140LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ClientLastContactTime"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_258_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3140LU));
}

/* ClientConnectionTime - ns=0;i=3139 */

static UA_StatusCode function_namespace0_generated_259_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientConnectionTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3139LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ClientConnectionTime"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_259_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3139LU));
}

/* MaxResponseMessageSize - ns=0;i=3138 */

static UA_StatusCode function_namespace0_generated_260_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxResponseMessageSize");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3138LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "MaxResponseMessageSize"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_260_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3138LU));
}

/* ActualSessionTimeout - ns=0;i=3137 */

static UA_StatusCode function_namespace0_generated_261_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 290LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ActualSessionTimeout");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3137LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ActualSessionTimeout"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_261_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3137LU));
}

/* LocaleIds - ns=0;i=3136 */

static UA_StatusCode function_namespace0_generated_262_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 295LU);
attr.displayName = UA_LOCALIZEDTEXT("", "LocaleIds");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3136LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "LocaleIds"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_262_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3136LU));
}

/* EndpointUrl - ns=0;i=3135 */

static UA_StatusCode function_namespace0_generated_263_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EndpointUrl");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3135LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "EndpointUrl"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_263_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3135LU));
}

/* ServerUri - ns=0;i=3134 */

static UA_StatusCode function_namespace0_generated_264_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServerUri");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3134LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ServerUri"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_264_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3134LU));
}

/* ClientDescription - ns=0;i=3133 */

static UA_StatusCode function_namespace0_generated_265_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 308LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientDescription");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3133LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ClientDescription"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_265_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3133LU));
}

/* SessionName - ns=0;i=3132 */

static UA_StatusCode function_namespace0_generated_266_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionName");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3132LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionName"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_266_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3132LU));
}

/* SessionId - ns=0;i=3131 */

static UA_StatusCode function_namespace0_generated_267_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 17LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3131LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionId"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_267_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3131LU));
}

/* UnauthorizedRequestCount - ns=0;i=11891 */

static UA_StatusCode function_namespace0_generated_268_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "UnauthorizedRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11891LU),UA_NODEID_NUMERIC(ns[0], 2030LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "UnauthorizedRequestCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_268_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11891LU));
}

/* ServerDiagnosticsSummaryType - ns=0;i=2150 */

static UA_StatusCode function_namespace0_generated_269_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 859LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServerDiagnosticsSummaryType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(ns[0], 2150LU),UA_NODEID_NUMERIC(ns[0], 63LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "ServerDiagnosticsSummaryType"),UA_NODEID_NUMERIC(ns[0], 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_269_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2150LU));
}

/* RejectedRequestsCount - ns=0;i=2163 */

static UA_StatusCode function_namespace0_generated_270_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RejectedRequestsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2163LU),UA_NODEID_NUMERIC(ns[0], 2150LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "RejectedRequestsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_270_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2163LU));
}

/* SecurityRejectedRequestsCount - ns=0;i=2162 */

static UA_StatusCode function_namespace0_generated_271_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecurityRejectedRequestsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2162LU),UA_NODEID_NUMERIC(ns[0], 2150LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SecurityRejectedRequestsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_271_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2162LU));
}

/* CumulatedSubscriptionCount - ns=0;i=2161 */

static UA_StatusCode function_namespace0_generated_272_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CumulatedSubscriptionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2161LU),UA_NODEID_NUMERIC(ns[0], 2150LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CumulatedSubscriptionCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_272_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2161LU));
}

/* CurrentSubscriptionCount - ns=0;i=2160 */

static UA_StatusCode function_namespace0_generated_273_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentSubscriptionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2160LU),UA_NODEID_NUMERIC(ns[0], 2150LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CurrentSubscriptionCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_273_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2160LU));
}

/* PublishingIntervalCount - ns=0;i=2159 */

static UA_StatusCode function_namespace0_generated_274_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublishingIntervalCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2159LU),UA_NODEID_NUMERIC(ns[0], 2150LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "PublishingIntervalCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_274_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2159LU));
}

/* SessionAbortCount - ns=0;i=2157 */

static UA_StatusCode function_namespace0_generated_275_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionAbortCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2157LU),UA_NODEID_NUMERIC(ns[0], 2150LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionAbortCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_275_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2157LU));
}

/* SessionTimeoutCount - ns=0;i=2156 */

static UA_StatusCode function_namespace0_generated_276_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionTimeoutCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2156LU),UA_NODEID_NUMERIC(ns[0], 2150LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionTimeoutCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_276_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2156LU));
}

/* RejectedSessionCount - ns=0;i=2155 */

static UA_StatusCode function_namespace0_generated_277_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RejectedSessionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2155LU),UA_NODEID_NUMERIC(ns[0], 2150LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "RejectedSessionCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_277_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2155LU));
}

/* SecurityRejectedSessionCount - ns=0;i=2154 */

static UA_StatusCode function_namespace0_generated_278_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecurityRejectedSessionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2154LU),UA_NODEID_NUMERIC(ns[0], 2150LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SecurityRejectedSessionCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_278_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2154LU));
}

/* CumulatedSessionCount - ns=0;i=2153 */

static UA_StatusCode function_namespace0_generated_279_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CumulatedSessionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2153LU),UA_NODEID_NUMERIC(ns[0], 2150LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CumulatedSessionCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_279_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2153LU));
}

/* CurrentSessionCount - ns=0;i=2152 */

static UA_StatusCode function_namespace0_generated_280_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentSessionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2152LU),UA_NODEID_NUMERIC(ns[0], 2150LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CurrentSessionCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_280_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2152LU));
}

/* ServerViewCount - ns=0;i=2151 */

static UA_StatusCode function_namespace0_generated_281_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServerViewCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2151LU),UA_NODEID_NUMERIC(ns[0], 2150LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ServerViewCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_281_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2151LU));
}

/* SamplingIntervalDiagnosticsType - ns=0;i=2165 */

static UA_StatusCode function_namespace0_generated_282_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 856LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SamplingIntervalDiagnosticsType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(ns[0], 2165LU),UA_NODEID_NUMERIC(ns[0], 63LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "SamplingIntervalDiagnosticsType"),UA_NODEID_NUMERIC(ns[0], 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_282_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2165LU));
}

/* SamplingInterval - ns=0;i=2166 */

static UA_StatusCode function_namespace0_generated_283_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 290LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SamplingInterval");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2166LU),UA_NODEID_NUMERIC(ns[0], 2165LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SamplingInterval"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_283_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2166LU));
}

/* DisabledMonitoredItemsSamplingCount - ns=0;i=11699 */

static UA_StatusCode function_namespace0_generated_284_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DisabledMonitoredItemsSamplingCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11699LU),UA_NODEID_NUMERIC(ns[0], 2165LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "DisabledMonitoredItemsSamplingCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_284_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11699LU));
}

/* MaxSampledMonitoredItemsCount - ns=0;i=11698 */

static UA_StatusCode function_namespace0_generated_285_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxSampledMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11698LU),UA_NODEID_NUMERIC(ns[0], 2165LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "MaxSampledMonitoredItemsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_285_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11698LU));
}

/* SampledMonitoredItemsCount - ns=0;i=11697 */

static UA_StatusCode function_namespace0_generated_286_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SampledMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11697LU),UA_NODEID_NUMERIC(ns[0], 2165LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SampledMonitoredItemsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_286_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11697LU));
}

/* SamplingIntervalDiagnosticsArrayType - ns=0;i=2164 */

static UA_StatusCode function_namespace0_generated_287_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 856LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SamplingIntervalDiagnosticsArrayType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(ns[0], 2164LU),UA_NODEID_NUMERIC(ns[0], 63LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "SamplingIntervalDiagnosticsArrayType"),UA_NODEID_NUMERIC(ns[0], 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_287_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2164LU));
}

/* SamplingIntervalDiagnostics - ns=0;i=12779 */

static UA_StatusCode function_namespace0_generated_288_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 856LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SamplingIntervalDiagnostics");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12779LU),UA_NODEID_NUMERIC(ns[0], 2164LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SamplingIntervalDiagnostics"),UA_NODEID_NUMERIC(ns[0], 2165LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_288_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12779LU));
}

/* DisabledMonitoredItemsSamplingCount - ns=0;i=12783 */

static UA_StatusCode function_namespace0_generated_289_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DisabledMonitoredItemsSamplingCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12783LU),UA_NODEID_NUMERIC(ns[0], 12779LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "DisabledMonitoredItemsSamplingCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_289_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12783LU));
}

/* MaxSampledMonitoredItemsCount - ns=0;i=12782 */

static UA_StatusCode function_namespace0_generated_290_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxSampledMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12782LU),UA_NODEID_NUMERIC(ns[0], 12779LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "MaxSampledMonitoredItemsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_290_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12782LU));
}

/* SampledMonitoredItemsCount - ns=0;i=12781 */

static UA_StatusCode function_namespace0_generated_291_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SampledMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12781LU),UA_NODEID_NUMERIC(ns[0], 12779LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SampledMonitoredItemsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_291_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12781LU));
}

/* SamplingInterval - ns=0;i=12780 */

static UA_StatusCode function_namespace0_generated_292_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 290LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SamplingInterval");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12780LU),UA_NODEID_NUMERIC(ns[0], 12779LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SamplingInterval"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_292_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12780LU));
}

/* SessionDiagnosticsArrayType - ns=0;i=2196 */

static UA_StatusCode function_namespace0_generated_293_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 865LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionDiagnosticsArrayType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(ns[0], 2196LU),UA_NODEID_NUMERIC(ns[0], 63LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "SessionDiagnosticsArrayType"),UA_NODEID_NUMERIC(ns[0], 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_293_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2196LU));
}

/* SessionDiagnostics - ns=0;i=12816 */

static UA_StatusCode function_namespace0_generated_294_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 865LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionDiagnostics");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 2196LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionDiagnostics"),UA_NODEID_NUMERIC(ns[0], 2197LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_294_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12816LU));
}

/* UnregisterNodesCount - ns=0;i=12859 */

static UA_StatusCode function_namespace0_generated_295_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "UnregisterNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12859LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "UnregisterNodesCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_295_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12859LU));
}

/* RegisterNodesCount - ns=0;i=12858 */

static UA_StatusCode function_namespace0_generated_296_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RegisterNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12858LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "RegisterNodesCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_296_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12858LU));
}

/* QueryNextCount - ns=0;i=12857 */

static UA_StatusCode function_namespace0_generated_297_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "QueryNextCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12857LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "QueryNextCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_297_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12857LU));
}

/* QueryFirstCount - ns=0;i=12856 */

static UA_StatusCode function_namespace0_generated_298_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "QueryFirstCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12856LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "QueryFirstCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_298_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12856LU));
}

/* TranslateBrowsePathsToNodeIdsCount - ns=0;i=12855 */

static UA_StatusCode function_namespace0_generated_299_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TranslateBrowsePathsToNodeIdsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12855LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "TranslateBrowsePathsToNodeIdsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_299_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12855LU));
}

/* BrowseNextCount - ns=0;i=12854 */

static UA_StatusCode function_namespace0_generated_300_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "BrowseNextCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12854LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "BrowseNextCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_300_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12854LU));
}

/* BrowseCount - ns=0;i=12853 */

static UA_StatusCode function_namespace0_generated_301_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "BrowseCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12853LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "BrowseCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_301_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12853LU));
}

/* DeleteReferencesCount - ns=0;i=12852 */

static UA_StatusCode function_namespace0_generated_302_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteReferencesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12852LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "DeleteReferencesCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_302_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12852LU));
}

/* DeleteNodesCount - ns=0;i=12851 */

static UA_StatusCode function_namespace0_generated_303_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12851LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "DeleteNodesCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_303_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12851LU));
}

/* AddReferencesCount - ns=0;i=12850 */

static UA_StatusCode function_namespace0_generated_304_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AddReferencesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12850LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "AddReferencesCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_304_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12850LU));
}

/* AddNodesCount - ns=0;i=12849 */

static UA_StatusCode function_namespace0_generated_305_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AddNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12849LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "AddNodesCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_305_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12849LU));
}

/* DeleteSubscriptionsCount - ns=0;i=12848 */

static UA_StatusCode function_namespace0_generated_306_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteSubscriptionsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12848LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "DeleteSubscriptionsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_306_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12848LU));
}

/* TransferSubscriptionsCount - ns=0;i=12847 */

static UA_StatusCode function_namespace0_generated_307_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransferSubscriptionsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12847LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "TransferSubscriptionsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_307_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12847LU));
}

/* RepublishCount - ns=0;i=12846 */

static UA_StatusCode function_namespace0_generated_308_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RepublishCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12846LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "RepublishCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_308_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12846LU));
}

/* PublishCount - ns=0;i=12845 */

static UA_StatusCode function_namespace0_generated_309_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublishCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12845LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "PublishCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_309_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12845LU));
}

/* SetPublishingModeCount - ns=0;i=12844 */

static UA_StatusCode function_namespace0_generated_310_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SetPublishingModeCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12844LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SetPublishingModeCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_310_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12844LU));
}

/* ModifySubscriptionCount - ns=0;i=12843 */

static UA_StatusCode function_namespace0_generated_311_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ModifySubscriptionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12843LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ModifySubscriptionCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_311_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12843LU));
}

/* CreateSubscriptionCount - ns=0;i=12842 */

static UA_StatusCode function_namespace0_generated_312_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CreateSubscriptionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12842LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CreateSubscriptionCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_312_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12842LU));
}

/* DeleteMonitoredItemsCount - ns=0;i=12841 */

static UA_StatusCode function_namespace0_generated_313_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12841LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "DeleteMonitoredItemsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_313_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12841LU));
}

/* SetTriggeringCount - ns=0;i=12840 */

static UA_StatusCode function_namespace0_generated_314_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SetTriggeringCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12840LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SetTriggeringCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_314_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12840LU));
}

/* SetMonitoringModeCount - ns=0;i=12839 */

static UA_StatusCode function_namespace0_generated_315_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SetMonitoringModeCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12839LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SetMonitoringModeCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_315_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12839LU));
}

/* ModifyMonitoredItemsCount - ns=0;i=12838 */

static UA_StatusCode function_namespace0_generated_316_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ModifyMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12838LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ModifyMonitoredItemsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_316_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12838LU));
}

/* CreateMonitoredItemsCount - ns=0;i=12837 */

static UA_StatusCode function_namespace0_generated_317_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CreateMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12837LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CreateMonitoredItemsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_317_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12837LU));
}

/* CallCount - ns=0;i=12836 */

static UA_StatusCode function_namespace0_generated_318_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CallCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12836LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CallCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_318_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12836LU));
}

/* HistoryUpdateCount - ns=0;i=12835 */

static UA_StatusCode function_namespace0_generated_319_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "HistoryUpdateCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12835LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "HistoryUpdateCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_319_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12835LU));
}

/* WriteCount - ns=0;i=12834 */

static UA_StatusCode function_namespace0_generated_320_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "WriteCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12834LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "WriteCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_320_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12834LU));
}

/* HistoryReadCount - ns=0;i=12833 */

static UA_StatusCode function_namespace0_generated_321_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "HistoryReadCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12833LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "HistoryReadCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_321_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12833LU));
}

/* ReadCount - ns=0;i=12832 */

static UA_StatusCode function_namespace0_generated_322_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ReadCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12832LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ReadCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_322_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12832LU));
}

/* UnauthorizedRequestCount - ns=0;i=12831 */

static UA_StatusCode function_namespace0_generated_323_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "UnauthorizedRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12831LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "UnauthorizedRequestCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_323_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12831LU));
}

/* TotalRequestCount - ns=0;i=12830 */

static UA_StatusCode function_namespace0_generated_324_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TotalRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12830LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "TotalRequestCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_324_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12830LU));
}

/* CurrentPublishRequestsInQueue - ns=0;i=12829 */

static UA_StatusCode function_namespace0_generated_325_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentPublishRequestsInQueue");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12829LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CurrentPublishRequestsInQueue"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_325_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12829LU));
}

/* CurrentMonitoredItemsCount - ns=0;i=12828 */

static UA_StatusCode function_namespace0_generated_326_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12828LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CurrentMonitoredItemsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_326_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12828LU));
}

/* CurrentSubscriptionsCount - ns=0;i=12827 */

static UA_StatusCode function_namespace0_generated_327_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentSubscriptionsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12827LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CurrentSubscriptionsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_327_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12827LU));
}

/* ClientLastContactTime - ns=0;i=12826 */

static UA_StatusCode function_namespace0_generated_328_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientLastContactTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12826LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ClientLastContactTime"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_328_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12826LU));
}

/* ClientConnectionTime - ns=0;i=12825 */

static UA_StatusCode function_namespace0_generated_329_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientConnectionTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12825LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ClientConnectionTime"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_329_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12825LU));
}

/* MaxResponseMessageSize - ns=0;i=12824 */

static UA_StatusCode function_namespace0_generated_330_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxResponseMessageSize");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12824LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "MaxResponseMessageSize"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_330_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12824LU));
}

/* ActualSessionTimeout - ns=0;i=12823 */

static UA_StatusCode function_namespace0_generated_331_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 290LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ActualSessionTimeout");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12823LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ActualSessionTimeout"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_331_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12823LU));
}

/* LocaleIds - ns=0;i=12822 */

static UA_StatusCode function_namespace0_generated_332_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 295LU);
attr.displayName = UA_LOCALIZEDTEXT("", "LocaleIds");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12822LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "LocaleIds"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_332_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12822LU));
}

/* EndpointUrl - ns=0;i=12821 */

static UA_StatusCode function_namespace0_generated_333_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EndpointUrl");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12821LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "EndpointUrl"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_333_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12821LU));
}

/* ServerUri - ns=0;i=12820 */

static UA_StatusCode function_namespace0_generated_334_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServerUri");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12820LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ServerUri"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_334_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12820LU));
}

/* ClientDescription - ns=0;i=12819 */

static UA_StatusCode function_namespace0_generated_335_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 308LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientDescription");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12819LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ClientDescription"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_335_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12819LU));
}

/* SessionName - ns=0;i=12818 */

static UA_StatusCode function_namespace0_generated_336_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionName");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12818LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionName"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_336_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12818LU));
}

/* SessionId - ns=0;i=12817 */

static UA_StatusCode function_namespace0_generated_337_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 17LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12817LU),UA_NODEID_NUMERIC(ns[0], 12816LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionId"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_337_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12817LU));
}

/* SessionSecurityDiagnosticsArrayType - ns=0;i=2243 */

static UA_StatusCode function_namespace0_generated_338_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 868LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionSecurityDiagnosticsArrayType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(ns[0], 2243LU),UA_NODEID_NUMERIC(ns[0], 63LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "SessionSecurityDiagnosticsArrayType"),UA_NODEID_NUMERIC(ns[0], 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_338_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2243LU));
}

/* SessionSecurityDiagnostics - ns=0;i=12860 */

static UA_StatusCode function_namespace0_generated_339_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 868LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionSecurityDiagnostics");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12860LU),UA_NODEID_NUMERIC(ns[0], 2243LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionSecurityDiagnostics"),UA_NODEID_NUMERIC(ns[0], 2244LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_339_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12860LU));
}

/* ClientCertificate - ns=0;i=12869 */

static UA_StatusCode function_namespace0_generated_340_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 15LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientCertificate");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12869LU),UA_NODEID_NUMERIC(ns[0], 12860LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ClientCertificate"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_340_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12869LU));
}

/* SecurityPolicyUri - ns=0;i=12868 */

static UA_StatusCode function_namespace0_generated_341_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecurityPolicyUri");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12868LU),UA_NODEID_NUMERIC(ns[0], 12860LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SecurityPolicyUri"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_341_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12868LU));
}

/* SecurityMode - ns=0;i=12867 */

static UA_StatusCode function_namespace0_generated_342_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 302LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecurityMode");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12867LU),UA_NODEID_NUMERIC(ns[0], 12860LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SecurityMode"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_342_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12867LU));
}

/* TransportProtocol - ns=0;i=12866 */

static UA_StatusCode function_namespace0_generated_343_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransportProtocol");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12866LU),UA_NODEID_NUMERIC(ns[0], 12860LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "TransportProtocol"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_343_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12866LU));
}

/* Encoding - ns=0;i=12865 */

static UA_StatusCode function_namespace0_generated_344_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Encoding");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12865LU),UA_NODEID_NUMERIC(ns[0], 12860LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "Encoding"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_344_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12865LU));
}

/* AuthenticationMechanism - ns=0;i=12864 */

static UA_StatusCode function_namespace0_generated_345_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AuthenticationMechanism");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12864LU),UA_NODEID_NUMERIC(ns[0], 12860LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "AuthenticationMechanism"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_345_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12864LU));
}

/* ClientUserIdHistory - ns=0;i=12863 */

static UA_StatusCode function_namespace0_generated_346_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientUserIdHistory");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12863LU),UA_NODEID_NUMERIC(ns[0], 12860LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ClientUserIdHistory"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_346_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12863LU));
}

/* ClientUserIdOfSession - ns=0;i=12862 */

static UA_StatusCode function_namespace0_generated_347_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientUserIdOfSession");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12862LU),UA_NODEID_NUMERIC(ns[0], 12860LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ClientUserIdOfSession"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_347_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12862LU));
}

/* SessionId - ns=0;i=12861 */

static UA_StatusCode function_namespace0_generated_348_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 17LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12861LU),UA_NODEID_NUMERIC(ns[0], 12860LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionId"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_348_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12861LU));
}

/* SessionsDiagnosticsSummaryType - ns=0;i=2026 */

static UA_StatusCode function_namespace0_generated_349_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "SessionsDiagnosticsSummaryType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(ns[0], 2026LU),UA_NODEID_NUMERIC(ns[0], 58LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "SessionsDiagnosticsSummaryType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_349_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2026LU));
}

/* SessionSecurityDiagnosticsArray - ns=0;i=2028 */

static UA_StatusCode function_namespace0_generated_350_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 868LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionSecurityDiagnosticsArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2028LU),UA_NODEID_NUMERIC(ns[0], 2026LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionSecurityDiagnosticsArray"),UA_NODEID_NUMERIC(ns[0], 2243LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_350_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2028LU));
}

/* SessionDiagnosticsArray - ns=0;i=2027 */

static UA_StatusCode function_namespace0_generated_351_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 865LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionDiagnosticsArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2027LU),UA_NODEID_NUMERIC(ns[0], 2026LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionDiagnosticsArray"),UA_NODEID_NUMERIC(ns[0], 2196LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_351_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2027LU));
}

/* <ClientName> - ns=0;i=12097 */

static UA_StatusCode function_namespace0_generated_352_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "<ClientName>");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(ns[0], 12097LU),UA_NODEID_NUMERIC(ns[0], 2026LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "<ClientName>"),UA_NODEID_NUMERIC(ns[0], 2029LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_352_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12097LU));
}

/* SubscriptionDiagnosticsArray - ns=0;i=12152 */

static UA_StatusCode function_namespace0_generated_353_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 874LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SubscriptionDiagnosticsArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12152LU),UA_NODEID_NUMERIC(ns[0], 12097LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SubscriptionDiagnosticsArray"),UA_NODEID_NUMERIC(ns[0], 2171LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_353_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12152LU));
}

/* SessionSecurityDiagnostics - ns=0;i=12142 */

static UA_StatusCode function_namespace0_generated_354_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 868LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionSecurityDiagnostics");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12142LU),UA_NODEID_NUMERIC(ns[0], 12097LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionSecurityDiagnostics"),UA_NODEID_NUMERIC(ns[0], 2244LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_354_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12142LU));
}

/* ClientCertificate - ns=0;i=12151 */

static UA_StatusCode function_namespace0_generated_355_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 15LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientCertificate");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12151LU),UA_NODEID_NUMERIC(ns[0], 12142LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ClientCertificate"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_355_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12151LU));
}

/* SecurityPolicyUri - ns=0;i=12150 */

static UA_StatusCode function_namespace0_generated_356_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecurityPolicyUri");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12150LU),UA_NODEID_NUMERIC(ns[0], 12142LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SecurityPolicyUri"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_356_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12150LU));
}

/* SecurityMode - ns=0;i=12149 */

static UA_StatusCode function_namespace0_generated_357_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 302LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecurityMode");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12149LU),UA_NODEID_NUMERIC(ns[0], 12142LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SecurityMode"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_357_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12149LU));
}

/* TransportProtocol - ns=0;i=12148 */

static UA_StatusCode function_namespace0_generated_358_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransportProtocol");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12148LU),UA_NODEID_NUMERIC(ns[0], 12142LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "TransportProtocol"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_358_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12148LU));
}

/* Encoding - ns=0;i=12147 */

static UA_StatusCode function_namespace0_generated_359_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Encoding");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12147LU),UA_NODEID_NUMERIC(ns[0], 12142LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "Encoding"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_359_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12147LU));
}

/* AuthenticationMechanism - ns=0;i=12146 */

static UA_StatusCode function_namespace0_generated_360_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AuthenticationMechanism");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12146LU),UA_NODEID_NUMERIC(ns[0], 12142LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "AuthenticationMechanism"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_360_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12146LU));
}

/* ClientUserIdHistory - ns=0;i=12145 */

static UA_StatusCode function_namespace0_generated_361_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientUserIdHistory");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12145LU),UA_NODEID_NUMERIC(ns[0], 12142LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ClientUserIdHistory"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_361_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12145LU));
}

/* ClientUserIdOfSession - ns=0;i=12144 */

static UA_StatusCode function_namespace0_generated_362_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientUserIdOfSession");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12144LU),UA_NODEID_NUMERIC(ns[0], 12142LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ClientUserIdOfSession"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_362_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12144LU));
}

/* SessionId - ns=0;i=12143 */

static UA_StatusCode function_namespace0_generated_363_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 17LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12143LU),UA_NODEID_NUMERIC(ns[0], 12142LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionId"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_363_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12143LU));
}

/* SessionDiagnostics - ns=0;i=12098 */

static UA_StatusCode function_namespace0_generated_364_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 865LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionDiagnostics");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 12097LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionDiagnostics"),UA_NODEID_NUMERIC(ns[0], 2197LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_364_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12098LU));
}

/* UnregisterNodesCount - ns=0;i=12141 */

static UA_StatusCode function_namespace0_generated_365_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "UnregisterNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12141LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "UnregisterNodesCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_365_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12141LU));
}

/* RegisterNodesCount - ns=0;i=12140 */

static UA_StatusCode function_namespace0_generated_366_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RegisterNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12140LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "RegisterNodesCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_366_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12140LU));
}

/* QueryNextCount - ns=0;i=12139 */

static UA_StatusCode function_namespace0_generated_367_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "QueryNextCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12139LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "QueryNextCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_367_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12139LU));
}

/* QueryFirstCount - ns=0;i=12138 */

static UA_StatusCode function_namespace0_generated_368_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "QueryFirstCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12138LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "QueryFirstCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_368_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12138LU));
}

/* TranslateBrowsePathsToNodeIdsCount - ns=0;i=12137 */

static UA_StatusCode function_namespace0_generated_369_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TranslateBrowsePathsToNodeIdsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12137LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "TranslateBrowsePathsToNodeIdsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_369_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12137LU));
}

/* BrowseNextCount - ns=0;i=12136 */

static UA_StatusCode function_namespace0_generated_370_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "BrowseNextCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12136LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "BrowseNextCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_370_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12136LU));
}

/* BrowseCount - ns=0;i=12135 */

static UA_StatusCode function_namespace0_generated_371_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "BrowseCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12135LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "BrowseCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_371_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12135LU));
}

/* DeleteReferencesCount - ns=0;i=12134 */

static UA_StatusCode function_namespace0_generated_372_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteReferencesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12134LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "DeleteReferencesCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_372_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12134LU));
}

/* DeleteNodesCount - ns=0;i=12133 */

static UA_StatusCode function_namespace0_generated_373_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12133LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "DeleteNodesCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_373_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12133LU));
}

/* AddReferencesCount - ns=0;i=12132 */

static UA_StatusCode function_namespace0_generated_374_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AddReferencesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12132LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "AddReferencesCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_374_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12132LU));
}

/* AddNodesCount - ns=0;i=12131 */

static UA_StatusCode function_namespace0_generated_375_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AddNodesCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12131LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "AddNodesCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_375_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12131LU));
}

/* DeleteSubscriptionsCount - ns=0;i=12130 */

static UA_StatusCode function_namespace0_generated_376_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteSubscriptionsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12130LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "DeleteSubscriptionsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_376_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12130LU));
}

/* TransferSubscriptionsCount - ns=0;i=12129 */

static UA_StatusCode function_namespace0_generated_377_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TransferSubscriptionsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12129LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "TransferSubscriptionsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_377_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12129LU));
}

/* RepublishCount - ns=0;i=12128 */

static UA_StatusCode function_namespace0_generated_378_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RepublishCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12128LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "RepublishCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_378_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12128LU));
}

/* PublishCount - ns=0;i=12127 */

static UA_StatusCode function_namespace0_generated_379_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublishCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12127LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "PublishCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_379_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12127LU));
}

/* SetPublishingModeCount - ns=0;i=12126 */

static UA_StatusCode function_namespace0_generated_380_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SetPublishingModeCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12126LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SetPublishingModeCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_380_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12126LU));
}

/* ModifySubscriptionCount - ns=0;i=12125 */

static UA_StatusCode function_namespace0_generated_381_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ModifySubscriptionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12125LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ModifySubscriptionCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_381_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12125LU));
}

/* CreateSubscriptionCount - ns=0;i=12124 */

static UA_StatusCode function_namespace0_generated_382_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CreateSubscriptionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12124LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CreateSubscriptionCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_382_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12124LU));
}

/* DeleteMonitoredItemsCount - ns=0;i=12123 */

static UA_StatusCode function_namespace0_generated_383_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12123LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "DeleteMonitoredItemsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_383_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12123LU));
}

/* SetTriggeringCount - ns=0;i=12122 */

static UA_StatusCode function_namespace0_generated_384_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SetTriggeringCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12122LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SetTriggeringCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_384_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12122LU));
}

/* SetMonitoringModeCount - ns=0;i=12121 */

static UA_StatusCode function_namespace0_generated_385_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SetMonitoringModeCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12121LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SetMonitoringModeCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_385_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12121LU));
}

/* ModifyMonitoredItemsCount - ns=0;i=12120 */

static UA_StatusCode function_namespace0_generated_386_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ModifyMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12120LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ModifyMonitoredItemsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_386_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12120LU));
}

/* CreateMonitoredItemsCount - ns=0;i=12119 */

static UA_StatusCode function_namespace0_generated_387_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CreateMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12119LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CreateMonitoredItemsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_387_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12119LU));
}

/* CallCount - ns=0;i=12118 */

static UA_StatusCode function_namespace0_generated_388_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CallCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12118LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CallCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_388_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12118LU));
}

/* HistoryUpdateCount - ns=0;i=12117 */

static UA_StatusCode function_namespace0_generated_389_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "HistoryUpdateCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12117LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "HistoryUpdateCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_389_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12117LU));
}

/* WriteCount - ns=0;i=12116 */

static UA_StatusCode function_namespace0_generated_390_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "WriteCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12116LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "WriteCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_390_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12116LU));
}

/* HistoryReadCount - ns=0;i=12115 */

static UA_StatusCode function_namespace0_generated_391_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "HistoryReadCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12115LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "HistoryReadCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_391_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12115LU));
}

/* ReadCount - ns=0;i=12114 */

static UA_StatusCode function_namespace0_generated_392_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ReadCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12114LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ReadCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_392_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12114LU));
}

/* UnauthorizedRequestCount - ns=0;i=12113 */

static UA_StatusCode function_namespace0_generated_393_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "UnauthorizedRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12113LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "UnauthorizedRequestCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_393_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12113LU));
}

/* TotalRequestCount - ns=0;i=12112 */

static UA_StatusCode function_namespace0_generated_394_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 871LU);
attr.displayName = UA_LOCALIZEDTEXT("", "TotalRequestCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12112LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "TotalRequestCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_394_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12112LU));
}

/* CurrentPublishRequestsInQueue - ns=0;i=12111 */

static UA_StatusCode function_namespace0_generated_395_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentPublishRequestsInQueue");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12111LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CurrentPublishRequestsInQueue"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_395_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12111LU));
}

/* CurrentMonitoredItemsCount - ns=0;i=12110 */

static UA_StatusCode function_namespace0_generated_396_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentMonitoredItemsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12110LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CurrentMonitoredItemsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_396_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12110LU));
}

/* CurrentSubscriptionsCount - ns=0;i=12109 */

static UA_StatusCode function_namespace0_generated_397_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentSubscriptionsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12109LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CurrentSubscriptionsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_397_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12109LU));
}

/* ClientLastContactTime - ns=0;i=12108 */

static UA_StatusCode function_namespace0_generated_398_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientLastContactTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12108LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ClientLastContactTime"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_398_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12108LU));
}

/* ClientConnectionTime - ns=0;i=12107 */

static UA_StatusCode function_namespace0_generated_399_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientConnectionTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12107LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ClientConnectionTime"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_399_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12107LU));
}

/* MaxResponseMessageSize - ns=0;i=12106 */

static UA_StatusCode function_namespace0_generated_400_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxResponseMessageSize");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12106LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "MaxResponseMessageSize"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_400_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12106LU));
}

/* ActualSessionTimeout - ns=0;i=12105 */

static UA_StatusCode function_namespace0_generated_401_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 290LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ActualSessionTimeout");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12105LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ActualSessionTimeout"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_401_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12105LU));
}

/* LocaleIds - ns=0;i=12104 */

static UA_StatusCode function_namespace0_generated_402_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 295LU);
attr.displayName = UA_LOCALIZEDTEXT("", "LocaleIds");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12104LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "LocaleIds"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_402_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12104LU));
}

/* EndpointUrl - ns=0;i=12103 */

static UA_StatusCode function_namespace0_generated_403_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EndpointUrl");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12103LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "EndpointUrl"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_403_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12103LU));
}

/* ServerUri - ns=0;i=12102 */

static UA_StatusCode function_namespace0_generated_404_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServerUri");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12102LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ServerUri"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_404_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12102LU));
}

/* ClientDescription - ns=0;i=12101 */

static UA_StatusCode function_namespace0_generated_405_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 308LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ClientDescription");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12101LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ClientDescription"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_405_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12101LU));
}

/* SessionName - ns=0;i=12100 */

static UA_StatusCode function_namespace0_generated_406_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionName");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12100LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionName"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_406_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12100LU));
}

/* SessionId - ns=0;i=12099 */

static UA_StatusCode function_namespace0_generated_407_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 17LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionId");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12099LU),UA_NODEID_NUMERIC(ns[0], 12098LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionId"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_407_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12099LU));
}

/* InterfaceTypes - ns=0;i=17708 */

static UA_StatusCode function_namespace0_generated_408_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "InterfaceTypes");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(ns[0], 17708LU),UA_NODEID_NUMERIC(ns[0], 86LU),UA_NODEID_NUMERIC(ns[0], 35LU),UA_QUALIFIEDNAME(ns[0], "InterfaceTypes"),UA_NODEID_NUMERIC(ns[0], 61LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_408_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 17708LU));
}

/* BaseInterfaceType - ns=0;i=17602 */

static UA_StatusCode function_namespace0_generated_409_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.isAbstract = true;
attr.displayName = UA_LOCALIZEDTEXT("", "BaseInterfaceType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(ns[0], 17602LU),UA_NODEID_NUMERIC(ns[0], 58LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "BaseInterfaceType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 17602LU), UA_NODEID_NUMERIC(ns[0], 35LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 17708LU), false);
return retVal;
}

static UA_StatusCode function_namespace0_generated_409_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 17602LU));
}

/* BuildInfoType - ns=0;i=3051 */

static UA_StatusCode function_namespace0_generated_410_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 338LU);
attr.displayName = UA_LOCALIZEDTEXT("", "BuildInfoType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(ns[0], 3051LU),UA_NODEID_NUMERIC(ns[0], 63LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "BuildInfoType"),UA_NODEID_NUMERIC(ns[0], 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_410_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3051LU));
}

/* ServerStatusType - ns=0;i=2138 */

static UA_StatusCode function_namespace0_generated_411_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 862LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServerStatusType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(ns[0], 2138LU),UA_NODEID_NUMERIC(ns[0], 63LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "ServerStatusType"),UA_NODEID_NUMERIC(ns[0], 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_411_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2138LU));
}

/* OperationLimitsType - ns=0;i=11564 */

static UA_StatusCode function_namespace0_generated_412_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "OperationLimitsType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(ns[0], 11564LU),UA_NODEID_NUMERIC(ns[0], 61LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "OperationLimitsType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_412_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11564LU));
}

/* MaxMonitoredItemsPerCall - ns=0;i=11574 */

static UA_StatusCode function_namespace0_generated_413_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxMonitoredItemsPerCall");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11574LU),UA_NODEID_NUMERIC(ns[0], 11564LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "MaxMonitoredItemsPerCall"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_413_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11574LU));
}

/* MaxNodesPerNodeManagement - ns=0;i=11573 */

static UA_StatusCode function_namespace0_generated_414_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerNodeManagement");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11573LU),UA_NODEID_NUMERIC(ns[0], 11564LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "MaxNodesPerNodeManagement"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_414_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11573LU));
}

/* MaxNodesPerTranslateBrowsePathsToNodeIds - ns=0;i=11572 */

static UA_StatusCode function_namespace0_generated_415_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerTranslateBrowsePathsToNodeIds");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11572LU),UA_NODEID_NUMERIC(ns[0], 11564LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "MaxNodesPerTranslateBrowsePathsToNodeIds"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_415_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11572LU));
}

/* MaxNodesPerRegisterNodes - ns=0;i=11571 */

static UA_StatusCode function_namespace0_generated_416_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerRegisterNodes");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11571LU),UA_NODEID_NUMERIC(ns[0], 11564LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "MaxNodesPerRegisterNodes"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_416_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11571LU));
}

/* MaxNodesPerBrowse - ns=0;i=11570 */

static UA_StatusCode function_namespace0_generated_417_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerBrowse");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11570LU),UA_NODEID_NUMERIC(ns[0], 11564LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "MaxNodesPerBrowse"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_417_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11570LU));
}

/* MaxNodesPerMethodCall - ns=0;i=11569 */

static UA_StatusCode function_namespace0_generated_418_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerMethodCall");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11569LU),UA_NODEID_NUMERIC(ns[0], 11564LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "MaxNodesPerMethodCall"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_418_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11569LU));
}

/* MaxNodesPerWrite - ns=0;i=11567 */

static UA_StatusCode function_namespace0_generated_419_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerWrite");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11567LU),UA_NODEID_NUMERIC(ns[0], 11564LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "MaxNodesPerWrite"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_419_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11567LU));
}

/* MaxNodesPerRead - ns=0;i=11565 */

static UA_StatusCode function_namespace0_generated_420_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerRead");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11565LU),UA_NODEID_NUMERIC(ns[0], 11564LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "MaxNodesPerRead"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_420_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11565LU));
}

/* ServerRedundancyType - ns=0;i=2034 */

static UA_StatusCode function_namespace0_generated_421_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ServerRedundancyType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(ns[0], 2034LU),UA_NODEID_NUMERIC(ns[0], 58LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "ServerRedundancyType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_421_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2034LU));
}

/* RedundancySupport - ns=0;i=2035 */

static UA_StatusCode function_namespace0_generated_422_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 851LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RedundancySupport");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2035LU),UA_NODEID_NUMERIC(ns[0], 2034LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "RedundancySupport"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_422_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2035LU));
}

/* VendorServerInfoType - ns=0;i=2033 */

static UA_StatusCode function_namespace0_generated_423_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "VendorServerInfoType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(ns[0], 2033LU),UA_NODEID_NUMERIC(ns[0], 58LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "VendorServerInfoType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_423_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2033LU));
}

/* ServerDiagnosticsType - ns=0;i=2020 */

static UA_StatusCode function_namespace0_generated_424_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ServerDiagnosticsType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(ns[0], 2020LU),UA_NODEID_NUMERIC(ns[0], 58LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "ServerDiagnosticsType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_424_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2020LU));
}

/* SessionsDiagnosticsSummary - ns=0;i=2744 */

static UA_StatusCode function_namespace0_generated_425_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "SessionsDiagnosticsSummary");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(ns[0], 2744LU),UA_NODEID_NUMERIC(ns[0], 2020LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionsDiagnosticsSummary"),UA_NODEID_NUMERIC(ns[0], 2026LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_425_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2744LU));
}

/* SessionSecurityDiagnosticsArray - ns=0;i=3130 */

static UA_StatusCode function_namespace0_generated_426_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 868LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionSecurityDiagnosticsArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3130LU),UA_NODEID_NUMERIC(ns[0], 2744LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionSecurityDiagnosticsArray"),UA_NODEID_NUMERIC(ns[0], 2243LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_426_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3130LU));
}

/* SessionDiagnosticsArray - ns=0;i=3129 */

static UA_StatusCode function_namespace0_generated_427_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 865LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionDiagnosticsArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3129LU),UA_NODEID_NUMERIC(ns[0], 2744LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionDiagnosticsArray"),UA_NODEID_NUMERIC(ns[0], 2196LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_427_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3129LU));
}

/* EnabledFlag - ns=0;i=2025 */

static UA_StatusCode function_namespace0_generated_428_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 3;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EnabledFlag");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2025LU),UA_NODEID_NUMERIC(ns[0], 2020LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "EnabledFlag"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_428_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2025LU));
}

/* SubscriptionDiagnosticsArray - ns=0;i=2023 */

static UA_StatusCode function_namespace0_generated_429_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 874LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SubscriptionDiagnosticsArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2023LU),UA_NODEID_NUMERIC(ns[0], 2020LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SubscriptionDiagnosticsArray"),UA_NODEID_NUMERIC(ns[0], 2171LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_429_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2023LU));
}

/* SamplingIntervalDiagnosticsArray - ns=0;i=2022 */

static UA_StatusCode function_namespace0_generated_430_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 856LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SamplingIntervalDiagnosticsArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2022LU),UA_NODEID_NUMERIC(ns[0], 2020LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SamplingIntervalDiagnosticsArray"),UA_NODEID_NUMERIC(ns[0], 2164LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_430_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2022LU));
}

/* ServerDiagnosticsSummary - ns=0;i=2021 */

static UA_StatusCode function_namespace0_generated_431_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 859LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServerDiagnosticsSummary");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2021LU),UA_NODEID_NUMERIC(ns[0], 2020LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ServerDiagnosticsSummary"),UA_NODEID_NUMERIC(ns[0], 2150LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_431_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2021LU));
}

/* RejectedRequestsCount - ns=0;i=3128 */

static UA_StatusCode function_namespace0_generated_432_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RejectedRequestsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3128LU),UA_NODEID_NUMERIC(ns[0], 2021LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "RejectedRequestsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_432_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3128LU));
}

/* SecurityRejectedRequestsCount - ns=0;i=3127 */

static UA_StatusCode function_namespace0_generated_433_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecurityRejectedRequestsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3127LU),UA_NODEID_NUMERIC(ns[0], 2021LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SecurityRejectedRequestsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_433_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3127LU));
}

/* CumulatedSubscriptionCount - ns=0;i=3126 */

static UA_StatusCode function_namespace0_generated_434_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CumulatedSubscriptionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3126LU),UA_NODEID_NUMERIC(ns[0], 2021LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CumulatedSubscriptionCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_434_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3126LU));
}

/* CurrentSubscriptionCount - ns=0;i=3125 */

static UA_StatusCode function_namespace0_generated_435_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentSubscriptionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3125LU),UA_NODEID_NUMERIC(ns[0], 2021LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CurrentSubscriptionCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_435_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3125LU));
}

/* PublishingIntervalCount - ns=0;i=3124 */

static UA_StatusCode function_namespace0_generated_436_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublishingIntervalCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3124LU),UA_NODEID_NUMERIC(ns[0], 2021LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "PublishingIntervalCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_436_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3124LU));
}

/* SessionAbortCount - ns=0;i=3122 */

static UA_StatusCode function_namespace0_generated_437_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionAbortCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3122LU),UA_NODEID_NUMERIC(ns[0], 2021LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionAbortCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_437_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3122LU));
}

/* SessionTimeoutCount - ns=0;i=3121 */

static UA_StatusCode function_namespace0_generated_438_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionTimeoutCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3121LU),UA_NODEID_NUMERIC(ns[0], 2021LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionTimeoutCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_438_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3121LU));
}

/* RejectedSessionCount - ns=0;i=3120 */

static UA_StatusCode function_namespace0_generated_439_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RejectedSessionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3120LU),UA_NODEID_NUMERIC(ns[0], 2021LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "RejectedSessionCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_439_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3120LU));
}

/* SecurityRejectedSessionCount - ns=0;i=3119 */

static UA_StatusCode function_namespace0_generated_440_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecurityRejectedSessionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3119LU),UA_NODEID_NUMERIC(ns[0], 2021LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SecurityRejectedSessionCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_440_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3119LU));
}

/* CumulatedSessionCount - ns=0;i=3118 */

static UA_StatusCode function_namespace0_generated_441_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CumulatedSessionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3118LU),UA_NODEID_NUMERIC(ns[0], 2021LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CumulatedSessionCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_441_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3118LU));
}

/* CurrentSessionCount - ns=0;i=3117 */

static UA_StatusCode function_namespace0_generated_442_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentSessionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3117LU),UA_NODEID_NUMERIC(ns[0], 2021LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CurrentSessionCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_442_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3117LU));
}

/* ServerViewCount - ns=0;i=3116 */

static UA_StatusCode function_namespace0_generated_443_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServerViewCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3116LU),UA_NODEID_NUMERIC(ns[0], 2021LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ServerViewCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_443_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3116LU));
}

/* ServerCapabilitiesType - ns=0;i=2013 */

static UA_StatusCode function_namespace0_generated_444_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ServerCapabilitiesType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(ns[0], 2013LU),UA_NODEID_NUMERIC(ns[0], 58LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "ServerCapabilitiesType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_444_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2013LU));
}

/* OperationLimits - ns=0;i=11551 */

static UA_StatusCode function_namespace0_generated_445_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "OperationLimits");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(ns[0], 11551LU),UA_NODEID_NUMERIC(ns[0], 2013LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "OperationLimits"),UA_NODEID_NUMERIC(ns[0], 11564LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_445_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11551LU));
}

/* ServerType - ns=0;i=2004 */

static UA_StatusCode function_namespace0_generated_446_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ServerType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(ns[0], 2004LU),UA_NODEID_NUMERIC(ns[0], 58LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "ServerType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_446_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2004LU));
}

/* Server - ns=0;i=2253 */

static UA_StatusCode function_namespace0_generated_447_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.eventNotifier = UA_EVENTNOTIFIER_SUBSCRIBE_TO_EVENT;
attr.displayName = UA_LOCALIZEDTEXT("", "Server");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(ns[0], 2253LU),UA_NODEID_NUMERIC(ns[0], 85LU),UA_NODEID_NUMERIC(ns[0], 35LU),UA_QUALIFIEDNAME(ns[0], "Server"),UA_NODEID_NUMERIC(ns[0], 2004LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_447_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2253LU));
}

/* Auditing - ns=0;i=2994 */

static UA_StatusCode function_namespace0_generated_448_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 1000.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "Auditing");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2994LU),UA_NODEID_NUMERIC(ns[0], 2253LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "Auditing"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_448_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2994LU));
}

/* ServerRedundancy - ns=0;i=2296 */

static UA_StatusCode function_namespace0_generated_449_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ServerRedundancy");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(ns[0], 2296LU),UA_NODEID_NUMERIC(ns[0], 2253LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ServerRedundancy"),UA_NODEID_NUMERIC(ns[0], 2034LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_449_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2296LU));
}

/* RedundancySupport - ns=0;i=3709 */

static UA_StatusCode function_namespace0_generated_450_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 851LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RedundancySupport");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3709LU),UA_NODEID_NUMERIC(ns[0], 2296LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "RedundancySupport"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_450_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3709LU));
}

/* VendorServerInfo - ns=0;i=2295 */

static UA_StatusCode function_namespace0_generated_451_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "VendorServerInfo");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(ns[0], 2295LU),UA_NODEID_NUMERIC(ns[0], 2253LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "VendorServerInfo"),UA_NODEID_NUMERIC(ns[0], 2033LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_451_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2295LU));
}

/* ServerDiagnostics - ns=0;i=2274 */

static UA_StatusCode function_namespace0_generated_452_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ServerDiagnostics");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(ns[0], 2274LU),UA_NODEID_NUMERIC(ns[0], 2253LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ServerDiagnostics"),UA_NODEID_NUMERIC(ns[0], 2020LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_452_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2274LU));
}

/* SessionsDiagnosticsSummary - ns=0;i=3706 */

static UA_StatusCode function_namespace0_generated_453_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "SessionsDiagnosticsSummary");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(ns[0], 3706LU),UA_NODEID_NUMERIC(ns[0], 2274LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionsDiagnosticsSummary"),UA_NODEID_NUMERIC(ns[0], 2026LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_453_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3706LU));
}

/* SessionSecurityDiagnosticsArray - ns=0;i=3708 */

static UA_StatusCode function_namespace0_generated_454_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 868LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionSecurityDiagnosticsArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3708LU),UA_NODEID_NUMERIC(ns[0], 3706LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionSecurityDiagnosticsArray"),UA_NODEID_NUMERIC(ns[0], 2243LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_454_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3708LU));
}

/* SessionDiagnosticsArray - ns=0;i=3707 */

static UA_StatusCode function_namespace0_generated_455_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 865LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionDiagnosticsArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3707LU),UA_NODEID_NUMERIC(ns[0], 3706LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionDiagnosticsArray"),UA_NODEID_NUMERIC(ns[0], 2196LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_455_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3707LU));
}

/* EnabledFlag - ns=0;i=2294 */

static UA_StatusCode function_namespace0_generated_456_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 3;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "EnabledFlag");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2294LU),UA_NODEID_NUMERIC(ns[0], 2274LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "EnabledFlag"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_456_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2294LU));
}

/* SubscriptionDiagnosticsArray - ns=0;i=2290 */

static UA_StatusCode function_namespace0_generated_457_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 874LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SubscriptionDiagnosticsArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2290LU),UA_NODEID_NUMERIC(ns[0], 2274LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SubscriptionDiagnosticsArray"),UA_NODEID_NUMERIC(ns[0], 2171LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_457_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2290LU));
}

/* ServerDiagnosticsSummary - ns=0;i=2275 */

static UA_StatusCode function_namespace0_generated_458_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 859LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServerDiagnosticsSummary");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2275LU),UA_NODEID_NUMERIC(ns[0], 2274LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ServerDiagnosticsSummary"),UA_NODEID_NUMERIC(ns[0], 2150LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_458_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2275LU));
}

/* RejectedSessionCount - ns=0;i=3705 */

static UA_StatusCode function_namespace0_generated_459_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RejectedSessionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3705LU),UA_NODEID_NUMERIC(ns[0], 2275LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "RejectedSessionCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_459_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3705LU));
}

/* RejectedRequestsCount - ns=0;i=2288 */

static UA_StatusCode function_namespace0_generated_460_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "RejectedRequestsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2288LU),UA_NODEID_NUMERIC(ns[0], 2275LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "RejectedRequestsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_460_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2288LU));
}

/* SecurityRejectedRequestsCount - ns=0;i=2287 */

static UA_StatusCode function_namespace0_generated_461_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecurityRejectedRequestsCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2287LU),UA_NODEID_NUMERIC(ns[0], 2275LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SecurityRejectedRequestsCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_461_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2287LU));
}

/* CumulatedSubscriptionCount - ns=0;i=2286 */

static UA_StatusCode function_namespace0_generated_462_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CumulatedSubscriptionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2286LU),UA_NODEID_NUMERIC(ns[0], 2275LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CumulatedSubscriptionCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_462_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2286LU));
}

/* CurrentSubscriptionCount - ns=0;i=2285 */

static UA_StatusCode function_namespace0_generated_463_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentSubscriptionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2285LU),UA_NODEID_NUMERIC(ns[0], 2275LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CurrentSubscriptionCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_463_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2285LU));
}

/* PublishingIntervalCount - ns=0;i=2284 */

static UA_StatusCode function_namespace0_generated_464_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "PublishingIntervalCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2284LU),UA_NODEID_NUMERIC(ns[0], 2275LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "PublishingIntervalCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_464_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2284LU));
}

/* SessionAbortCount - ns=0;i=2282 */

static UA_StatusCode function_namespace0_generated_465_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionAbortCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2282LU),UA_NODEID_NUMERIC(ns[0], 2275LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionAbortCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_465_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2282LU));
}

/* SessionTimeoutCount - ns=0;i=2281 */

static UA_StatusCode function_namespace0_generated_466_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SessionTimeoutCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2281LU),UA_NODEID_NUMERIC(ns[0], 2275LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SessionTimeoutCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_466_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2281LU));
}

/* SecurityRejectedSessionCount - ns=0;i=2279 */

static UA_StatusCode function_namespace0_generated_467_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecurityRejectedSessionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2279LU),UA_NODEID_NUMERIC(ns[0], 2275LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SecurityRejectedSessionCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_467_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2279LU));
}

/* CumulatedSessionCount - ns=0;i=2278 */

static UA_StatusCode function_namespace0_generated_468_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CumulatedSessionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2278LU),UA_NODEID_NUMERIC(ns[0], 2275LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CumulatedSessionCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_468_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2278LU));
}

/* CurrentSessionCount - ns=0;i=2277 */

static UA_StatusCode function_namespace0_generated_469_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentSessionCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2277LU),UA_NODEID_NUMERIC(ns[0], 2275LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CurrentSessionCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_469_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2277LU));
}

/* ServerViewCount - ns=0;i=2276 */

static UA_StatusCode function_namespace0_generated_470_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServerViewCount");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2276LU),UA_NODEID_NUMERIC(ns[0], 2275LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ServerViewCount"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_470_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2276LU));
}

/* ServerCapabilities - ns=0;i=2268 */

static UA_StatusCode function_namespace0_generated_471_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ServerCapabilities");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(ns[0], 2268LU),UA_NODEID_NUMERIC(ns[0], 2253LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ServerCapabilities"),UA_NODEID_NUMERIC(ns[0], 2013LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_471_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2268LU));
}

/* SoftwareCertificates - ns=0;i=3704 */

static UA_StatusCode function_namespace0_generated_472_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 344LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SoftwareCertificates");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 3704LU),UA_NODEID_NUMERIC(ns[0], 2268LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "SoftwareCertificates"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_472_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3704LU));
}

/* AggregateFunctions - ns=0;i=2997 */

static UA_StatusCode function_namespace0_generated_473_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "AggregateFunctions");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(ns[0], 2997LU),UA_NODEID_NUMERIC(ns[0], 2268LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "AggregateFunctions"),UA_NODEID_NUMERIC(ns[0], 61LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_473_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2997LU));
}

/* ModellingRules - ns=0;i=2996 */

static UA_StatusCode function_namespace0_generated_474_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ModellingRules");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(ns[0], 2996LU),UA_NODEID_NUMERIC(ns[0], 2268LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ModellingRules"),UA_NODEID_NUMERIC(ns[0], 61LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_474_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2996LU));
}

/* MaxHistoryContinuationPoints - ns=0;i=2737 */

static UA_StatusCode function_namespace0_generated_475_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 5LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxHistoryContinuationPoints");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2737LU),UA_NODEID_NUMERIC(ns[0], 2268LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "MaxHistoryContinuationPoints"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_475_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2737LU));
}

/* MaxQueryContinuationPoints - ns=0;i=2736 */

static UA_StatusCode function_namespace0_generated_476_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 5LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxQueryContinuationPoints");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2736LU),UA_NODEID_NUMERIC(ns[0], 2268LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "MaxQueryContinuationPoints"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_476_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2736LU));
}

/* MaxBrowseContinuationPoints - ns=0;i=2735 */

static UA_StatusCode function_namespace0_generated_477_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 5LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxBrowseContinuationPoints");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2735LU),UA_NODEID_NUMERIC(ns[0], 2268LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "MaxBrowseContinuationPoints"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_477_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2735LU));
}

/* MinSupportedSampleRate - ns=0;i=2272 */

static UA_StatusCode function_namespace0_generated_478_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 290LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MinSupportedSampleRate");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2272LU),UA_NODEID_NUMERIC(ns[0], 2268LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "MinSupportedSampleRate"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_478_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2272LU));
}

/* LocaleIdArray - ns=0;i=2271 */

static UA_StatusCode function_namespace0_generated_479_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 295LU);
attr.displayName = UA_LOCALIZEDTEXT("", "LocaleIdArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2271LU),UA_NODEID_NUMERIC(ns[0], 2268LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "LocaleIdArray"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_479_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2271LU));
}

/* ServerProfileArray - ns=0;i=2269 */

static UA_StatusCode function_namespace0_generated_480_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServerProfileArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2269LU),UA_NODEID_NUMERIC(ns[0], 2268LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "ServerProfileArray"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_480_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2269LU));
}

/* OperationLimits - ns=0;i=11704 */

static UA_StatusCode function_namespace0_generated_481_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "OperationLimits");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(ns[0], 11704LU),UA_NODEID_NUMERIC(ns[0], 2268LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "OperationLimits"),UA_NODEID_NUMERIC(ns[0], 11564LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_481_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11704LU));
}

/* MaxMonitoredItemsPerCall - ns=0;i=11714 */

static UA_StatusCode function_namespace0_generated_482_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxMonitoredItemsPerCall");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11714LU),UA_NODEID_NUMERIC(ns[0], 11704LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "MaxMonitoredItemsPerCall"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_482_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11714LU));
}

/* MaxNodesPerNodeManagement - ns=0;i=11713 */

static UA_StatusCode function_namespace0_generated_483_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerNodeManagement");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11713LU),UA_NODEID_NUMERIC(ns[0], 11704LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "MaxNodesPerNodeManagement"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_483_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11713LU));
}

/* MaxNodesPerTranslateBrowsePathsToNodeIds - ns=0;i=11712 */

static UA_StatusCode function_namespace0_generated_484_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerTranslateBrowsePathsToNodeIds");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11712LU),UA_NODEID_NUMERIC(ns[0], 11704LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "MaxNodesPerTranslateBrowsePathsToNodeIds"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_484_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11712LU));
}

/* MaxNodesPerRegisterNodes - ns=0;i=11711 */

static UA_StatusCode function_namespace0_generated_485_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerRegisterNodes");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11711LU),UA_NODEID_NUMERIC(ns[0], 11704LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "MaxNodesPerRegisterNodes"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_485_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11711LU));
}

/* MaxNodesPerBrowse - ns=0;i=11710 */

static UA_StatusCode function_namespace0_generated_486_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerBrowse");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11710LU),UA_NODEID_NUMERIC(ns[0], 11704LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "MaxNodesPerBrowse"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_486_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11710LU));
}

/* MaxNodesPerMethodCall - ns=0;i=11709 */

static UA_StatusCode function_namespace0_generated_487_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerMethodCall");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11709LU),UA_NODEID_NUMERIC(ns[0], 11704LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "MaxNodesPerMethodCall"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_487_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11709LU));
}

/* MaxNodesPerWrite - ns=0;i=11707 */

static UA_StatusCode function_namespace0_generated_488_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerWrite");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11707LU),UA_NODEID_NUMERIC(ns[0], 11704LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "MaxNodesPerWrite"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_488_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11707LU));
}

/* MaxNodesPerRead - ns=0;i=11705 */

static UA_StatusCode function_namespace0_generated_489_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxNodesPerRead");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11705LU),UA_NODEID_NUMERIC(ns[0], 11704LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "MaxNodesPerRead"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_489_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11705LU));
}

/* HistoryServerCapabilities - ns=0;i=11192 */

static UA_StatusCode function_namespace0_generated_490_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "HistoryServerCapabilities");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(ns[0], 11192LU),UA_NODEID_NUMERIC(ns[0], 2268LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "HistoryServerCapabilities"),UA_NODEID_NUMERIC(ns[0], 2330LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_490_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11192LU));
}

/* DeleteEventCapability - ns=0;i=11502 */

static UA_StatusCode function_namespace0_generated_491_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteEventCapability");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11502LU),UA_NODEID_NUMERIC(ns[0], 11192LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "DeleteEventCapability"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_491_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11502LU));
}

/* UpdateEventCapability - ns=0;i=11283 */

static UA_StatusCode function_namespace0_generated_492_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "UpdateEventCapability");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11283LU),UA_NODEID_NUMERIC(ns[0], 11192LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "UpdateEventCapability"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_492_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11283LU));
}

/* ReplaceEventCapability - ns=0;i=11282 */

static UA_StatusCode function_namespace0_generated_493_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ReplaceEventCapability");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11282LU),UA_NODEID_NUMERIC(ns[0], 11192LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "ReplaceEventCapability"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_493_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11282LU));
}

/* InsertEventCapability - ns=0;i=11281 */

static UA_StatusCode function_namespace0_generated_494_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "InsertEventCapability");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11281LU),UA_NODEID_NUMERIC(ns[0], 11192LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "InsertEventCapability"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_494_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11281LU));
}

/* InsertAnnotationCapability - ns=0;i=11275 */

static UA_StatusCode function_namespace0_generated_495_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "InsertAnnotationCapability");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11275LU),UA_NODEID_NUMERIC(ns[0], 11192LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "InsertAnnotationCapability"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_495_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11275LU));
}

/* MaxReturnEventValues - ns=0;i=11274 */

static UA_StatusCode function_namespace0_generated_496_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxReturnEventValues");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11274LU),UA_NODEID_NUMERIC(ns[0], 11192LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "MaxReturnEventValues"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_496_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11274LU));
}

/* MaxReturnDataValues - ns=0;i=11273 */

static UA_StatusCode function_namespace0_generated_497_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "MaxReturnDataValues");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11273LU),UA_NODEID_NUMERIC(ns[0], 11192LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "MaxReturnDataValues"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_497_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11273LU));
}

/* AccessHistoryEventsCapability - ns=0;i=11242 */

static UA_StatusCode function_namespace0_generated_498_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AccessHistoryEventsCapability");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11242LU),UA_NODEID_NUMERIC(ns[0], 11192LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "AccessHistoryEventsCapability"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_498_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11242LU));
}

/* AggregateFunctions - ns=0;i=11201 */

static UA_StatusCode function_namespace0_generated_499_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "AggregateFunctions");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(ns[0], 11201LU),UA_NODEID_NUMERIC(ns[0], 11192LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "AggregateFunctions"),UA_NODEID_NUMERIC(ns[0], 61LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_499_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11201LU));
}

/* DeleteAtTimeCapability - ns=0;i=11200 */

static UA_StatusCode function_namespace0_generated_500_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteAtTimeCapability");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11200LU),UA_NODEID_NUMERIC(ns[0], 11192LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "DeleteAtTimeCapability"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_500_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11200LU));
}

/* DeleteRawCapability - ns=0;i=11199 */

static UA_StatusCode function_namespace0_generated_501_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DeleteRawCapability");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11199LU),UA_NODEID_NUMERIC(ns[0], 11192LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "DeleteRawCapability"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_501_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11199LU));
}

/* UpdateDataCapability - ns=0;i=11198 */

static UA_StatusCode function_namespace0_generated_502_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "UpdateDataCapability");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11198LU),UA_NODEID_NUMERIC(ns[0], 11192LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "UpdateDataCapability"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_502_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11198LU));
}

/* ReplaceDataCapability - ns=0;i=11197 */

static UA_StatusCode function_namespace0_generated_503_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ReplaceDataCapability");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11197LU),UA_NODEID_NUMERIC(ns[0], 11192LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "ReplaceDataCapability"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_503_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11197LU));
}

/* InsertDataCapability - ns=0;i=11196 */

static UA_StatusCode function_namespace0_generated_504_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "InsertDataCapability");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11196LU),UA_NODEID_NUMERIC(ns[0], 11192LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "InsertDataCapability"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_504_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11196LU));
}

/* AccessHistoryDataCapability - ns=0;i=11193 */

static UA_StatusCode function_namespace0_generated_505_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 1LU);
attr.displayName = UA_LOCALIZEDTEXT("", "AccessHistoryDataCapability");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11193LU),UA_NODEID_NUMERIC(ns[0], 11192LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "AccessHistoryDataCapability"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_505_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11193LU));
}

/* ServiceLevel - ns=0;i=2267 */

static UA_StatusCode function_namespace0_generated_506_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 1000.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 3LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServiceLevel");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2267LU),UA_NODEID_NUMERIC(ns[0], 2253LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "ServiceLevel"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_506_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2267LU));
}

/* ServerStatus - ns=0;i=2256 */

static UA_StatusCode function_namespace0_generated_507_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 1000.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 862LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServerStatus");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2256LU),UA_NODEID_NUMERIC(ns[0], 2253LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ServerStatus"),UA_NODEID_NUMERIC(ns[0], 2138LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_507_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2256LU));
}

/* ShutdownReason - ns=0;i=2993 */

static UA_StatusCode function_namespace0_generated_508_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 21LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ShutdownReason");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2993LU),UA_NODEID_NUMERIC(ns[0], 2256LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ShutdownReason"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_508_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2993LU));
}

/* SecondsTillShutdown - ns=0;i=2992 */

static UA_StatusCode function_namespace0_generated_509_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SecondsTillShutdown");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2992LU),UA_NODEID_NUMERIC(ns[0], 2256LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SecondsTillShutdown"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_509_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2992LU));
}

/* BuildInfo - ns=0;i=2260 */

static UA_StatusCode function_namespace0_generated_510_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 338LU);
attr.displayName = UA_LOCALIZEDTEXT("", "BuildInfo");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2260LU),UA_NODEID_NUMERIC(ns[0], 2256LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "BuildInfo"),UA_NODEID_NUMERIC(ns[0], 3051LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_510_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2260LU));
}

/* BuildDate - ns=0;i=2266 */

static UA_StatusCode function_namespace0_generated_511_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 1000.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "BuildDate");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2266LU),UA_NODEID_NUMERIC(ns[0], 2260LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "BuildDate"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_511_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2266LU));
}

/* BuildNumber - ns=0;i=2265 */

static UA_StatusCode function_namespace0_generated_512_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 1000.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "BuildNumber");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2265LU),UA_NODEID_NUMERIC(ns[0], 2260LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "BuildNumber"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_512_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2265LU));
}

/* SoftwareVersion - ns=0;i=2264 */

static UA_StatusCode function_namespace0_generated_513_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 1000.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "SoftwareVersion");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2264LU),UA_NODEID_NUMERIC(ns[0], 2260LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "SoftwareVersion"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_513_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2264LU));
}

/* ManufacturerName - ns=0;i=2263 */

static UA_StatusCode function_namespace0_generated_514_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 1000.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ManufacturerName");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2263LU),UA_NODEID_NUMERIC(ns[0], 2260LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ManufacturerName"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_514_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2263LU));
}

/* ProductUri - ns=0;i=2262 */

static UA_StatusCode function_namespace0_generated_515_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 1000.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ProductUri");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2262LU),UA_NODEID_NUMERIC(ns[0], 2260LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ProductUri"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_515_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2262LU));
}

/* ProductName - ns=0;i=2261 */

static UA_StatusCode function_namespace0_generated_516_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 1000.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ProductName");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2261LU),UA_NODEID_NUMERIC(ns[0], 2260LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ProductName"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_516_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2261LU));
}

/* State - ns=0;i=2259 */

static UA_StatusCode function_namespace0_generated_517_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 852LU);
attr.displayName = UA_LOCALIZEDTEXT("", "State");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2259LU),UA_NODEID_NUMERIC(ns[0], 2256LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "State"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_517_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2259LU));
}

/* CurrentTime - ns=0;i=2258 */

static UA_StatusCode function_namespace0_generated_518_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "CurrentTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2258LU),UA_NODEID_NUMERIC(ns[0], 2256LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "CurrentTime"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_518_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2258LU));
}

/* StartTime - ns=0;i=2257 */

static UA_StatusCode function_namespace0_generated_519_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 294LU);
attr.displayName = UA_LOCALIZEDTEXT("", "StartTime");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2257LU),UA_NODEID_NUMERIC(ns[0], 2256LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "StartTime"),UA_NODEID_NUMERIC(ns[0], 63LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_519_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2257LU));
}

/* NamespaceArray - ns=0;i=2255 */

static UA_StatusCode function_namespace0_generated_520_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 1000.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "NamespaceArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2255LU),UA_NODEID_NUMERIC(ns[0], 2253LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "NamespaceArray"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_520_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2255LU));
}

/* ServerArray - ns=0;i=2254 */

static UA_StatusCode function_namespace0_generated_521_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 1000.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "ServerArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 2254LU),UA_NODEID_NUMERIC(ns[0], 2253LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "ServerArray"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_521_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2254LU));
}

/* ResendData - ns=0;i=12873 */

static UA_StatusCode function_namespace0_generated_522_begin(UA_Server *server, UA_UInt16* ns) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "ResendData");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(ns[0], 12873LU),UA_NODEID_NUMERIC(ns[0], 2253LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "ResendData"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_522_finish(UA_Server *server, UA_UInt16* ns) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12873LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=12874 */

static UA_StatusCode function_namespace0_generated_523_begin(UA_Server *server, UA_UInt16* ns) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 1;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 296LU);
UA_Argument variablenode_ns_0_i_12874_variant_DataContents[1];

UA_init(&variablenode_ns_0_i_12874_variant_DataContents[0], &UA_TYPES[UA_TYPES_ARGUMENT]);
variablenode_ns_0_i_12874_variant_DataContents[0].name = UA_STRING("SubscriptionId");
variablenode_ns_0_i_12874_variant_DataContents[0].dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
variablenode_ns_0_i_12874_variant_DataContents[0].valueRank = (UA_Int32) -1;
UA_Variant_setArray(&attr.value, &variablenode_ns_0_i_12874_variant_DataContents, (UA_Int32) 1, &UA_TYPES[UA_TYPES_ARGUMENT]);
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 12874LU),UA_NODEID_NUMERIC(ns[0], 12873LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "InputArguments"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);

return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_523_finish(UA_Server *server, UA_UInt16* ns) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 12874LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* GetMonitoredItems - ns=0;i=11492 */

static UA_StatusCode function_namespace0_generated_524_begin(UA_Server *server, UA_UInt16* ns) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_MethodAttributes attr = UA_MethodAttributes_default;
attr.executable = true;
attr.userExecutable = true;
attr.displayName = UA_LOCALIZEDTEXT("", "GetMonitoredItems");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_METHOD,UA_NODEID_NUMERIC(ns[0], 11492LU),UA_NODEID_NUMERIC(ns[0], 2253LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "GetMonitoredItems"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_METHODATTRIBUTES],NULL, NULL);
return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_524_finish(UA_Server *server, UA_UInt16* ns) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addMethodNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11492LU), NULL, 0, NULL, 0, NULL);
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* OutputArguments - ns=0;i=11494 */

static UA_StatusCode function_namespace0_generated_525_begin(UA_Server *server, UA_UInt16* ns) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 296LU);
UA_Argument variablenode_ns_0_i_11494_variant_DataContents[2];

UA_init(&variablenode_ns_0_i_11494_variant_DataContents[0], &UA_TYPES[UA_TYPES_ARGUMENT]);
variablenode_ns_0_i_11494_variant_DataContents[0].name = UA_STRING("ServerHandles");
variablenode_ns_0_i_11494_variant_DataContents[0].dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
variablenode_ns_0_i_11494_variant_DataContents[0].valueRank = (UA_Int32) 1;
UA_STACKARRAY(UA_UInt32, variablenode_ns_0_i_11494_variant_DataContents0_arrayDimensions, 1);
UA_init(variablenode_ns_0_i_11494_variant_DataContents0_arrayDimensions, &UA_TYPES[UA_TYPES_UINT32]);
variablenode_ns_0_i_11494_variant_DataContents0_arrayDimensions[0] = (UA_UInt32) 0;
variablenode_ns_0_i_11494_variant_DataContents[0].arrayDimensionsSize = 1;
variablenode_ns_0_i_11494_variant_DataContents[0].arrayDimensions = variablenode_ns_0_i_11494_variant_DataContents0_arrayDimensions;

UA_init(&variablenode_ns_0_i_11494_variant_DataContents[1], &UA_TYPES[UA_TYPES_ARGUMENT]);
variablenode_ns_0_i_11494_variant_DataContents[1].name = UA_STRING("ClientHandles");
variablenode_ns_0_i_11494_variant_DataContents[1].dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
variablenode_ns_0_i_11494_variant_DataContents[1].valueRank = (UA_Int32) 1;
UA_STACKARRAY(UA_UInt32, variablenode_ns_0_i_11494_variant_DataContents1_arrayDimensions, 1);
UA_init(variablenode_ns_0_i_11494_variant_DataContents1_arrayDimensions, &UA_TYPES[UA_TYPES_UINT32]);
variablenode_ns_0_i_11494_variant_DataContents1_arrayDimensions[0] = (UA_UInt32) 0;
variablenode_ns_0_i_11494_variant_DataContents[1].arrayDimensionsSize = 1;
variablenode_ns_0_i_11494_variant_DataContents[1].arrayDimensions = variablenode_ns_0_i_11494_variant_DataContents1_arrayDimensions;
UA_Variant_setArray(&attr.value, &variablenode_ns_0_i_11494_variant_DataContents, (UA_Int32) 2, &UA_TYPES[UA_TYPES_ARGUMENT]);
attr.displayName = UA_LOCALIZEDTEXT("", "OutputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11494LU),UA_NODEID_NUMERIC(ns[0], 11492LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "OutputArguments"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);


return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_525_finish(UA_Server *server, UA_UInt16* ns) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11494LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* InputArguments - ns=0;i=11493 */

static UA_StatusCode function_namespace0_generated_526_begin(UA_Server *server, UA_UInt16* ns) {
#ifdef UA_ENABLE_METHODCALLS
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
attr.valueRank = 1;
attr.arrayDimensionsSize = 1;
UA_UInt32 arrayDimensions[1];
arrayDimensions[0] = 0;
attr.arrayDimensions = &arrayDimensions[0];
attr.dataType = UA_NODEID_NUMERIC(ns[0], 296LU);
UA_Argument variablenode_ns_0_i_11493_variant_DataContents[1];

UA_init(&variablenode_ns_0_i_11493_variant_DataContents[0], &UA_TYPES[UA_TYPES_ARGUMENT]);
variablenode_ns_0_i_11493_variant_DataContents[0].name = UA_STRING("SubscriptionId");
variablenode_ns_0_i_11493_variant_DataContents[0].dataType = UA_NODEID_NUMERIC(ns[0], 7LU);
variablenode_ns_0_i_11493_variant_DataContents[0].valueRank = (UA_Int32) -1;
UA_Variant_setArray(&attr.value, &variablenode_ns_0_i_11493_variant_DataContents, (UA_Int32) 1, &UA_TYPES[UA_TYPES_ARGUMENT]);
attr.displayName = UA_LOCALIZEDTEXT("", "InputArguments");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11493LU),UA_NODEID_NUMERIC(ns[0], 11492LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "InputArguments"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);

return retVal;
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

static UA_StatusCode function_namespace0_generated_526_finish(UA_Server *server, UA_UInt16* ns) {
#ifdef UA_ENABLE_METHODCALLS
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11493LU));
#else
return UA_STATUSCODE_GOOD;
#endif /* UA_ENABLE_METHODCALLS */
}

/* VendorServerInfo - ns=0;i=2011 */

static UA_StatusCode function_namespace0_generated_527_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "VendorServerInfo");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(ns[0], 2011LU),UA_NODEID_NUMERIC(ns[0], 2004LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "VendorServerInfo"),UA_NODEID_NUMERIC(ns[0], 2033LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_527_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 2011LU));
}

/* ModellingRuleType - ns=0;i=77 */

static UA_StatusCode function_namespace0_generated_528_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ModellingRuleType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(ns[0], 77LU),UA_NODEID_NUMERIC(ns[0], 58LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "ModellingRuleType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_528_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 77LU));
}

/* ExposesItsArray - ns=0;i=83 */

static UA_StatusCode function_namespace0_generated_529_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "ExposesItsArray");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(ns[0], 83LU),UA_NODEID_NUMERIC(ns[0], 0LU),UA_NODEID_NUMERIC(ns[0], 0LU),UA_QUALIFIEDNAME(ns[0], "ExposesItsArray"),UA_NODEID_NUMERIC(ns[0], 77LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 83LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12860LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 83LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12816LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 83LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12779LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 83LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12784LU), false);
return retVal;
}

static UA_StatusCode function_namespace0_generated_529_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 83LU));
}

/* NamingRule - ns=0;i=114 */

static UA_StatusCode function_namespace0_generated_530_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 120LU);
UA_Int32 *variablenode_ns_0_i_114_variant_DataContents =  UA_Int32_new();
if (!variablenode_ns_0_i_114_variant_DataContents) return UA_STATUSCODE_BADOUTOFMEMORY;
UA_Int32_init(variablenode_ns_0_i_114_variant_DataContents);
*variablenode_ns_0_i_114_variant_DataContents = (UA_Int32) 3;
UA_Variant_setScalar(&attr.value, variablenode_ns_0_i_114_variant_DataContents, &UA_TYPES[UA_TYPES_INT32]);
attr.displayName = UA_LOCALIZEDTEXT("", "NamingRule");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 114LU),UA_NODEID_NUMERIC(ns[0], 83LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "NamingRule"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
UA_Int32_delete(variablenode_ns_0_i_114_variant_DataContents);
return retVal;
}

static UA_StatusCode function_namespace0_generated_530_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 114LU));
}

/* Optional - ns=0;i=80 */

static UA_StatusCode function_namespace0_generated_531_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Optional");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(ns[0], 80LU),UA_NODEID_NUMERIC(ns[0], 0LU),UA_NODEID_NUMERIC(ns[0], 0LU),UA_QUALIFIEDNAME(ns[0], "Optional"),UA_NODEID_NUMERIC(ns[0], 77LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11551LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11565LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11567LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11569LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11570LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11571LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11572LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11573LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11574LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2022LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3190LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2366LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2367LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2370LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 80LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2371LU), false);
return retVal;
}

static UA_StatusCode function_namespace0_generated_531_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 80LU));
}

/* NamingRule - ns=0;i=113 */

static UA_StatusCode function_namespace0_generated_532_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 120LU);
UA_Int32 *variablenode_ns_0_i_113_variant_DataContents =  UA_Int32_new();
if (!variablenode_ns_0_i_113_variant_DataContents) return UA_STATUSCODE_BADOUTOFMEMORY;
UA_Int32_init(variablenode_ns_0_i_113_variant_DataContents);
*variablenode_ns_0_i_113_variant_DataContents = (UA_Int32) 2;
UA_Variant_setScalar(&attr.value, variablenode_ns_0_i_113_variant_DataContents, &UA_TYPES[UA_TYPES_INT32]);
attr.displayName = UA_LOCALIZEDTEXT("", "NamingRule");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 113LU),UA_NODEID_NUMERIC(ns[0], 80LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "NamingRule"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
UA_Int32_delete(variablenode_ns_0_i_113_variant_DataContents);
return retVal;
}

static UA_StatusCode function_namespace0_generated_532_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 113LU));
}

/* Mandatory - ns=0;i=78 */

static UA_StatusCode function_namespace0_generated_533_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Mandatory");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(ns[0], 78LU),UA_NODEID_NUMERIC(ns[0], 0LU),UA_NODEID_NUMERIC(ns[0], 0LU),UA_QUALIFIEDNAME(ns[0], "Mandatory"),UA_NODEID_NUMERIC(ns[0], 77LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12169LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2011LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2035LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 7611LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2021LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3116LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3117LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3118LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3119LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3120LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3121LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3122LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3124LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3125LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3126LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3127LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3128LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2023LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12142LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12152LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12143LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12144LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12145LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12146LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12147LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12148LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12149LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12150LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12151LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2027LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2028LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12098LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12099LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12100LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12101LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12102LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12103LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12104LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12105LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12106LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12107LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12108LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12109LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12110LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12111LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12112LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12113LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12114LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12115LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12116LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12117LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12118LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12119LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12120LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12121LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12122LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12123LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12124LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12125LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12126LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12127LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12128LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12129LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12130LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12131LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12132LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12133LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12134LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12135LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12136LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12137LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12138LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12139LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12140LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12141LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12861LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12862LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12863LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12864LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12865LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12866LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12867LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12868LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12869LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2744LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3129LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3130LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2025LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12817LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12818LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12819LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12820LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12821LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12822LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12823LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12824LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12825LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12826LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12827LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12828LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12829LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12830LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12831LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12832LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12833LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12834LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12835LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12836LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12837LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12838LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12839LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12840LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12841LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12842LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12843LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12844LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12845LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12846LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12847LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12848LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12849LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12850LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12851LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12852LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12853LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12854LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12855LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12856LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12857LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12858LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12859LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12780LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12781LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12782LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12783LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2166LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11697LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11698LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11699LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2151LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2152LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2153LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2154LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2155LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2156LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2157LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2159LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2160LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2161LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2162LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2163LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 7595LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 7597LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2030LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3131LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3132LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3133LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3134LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3135LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3136LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3137LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3138LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3139LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3140LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3141LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3142LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3143LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 8898LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11891LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3151LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3152LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3153LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3154LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3155LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3156LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3157LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3158LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3159LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3160LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3161LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3162LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3163LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3164LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3165LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3166LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3167LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3168LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3169LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3170LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3171LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3172LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3173LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3174LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3175LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3176LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3177LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3178LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2031LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3179LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3180LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3181LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3182LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3183LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3184LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3185LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3186LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3187LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2245LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2246LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2247LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2248LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2249LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2250LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2251LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2252LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3058LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2032LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12785LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12786LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12787LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12788LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12789LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12790LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12791LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12792LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12793LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12794LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12795LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12796LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12797LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12798LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12799LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12800LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12801LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12802LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12803LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12804LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12805LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12806LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12807LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12808LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12809LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12810LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12811LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12812LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12813LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12814LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12815LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2173LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2174LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2175LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2176LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2177LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 8888LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2179LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2180LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2181LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2182LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2183LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2184LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2185LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2186LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2187LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2188LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2189LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2190LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2191LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2998LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2193LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 8889LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 8890LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 8891LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 8892LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 8893LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 8894LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 8895LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 8896LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 8897LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 8902LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2198LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2199LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2200LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2201LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2202LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2203LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2204LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 3050LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2205LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2206LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2207LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2208LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2209LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 8900LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11892LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2217LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2218LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2219LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2220LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2221LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2222LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2223LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2224LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2225LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2226LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2227LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2228LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2229LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2230LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2231LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2232LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2233LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2234LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2235LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2236LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2237LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2238LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2239LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2240LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2241LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2242LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2730LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2731LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2042LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2043LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2044LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2045LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2046LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2047LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2050LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2051LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2369LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2374LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2375LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 2377LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11241LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 11461LU), false);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 78LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12078LU), false);
return retVal;
}

static UA_StatusCode function_namespace0_generated_533_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 78LU));
}

/* NamingRule - ns=0;i=112 */

static UA_StatusCode function_namespace0_generated_534_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 120LU);
UA_Int32 *variablenode_ns_0_i_112_variant_DataContents =  UA_Int32_new();
if (!variablenode_ns_0_i_112_variant_DataContents) return UA_STATUSCODE_BADOUTOFMEMORY;
UA_Int32_init(variablenode_ns_0_i_112_variant_DataContents);
*variablenode_ns_0_i_112_variant_DataContents = (UA_Int32) 1;
UA_Variant_setScalar(&attr.value, variablenode_ns_0_i_112_variant_DataContents, &UA_TYPES[UA_TYPES_INT32]);
attr.displayName = UA_LOCALIZEDTEXT("", "NamingRule");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 112LU),UA_NODEID_NUMERIC(ns[0], 78LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "NamingRule"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
UA_Int32_delete(variablenode_ns_0_i_112_variant_DataContents);
return retVal;
}

static UA_StatusCode function_namespace0_generated_534_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 112LU));
}

/* MandatoryPlaceholder - ns=0;i=11510 */

static UA_StatusCode function_namespace0_generated_535_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "MandatoryPlaceholder");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(ns[0], 11510LU),UA_NODEID_NUMERIC(ns[0], 0LU),UA_NODEID_NUMERIC(ns[0], 0LU),UA_QUALIFIEDNAME(ns[0], "MandatoryPlaceholder"),UA_NODEID_NUMERIC(ns[0], 77LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_535_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11510LU));
}

/* NamingRule - ns=0;i=11511 */

static UA_StatusCode function_namespace0_generated_536_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 120LU);
UA_Int32 *variablenode_ns_0_i_11511_variant_DataContents =  UA_Int32_new();
if (!variablenode_ns_0_i_11511_variant_DataContents) return UA_STATUSCODE_BADOUTOFMEMORY;
UA_Int32_init(variablenode_ns_0_i_11511_variant_DataContents);
*variablenode_ns_0_i_11511_variant_DataContents = (UA_Int32) 1;
UA_Variant_setScalar(&attr.value, variablenode_ns_0_i_11511_variant_DataContents, &UA_TYPES[UA_TYPES_INT32]);
attr.displayName = UA_LOCALIZEDTEXT("", "NamingRule");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11511LU),UA_NODEID_NUMERIC(ns[0], 11510LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "NamingRule"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
UA_Int32_delete(variablenode_ns_0_i_11511_variant_DataContents);
return retVal;
}

static UA_StatusCode function_namespace0_generated_536_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11511LU));
}

/* OptionalPlaceholder - ns=0;i=11508 */

static UA_StatusCode function_namespace0_generated_537_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "OptionalPlaceholder");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(ns[0], 11508LU),UA_NODEID_NUMERIC(ns[0], 0LU),UA_NODEID_NUMERIC(ns[0], 0LU),UA_QUALIFIEDNAME(ns[0], "OptionalPlaceholder"),UA_NODEID_NUMERIC(ns[0], 77LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 11508LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 12097LU), false);
return retVal;
}

static UA_StatusCode function_namespace0_generated_537_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11508LU));
}

/* NamingRule - ns=0;i=11509 */

static UA_StatusCode function_namespace0_generated_538_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 120LU);
UA_Int32 *variablenode_ns_0_i_11509_variant_DataContents =  UA_Int32_new();
if (!variablenode_ns_0_i_11509_variant_DataContents) return UA_STATUSCODE_BADOUTOFMEMORY;
UA_Int32_init(variablenode_ns_0_i_11509_variant_DataContents);
*variablenode_ns_0_i_11509_variant_DataContents = (UA_Int32) 2;
UA_Variant_setScalar(&attr.value, variablenode_ns_0_i_11509_variant_DataContents, &UA_TYPES[UA_TYPES_INT32]);
attr.displayName = UA_LOCALIZEDTEXT("", "NamingRule");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 11509LU),UA_NODEID_NUMERIC(ns[0], 11508LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "NamingRule"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
UA_Int32_delete(variablenode_ns_0_i_11509_variant_DataContents);
return retVal;
}

static UA_StatusCode function_namespace0_generated_538_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 11509LU));
}

/* NamingRule - ns=0;i=111 */

static UA_StatusCode function_namespace0_generated_539_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 120LU);
UA_Int32 *variablenode_ns_0_i_111_variant_DataContents =  UA_Int32_new();
if (!variablenode_ns_0_i_111_variant_DataContents) return UA_STATUSCODE_BADOUTOFMEMORY;
UA_Int32_init(variablenode_ns_0_i_111_variant_DataContents);
*variablenode_ns_0_i_111_variant_DataContents = (UA_Int32) 1;
UA_Variant_setScalar(&attr.value, variablenode_ns_0_i_111_variant_DataContents, &UA_TYPES[UA_TYPES_INT32]);
attr.displayName = UA_LOCALIZEDTEXT("", "NamingRule");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 111LU),UA_NODEID_NUMERIC(ns[0], 77LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "NamingRule"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
UA_Int32_delete(variablenode_ns_0_i_111_variant_DataContents);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 111LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 78LU), true);
return retVal;
}

static UA_StatusCode function_namespace0_generated_539_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 111LU));
}

/* DataTypeEncodingType - ns=0;i=76 */

static UA_StatusCode function_namespace0_generated_540_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "DataTypeEncodingType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(ns[0], 76LU),UA_NODEID_NUMERIC(ns[0], 58LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "DataTypeEncodingType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_540_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 76LU));
}

/* Default Binary - ns=0;i=8251 */

static UA_StatusCode function_namespace0_generated_541_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Default Binary");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(ns[0], 8251LU),UA_NODEID_NUMERIC(ns[0], 0LU),UA_NODEID_NUMERIC(ns[0], 0LU),UA_QUALIFIEDNAME(ns[0], "Default Binary"),UA_NODEID_NUMERIC(ns[0], 76LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 8251LU), UA_NODEID_NUMERIC(ns[0], 38LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 7594LU), false);
return retVal;
}

static UA_StatusCode function_namespace0_generated_541_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 8251LU));
}

/* Default Binary - ns=0;i=298 */

static UA_StatusCode function_namespace0_generated_542_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Default Binary");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(ns[0], 298LU),UA_NODEID_NUMERIC(ns[0], 0LU),UA_NODEID_NUMERIC(ns[0], 0LU),UA_QUALIFIEDNAME(ns[0], "Default Binary"),UA_NODEID_NUMERIC(ns[0], 76LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 298LU), UA_NODEID_NUMERIC(ns[0], 38LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 296LU), false);
return retVal;
}

static UA_StatusCode function_namespace0_generated_542_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 298LU));
}

/* Default JSON - ns=0;i=15376 */

static UA_StatusCode function_namespace0_generated_543_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Default JSON");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(ns[0], 15376LU),UA_NODEID_NUMERIC(ns[0], 0LU),UA_NODEID_NUMERIC(ns[0], 0LU),UA_QUALIFIEDNAME(ns[0], "Default JSON"),UA_NODEID_NUMERIC(ns[0], 76LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 15376LU), UA_NODEID_NUMERIC(ns[0], 38LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 887LU), false);
return retVal;
}

static UA_StatusCode function_namespace0_generated_543_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 15376LU));
}

/* Default JSON - ns=0;i=15375 */

static UA_StatusCode function_namespace0_generated_544_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Default JSON");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(ns[0], 15375LU),UA_NODEID_NUMERIC(ns[0], 0LU),UA_NODEID_NUMERIC(ns[0], 0LU),UA_QUALIFIEDNAME(ns[0], "Default JSON"),UA_NODEID_NUMERIC(ns[0], 76LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 15375LU), UA_NODEID_NUMERIC(ns[0], 38LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 884LU), false);
return retVal;
}

static UA_StatusCode function_namespace0_generated_544_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 15375LU));
}

/* DataTypeSystemType - ns=0;i=75 */

static UA_StatusCode function_namespace0_generated_545_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "DataTypeSystemType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECTTYPE,UA_NODEID_NUMERIC(ns[0], 75LU),UA_NODEID_NUMERIC(ns[0], 58LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "DataTypeSystemType"), UA_NODEID_NULL,(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTTYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_545_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 75LU));
}

/* OPC Binary - ns=0;i=93 */

static UA_StatusCode function_namespace0_generated_546_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "OPC Binary");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(ns[0], 93LU),UA_NODEID_NUMERIC(ns[0], 90LU),UA_NODEID_NUMERIC(ns[0], 35LU),UA_QUALIFIEDNAME(ns[0], "OPC Binary"),UA_NODEID_NUMERIC(ns[0], 75LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_546_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 93LU));
}

/* XML Schema - ns=0;i=92 */

static UA_StatusCode function_namespace0_generated_547_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "XML Schema");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(ns[0], 92LU),UA_NODEID_NUMERIC(ns[0], 90LU),UA_NODEID_NUMERIC(ns[0], 35LU),UA_QUALIFIEDNAME(ns[0], "XML Schema"),UA_NODEID_NUMERIC(ns[0], 75LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_547_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 92LU));
}

/* DataTypeDictionaryType - ns=0;i=72 */

static UA_StatusCode function_namespace0_generated_548_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 15LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DataTypeDictionaryType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(ns[0], 72LU),UA_NODEID_NUMERIC(ns[0], 63LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "DataTypeDictionaryType"),UA_NODEID_NUMERIC(ns[0], 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_548_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 72LU));
}

/* Opc.Ua - ns=0;i=7617 */
static const UA_Byte variablenode_ns_0_i_7617_variant_DataContents_byteArray[177218] = {60, 111, 112, 99, 58, 84, 121, 112, 101, 68, 105, 99, 116, 105, 111, 110, 97, 114, 121, 13, 10, 32, 32, 120, 109, 108, 110, 115, 58, 111, 112, 99, 61, 34, 104, 116, 116, 112, 58, 47, 47, 111, 112, 99, 102, 111, 117, 110, 100, 97, 116, 105, 111, 110, 46, 111, 114, 103, 47, 66, 105, 110, 97, 114, 121, 83, 99, 104, 101, 109, 97, 47, 34, 13, 10, 32, 32, 120, 109, 108, 110, 115, 58, 120, 115, 105, 61, 34, 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 119, 51, 46, 111, 114, 103, 47, 50, 48, 48, 49, 47, 88, 77, 76, 83, 99, 104, 101, 109, 97, 45, 105, 110, 115, 116, 97, 110, 99, 101, 34, 13, 10, 32, 32, 120, 109, 108, 110, 115, 58, 117, 97, 61, 34, 104, 116, 116, 112, 58, 47, 47, 111, 112, 99, 102, 111, 117, 110, 100, 97, 116, 105, 111, 110, 46, 111, 114, 103, 47, 85, 65, 47, 34, 13, 10, 32, 32, 120, 109, 108, 110, 115, 58, 116, 110, 115, 61, 34, 104, 116, 116, 112, 58, 47, 47, 111, 112, 99, 102, 111, 117, 110, 100, 97, 116, 105, 111, 110, 46, 111, 114, 103, 47, 85, 65, 47, 34, 13, 10, 32, 32, 68, 101, 102, 97, 117, 108, 116, 66, 121, 116, 101, 79, 114, 100, 101, 114, 61, 34, 76, 105, 116, 116, 108, 101, 69, 110, 100, 105, 97, 110, 34, 13, 10, 32, 32, 84, 97, 114, 103, 101, 116, 78, 97, 109, 101, 115, 112, 97, 99, 101, 61, 34, 104, 116, 116, 112, 58, 47, 47, 111, 112, 99, 102, 111, 117, 110, 100, 97, 116, 105, 111, 110, 46, 111, 114, 103, 47, 85, 65, 47, 34, 13, 10, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 73, 109, 112, 111, 114, 116, 32, 78, 97, 109, 101, 115, 112, 97, 99, 101, 61, 34, 104, 116, 116, 112, 58, 47, 47, 111, 112, 99, 102, 111, 117, 110, 100, 97, 116, 105, 111, 110, 46, 111, 114, 103, 47, 66, 105, 110, 97, 114, 121, 83, 99, 104, 101, 109, 97, 47, 34, 32, 47, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 88, 109, 108, 69, 108, 101, 109, 101, 110, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 65, 110, 32, 88, 77, 76, 32, 101, 108, 101, 109, 101, 110, 116, 32, 101, 110, 99, 111, 100, 101, 100, 32, 97, 115, 32, 97, 32, 85, 84, 70, 45, 56, 32, 115, 116, 114, 105, 110, 103, 46, 60, 47, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 101, 110, 103, 116, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 67, 104, 97, 114, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 76, 101, 110, 103, 116, 104, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 54, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 84, 104, 101, 32, 112, 111, 115, 115, 105, 98, 108, 101, 32, 101, 110, 99, 111, 100, 105, 110, 103, 115, 32, 102, 111, 114, 32, 97, 32, 78, 111, 100, 101, 73, 100, 32, 118, 97, 108, 117, 101, 46, 60, 47, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 84, 119, 111, 66, 121, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 70, 111, 117, 114, 66, 121, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 117, 109, 101, 114, 105, 99, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 105, 110, 103, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 71, 117, 105, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 86, 97, 108, 117, 101, 61, 34, 53, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 119, 111, 66, 121, 116, 101, 78, 111, 100, 101, 73, 100, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 100, 101, 110, 116, 105, 102, 105, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 70, 111, 117, 114, 66, 121, 116, 101, 78, 111, 100, 101, 73, 100, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 73, 110, 100, 101, 120, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 100, 101, 110, 116, 105, 102, 105, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 117, 109, 101, 114, 105, 99, 78, 111, 100, 101, 73, 100, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 73, 110, 100, 101, 120, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 100, 101, 110, 116, 105, 102, 105, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 105, 110, 103, 78, 111, 100, 101, 73, 100, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 73, 110, 100, 101, 120, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 100, 101, 110, 116, 105, 102, 105, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 67, 104, 97, 114, 65, 114, 114, 97, 121, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 71, 117, 105, 100, 78, 111, 100, 101, 73, 100, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 73, 110, 100, 101, 120, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 100, 101, 110, 116, 105, 102, 105, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 71, 117, 105, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 78, 111, 100, 101, 73, 100, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 73, 110, 100, 101, 120, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 100, 101, 110, 116, 105, 102, 105, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 65, 110, 32, 105, 100, 101, 110, 116, 105, 102, 105, 101, 114, 32, 102, 111, 114, 32, 97, 32, 110, 111, 100, 101, 32, 105, 110, 32, 97, 32, 85, 65, 32, 115, 101, 114, 118, 101, 114, 32, 97, 100, 100, 114, 101, 115, 115, 32, 115, 112, 97, 99, 101, 46, 60, 47, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 101, 114, 118, 101, 100, 49, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 76, 101, 110, 103, 116, 104, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 119, 111, 66, 121, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 84, 119, 111, 66, 121, 116, 101, 78, 111, 100, 101, 73, 100, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 111, 117, 114, 66, 121, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 70, 111, 117, 114, 66, 121, 116, 101, 78, 111, 100, 101, 73, 100, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 117, 109, 101, 114, 105, 99, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 117, 109, 101, 114, 105, 99, 78, 111, 100, 101, 73, 100, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 105, 110, 103, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 114, 105, 110, 103, 78, 111, 100, 101, 73, 100, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 71, 117, 105, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 71, 117, 105, 100, 78, 111, 100, 101, 73, 100, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 78, 111, 100, 101, 73, 100, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 53, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 65, 110, 32, 105, 100, 101, 110, 116, 105, 102, 105, 101, 114, 32, 102, 111, 114, 32, 97, 32, 110, 111, 100, 101, 32, 105, 110, 32, 97, 32, 85, 65, 32, 115, 101, 114, 118, 101, 114, 32, 97, 100, 100, 114, 101, 115, 115, 32, 115, 112, 97, 99, 101, 32, 113, 117, 97, 108, 105, 102, 105, 101, 100, 32, 119, 105, 116, 104, 32, 97, 32, 99, 111, 109, 112, 108, 101, 116, 101, 32, 110, 97, 109, 101, 115, 112, 97, 99, 101, 32, 115, 116, 114, 105, 110, 103, 46, 60, 47, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 73, 110, 100, 101, 120, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 85, 82, 73, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 119, 111, 66, 121, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 84, 119, 111, 66, 121, 116, 101, 78, 111, 100, 101, 73, 100, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 111, 117, 114, 66, 121, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 70, 111, 117, 114, 66, 121, 116, 101, 78, 111, 100, 101, 73, 100, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 117, 109, 101, 114, 105, 99, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 117, 109, 101, 114, 105, 99, 78, 111, 100, 101, 73, 100, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 105, 110, 103, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 114, 105, 110, 103, 78, 111, 100, 101, 73, 100, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 71, 117, 105, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 71, 117, 105, 100, 78, 111, 100, 101, 73, 100, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 78, 111, 100, 101, 73, 100, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 100, 101, 73, 100, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 53, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 85, 82, 73, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 67, 104, 97, 114, 65, 114, 114, 97, 121, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 85, 82, 73, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 73, 110, 100, 101, 120, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 83, 101, 114, 118, 101, 114, 73, 110, 100, 101, 120, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 32, 66, 121, 116, 101, 79, 114, 100, 101, 114, 83, 105, 103, 110, 105, 102, 105, 99, 97, 110, 116, 61, 34, 116, 114, 117, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 65, 32, 51, 50, 45, 98, 105, 116, 32, 115, 116, 97, 116, 117, 115, 32, 99, 111, 100, 101, 32, 118, 97, 108, 117, 101, 46, 60, 47, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 65, 32, 114, 101, 99, 117, 114, 115, 105, 118, 101, 32, 115, 116, 114, 117, 99, 116, 117, 114, 101, 32, 99, 111, 110, 116, 97, 105, 110, 105, 110, 103, 32, 100, 105, 97, 103, 110, 111, 115, 116, 105, 99, 32, 105, 110, 102, 111, 114, 109, 97, 116, 105, 111, 110, 32, 97, 115, 115, 111, 99, 105, 97, 116, 101, 100, 32, 119, 105, 116, 104, 32, 97, 32, 115, 116, 97, 116, 117, 115, 32, 99, 111, 100, 101, 46, 60, 47, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 121, 109, 98, 111, 108, 105, 99, 73, 100, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 85, 82, 73, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 101, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 105, 116, 105, 111, 110, 97, 108, 73, 110, 102, 111, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 110, 101, 114, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 110, 101, 114, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 101, 114, 118, 101, 100, 49, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 76, 101, 110, 103, 116, 104, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 121, 109, 98, 111, 108, 105, 99, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 83, 121, 109, 98, 111, 108, 105, 99, 73, 100, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 85, 82, 73, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 85, 82, 73, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 76, 111, 99, 97, 108, 101, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 105, 116, 105, 111, 110, 97, 108, 73, 110, 102, 111, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 67, 104, 97, 114, 65, 114, 114, 97, 121, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 65, 100, 100, 105, 116, 105, 111, 110, 97, 108, 73, 110, 102, 111, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 110, 101, 114, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 73, 110, 110, 101, 114, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 110, 101, 114, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 73, 110, 110, 101, 114, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 65, 32, 115, 116, 114, 105, 110, 103, 32, 113, 117, 97, 108, 105, 102, 105, 101, 100, 32, 119, 105, 116, 104, 32, 97, 32, 110, 97, 109, 101, 115, 112, 97, 99, 101, 32, 105, 110, 100, 101, 120, 46, 60, 47, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 73, 110, 100, 101, 120, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 67, 104, 97, 114, 65, 114, 114, 97, 121, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 65, 32, 115, 116, 114, 105, 110, 103, 32, 113, 117, 97, 108, 105, 102, 105, 101, 100, 32, 119, 105, 116, 104, 32, 97, 32, 110, 97, 109, 101, 115, 112, 97, 99, 101, 32, 105, 110, 100, 101, 120, 46, 60, 47, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 101, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 101, 120, 116, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 101, 114, 118, 101, 100, 49, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 76, 101, 110, 103, 116, 104, 61, 34, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 67, 104, 97, 114, 65, 114, 114, 97, 121, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 76, 111, 99, 97, 108, 101, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 101, 120, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 67, 104, 97, 114, 65, 114, 114, 97, 121, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 84, 101, 120, 116, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 86, 97, 108, 117, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 65, 32, 118, 97, 108, 117, 101, 32, 119, 105, 116, 104, 32, 97, 110, 32, 97, 115, 115, 111, 99, 105, 97, 116, 101, 100, 32, 116, 105, 109, 101, 115, 116, 97, 109, 112, 44, 32, 97, 110, 100, 32, 113, 117, 97, 108, 105, 116, 121, 46, 60, 47, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 111, 117, 114, 99, 101, 84, 105, 109, 101, 115, 116, 97, 109, 112, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 84, 105, 109, 101, 115, 116, 97, 109, 112, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 111, 117, 114, 99, 101, 80, 105, 99, 111, 115, 101, 99, 111, 110, 100, 115, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 80, 105, 99, 111, 115, 101, 99, 111, 110, 100, 115, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 101, 114, 118, 101, 100, 49, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 76, 101, 110, 103, 116, 104, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 108, 117, 101, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 111, 117, 114, 99, 101, 84, 105, 109, 101, 115, 116, 97, 109, 112, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 83, 111, 117, 114, 99, 101, 84, 105, 109, 101, 115, 116, 97, 109, 112, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 111, 117, 114, 99, 101, 80, 105, 99, 111, 115, 101, 99, 111, 110, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 83, 111, 117, 114, 99, 101, 80, 105, 99, 111, 115, 101, 99, 111, 110, 100, 115, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 84, 105, 109, 101, 115, 116, 97, 109, 112, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 83, 101, 114, 118, 101, 114, 84, 105, 109, 101, 115, 116, 97, 109, 112, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 80, 105, 99, 111, 115, 101, 99, 111, 110, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 83, 101, 114, 118, 101, 114, 80, 105, 99, 111, 115, 101, 99, 111, 110, 100, 115, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 65, 32, 115, 101, 114, 105, 97, 108, 105, 122, 101, 100, 32, 111, 98, 106, 101, 99, 116, 32, 112, 114, 101, 102, 105, 120, 101, 100, 32, 119, 105, 116, 104, 32, 105, 116, 115, 32, 100, 97, 116, 97, 32, 116, 121, 112, 101, 32, 105, 100, 101, 110, 116, 105, 102, 105, 101, 114, 46, 60, 47, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 121, 112, 101, 73, 100, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 105, 110, 97, 114, 121, 66, 111, 100, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 88, 109, 108, 66, 111, 100, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 101, 114, 118, 101, 100, 49, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 76, 101, 110, 103, 116, 104, 61, 34, 53, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 121, 112, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 84, 121, 112, 101, 73, 100, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 111, 100, 121, 76, 101, 110, 103, 116, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 111, 100, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 66, 111, 100, 121, 76, 101, 110, 103, 116, 104, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 86, 97, 114, 105, 97, 110, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 65, 32, 117, 110, 105, 111, 110, 32, 111, 102, 32, 115, 101, 118, 101, 114, 97, 108, 32, 116, 121, 112, 101, 115, 46, 60, 47, 111, 112, 99, 58, 68, 111, 99, 117, 109, 101, 110, 116, 97, 116, 105, 111, 110, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 76, 101, 110, 103, 116, 104, 61, 34, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 76, 101, 110, 103, 116, 104, 61, 34, 49, 34, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 105, 116, 34, 32, 76, 101, 110, 103, 116, 104, 61, 34, 49, 34, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 111, 111, 108, 101, 97, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 66, 121, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 66, 121, 116, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 121, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 116, 49, 54, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 49, 54, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 73, 110, 116, 49, 54, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 53, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 116, 51, 50, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 73, 110, 116, 51, 50, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 55, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 116, 54, 52, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 54, 52, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 73, 110, 116, 54, 52, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 54, 52, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 57, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 108, 111, 97, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 70, 108, 111, 97, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 49, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 111, 117, 98, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 49, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 105, 110, 103, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 67, 104, 97, 114, 65, 114, 114, 97, 121, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 49, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 49, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 71, 117, 105, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 71, 117, 105, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 49, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 49, 53, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 88, 109, 108, 69, 108, 101, 109, 101, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 88, 109, 108, 69, 108, 101, 109, 101, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 49, 55, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 49, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 49, 57, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 50, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 50, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 50, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 97, 116, 97, 86, 97, 108, 117, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 50, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 114, 105, 97, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 50, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 86, 97, 114, 105, 97, 110, 116, 84, 121, 112, 101, 34, 32, 83, 119, 105, 116, 99, 104, 86, 97, 108, 117, 101, 61, 34, 50, 53, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 83, 119, 105, 116, 99, 104, 70, 105, 101, 108, 100, 61, 34, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 105, 110, 103, 82, 117, 108, 101, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 77, 97, 110, 100, 97, 116, 111, 114, 121, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 79, 112, 116, 105, 111, 110, 97, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 115, 116, 114, 97, 105, 110, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 32, 32, 32, 32, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 73, 109, 97, 103, 101, 66, 77, 80, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 73, 109, 97, 103, 101, 71, 73, 70, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 73, 109, 97, 103, 101, 74, 80, 71, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 73, 109, 97, 103, 101, 80, 78, 71, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 117, 100, 105, 111, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 105, 116, 70, 105, 101, 108, 100, 77, 97, 115, 107, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 75, 101, 121, 86, 97, 108, 117, 101, 80, 97, 105, 114, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 75, 101, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 105, 116, 105, 111, 110, 97, 108, 80, 97, 114, 97, 109, 101, 116, 101, 114, 115, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 80, 97, 114, 97, 109, 101, 116, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 97, 114, 97, 109, 101, 116, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 75, 101, 121, 86, 97, 108, 117, 101, 80, 97, 105, 114, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 80, 97, 114, 97, 109, 101, 116, 101, 114, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 112, 104, 101, 109, 101, 114, 97, 108, 75, 101, 121, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 99, 75, 101, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 105, 103, 110, 97, 116, 117, 114, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 112, 111, 105, 110, 116, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 112, 111, 105, 110, 116, 85, 114, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 101, 115, 115, 97, 103, 101, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 80, 111, 108, 105, 99, 121, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 112, 111, 114, 116, 80, 114, 111, 102, 105, 108, 101, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 97, 116, 105, 111, 110, 97, 108, 78, 117, 109, 98, 101, 114, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 117, 109, 101, 114, 97, 116, 111, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 110, 111, 109, 105, 110, 97, 116, 111, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 86, 101, 99, 116, 111, 114, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 104, 114, 101, 101, 68, 86, 101, 99, 116, 111, 114, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 86, 101, 99, 116, 111, 114, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 88, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 89, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 90, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 97, 114, 116, 101, 115, 105, 97, 110, 67, 111, 111, 114, 100, 105, 110, 97, 116, 101, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 104, 114, 101, 101, 68, 67, 97, 114, 116, 101, 115, 105, 97, 110, 67, 111, 111, 114, 100, 105, 110, 97, 116, 101, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 67, 97, 114, 116, 101, 115, 105, 97, 110, 67, 111, 111, 114, 100, 105, 110, 97, 116, 101, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 88, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 89, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 90, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 79, 114, 105, 101, 110, 116, 97, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 104, 114, 101, 101, 68, 79, 114, 105, 101, 110, 116, 97, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 79, 114, 105, 101, 110, 116, 97, 116, 105, 111, 110, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 70, 114, 97, 109, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 104, 114, 101, 101, 68, 70, 114, 97, 109, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 70, 114, 97, 109, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 97, 114, 116, 101, 115, 105, 97, 110, 67, 111, 111, 114, 100, 105, 110, 97, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 84, 104, 114, 101, 101, 68, 67, 97, 114, 116, 101, 115, 105, 97, 110, 67, 111, 111, 114, 100, 105, 110, 97, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 79, 114, 105, 101, 110, 116, 97, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 84, 104, 114, 101, 101, 68, 79, 114, 105, 101, 110, 116, 97, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 79, 112, 101, 110, 70, 105, 108, 101, 77, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 69, 114, 97, 115, 101, 69, 120, 105, 115, 116, 105, 110, 103, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 112, 112, 101, 110, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 73, 100, 101, 110, 116, 105, 116, 121, 67, 114, 105, 116, 101, 114, 105, 97, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 78, 97, 109, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 84, 104, 117, 109, 98, 112, 114, 105, 110, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 71, 114, 111, 117, 112, 73, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 110, 111, 110, 121, 109, 111, 117, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 53, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 101, 100, 85, 115, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 73, 100, 101, 110, 116, 105, 116, 121, 77, 97, 112, 112, 105, 110, 103, 82, 117, 108, 101, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 114, 105, 116, 101, 114, 105, 97, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 73, 100, 101, 110, 116, 105, 116, 121, 67, 114, 105, 116, 101, 114, 105, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 114, 105, 116, 101, 114, 105, 97, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 117, 114, 114, 101, 110, 99, 121, 85, 110, 105, 116, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 117, 109, 101, 114, 105, 99, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 120, 112, 111, 110, 101, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 108, 112, 104, 97, 98, 101, 116, 105, 99, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 117, 114, 114, 101, 110, 99, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 114, 117, 115, 116, 76, 105, 115, 116, 77, 97, 115, 107, 115, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 84, 114, 117, 115, 116, 101, 100, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 84, 114, 117, 115, 116, 101, 100, 67, 114, 108, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 115, 115, 117, 101, 114, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 115, 115, 117, 101, 114, 67, 114, 108, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 108, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 53, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 114, 117, 115, 116, 76, 105, 115, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 112, 101, 99, 105, 102, 105, 101, 100, 76, 105, 115, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 84, 114, 117, 115, 116, 101, 100, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 117, 115, 116, 101, 100, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 84, 114, 117, 115, 116, 101, 100, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 84, 114, 117, 115, 116, 101, 100, 67, 114, 108, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 117, 115, 116, 101, 100, 67, 114, 108, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 84, 114, 117, 115, 116, 101, 100, 67, 114, 108, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 73, 115, 115, 117, 101, 114, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 115, 117, 101, 114, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 73, 115, 115, 117, 101, 114, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 73, 115, 115, 117, 101, 114, 67, 114, 108, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 115, 117, 101, 114, 67, 114, 108, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 73, 115, 115, 117, 101, 114, 67, 114, 108, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 99, 105, 109, 97, 108, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 99, 97, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 83, 99, 104, 101, 109, 97, 72, 101, 97, 100, 101, 114, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 97, 109, 101, 115, 112, 97, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 97, 109, 101, 115, 112, 97, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 110, 117, 109, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 117, 109, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 110, 117, 109, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 110, 117, 109, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 105, 109, 112, 108, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 105, 109, 112, 108, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 105, 109, 112, 108, 101, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 105, 109, 112, 108, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 110, 117, 109, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 117, 109, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 110, 117, 109, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 117, 105, 108, 116, 73, 110, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 105, 109, 112, 108, 101, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 97, 115, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 117, 105, 108, 116, 73, 110, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 65, 66, 105, 110, 97, 114, 121, 70, 105, 108, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 84, 121, 112, 101, 83, 99, 104, 101, 109, 97, 72, 101, 97, 100, 101, 114, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 97, 109, 101, 115, 112, 97, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 97, 109, 101, 115, 112, 97, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 110, 117, 109, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 117, 109, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 110, 117, 109, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 110, 117, 109, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 105, 109, 112, 108, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 105, 109, 112, 108, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 105, 109, 112, 108, 101, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 105, 109, 112, 108, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 99, 104, 101, 109, 97, 76, 111, 99, 97, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 70, 105, 108, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 108, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 75, 101, 121, 86, 97, 108, 117, 101, 80, 97, 105, 114, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 70, 105, 108, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 111, 100, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 83, 117, 98, 83, 116, 97, 116, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 97, 98, 108, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 80, 97, 117, 115, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 79, 112, 101, 114, 97, 116, 105, 111, 110, 97, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 69, 114, 114, 111, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 77, 101, 116, 97, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 84, 121, 112, 101, 83, 99, 104, 101, 109, 97, 72, 101, 97, 100, 101, 114, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 97, 109, 101, 115, 112, 97, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 97, 109, 101, 115, 112, 97, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 110, 117, 109, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 117, 109, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 110, 117, 109, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 110, 117, 109, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 105, 109, 112, 108, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 105, 109, 112, 108, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 105, 109, 112, 108, 101, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 105, 109, 112, 108, 101, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 70, 105, 101, 108, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 101, 108, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 70, 105, 101, 108, 100, 77, 101, 116, 97, 68, 97, 116, 97, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 70, 105, 101, 108, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 67, 108, 97, 115, 115, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 71, 117, 105, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 86, 101, 114, 115, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 86, 101, 114, 115, 105, 111, 110, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 70, 105, 101, 108, 100, 77, 101, 116, 97, 68, 97, 116, 97, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 101, 108, 100, 70, 108, 97, 103, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 83, 101, 116, 70, 105, 101, 108, 100, 70, 108, 97, 103, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 117, 105, 108, 116, 73, 110, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 82, 97, 110, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 83, 116, 114, 105, 110, 103, 76, 101, 110, 103, 116, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 70, 105, 101, 108, 100, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 71, 117, 105, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 75, 101, 121, 86, 97, 108, 117, 101, 80, 97, 105, 114, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 70, 105, 101, 108, 100, 70, 108, 97, 103, 115, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 49, 54, 34, 32, 73, 115, 79, 112, 116, 105, 111, 110, 83, 101, 116, 61, 34, 116, 114, 117, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 80, 114, 111, 109, 111, 116, 101, 100, 70, 105, 101, 108, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 86, 101, 114, 115, 105, 111, 110, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 106, 111, 114, 86, 101, 114, 115, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 105, 110, 111, 114, 86, 101, 114, 115, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 101, 100, 68, 97, 116, 97, 83, 101, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 83, 101, 116, 70, 111, 108, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 70, 111, 108, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 83, 101, 116, 70, 111, 108, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 77, 101, 116, 97, 68, 97, 116, 97, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 83, 101, 116, 77, 101, 116, 97, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 120, 116, 101, 110, 115, 105, 111, 110, 70, 105, 101, 108, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 120, 116, 101, 110, 115, 105, 111, 110, 70, 105, 101, 108, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 75, 101, 121, 86, 97, 108, 117, 101, 80, 97, 105, 114, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 120, 116, 101, 110, 115, 105, 111, 110, 70, 105, 101, 108, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 83, 111, 117, 114, 99, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 101, 100, 68, 97, 116, 97, 83, 101, 116, 83, 111, 117, 114, 99, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 101, 100, 86, 97, 114, 105, 97, 98, 108, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 101, 100, 86, 97, 114, 105, 97, 98, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 116, 116, 114, 105, 98, 117, 116, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 97, 109, 112, 108, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 72, 105, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 97, 100, 98, 97, 110, 100, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 97, 100, 98, 97, 110, 100, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 100, 101, 120, 82, 97, 110, 103, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 116, 105, 116, 117, 116, 101, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 77, 101, 116, 97, 68, 97, 116, 97, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 101, 116, 97, 68, 97, 116, 97, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 77, 101, 116, 97, 68, 97, 116, 97, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 101, 100, 68, 97, 116, 97, 73, 116, 101, 109, 115, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 108, 105, 115, 104, 101, 100, 68, 97, 116, 97, 83, 101, 116, 83, 111, 117, 114, 99, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 80, 117, 98, 108, 105, 115, 104, 101, 100, 68, 97, 116, 97, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 101, 100, 68, 97, 116, 97, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 108, 105, 115, 104, 101, 100, 86, 97, 114, 105, 97, 98, 108, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 80, 117, 98, 108, 105, 115, 104, 101, 100, 68, 97, 116, 97, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 101, 100, 69, 118, 101, 110, 116, 115, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 108, 105, 115, 104, 101, 100, 68, 97, 116, 97, 83, 101, 116, 83, 111, 117, 114, 99, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 78, 111, 116, 105, 102, 105, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 108, 101, 99, 116, 101, 100, 70, 105, 101, 108, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 108, 101, 99, 116, 101, 100, 70, 105, 101, 108, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 105, 109, 112, 108, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 79, 112, 101, 114, 97, 110, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 108, 101, 99, 116, 101, 100, 70, 105, 101, 108, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 108, 116, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 67, 111, 110, 116, 101, 110, 116, 70, 105, 108, 116, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 70, 105, 101, 108, 100, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 32, 73, 115, 79, 112, 116, 105, 111, 110, 83, 101, 116, 61, 34, 116, 114, 117, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 111, 117, 114, 99, 101, 84, 105, 109, 101, 115, 116, 97, 109, 112, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 84, 105, 109, 101, 115, 116, 97, 109, 112, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 111, 117, 114, 99, 101, 80, 105, 99, 111, 83, 101, 99, 111, 110, 100, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 80, 105, 99, 111, 83, 101, 99, 111, 110, 100, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 97, 119, 68, 97, 116, 97, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 97, 98, 108, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 70, 105, 101, 108, 100, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 83, 101, 116, 70, 105, 101, 108, 100, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 75, 101, 121, 70, 114, 97, 109, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 75, 101, 121, 86, 97, 108, 117, 101, 80, 97, 105, 114, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 112, 111, 114, 116, 83, 101, 116, 116, 105, 110, 103, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 101, 115, 115, 97, 103, 101, 83, 101, 116, 116, 105, 110, 103, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 83, 117, 98, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 97, 98, 108, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 101, 115, 115, 97, 103, 101, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 71, 114, 111, 117, 112, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 99, 117, 114, 105, 116, 121, 75, 101, 121, 83, 101, 114, 118, 105, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 75, 101, 121, 83, 101, 114, 118, 105, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 110, 100, 112, 111, 105, 110, 116, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 99, 117, 114, 105, 116, 121, 75, 101, 121, 83, 101, 114, 118, 105, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 83, 105, 122, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 71, 114, 111, 117, 112, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 71, 114, 111, 117, 112, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 75, 101, 121, 86, 97, 108, 117, 101, 80, 97, 105, 114, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 71, 114, 111, 117, 112, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 83, 117, 98, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 83, 117, 98, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 97, 98, 108, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 83, 117, 98, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 101, 115, 115, 97, 103, 101, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 83, 117, 98, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 71, 114, 111, 117, 112, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 83, 117, 98, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 99, 117, 114, 105, 116, 121, 75, 101, 121, 83, 101, 114, 118, 105, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 75, 101, 121, 83, 101, 114, 118, 105, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 110, 100, 112, 111, 105, 110, 116, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 99, 117, 114, 105, 116, 121, 75, 101, 121, 83, 101, 114, 118, 105, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 83, 105, 122, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 83, 117, 98, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 71, 114, 111, 117, 112, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 71, 114, 111, 117, 112, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 75, 101, 121, 86, 97, 108, 117, 101, 80, 97, 105, 114, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 71, 114, 111, 117, 112, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 75, 101, 101, 112, 65, 108, 105, 118, 101, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 114, 105, 111, 114, 105, 116, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 72, 101, 97, 100, 101, 114, 76, 97, 121, 111, 117, 116, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 112, 111, 114, 116, 83, 101, 116, 116, 105, 110, 103, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 101, 115, 115, 97, 103, 101, 83, 101, 116, 116, 105, 110, 103, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 83, 117, 98, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 97, 98, 108, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 101, 114, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 112, 111, 114, 116, 80, 114, 111, 102, 105, 108, 101, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 114, 101, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 75, 101, 121, 86, 97, 108, 117, 101, 80, 97, 105, 114, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 112, 111, 114, 116, 83, 101, 116, 116, 105, 110, 103, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 97, 100, 101, 114, 71, 114, 111, 117, 112, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 101, 114, 71, 114, 111, 117, 112, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 97, 100, 101, 114, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 97, 100, 101, 114, 71, 114, 111, 117, 112, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 101, 116, 119, 111, 114, 107, 65, 100, 100, 114, 101, 115, 115, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 101, 116, 119, 111, 114, 107, 73, 110, 116, 101, 114, 102, 97, 99, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 101, 116, 119, 111, 114, 107, 65, 100, 100, 114, 101, 115, 115, 85, 114, 108, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 101, 116, 119, 111, 114, 107, 65, 100, 100, 114, 101, 115, 115, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 101, 116, 119, 111, 114, 107, 73, 110, 116, 101, 114, 102, 97, 99, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 101, 116, 119, 111, 114, 107, 65, 100, 100, 114, 101, 115, 115, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 114, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 101, 114, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 83, 117, 98, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 83, 117, 98, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 97, 98, 108, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 83, 117, 98, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 101, 115, 115, 97, 103, 101, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 83, 117, 98, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 71, 114, 111, 117, 112, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 83, 117, 98, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 99, 117, 114, 105, 116, 121, 75, 101, 121, 83, 101, 114, 118, 105, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 75, 101, 121, 83, 101, 114, 118, 105, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 110, 100, 112, 111, 105, 110, 116, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 99, 117, 114, 105, 116, 121, 75, 101, 121, 83, 101, 114, 118, 105, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 83, 105, 122, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 83, 117, 98, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 71, 114, 111, 117, 112, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 71, 114, 111, 117, 112, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 75, 101, 121, 86, 97, 108, 117, 101, 80, 97, 105, 114, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 71, 114, 111, 117, 112, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 112, 111, 114, 116, 83, 101, 116, 116, 105, 110, 103, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 101, 115, 115, 97, 103, 101, 83, 101, 116, 116, 105, 110, 103, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 101, 114, 71, 114, 111, 117, 112, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 101, 114, 71, 114, 111, 117, 112, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 97, 98, 108, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 101, 114, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 77, 101, 116, 97, 68, 97, 116, 97, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 83, 101, 116, 77, 101, 116, 97, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 70, 105, 101, 108, 100, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 83, 101, 116, 70, 105, 101, 108, 100, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 101, 115, 115, 97, 103, 101, 82, 101, 99, 101, 105, 118, 101, 84, 105, 109, 101, 111, 117, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 75, 101, 121, 70, 114, 97, 109, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 72, 101, 97, 100, 101, 114, 76, 97, 121, 111, 117, 116, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 101, 115, 115, 97, 103, 101, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 71, 114, 111, 117, 112, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 99, 117, 114, 105, 116, 121, 75, 101, 121, 83, 101, 114, 118, 105, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 75, 101, 121, 83, 101, 114, 118, 105, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 110, 100, 112, 111, 105, 110, 116, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 99, 117, 114, 105, 116, 121, 75, 101, 121, 83, 101, 114, 118, 105, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 75, 101, 121, 86, 97, 108, 117, 101, 80, 97, 105, 114, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 80, 114, 111, 112, 101, 114, 116, 105, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 112, 111, 114, 116, 83, 101, 116, 116, 105, 110, 103, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 101, 115, 115, 97, 103, 101, 83, 101, 116, 116, 105, 110, 103, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 98, 101, 100, 68, 97, 116, 97, 83, 101, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 98, 101, 100, 68, 97, 116, 97, 83, 101, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 97, 114, 103, 101, 116, 86, 97, 114, 105, 97, 98, 108, 101, 115, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 83, 117, 98, 115, 99, 114, 105, 98, 101, 100, 68, 97, 116, 97, 83, 101, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 84, 97, 114, 103, 101, 116, 86, 97, 114, 105, 97, 98, 108, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 97, 114, 103, 101, 116, 86, 97, 114, 105, 97, 98, 108, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 70, 105, 101, 108, 100, 84, 97, 114, 103, 101, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 84, 97, 114, 103, 101, 116, 86, 97, 114, 105, 97, 98, 108, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 70, 105, 101, 108, 100, 84, 97, 114, 103, 101, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 70, 105, 101, 108, 100, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 71, 117, 105, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 99, 101, 105, 118, 101, 114, 73, 110, 100, 101, 120, 82, 97, 110, 103, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 97, 114, 103, 101, 116, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 116, 116, 114, 105, 98, 117, 116, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 73, 110, 100, 101, 120, 82, 97, 110, 103, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 79, 118, 101, 114, 114, 105, 100, 101, 86, 97, 108, 117, 101, 72, 97, 110, 100, 108, 105, 110, 103, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 79, 118, 101, 114, 114, 105, 100, 101, 86, 97, 108, 117, 101, 72, 97, 110, 100, 108, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 79, 118, 101, 114, 114, 105, 100, 101, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 79, 118, 101, 114, 114, 105, 100, 101, 86, 97, 108, 117, 101, 72, 97, 110, 100, 108, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 97, 98, 108, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 85, 115, 97, 98, 108, 101, 86, 97, 108, 117, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 79, 118, 101, 114, 114, 105, 100, 101, 86, 97, 108, 117, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 98, 101, 100, 68, 97, 116, 97, 83, 101, 116, 77, 105, 114, 114, 111, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 83, 117, 98, 115, 99, 114, 105, 98, 101, 100, 68, 97, 116, 97, 83, 101, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 97, 114, 101, 110, 116, 78, 111, 100, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 83, 117, 98, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 80, 117, 98, 108, 105, 115, 104, 101, 100, 68, 97, 116, 97, 83, 101, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 101, 100, 68, 97, 116, 97, 83, 101, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 108, 105, 115, 104, 101, 100, 68, 97, 116, 97, 83, 101, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 80, 117, 98, 108, 105, 115, 104, 101, 100, 68, 97, 116, 97, 83, 101, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 80, 117, 98, 83, 117, 98, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 97, 98, 108, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 79, 114, 100, 101, 114, 105, 110, 103, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 110, 100, 101, 102, 105, 110, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 115, 99, 101, 110, 100, 105, 110, 103, 87, 114, 105, 116, 101, 114, 73, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 115, 99, 101, 110, 100, 105, 110, 103, 87, 114, 105, 116, 101, 114, 73, 100, 83, 105, 110, 103, 108, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 97, 100, 112, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 32, 73, 115, 79, 112, 116, 105, 111, 110, 83, 101, 116, 61, 34, 116, 114, 117, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 101, 114, 73, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 71, 114, 111, 117, 112, 72, 101, 97, 100, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 73, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 71, 114, 111, 117, 112, 86, 101, 114, 115, 105, 111, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 78, 117, 109, 98, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 113, 117, 101, 110, 99, 101, 78, 117, 109, 98, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 80, 97, 121, 108, 111, 97, 100, 72, 101, 97, 100, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 115, 116, 97, 109, 112, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 50, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 80, 105, 99, 111, 83, 101, 99, 111, 110, 100, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 53, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 67, 108, 97, 115, 115, 73, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 53, 49, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 80, 114, 111, 109, 111, 116, 101, 100, 70, 105, 101, 108, 100, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 48, 50, 52, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 97, 100, 112, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 71, 114, 111, 117, 112, 86, 101, 114, 115, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 79, 114, 100, 101, 114, 105, 110, 103, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 83, 101, 116, 79, 114, 100, 101, 114, 105, 110, 103, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 85, 97, 100, 112, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 97, 109, 112, 108, 105, 110, 103, 79, 102, 102, 115, 101, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 79, 102, 102, 115, 101, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 79, 102, 102, 115, 101, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 79, 102, 102, 115, 101, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 97, 100, 112, 68, 97, 116, 97, 83, 101, 116, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 32, 73, 115, 79, 112, 116, 105, 111, 110, 83, 101, 116, 61, 34, 116, 114, 117, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 115, 116, 97, 109, 112, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 80, 105, 99, 111, 83, 101, 99, 111, 110, 100, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 77, 97, 106, 111, 114, 86, 101, 114, 115, 105, 111, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 77, 105, 110, 111, 114, 86, 101, 114, 115, 105, 111, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 113, 117, 101, 110, 99, 101, 78, 117, 109, 98, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 97, 100, 112, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 85, 97, 100, 112, 68, 97, 116, 97, 83, 101, 116, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 102, 105, 103, 117, 114, 101, 100, 83, 105, 122, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 78, 117, 109, 98, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 79, 102, 102, 115, 101, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 97, 100, 112, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 71, 114, 111, 117, 112, 86, 101, 114, 115, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 78, 117, 109, 98, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 79, 102, 102, 115, 101, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 67, 108, 97, 115, 115, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 71, 117, 105, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 85, 97, 100, 112, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 85, 97, 100, 112, 68, 97, 116, 97, 83, 101, 116, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 99, 101, 105, 118, 101, 79, 102, 102, 115, 101, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 114, 111, 99, 101, 115, 115, 105, 110, 103, 79, 102, 102, 115, 101, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 74, 115, 111, 110, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 32, 73, 115, 79, 112, 116, 105, 111, 110, 83, 101, 116, 61, 34, 116, 114, 117, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 72, 101, 97, 100, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 77, 101, 115, 115, 97, 103, 101, 72, 101, 97, 100, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 105, 110, 103, 108, 101, 68, 97, 116, 97, 83, 101, 116, 77, 101, 115, 115, 97, 103, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 101, 114, 73, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 67, 108, 97, 115, 115, 73, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 112, 108, 121, 84, 111, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 74, 115, 111, 110, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 74, 115, 111, 110, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 74, 115, 111, 110, 68, 97, 116, 97, 83, 101, 116, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 32, 73, 115, 79, 112, 116, 105, 111, 110, 83, 101, 116, 61, 34, 116, 114, 117, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 73, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 77, 101, 116, 97, 68, 97, 116, 97, 86, 101, 114, 115, 105, 111, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 113, 117, 101, 110, 99, 101, 78, 117, 109, 98, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 115, 116, 97, 109, 112, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 74, 115, 111, 110, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 74, 115, 111, 110, 68, 97, 116, 97, 83, 101, 116, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 74, 115, 111, 110, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 77, 101, 115, 115, 97, 103, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 74, 115, 111, 110, 78, 101, 116, 119, 111, 114, 107, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 101, 116, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 74, 115, 111, 110, 68, 97, 116, 97, 83, 101, 116, 77, 101, 115, 115, 97, 103, 101, 67, 111, 110, 116, 101, 110, 116, 77, 97, 115, 107, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 103, 114, 97, 109, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 99, 111, 118, 101, 114, 121, 65, 100, 100, 114, 101, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 103, 114, 97, 109, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 101, 115, 115, 97, 103, 101, 82, 101, 112, 101, 97, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 101, 115, 115, 97, 103, 101, 82, 101, 112, 101, 97, 116, 68, 101, 108, 97, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 107, 101, 114, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 111, 117, 114, 99, 101, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 105, 111, 110, 80, 114, 111, 102, 105, 108, 101, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 107, 101, 114, 84, 114, 97, 110, 115, 112, 111, 114, 116, 81, 117, 97, 108, 105, 116, 121, 79, 102, 83, 101, 114, 118, 105, 99, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 116, 83, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 66, 101, 115, 116, 69, 102, 102, 111, 114, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 116, 76, 101, 97, 115, 116, 79, 110, 99, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 116, 77, 111, 115, 116, 79, 110, 99, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 69, 120, 97, 99, 116, 108, 121, 79, 110, 99, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 107, 101, 114, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 87, 114, 105, 116, 101, 114, 71, 114, 111, 117, 112, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 81, 117, 101, 117, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 111, 117, 114, 99, 101, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 105, 111, 110, 80, 114, 111, 102, 105, 108, 101, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 68, 101, 108, 105, 118, 101, 114, 121, 71, 117, 97, 114, 97, 110, 116, 101, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 66, 114, 111, 107, 101, 114, 84, 114, 97, 110, 115, 112, 111, 114, 116, 81, 117, 97, 108, 105, 116, 121, 79, 102, 83, 101, 114, 118, 105, 99, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 107, 101, 114, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 83, 101, 116, 87, 114, 105, 116, 101, 114, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 81, 117, 101, 117, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 111, 117, 114, 99, 101, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 105, 111, 110, 80, 114, 111, 102, 105, 108, 101, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 68, 101, 108, 105, 118, 101, 114, 121, 71, 117, 97, 114, 97, 110, 116, 101, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 66, 114, 111, 107, 101, 114, 84, 114, 97, 110, 115, 112, 111, 114, 116, 81, 117, 97, 108, 105, 116, 121, 79, 102, 83, 101, 114, 118, 105, 99, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 101, 116, 97, 68, 97, 116, 97, 81, 117, 101, 117, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 101, 116, 97, 68, 97, 116, 97, 85, 112, 100, 97, 116, 101, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 107, 101, 114, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 83, 101, 116, 82, 101, 97, 100, 101, 114, 84, 114, 97, 110, 115, 112, 111, 114, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 81, 117, 101, 117, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 111, 117, 114, 99, 101, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 105, 111, 110, 80, 114, 111, 102, 105, 108, 101, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 68, 101, 108, 105, 118, 101, 114, 121, 71, 117, 97, 114, 97, 110, 116, 101, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 66, 114, 111, 107, 101, 114, 84, 114, 97, 110, 115, 112, 111, 114, 116, 81, 117, 97, 108, 105, 116, 121, 79, 102, 83, 101, 114, 118, 105, 99, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 101, 116, 97, 68, 97, 116, 97, 81, 117, 101, 117, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 115, 76, 101, 118, 101, 108, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 66, 97, 115, 105, 99, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 100, 118, 97, 110, 99, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 102, 111, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 76, 111, 103, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 98, 117, 103, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 83, 117, 98, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 115, 67, 111, 117, 110, 116, 101, 114, 67, 108, 97, 115, 115, 105, 102, 105, 99, 97, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 102, 111, 114, 109, 97, 116, 105, 111, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 69, 114, 114, 111, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 108, 105, 97, 115, 78, 97, 109, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 108, 105, 97, 115, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 100, 78, 111, 100, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 100, 78, 111, 100, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 100, 78, 111, 100, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 73, 100, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 117, 109, 101, 114, 105, 99, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 105, 110, 103, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 71, 117, 105, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 79, 112, 97, 113, 117, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 110, 115, 112, 101, 99, 105, 102, 105, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 79, 98, 106, 101, 99, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 86, 97, 114, 105, 97, 98, 108, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 77, 101, 116, 104, 111, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 79, 98, 106, 101, 99, 116, 84, 121, 112, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 86, 97, 114, 105, 97, 98, 108, 101, 84, 121, 112, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 84, 121, 112, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 86, 105, 101, 119, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 50, 56, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 32, 73, 115, 79, 112, 116, 105, 111, 110, 83, 101, 116, 61, 34, 116, 114, 117, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 72, 105, 115, 116, 111, 114, 105, 122, 105, 110, 103, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 72, 105, 115, 116, 111, 114, 121, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 50, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 115, 101, 114, 116, 72, 105, 115, 116, 111, 114, 121, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 53, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 100, 105, 102, 121, 72, 105, 115, 116, 111, 114, 121, 34, 32, 86, 97, 108, 117, 101, 61, 34, 53, 49, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 72, 105, 115, 116, 111, 114, 121, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 48, 50, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 99, 101, 105, 118, 101, 69, 118, 101, 110, 116, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 48, 52, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 67, 97, 108, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 48, 57, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 82, 101, 102, 101, 114, 101, 110, 99, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 49, 57, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 109, 111, 118, 101, 82, 101, 102, 101, 114, 101, 110, 99, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 51, 56, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 78, 111, 100, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 50, 55, 54, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 78, 111, 100, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 53, 53, 51, 54, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 76, 101, 118, 101, 108, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 56, 34, 32, 73, 115, 79, 112, 116, 105, 111, 110, 83, 101, 116, 61, 34, 116, 114, 117, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 67, 117, 114, 114, 101, 110, 116, 82, 101, 97, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 67, 117, 114, 114, 101, 110, 116, 87, 114, 105, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 87, 114, 105, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 109, 97, 110, 116, 105, 99, 67, 104, 97, 110, 103, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 87, 114, 105, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 115, 116, 97, 109, 112, 87, 114, 105, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 52, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 76, 101, 118, 101, 108, 69, 120, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 32, 73, 115, 79, 112, 116, 105, 111, 110, 83, 101, 116, 61, 34, 116, 114, 117, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 67, 117, 114, 114, 101, 110, 116, 82, 101, 97, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 67, 117, 114, 114, 101, 110, 116, 87, 114, 105, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 87, 114, 105, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 109, 97, 110, 116, 105, 99, 67, 104, 97, 110, 103, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 87, 114, 105, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 115, 116, 97, 109, 112, 87, 114, 105, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 97, 116, 111, 109, 105, 99, 82, 101, 97, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 53, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 97, 116, 111, 109, 105, 99, 87, 114, 105, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 53, 49, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 70, 117, 108, 108, 65, 114, 114, 97, 121, 79, 110, 108, 121, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 48, 50, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 83, 117, 98, 68, 97, 116, 97, 84, 121, 112, 101, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 48, 52, 56, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 78, 111, 116, 105, 102, 105, 101, 114, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 56, 34, 32, 73, 115, 79, 112, 116, 105, 111, 110, 83, 101, 116, 61, 34, 116, 114, 117, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 98, 101, 84, 111, 69, 118, 101, 110, 116, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 87, 114, 105, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 49, 54, 34, 32, 73, 115, 79, 112, 116, 105, 111, 110, 83, 101, 116, 61, 34, 116, 114, 117, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 105, 103, 110, 105, 110, 103, 82, 101, 113, 117, 105, 114, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 69, 110, 99, 114, 121, 112, 116, 105, 111, 110, 82, 101, 113, 117, 105, 114, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 115, 115, 105, 111, 110, 82, 101, 113, 117, 105, 114, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 112, 112, 108, 121, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 115, 84, 111, 66, 114, 111, 119, 115, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 117, 99, 116, 117, 114, 101, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 117, 99, 116, 117, 114, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 117, 99, 116, 117, 114, 101, 87, 105, 116, 104, 79, 112, 116, 105, 111, 110, 97, 108, 70, 105, 101, 108, 100, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 110, 105, 111, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 117, 99, 116, 117, 114, 101, 70, 105, 101, 108, 100, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 82, 97, 110, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 83, 116, 114, 105, 110, 103, 76, 101, 110, 103, 116, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 79, 112, 116, 105, 111, 110, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 102, 97, 117, 108, 116, 69, 110, 99, 111, 100, 105, 110, 103, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 97, 115, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 117, 99, 116, 117, 114, 101, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 70, 105, 101, 108, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 101, 108, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 70, 105, 101, 108, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 70, 105, 101, 108, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 110, 117, 109, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 70, 105, 101, 108, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 101, 108, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 110, 117, 109, 70, 105, 101, 108, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 70, 105, 101, 108, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 102, 101, 114, 101, 110, 99, 101, 78, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 115, 116, 97, 110, 99, 101, 78, 111, 100, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 102, 101, 114, 101, 110, 99, 101, 78, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 121, 112, 101, 78, 111, 100, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 102, 101, 114, 101, 110, 99, 101, 78, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 79, 98, 106, 101, 99, 116, 78, 111, 100, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 73, 110, 115, 116, 97, 110, 99, 101, 78, 111, 100, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 102, 101, 114, 101, 110, 99, 101, 78, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 78, 111, 116, 105, 102, 105, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 79, 98, 106, 101, 99, 116, 84, 121, 112, 101, 78, 111, 100, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 84, 121, 112, 101, 78, 111, 100, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 102, 101, 114, 101, 110, 99, 101, 78, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 65, 98, 115, 116, 114, 97, 99, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 86, 97, 114, 105, 97, 98, 108, 101, 78, 111, 100, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 73, 110, 115, 116, 97, 110, 99, 101, 78, 111, 100, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 102, 101, 114, 101, 110, 99, 101, 78, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 82, 97, 110, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 76, 101, 118, 101, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 65, 99, 99, 101, 115, 115, 76, 101, 118, 101, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 105, 110, 105, 109, 117, 109, 83, 97, 109, 112, 108, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 105, 122, 105, 110, 103, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 76, 101, 118, 101, 108, 69, 120, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 86, 97, 114, 105, 97, 98, 108, 101, 84, 121, 112, 101, 78, 111, 100, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 84, 121, 112, 101, 78, 111, 100, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 102, 101, 114, 101, 110, 99, 101, 78, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 82, 97, 110, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 65, 98, 115, 116, 114, 97, 99, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 84, 121, 112, 101, 78, 111, 100, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 84, 121, 112, 101, 78, 111, 100, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 102, 101, 114, 101, 110, 99, 101, 78, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 65, 98, 115, 116, 114, 97, 99, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 121, 109, 109, 101, 116, 114, 105, 99, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 118, 101, 114, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 101, 116, 104, 111, 100, 78, 111, 100, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 73, 110, 115, 116, 97, 110, 99, 101, 78, 111, 100, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 102, 101, 114, 101, 110, 99, 101, 78, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 120, 101, 99, 117, 116, 97, 98, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 69, 120, 101, 99, 117, 116, 97, 98, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 86, 105, 101, 119, 78, 111, 100, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 73, 110, 115, 116, 97, 110, 99, 101, 78, 111, 100, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 102, 101, 114, 101, 110, 99, 101, 78, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 97, 105, 110, 115, 78, 111, 76, 111, 111, 112, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 78, 111, 116, 105, 102, 105, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 78, 111, 100, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 84, 121, 112, 101, 78, 111, 100, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 49, 54, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 102, 101, 114, 101, 110, 99, 101, 78, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 65, 98, 115, 116, 114, 97, 99, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 78, 111, 100, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 84, 121, 112, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 73, 110, 118, 101, 114, 115, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 97, 114, 103, 101, 116, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 114, 103, 117, 109, 101, 110, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 82, 97, 110, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 110, 117, 109, 86, 97, 108, 117, 101, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 54, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 110, 117, 109, 70, 105, 101, 108, 100, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 69, 110, 117, 109, 86, 97, 108, 117, 101, 84, 121, 112, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 54, 52, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 69, 110, 117, 109, 86, 97, 108, 117, 101, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 69, 110, 117, 109, 86, 97, 108, 117, 101, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 69, 110, 117, 109, 86, 97, 108, 117, 101, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 79, 112, 116, 105, 111, 110, 83, 101, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 105, 100, 66, 105, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 110, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 114, 109, 97, 108, 105, 122, 101, 100, 83, 116, 114, 105, 110, 103, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 99, 105, 109, 97, 108, 83, 116, 114, 105, 110, 103, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 117, 114, 97, 116, 105, 111, 110, 83, 116, 114, 105, 110, 103, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 83, 116, 114, 105, 110, 103, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 101, 83, 116, 114, 105, 110, 103, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 117, 114, 97, 116, 105, 111, 110, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 116, 99, 84, 105, 109, 101, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 101, 73, 100, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 90, 111, 110, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 79, 102, 102, 115, 101, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 121, 108, 105, 103, 104, 116, 83, 97, 118, 105, 110, 103, 73, 110, 79, 102, 102, 115, 101, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 100, 101, 120, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 116, 101, 103, 101, 114, 73, 100, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 65, 110, 100, 83, 101, 114, 118, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 99, 111, 118, 101, 114, 121, 83, 101, 114, 118, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 114, 111, 100, 117, 99, 116, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 71, 97, 116, 101, 119, 97, 121, 83, 101, 114, 118, 101, 114, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 99, 111, 118, 101, 114, 121, 80, 114, 111, 102, 105, 108, 101, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 115, 99, 111, 118, 101, 114, 121, 85, 114, 108, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 99, 111, 118, 101, 114, 121, 85, 114, 108, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 115, 99, 111, 118, 101, 114, 121, 85, 114, 108, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 105, 111, 110, 84, 111, 107, 101, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 115, 116, 97, 109, 112, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 97, 110, 100, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 116, 117, 114, 110, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 117, 100, 105, 116, 69, 110, 116, 114, 121, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 111, 117, 116, 72, 105, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 105, 116, 105, 111, 110, 97, 108, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 115, 116, 97, 109, 112, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 97, 110, 100, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 105, 99, 101, 82, 101, 115, 117, 108, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 105, 99, 101, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 116, 114, 105, 110, 103, 84, 97, 98, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 114, 105, 110, 103, 84, 97, 98, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 116, 114, 105, 110, 103, 84, 97, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 105, 116, 105, 111, 110, 97, 108, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 86, 101, 114, 115, 105, 111, 110, 84, 105, 109, 101, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 105, 99, 101, 70, 97, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 115, 115, 105, 111, 110, 108, 101, 115, 115, 73, 110, 118, 111, 107, 101, 82, 101, 113, 117, 101, 115, 116, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 114, 105, 115, 86, 101, 114, 115, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 97, 109, 101, 115, 112, 97, 99, 101, 85, 114, 105, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 85, 114, 105, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 97, 109, 101, 115, 112, 97, 99, 101, 85, 114, 105, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 85, 114, 105, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 85, 114, 105, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 85, 114, 105, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 105, 99, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 115, 115, 105, 111, 110, 108, 101, 115, 115, 73, 110, 118, 111, 107, 101, 82, 101, 115, 112, 111, 110, 115, 101, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 97, 109, 101, 115, 112, 97, 99, 101, 85, 114, 105, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 85, 114, 105, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 97, 109, 101, 115, 112, 97, 99, 101, 85, 114, 105, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 85, 114, 105, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 85, 114, 105, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 85, 114, 105, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 105, 99, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 70, 105, 110, 100, 83, 101, 114, 118, 101, 114, 115, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 112, 111, 105, 110, 116, 85, 114, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 85, 114, 105, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 85, 114, 105, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 85, 114, 105, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 70, 105, 110, 100, 83, 101, 114, 118, 101, 114, 115, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 79, 110, 78, 101, 116, 119, 111, 114, 107, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 99, 111, 114, 100, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 99, 111, 118, 101, 114, 121, 85, 114, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 67, 97, 112, 97, 98, 105, 108, 105, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 67, 97, 112, 97, 98, 105, 108, 105, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 67, 97, 112, 97, 98, 105, 108, 105, 116, 105, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 70, 105, 110, 100, 83, 101, 114, 118, 101, 114, 115, 79, 110, 78, 101, 116, 119, 111, 114, 107, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 114, 116, 105, 110, 103, 82, 101, 99, 111, 114, 100, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 82, 101, 99, 111, 114, 100, 115, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 67, 97, 112, 97, 98, 105, 108, 105, 116, 121, 70, 105, 108, 116, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 67, 97, 112, 97, 98, 105, 108, 105, 116, 121, 70, 105, 108, 116, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 67, 97, 112, 97, 98, 105, 108, 105, 116, 121, 70, 105, 108, 116, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 70, 105, 110, 100, 83, 101, 114, 118, 101, 114, 115, 79, 110, 78, 101, 116, 119, 111, 114, 107, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 67, 111, 117, 110, 116, 101, 114, 82, 101, 115, 101, 116, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 101, 114, 79, 110, 78, 101, 116, 119, 111, 114, 107, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 73, 110, 115, 116, 97, 110, 99, 101, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 101, 115, 115, 97, 103, 101, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 118, 97, 108, 105, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 105, 103, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 105, 103, 110, 65, 110, 100, 69, 110, 99, 114, 121, 112, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 84, 111, 107, 101, 110, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 110, 111, 110, 121, 109, 111, 117, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 78, 97, 109, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 115, 115, 117, 101, 100, 84, 111, 107, 101, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 84, 111, 107, 101, 110, 80, 111, 108, 105, 99, 121, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 111, 108, 105, 99, 121, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 111, 107, 101, 110, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 85, 115, 101, 114, 84, 111, 107, 101, 110, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 115, 117, 101, 100, 84, 111, 107, 101, 110, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 115, 117, 101, 114, 69, 110, 100, 112, 111, 105, 110, 116, 85, 114, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 80, 111, 108, 105, 99, 121, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 112, 111, 105, 110, 116, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 112, 111, 105, 110, 116, 85, 114, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 101, 115, 115, 97, 103, 101, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 80, 111, 108, 105, 99, 121, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 85, 115, 101, 114, 84, 111, 107, 101, 110, 80, 111, 108, 105, 99, 121, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 85, 115, 101, 114, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 112, 111, 114, 116, 80, 114, 111, 102, 105, 108, 101, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 76, 101, 118, 101, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 71, 101, 116, 69, 110, 100, 112, 111, 105, 110, 116, 115, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 112, 111, 105, 110, 116, 85, 114, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 80, 114, 111, 102, 105, 108, 101, 85, 114, 105, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 114, 111, 102, 105, 108, 101, 85, 114, 105, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 80, 114, 111, 102, 105, 108, 101, 85, 114, 105, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 71, 101, 116, 69, 110, 100, 112, 111, 105, 110, 116, 115, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 110, 100, 112, 111, 105, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 112, 111, 105, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 110, 100, 112, 111, 105, 110, 116, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 110, 100, 112, 111, 105, 110, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 103, 105, 115, 116, 101, 114, 101, 100, 83, 101, 114, 118, 101, 114, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 114, 111, 100, 117, 99, 116, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 78, 97, 109, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 78, 97, 109, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 78, 97, 109, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 71, 97, 116, 101, 119, 97, 121, 83, 101, 114, 118, 101, 114, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 115, 99, 111, 118, 101, 114, 121, 85, 114, 108, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 99, 111, 118, 101, 114, 121, 85, 114, 108, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 115, 99, 111, 118, 101, 114, 121, 85, 114, 108, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 109, 97, 112, 104, 111, 114, 101, 70, 105, 108, 101, 80, 97, 116, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 79, 110, 108, 105, 110, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 103, 105, 115, 116, 101, 114, 83, 101, 114, 118, 101, 114, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 103, 105, 115, 116, 101, 114, 101, 100, 83, 101, 114, 118, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 103, 105, 115, 116, 101, 114, 83, 101, 114, 118, 101, 114, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 99, 111, 118, 101, 114, 121, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 100, 110, 115, 68, 105, 115, 99, 111, 118, 101, 114, 121, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 68, 105, 115, 99, 111, 118, 101, 114, 121, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 100, 110, 115, 83, 101, 114, 118, 101, 114, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 67, 97, 112, 97, 98, 105, 108, 105, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 67, 97, 112, 97, 98, 105, 108, 105, 116, 105, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 67, 97, 112, 97, 98, 105, 108, 105, 116, 105, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 103, 105, 115, 116, 101, 114, 83, 101, 114, 118, 101, 114, 50, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 103, 105, 115, 116, 101, 114, 101, 100, 83, 101, 114, 118, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 115, 99, 111, 118, 101, 114, 121, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 99, 111, 118, 101, 114, 121, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 115, 99, 111, 118, 101, 114, 121, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 103, 105, 115, 116, 101, 114, 83, 101, 114, 118, 101, 114, 50, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 84, 111, 107, 101, 110, 82, 101, 113, 117, 101, 115, 116, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 115, 115, 117, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 110, 101, 119, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 104, 97, 110, 110, 101, 108, 83, 101, 99, 117, 114, 105, 116, 121, 84, 111, 107, 101, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 104, 97, 110, 110, 101, 108, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 111, 107, 101, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 114, 101, 97, 116, 101, 100, 65, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 76, 105, 102, 101, 116, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 79, 112, 101, 110, 83, 101, 99, 117, 114, 101, 67, 104, 97, 110, 110, 101, 108, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 80, 114, 111, 116, 111, 99, 111, 108, 86, 101, 114, 115, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 99, 117, 114, 105, 116, 121, 84, 111, 107, 101, 110, 82, 101, 113, 117, 101, 115, 116, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 101, 115, 115, 97, 103, 101, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 78, 111, 110, 99, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 76, 105, 102, 101, 116, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 79, 112, 101, 110, 83, 101, 99, 117, 114, 101, 67, 104, 97, 110, 110, 101, 108, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 80, 114, 111, 116, 111, 99, 111, 108, 86, 101, 114, 115, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 84, 111, 107, 101, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 67, 104, 97, 110, 110, 101, 108, 83, 101, 99, 117, 114, 105, 116, 121, 84, 111, 107, 101, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 78, 111, 110, 99, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 108, 111, 115, 101, 83, 101, 99, 117, 114, 101, 67, 104, 97, 110, 110, 101, 108, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 108, 111, 115, 101, 83, 101, 99, 117, 114, 101, 67, 104, 97, 110, 110, 101, 108, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 105, 103, 110, 101, 100, 83, 111, 102, 116, 119, 97, 114, 101, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 68, 97, 116, 97, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 105, 103, 110, 97, 116, 117, 114, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 115, 115, 105, 111, 110, 65, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 105, 111, 110, 84, 111, 107, 101, 110, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 105, 103, 110, 97, 116, 117, 114, 101, 68, 97, 116, 97, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 108, 103, 111, 114, 105, 116, 104, 109, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 105, 103, 110, 97, 116, 117, 114, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 114, 101, 97, 116, 101, 83, 101, 115, 115, 105, 111, 110, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 112, 111, 105, 110, 116, 85, 114, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 115, 115, 105, 111, 110, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 78, 111, 110, 99, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 83, 101, 115, 115, 105, 111, 110, 84, 105, 109, 101, 111, 117, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 82, 101, 115, 112, 111, 110, 115, 101, 77, 101, 115, 115, 97, 103, 101, 83, 105, 122, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 114, 101, 97, 116, 101, 83, 101, 115, 115, 105, 111, 110, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 115, 115, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 105, 111, 110, 84, 111, 107, 101, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 83, 101, 115, 115, 105, 111, 110, 84, 105, 109, 101, 111, 117, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 78, 111, 110, 99, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 69, 110, 100, 112, 111, 105, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 69, 110, 100, 112, 111, 105, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 110, 100, 112, 111, 105, 110, 116, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 69, 110, 100, 112, 111, 105, 110, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 83, 111, 102, 116, 119, 97, 114, 101, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 83, 111, 102, 116, 119, 97, 114, 101, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 105, 103, 110, 101, 100, 83, 111, 102, 116, 119, 97, 114, 101, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 114, 118, 101, 114, 83, 111, 102, 116, 119, 97, 114, 101, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 83, 105, 103, 110, 97, 116, 117, 114, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 105, 103, 110, 97, 116, 117, 114, 101, 68, 97, 116, 97, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 82, 101, 113, 117, 101, 115, 116, 77, 101, 115, 115, 97, 103, 101, 83, 105, 122, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 111, 108, 105, 99, 121, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 110, 111, 110, 121, 109, 111, 117, 115, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 85, 115, 101, 114, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 111, 108, 105, 99, 121, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 85, 115, 101, 114, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 78, 97, 109, 101, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 85, 115, 101, 114, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 111, 108, 105, 99, 121, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 85, 115, 101, 114, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 97, 115, 115, 119, 111, 114, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 99, 114, 121, 112, 116, 105, 111, 110, 65, 108, 103, 111, 114, 105, 116, 104, 109, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 88, 53, 48, 57, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 85, 115, 101, 114, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 111, 108, 105, 99, 121, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 85, 115, 101, 114, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 68, 97, 116, 97, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 73, 115, 115, 117, 101, 100, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 85, 115, 101, 114, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 111, 108, 105, 99, 121, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 85, 115, 101, 114, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 111, 107, 101, 110, 68, 97, 116, 97, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 99, 114, 121, 112, 116, 105, 111, 110, 65, 108, 103, 111, 114, 105, 116, 104, 109, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 115, 97, 69, 110, 99, 114, 121, 112, 116, 101, 100, 83, 101, 99, 114, 101, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 99, 99, 69, 110, 99, 114, 121, 112, 116, 101, 100, 83, 101, 99, 114, 101, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 99, 116, 105, 118, 97, 116, 101, 83, 101, 115, 115, 105, 111, 110, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 83, 105, 103, 110, 97, 116, 117, 114, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 105, 103, 110, 97, 116, 117, 114, 101, 68, 97, 116, 97, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 67, 108, 105, 101, 110, 116, 83, 111, 102, 116, 119, 97, 114, 101, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 83, 111, 102, 116, 119, 97, 114, 101, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 105, 103, 110, 101, 100, 83, 111, 102, 116, 119, 97, 114, 101, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 67, 108, 105, 101, 110, 116, 83, 111, 102, 116, 119, 97, 114, 101, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 73, 100, 101, 110, 116, 105, 116, 121, 84, 111, 107, 101, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 84, 111, 107, 101, 110, 83, 105, 103, 110, 97, 116, 117, 114, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 105, 103, 110, 97, 116, 117, 114, 101, 68, 97, 116, 97, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 99, 116, 105, 118, 97, 116, 101, 83, 101, 115, 115, 105, 111, 110, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 78, 111, 110, 99, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 108, 111, 115, 101, 83, 101, 115, 115, 105, 111, 110, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 108, 111, 115, 101, 83, 101, 115, 115, 105, 111, 110, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 97, 110, 99, 101, 108, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 97, 110, 100, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 97, 110, 99, 101, 108, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 97, 110, 99, 101, 108, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 77, 97, 115, 107, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 76, 101, 118, 101, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 97, 105, 110, 115, 78, 111, 76, 111, 111, 112, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 78, 111, 116, 105, 102, 105, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 50, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 69, 120, 101, 99, 117, 116, 97, 98, 108, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 53, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 105, 122, 105, 110, 103, 34, 32, 86, 97, 108, 117, 101, 61, 34, 53, 49, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 118, 101, 114, 115, 101, 78, 97, 109, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 48, 50, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 115, 65, 98, 115, 116, 114, 97, 99, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 48, 52, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 77, 105, 110, 105, 109, 117, 109, 83, 97, 109, 112, 108, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 48, 57, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 49, 57, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 51, 56, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 121, 109, 109, 101, 116, 114, 105, 99, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 50, 55, 54, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 65, 99, 99, 101, 115, 115, 76, 101, 118, 101, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 53, 53, 51, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 69, 120, 101, 99, 117, 116, 97, 98, 108, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 51, 49, 48, 55, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 54, 50, 49, 52, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 82, 97, 110, 107, 34, 32, 86, 97, 108, 117, 101, 61, 34, 53, 50, 52, 50, 56, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 48, 52, 56, 53, 55, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 48, 57, 55, 49, 53, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 49, 57, 52, 51, 48, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 51, 56, 56, 54, 48, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 55, 55, 55, 50, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 108, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 51, 53, 53, 52, 52, 51, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 66, 97, 115, 101, 78, 111, 100, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 54, 53, 48, 49, 50, 50, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 79, 98, 106, 101, 99, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 54, 53, 48, 49, 51, 52, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 79, 98, 106, 101, 99, 116, 84, 121, 112, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 54, 53, 48, 51, 50, 54, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 86, 97, 114, 105, 97, 98, 108, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 54, 53, 55, 49, 51, 56, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 86, 97, 114, 105, 97, 98, 108, 101, 84, 121, 112, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 56, 54, 48, 48, 52, 51, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 77, 101, 116, 104, 111, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 54, 54, 51, 50, 53, 52, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 84, 121, 112, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 54, 53, 51, 55, 48, 54, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 86, 105, 101, 119, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 54, 53, 48, 49, 51, 53, 54, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 112, 101, 99, 105, 102, 105, 101, 100, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 79, 98, 106, 101, 99, 116, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 112, 101, 99, 105, 102, 105, 101, 100, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 78, 111, 116, 105, 102, 105, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 86, 97, 114, 105, 97, 98, 108, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 112, 101, 99, 105, 102, 105, 101, 100, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 82, 97, 110, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 76, 101, 118, 101, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 65, 99, 99, 101, 115, 115, 76, 101, 118, 101, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 105, 110, 105, 109, 117, 109, 83, 97, 109, 112, 108, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 105, 122, 105, 110, 103, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 101, 116, 104, 111, 100, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 112, 101, 99, 105, 102, 105, 101, 100, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 120, 101, 99, 117, 116, 97, 98, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 69, 120, 101, 99, 117, 116, 97, 98, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 79, 98, 106, 101, 99, 116, 84, 121, 112, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 112, 101, 99, 105, 102, 105, 101, 100, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 65, 98, 115, 116, 114, 97, 99, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 86, 97, 114, 105, 97, 98, 108, 101, 84, 121, 112, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 112, 101, 99, 105, 102, 105, 101, 100, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 82, 97, 110, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 65, 98, 115, 116, 114, 97, 99, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 84, 121, 112, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 112, 101, 99, 105, 102, 105, 101, 100, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 65, 98, 115, 116, 114, 97, 99, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 121, 109, 109, 101, 116, 114, 105, 99, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 118, 101, 114, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 112, 101, 99, 105, 102, 105, 101, 100, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 65, 98, 115, 116, 114, 97, 99, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 86, 105, 101, 119, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 112, 101, 99, 105, 102, 105, 101, 100, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 97, 105, 110, 115, 78, 111, 76, 111, 111, 112, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 78, 111, 116, 105, 102, 105, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 71, 101, 110, 101, 114, 105, 99, 65, 116, 116, 114, 105, 98, 117, 116, 101, 86, 97, 108, 117, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 116, 116, 114, 105, 98, 117, 116, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 71, 101, 110, 101, 114, 105, 99, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 112, 101, 99, 105, 102, 105, 101, 100, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 116, 116, 114, 105, 98, 117, 116, 101, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 116, 116, 114, 105, 98, 117, 116, 101, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 71, 101, 110, 101, 114, 105, 99, 65, 116, 116, 114, 105, 98, 117, 116, 101, 86, 97, 108, 117, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 116, 116, 114, 105, 98, 117, 116, 101, 86, 97, 108, 117, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 78, 111, 100, 101, 115, 73, 116, 101, 109, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 97, 114, 101, 110, 116, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 84, 121, 112, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 78, 101, 119, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 121, 112, 101, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 78, 111, 100, 101, 115, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 78, 111, 100, 101, 115, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 65, 100, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 115, 84, 111, 65, 100, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 100, 100, 78, 111, 100, 101, 115, 73, 116, 101, 109, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 65, 100, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 78, 111, 100, 101, 115, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 100, 100, 78, 111, 100, 101, 115, 82, 101, 115, 117, 108, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 73, 116, 101, 109, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 111, 117, 114, 99, 101, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 84, 121, 112, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 70, 111, 114, 119, 97, 114, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 97, 114, 103, 101, 116, 83, 101, 114, 118, 101, 114, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 97, 114, 103, 101, 116, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 97, 114, 103, 101, 116, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 84, 111, 65, 100, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 84, 111, 65, 100, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 100, 100, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 73, 116, 101, 109, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 84, 111, 65, 100, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 78, 111, 100, 101, 115, 73, 116, 101, 109, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 84, 97, 114, 103, 101, 116, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 78, 111, 100, 101, 115, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 68, 101, 108, 101, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 115, 84, 111, 68, 101, 108, 101, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 68, 101, 108, 101, 116, 101, 78, 111, 100, 101, 115, 73, 116, 101, 109, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 68, 101, 108, 101, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 78, 111, 100, 101, 115, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 73, 116, 101, 109, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 111, 117, 114, 99, 101, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 84, 121, 112, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 70, 111, 114, 119, 97, 114, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 97, 114, 103, 101, 116, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 66, 105, 100, 105, 114, 101, 99, 116, 105, 111, 110, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 84, 111, 68, 101, 108, 101, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 84, 111, 68, 101, 108, 101, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 68, 101, 108, 101, 116, 101, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 73, 116, 101, 109, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 84, 111, 68, 101, 108, 101, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 116, 116, 114, 105, 98, 117, 116, 101, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 32, 73, 115, 79, 112, 116, 105, 111, 110, 83, 101, 116, 61, 34, 116, 114, 117, 101, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 76, 101, 118, 101, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 114, 114, 97, 121, 68, 105, 109, 101, 110, 115, 105, 111, 110, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 97, 105, 110, 115, 78, 111, 76, 111, 111, 112, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 78, 111, 116, 105, 102, 105, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 50, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 69, 120, 101, 99, 117, 116, 97, 98, 108, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 53, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 105, 122, 105, 110, 103, 34, 32, 86, 97, 108, 117, 101, 61, 34, 53, 49, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 118, 101, 114, 115, 101, 78, 97, 109, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 48, 50, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 115, 65, 98, 115, 116, 114, 97, 99, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 48, 52, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 77, 105, 110, 105, 109, 117, 109, 83, 97, 109, 112, 108, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 48, 57, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 49, 57, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 51, 56, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 121, 109, 109, 101, 116, 114, 105, 99, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 50, 55, 54, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 65, 99, 99, 101, 115, 115, 76, 101, 118, 101, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 53, 53, 51, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 69, 120, 101, 99, 117, 116, 97, 98, 108, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 51, 49, 48, 55, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 54, 50, 49, 52, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 82, 97, 110, 107, 34, 32, 86, 97, 108, 117, 101, 61, 34, 53, 50, 52, 50, 56, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 77, 97, 115, 107, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 48, 52, 56, 53, 55, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 70, 111, 114, 86, 97, 114, 105, 97, 98, 108, 101, 84, 121, 112, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 48, 57, 55, 49, 53, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 49, 57, 52, 51, 48, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 111, 108, 101, 80, 101, 114, 109, 105, 115, 115, 105, 111, 110, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 51, 56, 56, 54, 48, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 82, 101, 115, 116, 114, 105, 99, 116, 105, 111, 110, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 55, 55, 55, 50, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 99, 99, 101, 115, 115, 76, 101, 118, 101, 108, 69, 120, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 51, 53, 53, 52, 52, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 68, 105, 114, 101, 99, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 70, 111, 114, 119, 97, 114, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 118, 101, 114, 115, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 66, 111, 116, 104, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 118, 97, 108, 105, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 86, 105, 101, 119, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 105, 101, 119, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 115, 116, 97, 109, 112, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 105, 101, 119, 86, 101, 114, 115, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 68, 105, 114, 101, 99, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 66, 114, 111, 119, 115, 101, 68, 105, 114, 101, 99, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 84, 121, 112, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 99, 108, 117, 100, 101, 83, 117, 98, 116, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 77, 97, 115, 107, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 82, 101, 115, 117, 108, 116, 77, 97, 115, 107, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 84, 121, 112, 101, 73, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 115, 70, 111, 114, 119, 97, 114, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 84, 121, 112, 101, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 108, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 84, 121, 112, 101, 73, 110, 102, 111, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 84, 97, 114, 103, 101, 116, 73, 110, 102, 111, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 48, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 84, 121, 112, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 70, 111, 114, 119, 97, 114, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 67, 108, 97, 115, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 121, 112, 101, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 105, 110, 117, 97, 116, 105, 111, 110, 80, 111, 105, 110, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 105, 110, 117, 97, 116, 105, 111, 110, 80, 111, 105, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 102, 101, 114, 101, 110, 99, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 105, 101, 119, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 86, 105, 101, 119, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 77, 97, 120, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 80, 101, 114, 78, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 66, 114, 111, 119, 115, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 115, 84, 111, 66, 114, 111, 119, 115, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 66, 114, 111, 119, 115, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 66, 114, 111, 119, 115, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 66, 114, 111, 119, 115, 101, 82, 101, 115, 117, 108, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 101, 120, 116, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 108, 101, 97, 115, 101, 67, 111, 110, 116, 105, 110, 117, 97, 116, 105, 111, 110, 80, 111, 105, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 67, 111, 110, 116, 105, 110, 117, 97, 116, 105, 111, 110, 80, 111, 105, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 105, 110, 117, 97, 116, 105, 111, 110, 80, 111, 105, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 67, 111, 110, 116, 105, 110, 117, 97, 116, 105, 111, 110, 80, 111, 105, 110, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 101, 120, 116, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 66, 114, 111, 119, 115, 101, 82, 101, 115, 117, 108, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 108, 97, 116, 105, 118, 101, 80, 97, 116, 104, 69, 108, 101, 109, 101, 110, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 84, 121, 112, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 73, 110, 118, 101, 114, 115, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 99, 108, 117, 100, 101, 83, 117, 98, 116, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 97, 114, 103, 101, 116, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 108, 97, 116, 105, 118, 101, 80, 97, 116, 104, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 108, 101, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 108, 101, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 108, 97, 116, 105, 118, 101, 80, 97, 116, 104, 69, 108, 101, 109, 101, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 108, 101, 109, 101, 110, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 114, 116, 105, 110, 103, 78, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 108, 97, 116, 105, 118, 101, 80, 97, 116, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 108, 97, 116, 105, 118, 101, 80, 97, 116, 104, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 84, 97, 114, 103, 101, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 97, 114, 103, 101, 116, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 109, 97, 105, 110, 105, 110, 103, 80, 97, 116, 104, 73, 110, 100, 101, 120, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 84, 97, 114, 103, 101, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 97, 114, 103, 101, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 84, 97, 114, 103, 101, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 84, 97, 114, 103, 101, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 108, 97, 116, 101, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 115, 84, 111, 78, 111, 100, 101, 73, 100, 115, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 108, 97, 116, 101, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 115, 84, 111, 78, 111, 100, 101, 73, 100, 115, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 82, 101, 115, 117, 108, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 103, 105, 115, 116, 101, 114, 78, 111, 100, 101, 115, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 82, 101, 103, 105, 115, 116, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 115, 84, 111, 82, 101, 103, 105, 115, 116, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 82, 101, 103, 105, 115, 116, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 103, 105, 115, 116, 101, 114, 78, 111, 100, 101, 115, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 103, 105, 115, 116, 101, 114, 101, 100, 78, 111, 100, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 103, 105, 115, 116, 101, 114, 101, 100, 78, 111, 100, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 103, 105, 115, 116, 101, 114, 101, 100, 78, 111, 100, 101, 73, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 110, 114, 101, 103, 105, 115, 116, 101, 114, 78, 111, 100, 101, 115, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 85, 110, 114, 101, 103, 105, 115, 116, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 115, 84, 111, 85, 110, 114, 101, 103, 105, 115, 116, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 85, 110, 114, 101, 103, 105, 115, 116, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 110, 114, 101, 103, 105, 115, 116, 101, 114, 78, 111, 100, 101, 115, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 111, 117, 110, 116, 101, 114, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 117, 109, 101, 114, 105, 99, 82, 97, 110, 103, 101, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 79, 112, 97, 113, 117, 101, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 112, 111, 105, 110, 116, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 79, 112, 101, 114, 97, 116, 105, 111, 110, 84, 105, 109, 101, 111, 117, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 66, 105, 110, 97, 114, 121, 69, 110, 99, 111, 100, 105, 110, 103, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 83, 116, 114, 105, 110, 103, 76, 101, 110, 103, 116, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 76, 101, 110, 103, 116, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 65, 114, 114, 97, 121, 76, 101, 110, 103, 116, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 77, 101, 115, 115, 97, 103, 101, 83, 105, 122, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 66, 117, 102, 102, 101, 114, 83, 105, 122, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 104, 97, 110, 110, 101, 108, 76, 105, 102, 101, 116, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 84, 111, 107, 101, 110, 76, 105, 102, 101, 116, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 81, 117, 101, 114, 121, 68, 97, 116, 97, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 108, 97, 116, 105, 118, 101, 80, 97, 116, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 108, 97, 116, 105, 118, 101, 80, 97, 116, 104, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 116, 116, 114, 105, 98, 117, 116, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 100, 101, 120, 82, 97, 110, 103, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 121, 112, 101, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 78, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 99, 108, 117, 100, 101, 83, 117, 98, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 81, 117, 101, 114, 121, 68, 97, 116, 97, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 70, 105, 108, 116, 101, 114, 79, 112, 101, 114, 97, 116, 111, 114, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 69, 113, 117, 97, 108, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 115, 78, 117, 108, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 71, 114, 101, 97, 116, 101, 114, 84, 104, 97, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 76, 101, 115, 115, 84, 104, 97, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 71, 114, 101, 97, 116, 101, 114, 84, 104, 97, 110, 79, 114, 69, 113, 117, 97, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 76, 101, 115, 115, 84, 104, 97, 110, 79, 114, 69, 113, 117, 97, 108, 34, 32, 86, 97, 108, 117, 101, 61, 34, 53, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 76, 105, 107, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 55, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 66, 101, 116, 119, 101, 101, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 76, 105, 115, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 57, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 110, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 79, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 67, 97, 115, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 86, 105, 101, 119, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 79, 102, 84, 121, 112, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 108, 97, 116, 101, 100, 84, 111, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 53, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 66, 105, 116, 119, 105, 115, 101, 65, 110, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 66, 105, 116, 119, 105, 115, 101, 79, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 55, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 81, 117, 101, 114, 121, 68, 97, 116, 97, 83, 101, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 121, 112, 101, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 78, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 112, 97, 110, 100, 101, 100, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 86, 97, 108, 117, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 82, 101, 102, 101, 114, 101, 110, 99, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 84, 121, 112, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 70, 111, 114, 119, 97, 114, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 100, 78, 111, 100, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 100, 78, 111, 100, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 102, 101, 114, 101, 110, 99, 101, 100, 78, 111, 100, 101, 73, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 101, 110, 116, 70, 105, 108, 116, 101, 114, 69, 108, 101, 109, 101, 110, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 108, 116, 101, 114, 79, 112, 101, 114, 97, 116, 111, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 70, 105, 108, 116, 101, 114, 79, 112, 101, 114, 97, 116, 111, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 70, 105, 108, 116, 101, 114, 79, 112, 101, 114, 97, 110, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 108, 116, 101, 114, 79, 112, 101, 114, 97, 110, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 70, 105, 108, 116, 101, 114, 79, 112, 101, 114, 97, 110, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 101, 110, 116, 70, 105, 108, 116, 101, 114, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 108, 101, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 108, 101, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 67, 111, 110, 116, 101, 110, 116, 70, 105, 108, 116, 101, 114, 69, 108, 101, 109, 101, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 108, 101, 109, 101, 110, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 70, 105, 108, 116, 101, 114, 79, 112, 101, 114, 97, 110, 100, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 108, 101, 109, 101, 110, 116, 79, 112, 101, 114, 97, 110, 100, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 70, 105, 108, 116, 101, 114, 79, 112, 101, 114, 97, 110, 100, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 100, 101, 120, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 76, 105, 116, 101, 114, 97, 108, 79, 112, 101, 114, 97, 110, 100, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 70, 105, 108, 116, 101, 114, 79, 112, 101, 114, 97, 110, 100, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 116, 116, 114, 105, 98, 117, 116, 101, 79, 112, 101, 114, 97, 110, 100, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 70, 105, 108, 116, 101, 114, 79, 112, 101, 114, 97, 110, 100, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 108, 105, 97, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 108, 97, 116, 105, 118, 101, 80, 97, 116, 104, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 116, 116, 114, 105, 98, 117, 116, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 100, 101, 120, 82, 97, 110, 103, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 105, 109, 112, 108, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 79, 112, 101, 114, 97, 110, 100, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 70, 105, 108, 116, 101, 114, 79, 112, 101, 114, 97, 110, 100, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 121, 112, 101, 68, 101, 102, 105, 110, 105, 116, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 116, 116, 114, 105, 98, 117, 116, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 100, 101, 120, 82, 97, 110, 103, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 101, 110, 116, 70, 105, 108, 116, 101, 114, 69, 108, 101, 109, 101, 110, 116, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 79, 112, 101, 114, 97, 110, 100, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 79, 112, 101, 114, 97, 110, 100, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 79, 112, 101, 114, 97, 110, 100, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 79, 112, 101, 114, 97, 110, 100, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 79, 112, 101, 114, 97, 110, 100, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 79, 112, 101, 114, 97, 110, 100, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 101, 110, 116, 70, 105, 108, 116, 101, 114, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 108, 101, 109, 101, 110, 116, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 108, 101, 109, 101, 110, 116, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 67, 111, 110, 116, 101, 110, 116, 70, 105, 108, 116, 101, 114, 69, 108, 101, 109, 101, 110, 116, 82, 101, 115, 117, 108, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 108, 101, 109, 101, 110, 116, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 108, 101, 109, 101, 110, 116, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 108, 101, 109, 101, 110, 116, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 108, 101, 109, 101, 110, 116, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 97, 114, 115, 105, 110, 103, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 81, 117, 101, 114, 121, 70, 105, 114, 115, 116, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 105, 101, 119, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 86, 105, 101, 119, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 84, 121, 112, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 100, 101, 84, 121, 112, 101, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 84, 121, 112, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 108, 116, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 67, 111, 110, 116, 101, 110, 116, 70, 105, 108, 116, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 68, 97, 116, 97, 83, 101, 116, 115, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 81, 117, 101, 114, 121, 70, 105, 114, 115, 116, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 81, 117, 101, 114, 121, 68, 97, 116, 97, 83, 101, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 81, 117, 101, 114, 121, 68, 97, 116, 97, 83, 101, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 81, 117, 101, 114, 121, 68, 97, 116, 97, 83, 101, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 81, 117, 101, 114, 121, 68, 97, 116, 97, 83, 101, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 105, 110, 117, 97, 116, 105, 111, 110, 80, 111, 105, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 80, 97, 114, 115, 105, 110, 103, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 97, 114, 115, 105, 110, 103, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 80, 97, 114, 115, 105, 110, 103, 82, 101, 115, 117, 108, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 80, 97, 114, 115, 105, 110, 103, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 108, 116, 101, 114, 82, 101, 115, 117, 108, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 67, 111, 110, 116, 101, 110, 116, 70, 105, 108, 116, 101, 114, 82, 101, 115, 117, 108, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 81, 117, 101, 114, 121, 78, 101, 120, 116, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 108, 101, 97, 115, 101, 67, 111, 110, 116, 105, 110, 117, 97, 116, 105, 111, 110, 80, 111, 105, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 105, 110, 117, 97, 116, 105, 111, 110, 80, 111, 105, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 81, 117, 101, 114, 121, 78, 101, 120, 116, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 81, 117, 101, 114, 121, 68, 97, 116, 97, 83, 101, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 81, 117, 101, 114, 121, 68, 97, 116, 97, 83, 101, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 81, 117, 101, 114, 121, 68, 97, 116, 97, 83, 101, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 81, 117, 101, 114, 121, 68, 97, 116, 97, 83, 101, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 67, 111, 110, 116, 105, 110, 117, 97, 116, 105, 111, 110, 80, 111, 105, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 115, 116, 97, 109, 112, 115, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 111, 117, 114, 99, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 66, 111, 116, 104, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 101, 105, 116, 104, 101, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 118, 97, 108, 105, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 86, 97, 108, 117, 101, 73, 100, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 116, 116, 114, 105, 98, 117, 116, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 100, 101, 120, 82, 97, 110, 103, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 69, 110, 99, 111, 100, 105, 110, 103, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 65, 103, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 115, 116, 97, 109, 112, 115, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 84, 105, 109, 101, 115, 116, 97, 109, 112, 115, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 82, 101, 97, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 115, 84, 111, 82, 101, 97, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 97, 100, 86, 97, 108, 117, 101, 73, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 82, 101, 97, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 97, 116, 97, 86, 97, 108, 117, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 86, 97, 108, 117, 101, 73, 100, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 100, 101, 120, 82, 97, 110, 103, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 69, 110, 99, 111, 100, 105, 110, 103, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 81, 117, 97, 108, 105, 102, 105, 101, 100, 78, 97, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 105, 110, 117, 97, 116, 105, 111, 110, 80, 111, 105, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 111, 110, 116, 105, 110, 117, 97, 116, 105, 111, 110, 80, 111, 105, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 68, 97, 116, 97, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 68, 101, 116, 97, 105, 108, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 69, 118, 101, 110, 116, 68, 101, 116, 97, 105, 108, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 68, 101, 116, 97, 105, 108, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 117, 109, 86, 97, 108, 117, 101, 115, 80, 101, 114, 78, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 114, 116, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 108, 116, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 118, 101, 110, 116, 70, 105, 108, 116, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 82, 97, 119, 77, 111, 100, 105, 102, 105, 101, 100, 68, 101, 116, 97, 105, 108, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 68, 101, 116, 97, 105, 108, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 82, 101, 97, 100, 77, 111, 100, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 114, 116, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 117, 109, 86, 97, 108, 117, 101, 115, 80, 101, 114, 78, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 116, 117, 114, 110, 66, 111, 117, 110, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 80, 114, 111, 99, 101, 115, 115, 101, 100, 68, 101, 116, 97, 105, 108, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 68, 101, 116, 97, 105, 108, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 114, 116, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 114, 111, 99, 101, 115, 115, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 103, 103, 114, 101, 103, 97, 116, 101, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 103, 103, 114, 101, 103, 97, 116, 101, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 103, 103, 114, 101, 103, 97, 116, 101, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 103, 103, 114, 101, 103, 97, 116, 101, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 103, 103, 114, 101, 103, 97, 116, 101, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 65, 116, 84, 105, 109, 101, 68, 101, 116, 97, 105, 108, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 68, 101, 116, 97, 105, 108, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 113, 84, 105, 109, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 84, 105, 109, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 113, 84, 105, 109, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 83, 105, 109, 112, 108, 101, 66, 111, 117, 110, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 65, 110, 110, 111, 116, 97, 116, 105, 111, 110, 68, 97, 116, 97, 68, 101, 116, 97, 105, 108, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 68, 101, 116, 97, 105, 108, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 113, 84, 105, 109, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 84, 105, 109, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 113, 84, 105, 109, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 68, 97, 116, 97, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 97, 116, 97, 86, 97, 108, 117, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 86, 97, 108, 117, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 100, 105, 102, 105, 99, 97, 116, 105, 111, 110, 73, 110, 102, 111, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 100, 105, 102, 105, 99, 97, 116, 105, 111, 110, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 112, 100, 97, 116, 101, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 77, 111, 100, 105, 102, 105, 101, 100, 68, 97, 116, 97, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 68, 97, 116, 97, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 97, 116, 97, 86, 97, 108, 117, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 97, 116, 97, 86, 97, 108, 117, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 77, 111, 100, 105, 102, 105, 99, 97, 116, 105, 111, 110, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 100, 105, 102, 105, 99, 97, 116, 105, 111, 110, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 111, 100, 105, 102, 105, 99, 97, 116, 105, 111, 110, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 77, 111, 100, 105, 102, 105, 99, 97, 116, 105, 111, 110, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 69, 118, 101, 110, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 118, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 69, 118, 101, 110, 116, 70, 105, 101, 108, 100, 76, 105, 115, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 118, 101, 110, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 68, 101, 116, 97, 105, 108, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 115, 116, 97, 109, 112, 115, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 84, 105, 109, 101, 115, 116, 97, 109, 112, 115, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 108, 101, 97, 115, 101, 67, 111, 110, 116, 105, 110, 117, 97, 116, 105, 111, 110, 80, 111, 105, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 82, 101, 97, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 115, 84, 111, 82, 101, 97, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 86, 97, 108, 117, 101, 73, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 82, 101, 97, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 82, 101, 115, 117, 108, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 86, 97, 108, 117, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 116, 116, 114, 105, 98, 117, 116, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 100, 101, 120, 82, 97, 110, 103, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 97, 116, 97, 86, 97, 108, 117, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 87, 114, 105, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 115, 84, 111, 87, 114, 105, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 87, 114, 105, 116, 101, 86, 97, 108, 117, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 111, 100, 101, 115, 84, 111, 87, 114, 105, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 115, 101, 114, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 112, 108, 97, 99, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 112, 100, 97, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 101, 114, 102, 111, 114, 109, 85, 112, 100, 97, 116, 101, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 73, 110, 115, 101, 114, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 112, 108, 97, 99, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 112, 100, 97, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 109, 111, 118, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 112, 100, 97, 116, 101, 68, 97, 116, 97, 68, 101, 116, 97, 105, 108, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 101, 114, 102, 111, 114, 109, 73, 110, 115, 101, 114, 116, 82, 101, 112, 108, 97, 99, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 80, 101, 114, 102, 111, 114, 109, 85, 112, 100, 97, 116, 101, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 85, 112, 100, 97, 116, 101, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 112, 100, 97, 116, 101, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 97, 116, 97, 86, 97, 108, 117, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 85, 112, 100, 97, 116, 101, 86, 97, 108, 117, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 112, 100, 97, 116, 101, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 97, 116, 97, 68, 101, 116, 97, 105, 108, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 101, 114, 102, 111, 114, 109, 73, 110, 115, 101, 114, 116, 82, 101, 112, 108, 97, 99, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 80, 101, 114, 102, 111, 114, 109, 85, 112, 100, 97, 116, 101, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 85, 112, 100, 97, 116, 101, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 112, 100, 97, 116, 101, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 97, 116, 97, 86, 97, 108, 117, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 85, 112, 100, 97, 116, 101, 86, 97, 108, 117, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 85, 112, 100, 97, 116, 101, 69, 118, 101, 110, 116, 68, 101, 116, 97, 105, 108, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 101, 114, 102, 111, 114, 109, 73, 110, 115, 101, 114, 116, 82, 101, 112, 108, 97, 99, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 80, 101, 114, 102, 111, 114, 109, 85, 112, 100, 97, 116, 101, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 108, 116, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 118, 101, 110, 116, 70, 105, 108, 116, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 118, 101, 110, 116, 68, 97, 116, 97, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 68, 97, 116, 97, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 69, 118, 101, 110, 116, 70, 105, 101, 108, 100, 76, 105, 115, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 118, 101, 110, 116, 68, 97, 116, 97, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 82, 97, 119, 77, 111, 100, 105, 102, 105, 101, 100, 68, 101, 116, 97, 105, 108, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 115, 68, 101, 108, 101, 116, 101, 77, 111, 100, 105, 102, 105, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 114, 116, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 65, 116, 84, 105, 109, 101, 68, 101, 116, 97, 105, 108, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 113, 84, 105, 109, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 84, 105, 109, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 113, 84, 105, 109, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 69, 118, 101, 110, 116, 68, 101, 116, 97, 105, 108, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 83, 111, 117, 114, 99, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 118, 101, 110, 116, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 118, 101, 110, 116, 73, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 79, 112, 101, 114, 97, 116, 105, 111, 110, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 79, 112, 101, 114, 97, 116, 105, 111, 110, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 79, 112, 101, 114, 97, 116, 105, 111, 110, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 68, 101, 116, 97, 105, 108, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 82, 101, 115, 117, 108, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 97, 108, 108, 77, 101, 116, 104, 111, 100, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 79, 98, 106, 101, 99, 116, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 101, 116, 104, 111, 100, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 97, 108, 108, 77, 101, 116, 104, 111, 100, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 79, 117, 116, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 79, 117, 116, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 79, 117, 116, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 97, 108, 108, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 77, 101, 116, 104, 111, 100, 115, 84, 111, 67, 97, 108, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 101, 116, 104, 111, 100, 115, 84, 111, 67, 97, 108, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 67, 97, 108, 108, 77, 101, 116, 104, 111, 100, 82, 101, 113, 117, 101, 115, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 77, 101, 116, 104, 111, 100, 115, 84, 111, 67, 97, 108, 108, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 97, 108, 108, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 67, 97, 108, 108, 77, 101, 116, 104, 111, 100, 82, 101, 115, 117, 108, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 77, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 97, 98, 108, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 97, 109, 112, 108, 105, 110, 103, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 112, 111, 114, 116, 105, 110, 103, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 67, 104, 97, 110, 103, 101, 84, 114, 105, 103, 103, 101, 114, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 86, 97, 108, 117, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 86, 97, 108, 117, 101, 84, 105, 109, 101, 115, 116, 97, 109, 112, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 97, 100, 98, 97, 110, 100, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 98, 115, 111, 108, 117, 116, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 80, 101, 114, 99, 101, 110, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 70, 105, 108, 116, 101, 114, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 67, 104, 97, 110, 103, 101, 70, 105, 108, 116, 101, 114, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 70, 105, 108, 116, 101, 114, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 105, 103, 103, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 68, 97, 116, 97, 67, 104, 97, 110, 103, 101, 84, 114, 105, 103, 103, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 97, 100, 98, 97, 110, 100, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 97, 100, 98, 97, 110, 100, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 70, 105, 108, 116, 101, 114, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 70, 105, 108, 116, 101, 114, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 108, 101, 99, 116, 67, 108, 97, 117, 115, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 108, 101, 99, 116, 67, 108, 97, 117, 115, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 105, 109, 112, 108, 101, 65, 116, 116, 114, 105, 98, 117, 116, 101, 79, 112, 101, 114, 97, 110, 100, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 108, 101, 99, 116, 67, 108, 97, 117, 115, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 104, 101, 114, 101, 67, 108, 97, 117, 115, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 67, 111, 110, 116, 101, 110, 116, 70, 105, 108, 116, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 103, 103, 114, 101, 103, 97, 116, 101, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 83, 101, 114, 118, 101, 114, 67, 97, 112, 97, 98, 105, 108, 105, 116, 105, 101, 115, 68, 101, 102, 97, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 101, 97, 116, 85, 110, 99, 101, 114, 116, 97, 105, 110, 65, 115, 66, 97, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 101, 114, 99, 101, 110, 116, 68, 97, 116, 97, 66, 97, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 101, 114, 99, 101, 110, 116, 68, 97, 116, 97, 71, 111, 111, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 83, 108, 111, 112, 101, 100, 69, 120, 116, 114, 97, 112, 111, 108, 97, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 103, 103, 114, 101, 103, 97, 116, 101, 70, 105, 108, 116, 101, 114, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 70, 105, 108, 116, 101, 114, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 114, 116, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 103, 103, 114, 101, 103, 97, 116, 101, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 114, 111, 99, 101, 115, 115, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 103, 103, 114, 101, 103, 97, 116, 101, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 103, 103, 114, 101, 103, 97, 116, 101, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 70, 105, 108, 116, 101, 114, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 70, 105, 108, 116, 101, 114, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 70, 105, 108, 116, 101, 114, 82, 101, 115, 117, 108, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 108, 101, 99, 116, 67, 108, 97, 117, 115, 101, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 108, 101, 99, 116, 67, 108, 97, 117, 115, 101, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 108, 101, 99, 116, 67, 108, 97, 117, 115, 101, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 101, 108, 101, 99, 116, 67, 108, 97, 117, 115, 101, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 108, 101, 99, 116, 67, 108, 97, 117, 115, 101, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 101, 108, 101, 99, 116, 67, 108, 97, 117, 115, 101, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 104, 101, 114, 101, 67, 108, 97, 117, 115, 101, 82, 101, 115, 117, 108, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 67, 111, 110, 116, 101, 110, 116, 70, 105, 108, 116, 101, 114, 82, 101, 115, 117, 108, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 103, 103, 114, 101, 103, 97, 116, 101, 70, 105, 108, 116, 101, 114, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 70, 105, 108, 116, 101, 114, 82, 101, 115, 117, 108, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 83, 116, 97, 114, 116, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 80, 114, 111, 99, 101, 115, 115, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 65, 103, 103, 114, 101, 103, 97, 116, 101, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 103, 103, 114, 101, 103, 97, 116, 101, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 80, 97, 114, 97, 109, 101, 116, 101, 114, 115, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 72, 97, 110, 100, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 97, 109, 112, 108, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 108, 116, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 81, 117, 101, 117, 101, 83, 105, 122, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 99, 97, 114, 100, 79, 108, 100, 101, 115, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 67, 114, 101, 97, 116, 101, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 116, 101, 109, 84, 111, 77, 111, 110, 105, 116, 111, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 97, 100, 86, 97, 108, 117, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 77, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 77, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 80, 97, 114, 97, 109, 101, 116, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 80, 97, 114, 97, 109, 101, 116, 101, 114, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 67, 114, 101, 97, 116, 101, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 83, 97, 109, 112, 108, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 81, 117, 101, 117, 101, 83, 105, 122, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 108, 116, 101, 114, 82, 101, 115, 117, 108, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 114, 101, 97, 116, 101, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 115, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 115, 116, 97, 109, 112, 115, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 84, 105, 109, 101, 115, 116, 97, 109, 112, 115, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 73, 116, 101, 109, 115, 84, 111, 67, 114, 101, 97, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 116, 101, 109, 115, 84, 111, 67, 114, 101, 97, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 67, 114, 101, 97, 116, 101, 82, 101, 113, 117, 101, 115, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 73, 116, 101, 109, 115, 84, 111, 67, 114, 101, 97, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 114, 101, 97, 116, 101, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 115, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 67, 114, 101, 97, 116, 101, 82, 101, 115, 117, 108, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 77, 111, 100, 105, 102, 121, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 80, 97, 114, 97, 109, 101, 116, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 80, 97, 114, 97, 109, 101, 116, 101, 114, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 77, 111, 100, 105, 102, 121, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 83, 97, 109, 112, 108, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 81, 117, 101, 117, 101, 83, 105, 122, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 70, 105, 108, 116, 101, 114, 82, 101, 115, 117, 108, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 100, 105, 102, 121, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 115, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 105, 109, 101, 115, 116, 97, 109, 112, 115, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 84, 105, 109, 101, 115, 116, 97, 109, 112, 115, 84, 111, 82, 101, 116, 117, 114, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 73, 116, 101, 109, 115, 84, 111, 77, 111, 100, 105, 102, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 116, 101, 109, 115, 84, 111, 77, 111, 100, 105, 102, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 77, 111, 100, 105, 102, 121, 82, 101, 113, 117, 101, 115, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 73, 116, 101, 109, 115, 84, 111, 77, 111, 100, 105, 102, 121, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 100, 105, 102, 121, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 115, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 77, 111, 100, 105, 102, 121, 82, 101, 115, 117, 108, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 116, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 77, 111, 100, 101, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 77, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 77, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 73, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 116, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 77, 111, 100, 101, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 116, 84, 114, 105, 103, 103, 101, 114, 105, 110, 103, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 105, 103, 103, 101, 114, 105, 110, 103, 73, 116, 101, 109, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 76, 105, 110, 107, 115, 84, 111, 65, 100, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 105, 110, 107, 115, 84, 111, 65, 100, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 76, 105, 110, 107, 115, 84, 111, 65, 100, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 76, 105, 110, 107, 115, 84, 111, 82, 101, 109, 111, 118, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 105, 110, 107, 115, 84, 111, 82, 101, 109, 111, 118, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 76, 105, 110, 107, 115, 84, 111, 82, 101, 109, 111, 118, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 116, 84, 114, 105, 103, 103, 101, 114, 105, 110, 103, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 100, 100, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 100, 100, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 100, 100, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 100, 100, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 109, 111, 118, 101, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 109, 111, 118, 101, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 109, 111, 118, 101, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 109, 111, 118, 101, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 109, 111, 118, 101, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 109, 111, 118, 101, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 115, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 73, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 115, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 114, 101, 97, 116, 101, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 76, 105, 102, 101, 116, 105, 109, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 77, 97, 120, 75, 101, 101, 112, 65, 108, 105, 118, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 115, 80, 101, 114, 80, 117, 98, 108, 105, 115, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 69, 110, 97, 98, 108, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 114, 105, 111, 114, 105, 116, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 114, 101, 97, 116, 101, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 76, 105, 102, 101, 116, 105, 109, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 77, 97, 120, 75, 101, 101, 112, 65, 108, 105, 118, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 100, 105, 102, 121, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 76, 105, 102, 101, 116, 105, 109, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 101, 100, 77, 97, 120, 75, 101, 101, 112, 65, 108, 105, 118, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 115, 80, 101, 114, 80, 117, 98, 108, 105, 115, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 114, 105, 111, 114, 105, 116, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 100, 105, 102, 121, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 76, 105, 102, 101, 116, 105, 109, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 118, 105, 115, 101, 100, 77, 97, 120, 75, 101, 101, 112, 65, 108, 105, 118, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 116, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 77, 111, 100, 101, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 69, 110, 97, 98, 108, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 116, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 77, 111, 100, 101, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 77, 101, 115, 115, 97, 103, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 113, 117, 101, 110, 99, 101, 78, 117, 109, 98, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 68, 97, 116, 97, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 68, 97, 116, 97, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 68, 97, 116, 97, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 68, 97, 116, 97, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 67, 104, 97, 110, 103, 101, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 68, 97, 116, 97, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 72, 97, 110, 100, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 97, 116, 97, 86, 97, 108, 117, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 76, 105, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 68, 97, 116, 97, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 118, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 118, 101, 110, 116, 70, 105, 101, 108, 100, 76, 105, 115, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 118, 101, 110, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 70, 105, 101, 108, 100, 76, 105, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 72, 97, 110, 100, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 118, 101, 110, 116, 70, 105, 101, 108, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 70, 105, 101, 108, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 118, 101, 110, 116, 70, 105, 101, 108, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 69, 118, 101, 110, 116, 70, 105, 101, 108, 100, 76, 105, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 118, 101, 110, 116, 70, 105, 101, 108, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 70, 105, 101, 108, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 118, 101, 110, 116, 70, 105, 101, 108, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 104, 97, 110, 103, 101, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 116, 110, 115, 58, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 68, 97, 116, 97, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 65, 99, 107, 110, 111, 119, 108, 101, 100, 103, 101, 109, 101, 110, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 113, 117, 101, 110, 99, 101, 78, 117, 109, 98, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 65, 99, 107, 110, 111, 119, 108, 101, 100, 103, 101, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 65, 99, 107, 110, 111, 119, 108, 101, 100, 103, 101, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 65, 99, 107, 110, 111, 119, 108, 101, 100, 103, 101, 109, 101, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 65, 99, 107, 110, 111, 119, 108, 101, 100, 103, 101, 109, 101, 110, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 118, 97, 105, 108, 97, 98, 108, 101, 83, 101, 113, 117, 101, 110, 99, 101, 78, 117, 109, 98, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 118, 97, 105, 108, 97, 98, 108, 101, 83, 101, 113, 117, 101, 110, 99, 101, 78, 117, 109, 98, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 118, 97, 105, 108, 97, 98, 108, 101, 83, 101, 113, 117, 101, 110, 99, 101, 78, 117, 109, 98, 101, 114, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 114, 101, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 77, 101, 115, 115, 97, 103, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 77, 101, 115, 115, 97, 103, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 112, 117, 98, 108, 105, 115, 104, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 116, 114, 97, 110, 115, 109, 105, 116, 83, 101, 113, 117, 101, 110, 99, 101, 78, 117, 109, 98, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 112, 117, 98, 108, 105, 115, 104, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 77, 101, 115, 115, 97, 103, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 77, 101, 115, 115, 97, 103, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 102, 101, 114, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 118, 97, 105, 108, 97, 98, 108, 101, 83, 101, 113, 117, 101, 110, 99, 101, 78, 117, 109, 98, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 118, 97, 105, 108, 97, 98, 108, 101, 83, 101, 113, 117, 101, 110, 99, 101, 78, 117, 109, 98, 101, 114, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 118, 97, 105, 108, 97, 98, 108, 101, 83, 101, 113, 117, 101, 110, 99, 101, 78, 117, 109, 98, 101, 114, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 102, 101, 114, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 115, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 110, 100, 73, 110, 105, 116, 105, 97, 108, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 102, 101, 114, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 115, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 84, 114, 97, 110, 115, 102, 101, 114, 82, 101, 115, 117, 108, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 115, 82, 101, 113, 117, 101, 115, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 113, 117, 101, 115, 116, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 115, 82, 101, 115, 112, 111, 110, 115, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 101, 115, 112, 111, 110, 115, 101, 72, 101, 97, 100, 101, 114, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 115, 117, 108, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 82, 101, 115, 117, 108, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 66, 117, 105, 108, 100, 73, 110, 102, 111, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 114, 111, 100, 117, 99, 116, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 110, 117, 102, 97, 99, 116, 117, 114, 101, 114, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 114, 111, 100, 117, 99, 116, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 111, 102, 116, 119, 97, 114, 101, 86, 101, 114, 115, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 117, 105, 108, 100, 78, 117, 109, 98, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 117, 105, 108, 100, 68, 97, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 100, 117, 110, 100, 97, 110, 99, 121, 83, 117, 112, 112, 111, 114, 116, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 110, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 67, 111, 108, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 87, 97, 114, 109, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 72, 111, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 112, 97, 114, 101, 110, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 72, 111, 116, 65, 110, 100, 77, 105, 114, 114, 111, 114, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 53, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 83, 116, 97, 116, 101, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 117, 110, 110, 105, 110, 103, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 70, 97, 105, 108, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 117, 115, 112, 101, 110, 100, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 83, 104, 117, 116, 100, 111, 119, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 84, 101, 115, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 53, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 67, 111, 109, 109, 117, 110, 105, 99, 97, 116, 105, 111, 110, 70, 97, 117, 108, 116, 34, 32, 86, 97, 108, 117, 101, 61, 34, 54, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 110, 107, 110, 111, 119, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 55, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 100, 117, 110, 100, 97, 110, 116, 83, 101, 114, 118, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 105, 99, 101, 76, 101, 118, 101, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 83, 116, 97, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 101, 114, 83, 116, 97, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 112, 111, 105, 110, 116, 85, 114, 108, 76, 105, 115, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 69, 110, 100, 112, 111, 105, 110, 116, 85, 114, 108, 76, 105, 115, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 112, 111, 105, 110, 116, 85, 114, 108, 76, 105, 115, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 69, 110, 100, 112, 111, 105, 110, 116, 85, 114, 108, 76, 105, 115, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 78, 101, 116, 119, 111, 114, 107, 71, 114, 111, 117, 112, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 78, 101, 116, 119, 111, 114, 107, 80, 97, 116, 104, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 101, 116, 119, 111, 114, 107, 80, 97, 116, 104, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 110, 100, 112, 111, 105, 110, 116, 85, 114, 108, 76, 105, 115, 116, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 78, 101, 116, 119, 111, 114, 107, 80, 97, 116, 104, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 97, 109, 112, 108, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 115, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 97, 109, 112, 108, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 97, 98, 108, 101, 100, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 115, 83, 117, 109, 109, 97, 114, 121, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 86, 105, 101, 119, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 117, 114, 114, 101, 110, 116, 83, 101, 115, 115, 105, 111, 110, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 117, 109, 117, 108, 97, 116, 101, 100, 83, 101, 115, 115, 105, 111, 110, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 82, 101, 106, 101, 99, 116, 101, 100, 83, 101, 115, 115, 105, 111, 110, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 106, 101, 99, 116, 101, 100, 83, 101, 115, 115, 105, 111, 110, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 115, 115, 105, 111, 110, 84, 105, 109, 101, 111, 117, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 115, 115, 105, 111, 110, 65, 98, 111, 114, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 117, 114, 114, 101, 110, 116, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 117, 109, 117, 108, 97, 116, 101, 100, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 82, 101, 106, 101, 99, 116, 101, 100, 82, 101, 113, 117, 101, 115, 116, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 106, 101, 99, 116, 101, 100, 82, 101, 113, 117, 101, 115, 116, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 83, 116, 97, 116, 117, 115, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 114, 116, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 117, 114, 114, 101, 110, 116, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 101, 114, 83, 116, 97, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 117, 105, 108, 100, 73, 110, 102, 111, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 66, 117, 105, 108, 100, 73, 110, 102, 111, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 111, 110, 100, 115, 84, 105, 108, 108, 83, 104, 117, 116, 100, 111, 119, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 104, 117, 116, 100, 111, 119, 110, 82, 101, 97, 115, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 115, 115, 105, 111, 110, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 115, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 115, 115, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 115, 115, 105, 111, 110, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 112, 112, 108, 105, 99, 97, 116, 105, 111, 110, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 101, 114, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 100, 112, 111, 105, 110, 116, 85, 114, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 76, 111, 99, 97, 108, 101, 73, 100, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 99, 116, 117, 97, 108, 83, 101, 115, 115, 105, 111, 110, 84, 105, 109, 101, 111, 117, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 82, 101, 115, 112, 111, 110, 115, 101, 77, 101, 115, 115, 97, 103, 101, 83, 105, 122, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 67, 111, 110, 110, 101, 99, 116, 105, 111, 110, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 76, 97, 115, 116, 67, 111, 110, 116, 97, 99, 116, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 117, 114, 114, 101, 110, 116, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 117, 114, 114, 101, 110, 116, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 117, 114, 114, 101, 110, 116, 80, 117, 98, 108, 105, 115, 104, 82, 101, 113, 117, 101, 115, 116, 115, 73, 110, 81, 117, 101, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 111, 116, 97, 108, 82, 101, 113, 117, 101, 115, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 110, 97, 117, 116, 104, 111, 114, 105, 122, 101, 100, 82, 101, 113, 117, 101, 115, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 100, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 82, 101, 97, 100, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 87, 114, 105, 116, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 72, 105, 115, 116, 111, 114, 121, 85, 112, 100, 97, 116, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 97, 108, 108, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 114, 101, 97, 116, 101, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 100, 105, 102, 121, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 116, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 77, 111, 100, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 116, 84, 114, 105, 103, 103, 101, 114, 105, 110, 103, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 114, 101, 97, 116, 101, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 100, 105, 102, 121, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 116, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 77, 111, 100, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 112, 117, 98, 108, 105, 115, 104, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 102, 101, 114, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 78, 111, 100, 101, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 100, 100, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 78, 111, 100, 101, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 108, 101, 116, 101, 82, 101, 102, 101, 114, 101, 110, 99, 101, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 66, 114, 111, 119, 115, 101, 78, 101, 120, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 108, 97, 116, 101, 66, 114, 111, 119, 115, 101, 80, 97, 116, 104, 115, 84, 111, 78, 111, 100, 101, 73, 100, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 81, 117, 101, 114, 121, 70, 105, 114, 115, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 81, 117, 101, 114, 121, 78, 101, 120, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 103, 105, 115, 116, 101, 114, 78, 111, 100, 101, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 110, 114, 101, 103, 105, 115, 116, 101, 114, 78, 111, 100, 101, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 115, 115, 105, 111, 110, 83, 101, 99, 117, 114, 105, 116, 121, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 115, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 115, 115, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 85, 115, 101, 114, 73, 100, 79, 102, 83, 101, 115, 115, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 67, 108, 105, 101, 110, 116, 85, 115, 101, 114, 73, 100, 72, 105, 115, 116, 111, 114, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 85, 115, 101, 114, 73, 100, 72, 105, 115, 116, 111, 114, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 67, 108, 105, 101, 110, 116, 85, 115, 101, 114, 73, 100, 72, 105, 115, 116, 111, 114, 121, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 117, 116, 104, 101, 110, 116, 105, 99, 97, 116, 105, 111, 110, 77, 101, 99, 104, 97, 110, 105, 115, 109, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 99, 111, 100, 105, 110, 103, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 112, 111, 114, 116, 80, 114, 111, 116, 111, 99, 111, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 77, 101, 115, 115, 97, 103, 101, 83, 101, 99, 117, 114, 105, 116, 121, 77, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 99, 117, 114, 105, 116, 121, 80, 111, 108, 105, 99, 121, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 108, 105, 101, 110, 116, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 114, 118, 105, 99, 101, 67, 111, 117, 110, 116, 101, 114, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 111, 116, 97, 108, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 114, 114, 111, 114, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 82, 101, 115, 117, 108, 116, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 83, 116, 97, 116, 117, 115, 67, 111, 100, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 73, 110, 102, 111, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 115, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 101, 115, 115, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 83, 117, 98, 115, 99, 114, 105, 112, 116, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 114, 105, 111, 114, 105, 116, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 73, 110, 116, 101, 114, 118, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 75, 101, 101, 112, 65, 108, 105, 118, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 76, 105, 102, 101, 116, 105, 109, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 97, 120, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 115, 80, 101, 114, 80, 117, 98, 108, 105, 115, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 105, 110, 103, 69, 110, 97, 98, 108, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 111, 111, 108, 101, 97, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 100, 105, 102, 121, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 97, 98, 108, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 97, 98, 108, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 112, 117, 98, 108, 105, 115, 104, 82, 101, 113, 117, 101, 115, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 112, 117, 98, 108, 105, 115, 104, 77, 101, 115, 115, 97, 103, 101, 82, 101, 113, 117, 101, 115, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 112, 117, 98, 108, 105, 115, 104, 77, 101, 115, 115, 97, 103, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 102, 101, 114, 82, 101, 113, 117, 101, 115, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 102, 101, 114, 114, 101, 100, 84, 111, 65, 108, 116, 67, 108, 105, 101, 110, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 114, 97, 110, 115, 102, 101, 114, 114, 101, 100, 84, 111, 83, 97, 109, 101, 67, 108, 105, 101, 110, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 80, 117, 98, 108, 105, 115, 104, 82, 101, 113, 117, 101, 115, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 67, 104, 97, 110, 103, 101, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 115, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 116, 101, 80, 117, 98, 108, 105, 115, 104, 82, 101, 113, 117, 101, 115, 116, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 117, 114, 114, 101, 110, 116, 75, 101, 101, 112, 65, 108, 105, 118, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 117, 114, 114, 101, 110, 116, 76, 105, 102, 101, 116, 105, 109, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 110, 97, 99, 107, 110, 111, 119, 108, 101, 100, 103, 101, 100, 77, 101, 115, 115, 97, 103, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 99, 97, 114, 100, 101, 100, 77, 101, 115, 115, 97, 103, 101, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 97, 98, 108, 101, 100, 77, 111, 110, 105, 116, 111, 114, 101, 100, 73, 116, 101, 109, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 111, 110, 105, 116, 111, 114, 105, 110, 103, 81, 117, 101, 117, 101, 79, 118, 101, 114, 102, 108, 111, 119, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 101, 120, 116, 83, 101, 113, 117, 101, 110, 99, 101, 78, 117, 109, 98, 101, 114, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 118, 101, 110, 116, 81, 117, 101, 117, 101, 79, 118, 101, 114, 70, 108, 111, 119, 67, 111, 117, 110, 116, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 85, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 100, 101, 108, 67, 104, 97, 110, 103, 101, 83, 116, 114, 117, 99, 116, 117, 114, 101, 86, 101, 114, 98, 77, 97, 115, 107, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 65, 100, 100, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 78, 111, 100, 101, 68, 101, 108, 101, 116, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 65, 100, 100, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 82, 101, 102, 101, 114, 101, 110, 99, 101, 68, 101, 108, 101, 116, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 56, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 68, 97, 116, 97, 84, 121, 112, 101, 67, 104, 97, 110, 103, 101, 100, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 54, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 77, 111, 100, 101, 108, 67, 104, 97, 110, 103, 101, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 102, 102, 101, 99, 116, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 102, 102, 101, 99, 116, 101, 100, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 101, 114, 98, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 66, 121, 116, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 83, 101, 109, 97, 110, 116, 105, 99, 67, 104, 97, 110, 103, 101, 83, 116, 114, 117, 99, 116, 117, 114, 101, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 102, 102, 101, 99, 116, 101, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 102, 102, 101, 99, 116, 101, 100, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 82, 97, 110, 103, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 111, 119, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 72, 105, 103, 104, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 85, 73, 110, 102, 111, 114, 109, 97, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 97, 109, 101, 115, 112, 97, 99, 101, 85, 114, 105, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 110, 105, 116, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 105, 115, 112, 108, 97, 121, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 68, 101, 115, 99, 114, 105, 112, 116, 105, 111, 110, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 120, 105, 115, 83, 99, 97, 108, 101, 69, 110, 117, 109, 101, 114, 97, 116, 105, 111, 110, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 76, 105, 110, 101, 97, 114, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 76, 111, 103, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 76, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 67, 111, 109, 112, 108, 101, 120, 78, 117, 109, 98, 101, 114, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 70, 108, 111, 97, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 109, 97, 103, 105, 110, 97, 114, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 70, 108, 111, 97, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 68, 111, 117, 98, 108, 101, 67, 111, 109, 112, 108, 101, 120, 78, 117, 109, 98, 101, 114, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 82, 101, 97, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 109, 97, 103, 105, 110, 97, 114, 121, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 120, 105, 115, 73, 110, 102, 111, 114, 109, 97, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 110, 103, 105, 110, 101, 101, 114, 105, 110, 103, 85, 110, 105, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 69, 85, 73, 110, 102, 111, 114, 109, 97, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 69, 85, 82, 97, 110, 103, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 82, 97, 110, 103, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 84, 105, 116, 108, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 76, 111, 99, 97, 108, 105, 122, 101, 100, 84, 101, 120, 116, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 120, 105, 115, 83, 99, 97, 108, 101, 84, 121, 112, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 120, 105, 115, 83, 99, 97, 108, 101, 69, 110, 117, 109, 101, 114, 97, 116, 105, 111, 110, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 65, 120, 105, 115, 83, 116, 101, 112, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 120, 105, 115, 83, 116, 101, 112, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 65, 120, 105, 115, 83, 116, 101, 112, 115, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 88, 86, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 88, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 111, 117, 98, 108, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 86, 97, 108, 117, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 70, 108, 111, 97, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 114, 111, 103, 114, 97, 109, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 114, 101, 97, 116, 101, 83, 101, 115, 115, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 114, 101, 97, 116, 101, 67, 108, 105, 101, 110, 116, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 118, 111, 99, 97, 116, 105, 111, 110, 67, 114, 101, 97, 116, 105, 111, 110, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 84, 114, 97, 110, 115, 105, 116, 105, 111, 110, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 67, 97, 108, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 83, 101, 115, 115, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 114, 103, 117, 109, 101, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 79, 117, 116, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 79, 117, 116, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 114, 103, 117, 109, 101, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 79, 117, 116, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 67, 97, 108, 108, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 82, 101, 116, 117, 114, 110, 83, 116, 97, 116, 117, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 116, 97, 116, 117, 115, 82, 101, 115, 117, 108, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 80, 114, 111, 103, 114, 97, 109, 68, 105, 97, 103, 110, 111, 115, 116, 105, 99, 50, 68, 97, 116, 97, 84, 121, 112, 101, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 114, 101, 97, 116, 101, 83, 101, 115, 115, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 67, 114, 101, 97, 116, 101, 67, 108, 105, 101, 110, 116, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 73, 110, 118, 111, 99, 97, 116, 105, 111, 110, 67, 114, 101, 97, 116, 105, 111, 110, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 84, 114, 97, 110, 115, 105, 116, 105, 111, 110, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 67, 97, 108, 108, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 83, 101, 115, 115, 105, 111, 110, 73, 100, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 78, 111, 100, 101, 73, 100, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 114, 103, 117, 109, 101, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 73, 110, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 79, 117, 116, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 79, 117, 116, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 65, 114, 103, 117, 109, 101, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 79, 117, 116, 112, 117, 116, 65, 114, 103, 117, 109, 101, 110, 116, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 73, 110, 112, 117, 116, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 73, 110, 112, 117, 116, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 73, 110, 112, 117, 116, 86, 97, 108, 117, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 78, 111, 79, 102, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 79, 117, 116, 112, 117, 116, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 73, 110, 116, 51, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 79, 117, 116, 112, 117, 116, 86, 97, 108, 117, 101, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 117, 97, 58, 86, 97, 114, 105, 97, 110, 116, 34, 32, 76, 101, 110, 103, 116, 104, 70, 105, 101, 108, 100, 61, 34, 78, 111, 79, 102, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 79, 117, 116, 112, 117, 116, 86, 97, 108, 117, 101, 115, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 67, 97, 108, 108, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 76, 97, 115, 116, 77, 101, 116, 104, 111, 100, 82, 101, 116, 117, 114, 110, 83, 116, 97, 116, 117, 115, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 116, 110, 115, 58, 83, 116, 97, 116, 117, 115, 82, 101, 115, 117, 108, 116, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 65, 110, 110, 111, 116, 97, 116, 105, 111, 110, 34, 32, 66, 97, 115, 101, 84, 121, 112, 101, 61, 34, 117, 97, 58, 69, 120, 116, 101, 110, 115, 105, 111, 110, 79, 98, 106, 101, 99, 116, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 77, 101, 115, 115, 97, 103, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 85, 115, 101, 114, 78, 97, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 83, 116, 114, 105, 110, 103, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 70, 105, 101, 108, 100, 32, 78, 97, 109, 101, 61, 34, 65, 110, 110, 111, 116, 97, 116, 105, 111, 110, 84, 105, 109, 101, 34, 32, 84, 121, 112, 101, 78, 97, 109, 101, 61, 34, 111, 112, 99, 58, 68, 97, 116, 101, 84, 105, 109, 101, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 83, 116, 114, 117, 99, 116, 117, 114, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 32, 78, 97, 109, 101, 61, 34, 69, 120, 99, 101, 112, 116, 105, 111, 110, 68, 101, 118, 105, 97, 116, 105, 111, 110, 70, 111, 114, 109, 97, 116, 34, 32, 76, 101, 110, 103, 116, 104, 73, 110, 66, 105, 116, 115, 61, 34, 51, 50, 34, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 65, 98, 115, 111, 108, 117, 116, 101, 86, 97, 108, 117, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 48, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 80, 101, 114, 99, 101, 110, 116, 79, 102, 86, 97, 108, 117, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 49, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 80, 101, 114, 99, 101, 110, 116, 79, 102, 82, 97, 110, 103, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 50, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 80, 101, 114, 99, 101, 110, 116, 79, 102, 69, 85, 82, 97, 110, 103, 101, 34, 32, 86, 97, 108, 117, 101, 61, 34, 51, 34, 32, 47, 62, 13, 10, 32, 32, 32, 32, 60, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 86, 97, 108, 117, 101, 32, 78, 97, 109, 101, 61, 34, 85, 110, 107, 110, 111, 119, 110, 34, 32, 86, 97, 108, 117, 101, 61, 34, 52, 34, 32, 47, 62, 13, 10, 32, 32, 60, 47, 111, 112, 99, 58, 69, 110, 117, 109, 101, 114, 97, 116, 101, 100, 84, 121, 112, 101, 62, 13, 10, 13, 10, 60, 47, 111, 112, 99, 58, 84, 121, 112, 101, 68, 105, 99, 116, 105, 111, 110, 97, 114, 121, 62};



static UA_StatusCode function_namespace0_generated_549_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 15LU);
UA_ByteString *variablenode_ns_0_i_7617_variant_DataContents =  UA_ByteString_new();
if (!variablenode_ns_0_i_7617_variant_DataContents) return UA_STATUSCODE_BADOUTOFMEMORY;
UA_ByteString_init(variablenode_ns_0_i_7617_variant_DataContents);
variablenode_ns_0_i_7617_variant_DataContents->length = 177218;
variablenode_ns_0_i_7617_variant_DataContents->data = (UA_Byte *)(void*)(uintptr_t)variablenode_ns_0_i_7617_variant_DataContents_byteArray;
UA_Variant_setScalar(&attr.value, variablenode_ns_0_i_7617_variant_DataContents, &UA_TYPES[UA_TYPES_BYTESTRING]);
attr.displayName = UA_LOCALIZEDTEXT("", "Opc.Ua");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 7617LU),UA_NODEID_NUMERIC(ns[0], 93LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "Opc.Ua"),UA_NODEID_NUMERIC(ns[0], 72LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
variablenode_ns_0_i_7617_variant_DataContents->data = NULL;
variablenode_ns_0_i_7617_variant_DataContents->length = 0;
UA_ByteString_delete(variablenode_ns_0_i_7617_variant_DataContents);
return retVal;
}

static UA_StatusCode function_namespace0_generated_549_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 7617LU));
}

/* NamespaceUri - ns=0;i=107 */

static UA_StatusCode function_namespace0_generated_550_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "NamespaceUri");

#ifdef UA_ENABLE_NODESET_COMPILER_DESCRIPTIONS

attr.description = UA_LOCALIZEDTEXT("", "A URI that uniquely identifies the dictionary.");

#endif

retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 107LU),UA_NODEID_NUMERIC(ns[0], 72LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "NamespaceUri"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 107LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 80LU), true);
return retVal;
}

static UA_StatusCode function_namespace0_generated_550_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 107LU));
}

/* DataTypeVersion - ns=0;i=106 */

static UA_StatusCode function_namespace0_generated_551_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DataTypeVersion");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 106LU),UA_NODEID_NUMERIC(ns[0], 72LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "DataTypeVersion"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 106LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 80LU), true);
return retVal;
}

static UA_StatusCode function_namespace0_generated_551_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 106LU));
}

/* DataTypeDescriptionType - ns=0;i=69 */

static UA_StatusCode function_namespace0_generated_552_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DataTypeDescriptionType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLETYPE,UA_NODEID_NUMERIC(ns[0], 69LU),UA_NODEID_NUMERIC(ns[0], 63LU),UA_NODEID_NUMERIC(ns[0], 45LU),UA_QUALIFIEDNAME(ns[0], "DataTypeDescriptionType"),UA_NODEID_NUMERIC(ns[0], 0LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLETYPEATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_552_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 69LU));
}

/* EnumValueType - ns=0;i=7656 */

static UA_StatusCode function_namespace0_generated_553_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
UA_String *variablenode_ns_0_i_7656_variant_DataContents =  UA_String_new();
if (!variablenode_ns_0_i_7656_variant_DataContents) return UA_STATUSCODE_BADOUTOFMEMORY;
UA_String_init(variablenode_ns_0_i_7656_variant_DataContents);
*variablenode_ns_0_i_7656_variant_DataContents = UA_STRING_ALLOC("EnumValueType");
UA_Variant_setScalar(&attr.value, variablenode_ns_0_i_7656_variant_DataContents, &UA_TYPES[UA_TYPES_STRING]);
attr.displayName = UA_LOCALIZEDTEXT("", "EnumValueType");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 7656LU),UA_NODEID_NUMERIC(ns[0], 7617LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "EnumValueType"),UA_NODEID_NUMERIC(ns[0], 69LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
UA_String_delete(variablenode_ns_0_i_7656_variant_DataContents);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 7656LU), UA_NODEID_NUMERIC(ns[0], 39LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 8251LU), false);
return retVal;
}

static UA_StatusCode function_namespace0_generated_553_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 7656LU));
}

/* Argument - ns=0;i=7650 */

static UA_StatusCode function_namespace0_generated_554_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
UA_String *variablenode_ns_0_i_7650_variant_DataContents =  UA_String_new();
if (!variablenode_ns_0_i_7650_variant_DataContents) return UA_STATUSCODE_BADOUTOFMEMORY;
UA_String_init(variablenode_ns_0_i_7650_variant_DataContents);
*variablenode_ns_0_i_7650_variant_DataContents = UA_STRING_ALLOC("Argument");
UA_Variant_setScalar(&attr.value, variablenode_ns_0_i_7650_variant_DataContents, &UA_TYPES[UA_TYPES_STRING]);
attr.displayName = UA_LOCALIZEDTEXT("", "Argument");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 7650LU),UA_NODEID_NUMERIC(ns[0], 7617LU),UA_NODEID_NUMERIC(ns[0], 47LU),UA_QUALIFIEDNAME(ns[0], "Argument"),UA_NODEID_NUMERIC(ns[0], 69LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
UA_String_delete(variablenode_ns_0_i_7650_variant_DataContents);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 7650LU), UA_NODEID_NUMERIC(ns[0], 39LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 298LU), false);
return retVal;
}

static UA_StatusCode function_namespace0_generated_554_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 7650LU));
}

/* DictionaryFragment - ns=0;i=105 */

static UA_StatusCode function_namespace0_generated_555_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 15LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DictionaryFragment");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 105LU),UA_NODEID_NUMERIC(ns[0], 69LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "DictionaryFragment"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 105LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 80LU), true);
return retVal;
}

static UA_StatusCode function_namespace0_generated_555_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 105LU));
}

/* DataTypeVersion - ns=0;i=104 */

static UA_StatusCode function_namespace0_generated_556_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_VariableAttributes attr = UA_VariableAttributes_default;
attr.minimumSamplingInterval = 0.000000;
attr.userAccessLevel = 1;
attr.accessLevel = 1;
/* Value rank inherited */
attr.valueRank = -2;
attr.dataType = UA_NODEID_NUMERIC(ns[0], 12LU);
attr.displayName = UA_LOCALIZEDTEXT("", "DataTypeVersion");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_VARIABLE,UA_NODEID_NUMERIC(ns[0], 104LU),UA_NODEID_NUMERIC(ns[0], 69LU),UA_NODEID_NUMERIC(ns[0], 46LU),UA_QUALIFIEDNAME(ns[0], "DataTypeVersion"),UA_NODEID_NUMERIC(ns[0], 68LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_VARIABLEATTRIBUTES],NULL, NULL);
retVal |= UA_Server_addReference(server, UA_NODEID_NUMERIC(ns[0], 104LU), UA_NODEID_NUMERIC(ns[0], 37LU), UA_EXPANDEDNODEID_NUMERIC(ns[0], 80LU), true);
return retVal;
}

static UA_StatusCode function_namespace0_generated_556_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 104LU));
}

/* Default XML - ns=0;i=3063 */

static UA_StatusCode function_namespace0_generated_557_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Default XML");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(ns[0], 3063LU),UA_NODEID_NUMERIC(ns[0], 0LU),UA_NODEID_NUMERIC(ns[0], 0LU),UA_QUALIFIEDNAME(ns[0], "Default XML"),UA_NODEID_NUMERIC(ns[0], 58LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_557_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3063LU));
}

/* Default Binary - ns=0;i=3062 */

static UA_StatusCode function_namespace0_generated_558_begin(UA_Server *server, UA_UInt16* ns) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("", "Default Binary");
retVal |= UA_Server_addNode_begin(server, UA_NODECLASS_OBJECT,UA_NODEID_NUMERIC(ns[0], 3062LU),UA_NODEID_NUMERIC(ns[0], 0LU),UA_NODEID_NUMERIC(ns[0], 0LU),UA_QUALIFIEDNAME(ns[0], "Default Binary"),UA_NODEID_NUMERIC(ns[0], 58LU),(const UA_NodeAttributes*)&attr, &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],NULL, NULL);
return retVal;
}

static UA_StatusCode function_namespace0_generated_558_finish(UA_Server *server, UA_UInt16* ns) {
return UA_Server_addNode_finish(server, UA_NODEID_NUMERIC(ns[0], 3062LU));
}

UA_StatusCode namespace0_generated(UA_Server *server) {
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
/* Use namespace ids generated by the server */
UA_UInt16 ns[1];
ns[0] = UA_Server_addNamespace(server, "http://opcfoundation.org/UA/");

/* Load custom datatype definitions into the server */
retVal |= function_namespace0_generated_0_begin(server, ns);
retVal |= function_namespace0_generated_0_finish(server, ns);
retVal |= function_namespace0_generated_1_begin(server, ns);
retVal |= function_namespace0_generated_1_finish(server, ns);
retVal |= function_namespace0_generated_2_begin(server, ns);
retVal |= function_namespace0_generated_2_finish(server, ns);
retVal |= function_namespace0_generated_3_begin(server, ns);
retVal |= function_namespace0_generated_3_finish(server, ns);
retVal |= function_namespace0_generated_4_begin(server, ns);
retVal |= function_namespace0_generated_4_finish(server, ns);
retVal |= function_namespace0_generated_5_begin(server, ns);
retVal |= function_namespace0_generated_5_finish(server, ns);
retVal |= function_namespace0_generated_6_begin(server, ns);
retVal |= function_namespace0_generated_7_begin(server, ns);
retVal |= function_namespace0_generated_8_begin(server, ns);
retVal |= function_namespace0_generated_9_begin(server, ns);
retVal |= function_namespace0_generated_10_begin(server, ns);
retVal |= function_namespace0_generated_11_begin(server, ns);
retVal |= function_namespace0_generated_12_begin(server, ns);
retVal |= function_namespace0_generated_13_begin(server, ns);
retVal |= function_namespace0_generated_14_begin(server, ns);
retVal |= function_namespace0_generated_15_begin(server, ns);
retVal |= function_namespace0_generated_16_begin(server, ns);
retVal |= function_namespace0_generated_17_begin(server, ns);
retVal |= function_namespace0_generated_18_begin(server, ns);
retVal |= function_namespace0_generated_19_begin(server, ns);
retVal |= function_namespace0_generated_20_begin(server, ns);
retVal |= function_namespace0_generated_21_begin(server, ns);
retVal |= function_namespace0_generated_22_begin(server, ns);
retVal |= function_namespace0_generated_23_begin(server, ns);
retVal |= function_namespace0_generated_24_begin(server, ns);
retVal |= function_namespace0_generated_25_begin(server, ns);
retVal |= function_namespace0_generated_26_begin(server, ns);
retVal |= function_namespace0_generated_27_begin(server, ns);
retVal |= function_namespace0_generated_28_begin(server, ns);
retVal |= function_namespace0_generated_29_begin(server, ns);
retVal |= function_namespace0_generated_30_begin(server, ns);
retVal |= function_namespace0_generated_31_begin(server, ns);
retVal |= function_namespace0_generated_32_begin(server, ns);
retVal |= function_namespace0_generated_33_begin(server, ns);
retVal |= function_namespace0_generated_34_begin(server, ns);
retVal |= function_namespace0_generated_35_begin(server, ns);
retVal |= function_namespace0_generated_36_begin(server, ns);
retVal |= function_namespace0_generated_37_begin(server, ns);
retVal |= function_namespace0_generated_38_begin(server, ns);
retVal |= function_namespace0_generated_39_begin(server, ns);
retVal |= function_namespace0_generated_40_begin(server, ns);
retVal |= function_namespace0_generated_41_begin(server, ns);
retVal |= function_namespace0_generated_42_begin(server, ns);
retVal |= function_namespace0_generated_43_begin(server, ns);
retVal |= function_namespace0_generated_44_begin(server, ns);
retVal |= function_namespace0_generated_45_begin(server, ns);
retVal |= function_namespace0_generated_46_begin(server, ns);
retVal |= function_namespace0_generated_47_begin(server, ns);
retVal |= function_namespace0_generated_48_begin(server, ns);
retVal |= function_namespace0_generated_49_begin(server, ns);
retVal |= function_namespace0_generated_50_begin(server, ns);
retVal |= function_namespace0_generated_51_begin(server, ns);
retVal |= function_namespace0_generated_52_begin(server, ns);
retVal |= function_namespace0_generated_53_begin(server, ns);
retVal |= function_namespace0_generated_54_begin(server, ns);
retVal |= function_namespace0_generated_55_begin(server, ns);
retVal |= function_namespace0_generated_56_begin(server, ns);
retVal |= function_namespace0_generated_57_begin(server, ns);
retVal |= function_namespace0_generated_58_begin(server, ns);
retVal |= function_namespace0_generated_59_begin(server, ns);
retVal |= function_namespace0_generated_60_begin(server, ns);
retVal |= function_namespace0_generated_61_begin(server, ns);
retVal |= function_namespace0_generated_62_begin(server, ns);
retVal |= function_namespace0_generated_63_begin(server, ns);
retVal |= function_namespace0_generated_64_begin(server, ns);
retVal |= function_namespace0_generated_65_begin(server, ns);
retVal |= function_namespace0_generated_66_begin(server, ns);
retVal |= function_namespace0_generated_67_begin(server, ns);
retVal |= function_namespace0_generated_68_begin(server, ns);
retVal |= function_namespace0_generated_69_begin(server, ns);
retVal |= function_namespace0_generated_70_begin(server, ns);
retVal |= function_namespace0_generated_71_begin(server, ns);
retVal |= function_namespace0_generated_72_begin(server, ns);
retVal |= function_namespace0_generated_73_begin(server, ns);
retVal |= function_namespace0_generated_74_begin(server, ns);
retVal |= function_namespace0_generated_75_begin(server, ns);
retVal |= function_namespace0_generated_76_begin(server, ns);
retVal |= function_namespace0_generated_77_begin(server, ns);
retVal |= function_namespace0_generated_78_begin(server, ns);
retVal |= function_namespace0_generated_79_begin(server, ns);
retVal |= function_namespace0_generated_80_begin(server, ns);
retVal |= function_namespace0_generated_81_begin(server, ns);
retVal |= function_namespace0_generated_82_begin(server, ns);
retVal |= function_namespace0_generated_83_begin(server, ns);
retVal |= function_namespace0_generated_84_begin(server, ns);
retVal |= function_namespace0_generated_85_begin(server, ns);
retVal |= function_namespace0_generated_86_begin(server, ns);
retVal |= function_namespace0_generated_87_begin(server, ns);
retVal |= function_namespace0_generated_88_begin(server, ns);
retVal |= function_namespace0_generated_89_begin(server, ns);
retVal |= function_namespace0_generated_90_begin(server, ns);
retVal |= function_namespace0_generated_91_begin(server, ns);
retVal |= function_namespace0_generated_92_begin(server, ns);
retVal |= function_namespace0_generated_93_begin(server, ns);
retVal |= function_namespace0_generated_94_begin(server, ns);
retVal |= function_namespace0_generated_95_begin(server, ns);
retVal |= function_namespace0_generated_96_begin(server, ns);
retVal |= function_namespace0_generated_97_begin(server, ns);
retVal |= function_namespace0_generated_98_begin(server, ns);
retVal |= function_namespace0_generated_99_begin(server, ns);
retVal |= function_namespace0_generated_100_begin(server, ns);
retVal |= function_namespace0_generated_101_begin(server, ns);
retVal |= function_namespace0_generated_102_begin(server, ns);
retVal |= function_namespace0_generated_103_begin(server, ns);
retVal |= function_namespace0_generated_104_begin(server, ns);
retVal |= function_namespace0_generated_105_begin(server, ns);
retVal |= function_namespace0_generated_106_begin(server, ns);
retVal |= function_namespace0_generated_107_begin(server, ns);
retVal |= function_namespace0_generated_108_begin(server, ns);
retVal |= function_namespace0_generated_109_begin(server, ns);
retVal |= function_namespace0_generated_110_begin(server, ns);
retVal |= function_namespace0_generated_111_begin(server, ns);
retVal |= function_namespace0_generated_112_begin(server, ns);
retVal |= function_namespace0_generated_113_begin(server, ns);
retVal |= function_namespace0_generated_114_begin(server, ns);
retVal |= function_namespace0_generated_115_begin(server, ns);
retVal |= function_namespace0_generated_116_begin(server, ns);
retVal |= function_namespace0_generated_117_begin(server, ns);
retVal |= function_namespace0_generated_118_begin(server, ns);
retVal |= function_namespace0_generated_119_begin(server, ns);
retVal |= function_namespace0_generated_120_begin(server, ns);
retVal |= function_namespace0_generated_121_begin(server, ns);
retVal |= function_namespace0_generated_122_begin(server, ns);
retVal |= function_namespace0_generated_123_begin(server, ns);
retVal |= function_namespace0_generated_124_begin(server, ns);
retVal |= function_namespace0_generated_125_begin(server, ns);
retVal |= function_namespace0_generated_126_begin(server, ns);
retVal |= function_namespace0_generated_127_begin(server, ns);
retVal |= function_namespace0_generated_128_begin(server, ns);
retVal |= function_namespace0_generated_129_begin(server, ns);
retVal |= function_namespace0_generated_130_begin(server, ns);
retVal |= function_namespace0_generated_131_begin(server, ns);
retVal |= function_namespace0_generated_132_begin(server, ns);
retVal |= function_namespace0_generated_133_begin(server, ns);
retVal |= function_namespace0_generated_134_begin(server, ns);
retVal |= function_namespace0_generated_135_begin(server, ns);
retVal |= function_namespace0_generated_136_begin(server, ns);
retVal |= function_namespace0_generated_137_begin(server, ns);
retVal |= function_namespace0_generated_138_begin(server, ns);
retVal |= function_namespace0_generated_139_begin(server, ns);
retVal |= function_namespace0_generated_140_begin(server, ns);
retVal |= function_namespace0_generated_141_begin(server, ns);
retVal |= function_namespace0_generated_142_begin(server, ns);
retVal |= function_namespace0_generated_143_begin(server, ns);
retVal |= function_namespace0_generated_144_begin(server, ns);
retVal |= function_namespace0_generated_145_begin(server, ns);
retVal |= function_namespace0_generated_146_begin(server, ns);
retVal |= function_namespace0_generated_147_begin(server, ns);
retVal |= function_namespace0_generated_148_begin(server, ns);
retVal |= function_namespace0_generated_149_begin(server, ns);
retVal |= function_namespace0_generated_150_begin(server, ns);
retVal |= function_namespace0_generated_151_begin(server, ns);
retVal |= function_namespace0_generated_152_begin(server, ns);
retVal |= function_namespace0_generated_153_begin(server, ns);
retVal |= function_namespace0_generated_154_begin(server, ns);
retVal |= function_namespace0_generated_155_begin(server, ns);
retVal |= function_namespace0_generated_156_begin(server, ns);
retVal |= function_namespace0_generated_157_begin(server, ns);
retVal |= function_namespace0_generated_158_begin(server, ns);
retVal |= function_namespace0_generated_159_begin(server, ns);
retVal |= function_namespace0_generated_160_begin(server, ns);
retVal |= function_namespace0_generated_161_begin(server, ns);
retVal |= function_namespace0_generated_162_begin(server, ns);
retVal |= function_namespace0_generated_163_begin(server, ns);
retVal |= function_namespace0_generated_164_begin(server, ns);
retVal |= function_namespace0_generated_165_begin(server, ns);
retVal |= function_namespace0_generated_166_begin(server, ns);
retVal |= function_namespace0_generated_167_begin(server, ns);
retVal |= function_namespace0_generated_168_begin(server, ns);
retVal |= function_namespace0_generated_169_begin(server, ns);
retVal |= function_namespace0_generated_170_begin(server, ns);
retVal |= function_namespace0_generated_171_begin(server, ns);
retVal |= function_namespace0_generated_172_begin(server, ns);
retVal |= function_namespace0_generated_173_begin(server, ns);
retVal |= function_namespace0_generated_174_begin(server, ns);
retVal |= function_namespace0_generated_175_begin(server, ns);
retVal |= function_namespace0_generated_176_begin(server, ns);
retVal |= function_namespace0_generated_177_begin(server, ns);
retVal |= function_namespace0_generated_178_begin(server, ns);
retVal |= function_namespace0_generated_179_begin(server, ns);
retVal |= function_namespace0_generated_180_begin(server, ns);
retVal |= function_namespace0_generated_181_begin(server, ns);
retVal |= function_namespace0_generated_182_begin(server, ns);
retVal |= function_namespace0_generated_183_begin(server, ns);
retVal |= function_namespace0_generated_184_begin(server, ns);
retVal |= function_namespace0_generated_185_begin(server, ns);
retVal |= function_namespace0_generated_186_begin(server, ns);
retVal |= function_namespace0_generated_187_begin(server, ns);
retVal |= function_namespace0_generated_188_begin(server, ns);
retVal |= function_namespace0_generated_189_begin(server, ns);
retVal |= function_namespace0_generated_190_begin(server, ns);
retVal |= function_namespace0_generated_191_begin(server, ns);
retVal |= function_namespace0_generated_192_begin(server, ns);
retVal |= function_namespace0_generated_193_begin(server, ns);
retVal |= function_namespace0_generated_194_begin(server, ns);
retVal |= function_namespace0_generated_195_begin(server, ns);
retVal |= function_namespace0_generated_196_begin(server, ns);
retVal |= function_namespace0_generated_197_begin(server, ns);
retVal |= function_namespace0_generated_198_begin(server, ns);
retVal |= function_namespace0_generated_199_begin(server, ns);
retVal |= function_namespace0_generated_200_begin(server, ns);
retVal |= function_namespace0_generated_201_begin(server, ns);
retVal |= function_namespace0_generated_202_begin(server, ns);
retVal |= function_namespace0_generated_203_begin(server, ns);
retVal |= function_namespace0_generated_204_begin(server, ns);
retVal |= function_namespace0_generated_205_begin(server, ns);
retVal |= function_namespace0_generated_206_begin(server, ns);
retVal |= function_namespace0_generated_207_begin(server, ns);
retVal |= function_namespace0_generated_208_begin(server, ns);
retVal |= function_namespace0_generated_209_begin(server, ns);
retVal |= function_namespace0_generated_210_begin(server, ns);
retVal |= function_namespace0_generated_211_begin(server, ns);
retVal |= function_namespace0_generated_212_begin(server, ns);
retVal |= function_namespace0_generated_213_begin(server, ns);
retVal |= function_namespace0_generated_214_begin(server, ns);
retVal |= function_namespace0_generated_215_begin(server, ns);
retVal |= function_namespace0_generated_216_begin(server, ns);
retVal |= function_namespace0_generated_217_begin(server, ns);
retVal |= function_namespace0_generated_218_begin(server, ns);
retVal |= function_namespace0_generated_219_begin(server, ns);
retVal |= function_namespace0_generated_220_begin(server, ns);
retVal |= function_namespace0_generated_221_begin(server, ns);
retVal |= function_namespace0_generated_222_begin(server, ns);
retVal |= function_namespace0_generated_223_begin(server, ns);
retVal |= function_namespace0_generated_224_begin(server, ns);
retVal |= function_namespace0_generated_225_begin(server, ns);
retVal |= function_namespace0_generated_226_begin(server, ns);
retVal |= function_namespace0_generated_227_begin(server, ns);
retVal |= function_namespace0_generated_228_begin(server, ns);
retVal |= function_namespace0_generated_229_begin(server, ns);
retVal |= function_namespace0_generated_230_begin(server, ns);
retVal |= function_namespace0_generated_231_begin(server, ns);
retVal |= function_namespace0_generated_232_begin(server, ns);
retVal |= function_namespace0_generated_233_begin(server, ns);
retVal |= function_namespace0_generated_234_begin(server, ns);
retVal |= function_namespace0_generated_235_begin(server, ns);
retVal |= function_namespace0_generated_236_begin(server, ns);
retVal |= function_namespace0_generated_237_begin(server, ns);
retVal |= function_namespace0_generated_238_begin(server, ns);
retVal |= function_namespace0_generated_239_begin(server, ns);
retVal |= function_namespace0_generated_240_begin(server, ns);
retVal |= function_namespace0_generated_241_begin(server, ns);
retVal |= function_namespace0_generated_242_begin(server, ns);
retVal |= function_namespace0_generated_243_begin(server, ns);
retVal |= function_namespace0_generated_244_begin(server, ns);
retVal |= function_namespace0_generated_245_begin(server, ns);
retVal |= function_namespace0_generated_246_begin(server, ns);
retVal |= function_namespace0_generated_247_begin(server, ns);
retVal |= function_namespace0_generated_248_begin(server, ns);
retVal |= function_namespace0_generated_249_begin(server, ns);
retVal |= function_namespace0_generated_250_begin(server, ns);
retVal |= function_namespace0_generated_251_begin(server, ns);
retVal |= function_namespace0_generated_252_begin(server, ns);
retVal |= function_namespace0_generated_253_begin(server, ns);
retVal |= function_namespace0_generated_254_begin(server, ns);
retVal |= function_namespace0_generated_255_begin(server, ns);
retVal |= function_namespace0_generated_256_begin(server, ns);
retVal |= function_namespace0_generated_257_begin(server, ns);
retVal |= function_namespace0_generated_258_begin(server, ns);
retVal |= function_namespace0_generated_259_begin(server, ns);
retVal |= function_namespace0_generated_260_begin(server, ns);
retVal |= function_namespace0_generated_261_begin(server, ns);
retVal |= function_namespace0_generated_262_begin(server, ns);
retVal |= function_namespace0_generated_263_begin(server, ns);
retVal |= function_namespace0_generated_264_begin(server, ns);
retVal |= function_namespace0_generated_265_begin(server, ns);
retVal |= function_namespace0_generated_266_begin(server, ns);
retVal |= function_namespace0_generated_267_begin(server, ns);
retVal |= function_namespace0_generated_268_begin(server, ns);
retVal |= function_namespace0_generated_269_begin(server, ns);
retVal |= function_namespace0_generated_270_begin(server, ns);
retVal |= function_namespace0_generated_271_begin(server, ns);
retVal |= function_namespace0_generated_272_begin(server, ns);
retVal |= function_namespace0_generated_273_begin(server, ns);
retVal |= function_namespace0_generated_274_begin(server, ns);
retVal |= function_namespace0_generated_275_begin(server, ns);
retVal |= function_namespace0_generated_276_begin(server, ns);
retVal |= function_namespace0_generated_277_begin(server, ns);
retVal |= function_namespace0_generated_278_begin(server, ns);
retVal |= function_namespace0_generated_279_begin(server, ns);
retVal |= function_namespace0_generated_280_begin(server, ns);
retVal |= function_namespace0_generated_281_begin(server, ns);
retVal |= function_namespace0_generated_282_begin(server, ns);
retVal |= function_namespace0_generated_283_begin(server, ns);
retVal |= function_namespace0_generated_284_begin(server, ns);
retVal |= function_namespace0_generated_285_begin(server, ns);
retVal |= function_namespace0_generated_286_begin(server, ns);
retVal |= function_namespace0_generated_287_begin(server, ns);
retVal |= function_namespace0_generated_288_begin(server, ns);
retVal |= function_namespace0_generated_289_begin(server, ns);
retVal |= function_namespace0_generated_290_begin(server, ns);
retVal |= function_namespace0_generated_291_begin(server, ns);
retVal |= function_namespace0_generated_292_begin(server, ns);
retVal |= function_namespace0_generated_293_begin(server, ns);
retVal |= function_namespace0_generated_294_begin(server, ns);
retVal |= function_namespace0_generated_295_begin(server, ns);
retVal |= function_namespace0_generated_296_begin(server, ns);
retVal |= function_namespace0_generated_297_begin(server, ns);
retVal |= function_namespace0_generated_298_begin(server, ns);
retVal |= function_namespace0_generated_299_begin(server, ns);
retVal |= function_namespace0_generated_300_begin(server, ns);
retVal |= function_namespace0_generated_301_begin(server, ns);
retVal |= function_namespace0_generated_302_begin(server, ns);
retVal |= function_namespace0_generated_303_begin(server, ns);
retVal |= function_namespace0_generated_304_begin(server, ns);
retVal |= function_namespace0_generated_305_begin(server, ns);
retVal |= function_namespace0_generated_306_begin(server, ns);
retVal |= function_namespace0_generated_307_begin(server, ns);
retVal |= function_namespace0_generated_308_begin(server, ns);
retVal |= function_namespace0_generated_309_begin(server, ns);
retVal |= function_namespace0_generated_310_begin(server, ns);
retVal |= function_namespace0_generated_311_begin(server, ns);
retVal |= function_namespace0_generated_312_begin(server, ns);
retVal |= function_namespace0_generated_313_begin(server, ns);
retVal |= function_namespace0_generated_314_begin(server, ns);
retVal |= function_namespace0_generated_315_begin(server, ns);
retVal |= function_namespace0_generated_316_begin(server, ns);
retVal |= function_namespace0_generated_317_begin(server, ns);
retVal |= function_namespace0_generated_318_begin(server, ns);
retVal |= function_namespace0_generated_319_begin(server, ns);
retVal |= function_namespace0_generated_320_begin(server, ns);
retVal |= function_namespace0_generated_321_begin(server, ns);
retVal |= function_namespace0_generated_322_begin(server, ns);
retVal |= function_namespace0_generated_323_begin(server, ns);
retVal |= function_namespace0_generated_324_begin(server, ns);
retVal |= function_namespace0_generated_325_begin(server, ns);
retVal |= function_namespace0_generated_326_begin(server, ns);
retVal |= function_namespace0_generated_327_begin(server, ns);
retVal |= function_namespace0_generated_328_begin(server, ns);
retVal |= function_namespace0_generated_329_begin(server, ns);
retVal |= function_namespace0_generated_330_begin(server, ns);
retVal |= function_namespace0_generated_331_begin(server, ns);
retVal |= function_namespace0_generated_332_begin(server, ns);
retVal |= function_namespace0_generated_333_begin(server, ns);
retVal |= function_namespace0_generated_334_begin(server, ns);
retVal |= function_namespace0_generated_335_begin(server, ns);
retVal |= function_namespace0_generated_336_begin(server, ns);
retVal |= function_namespace0_generated_337_begin(server, ns);
retVal |= function_namespace0_generated_338_begin(server, ns);
retVal |= function_namespace0_generated_339_begin(server, ns);
retVal |= function_namespace0_generated_340_begin(server, ns);
retVal |= function_namespace0_generated_341_begin(server, ns);
retVal |= function_namespace0_generated_342_begin(server, ns);
retVal |= function_namespace0_generated_343_begin(server, ns);
retVal |= function_namespace0_generated_344_begin(server, ns);
retVal |= function_namespace0_generated_345_begin(server, ns);
retVal |= function_namespace0_generated_346_begin(server, ns);
retVal |= function_namespace0_generated_347_begin(server, ns);
retVal |= function_namespace0_generated_348_begin(server, ns);
retVal |= function_namespace0_generated_349_begin(server, ns);
retVal |= function_namespace0_generated_350_begin(server, ns);
retVal |= function_namespace0_generated_351_begin(server, ns);
retVal |= function_namespace0_generated_352_begin(server, ns);
retVal |= function_namespace0_generated_353_begin(server, ns);
retVal |= function_namespace0_generated_354_begin(server, ns);
retVal |= function_namespace0_generated_355_begin(server, ns);
retVal |= function_namespace0_generated_356_begin(server, ns);
retVal |= function_namespace0_generated_357_begin(server, ns);
retVal |= function_namespace0_generated_358_begin(server, ns);
retVal |= function_namespace0_generated_359_begin(server, ns);
retVal |= function_namespace0_generated_360_begin(server, ns);
retVal |= function_namespace0_generated_361_begin(server, ns);
retVal |= function_namespace0_generated_362_begin(server, ns);
retVal |= function_namespace0_generated_363_begin(server, ns);
retVal |= function_namespace0_generated_364_begin(server, ns);
retVal |= function_namespace0_generated_365_begin(server, ns);
retVal |= function_namespace0_generated_366_begin(server, ns);
retVal |= function_namespace0_generated_367_begin(server, ns);
retVal |= function_namespace0_generated_368_begin(server, ns);
retVal |= function_namespace0_generated_369_begin(server, ns);
retVal |= function_namespace0_generated_370_begin(server, ns);
retVal |= function_namespace0_generated_371_begin(server, ns);
retVal |= function_namespace0_generated_372_begin(server, ns);
retVal |= function_namespace0_generated_373_begin(server, ns);
retVal |= function_namespace0_generated_374_begin(server, ns);
retVal |= function_namespace0_generated_375_begin(server, ns);
retVal |= function_namespace0_generated_376_begin(server, ns);
retVal |= function_namespace0_generated_377_begin(server, ns);
retVal |= function_namespace0_generated_378_begin(server, ns);
retVal |= function_namespace0_generated_379_begin(server, ns);
retVal |= function_namespace0_generated_380_begin(server, ns);
retVal |= function_namespace0_generated_381_begin(server, ns);
retVal |= function_namespace0_generated_382_begin(server, ns);
retVal |= function_namespace0_generated_383_begin(server, ns);
retVal |= function_namespace0_generated_384_begin(server, ns);
retVal |= function_namespace0_generated_385_begin(server, ns);
retVal |= function_namespace0_generated_386_begin(server, ns);
retVal |= function_namespace0_generated_387_begin(server, ns);
retVal |= function_namespace0_generated_388_begin(server, ns);
retVal |= function_namespace0_generated_389_begin(server, ns);
retVal |= function_namespace0_generated_390_begin(server, ns);
retVal |= function_namespace0_generated_391_begin(server, ns);
retVal |= function_namespace0_generated_392_begin(server, ns);
retVal |= function_namespace0_generated_393_begin(server, ns);
retVal |= function_namespace0_generated_394_begin(server, ns);
retVal |= function_namespace0_generated_395_begin(server, ns);
retVal |= function_namespace0_generated_396_begin(server, ns);
retVal |= function_namespace0_generated_397_begin(server, ns);
retVal |= function_namespace0_generated_398_begin(server, ns);
retVal |= function_namespace0_generated_399_begin(server, ns);
retVal |= function_namespace0_generated_400_begin(server, ns);
retVal |= function_namespace0_generated_401_begin(server, ns);
retVal |= function_namespace0_generated_402_begin(server, ns);
retVal |= function_namespace0_generated_403_begin(server, ns);
retVal |= function_namespace0_generated_404_begin(server, ns);
retVal |= function_namespace0_generated_405_begin(server, ns);
retVal |= function_namespace0_generated_406_begin(server, ns);
retVal |= function_namespace0_generated_407_begin(server, ns);
retVal |= function_namespace0_generated_408_begin(server, ns);
retVal |= function_namespace0_generated_409_begin(server, ns);
retVal |= function_namespace0_generated_410_begin(server, ns);
retVal |= function_namespace0_generated_411_begin(server, ns);
retVal |= function_namespace0_generated_412_begin(server, ns);
retVal |= function_namespace0_generated_413_begin(server, ns);
retVal |= function_namespace0_generated_414_begin(server, ns);
retVal |= function_namespace0_generated_415_begin(server, ns);
retVal |= function_namespace0_generated_416_begin(server, ns);
retVal |= function_namespace0_generated_417_begin(server, ns);
retVal |= function_namespace0_generated_418_begin(server, ns);
retVal |= function_namespace0_generated_419_begin(server, ns);
retVal |= function_namespace0_generated_420_begin(server, ns);
retVal |= function_namespace0_generated_421_begin(server, ns);
retVal |= function_namespace0_generated_422_begin(server, ns);
retVal |= function_namespace0_generated_423_begin(server, ns);
retVal |= function_namespace0_generated_424_begin(server, ns);
retVal |= function_namespace0_generated_425_begin(server, ns);
retVal |= function_namespace0_generated_426_begin(server, ns);
retVal |= function_namespace0_generated_427_begin(server, ns);
retVal |= function_namespace0_generated_428_begin(server, ns);
retVal |= function_namespace0_generated_429_begin(server, ns);
retVal |= function_namespace0_generated_430_begin(server, ns);
retVal |= function_namespace0_generated_431_begin(server, ns);
retVal |= function_namespace0_generated_432_begin(server, ns);
retVal |= function_namespace0_generated_433_begin(server, ns);
retVal |= function_namespace0_generated_434_begin(server, ns);
retVal |= function_namespace0_generated_435_begin(server, ns);
retVal |= function_namespace0_generated_436_begin(server, ns);
retVal |= function_namespace0_generated_437_begin(server, ns);
retVal |= function_namespace0_generated_438_begin(server, ns);
retVal |= function_namespace0_generated_439_begin(server, ns);
retVal |= function_namespace0_generated_440_begin(server, ns);
retVal |= function_namespace0_generated_441_begin(server, ns);
retVal |= function_namespace0_generated_442_begin(server, ns);
retVal |= function_namespace0_generated_443_begin(server, ns);
retVal |= function_namespace0_generated_444_begin(server, ns);
retVal |= function_namespace0_generated_445_begin(server, ns);
retVal |= function_namespace0_generated_446_begin(server, ns);
retVal |= function_namespace0_generated_447_begin(server, ns);
retVal |= function_namespace0_generated_448_begin(server, ns);
retVal |= function_namespace0_generated_449_begin(server, ns);
retVal |= function_namespace0_generated_450_begin(server, ns);
retVal |= function_namespace0_generated_451_begin(server, ns);
retVal |= function_namespace0_generated_452_begin(server, ns);
retVal |= function_namespace0_generated_453_begin(server, ns);
retVal |= function_namespace0_generated_454_begin(server, ns);
retVal |= function_namespace0_generated_455_begin(server, ns);
retVal |= function_namespace0_generated_456_begin(server, ns);
retVal |= function_namespace0_generated_457_begin(server, ns);
retVal |= function_namespace0_generated_458_begin(server, ns);
retVal |= function_namespace0_generated_459_begin(server, ns);
retVal |= function_namespace0_generated_460_begin(server, ns);
retVal |= function_namespace0_generated_461_begin(server, ns);
retVal |= function_namespace0_generated_462_begin(server, ns);
retVal |= function_namespace0_generated_463_begin(server, ns);
retVal |= function_namespace0_generated_464_begin(server, ns);
retVal |= function_namespace0_generated_465_begin(server, ns);
retVal |= function_namespace0_generated_466_begin(server, ns);
retVal |= function_namespace0_generated_467_begin(server, ns);
retVal |= function_namespace0_generated_468_begin(server, ns);
retVal |= function_namespace0_generated_469_begin(server, ns);
retVal |= function_namespace0_generated_470_begin(server, ns);
retVal |= function_namespace0_generated_471_begin(server, ns);
retVal |= function_namespace0_generated_472_begin(server, ns);
retVal |= function_namespace0_generated_473_begin(server, ns);
retVal |= function_namespace0_generated_474_begin(server, ns);
retVal |= function_namespace0_generated_475_begin(server, ns);
retVal |= function_namespace0_generated_476_begin(server, ns);
retVal |= function_namespace0_generated_477_begin(server, ns);
retVal |= function_namespace0_generated_478_begin(server, ns);
retVal |= function_namespace0_generated_479_begin(server, ns);
retVal |= function_namespace0_generated_480_begin(server, ns);
retVal |= function_namespace0_generated_481_begin(server, ns);
retVal |= function_namespace0_generated_482_begin(server, ns);
retVal |= function_namespace0_generated_483_begin(server, ns);
retVal |= function_namespace0_generated_484_begin(server, ns);
retVal |= function_namespace0_generated_485_begin(server, ns);
retVal |= function_namespace0_generated_486_begin(server, ns);
retVal |= function_namespace0_generated_487_begin(server, ns);
retVal |= function_namespace0_generated_488_begin(server, ns);
retVal |= function_namespace0_generated_489_begin(server, ns);
retVal |= function_namespace0_generated_490_begin(server, ns);
retVal |= function_namespace0_generated_491_begin(server, ns);
retVal |= function_namespace0_generated_492_begin(server, ns);
retVal |= function_namespace0_generated_493_begin(server, ns);
retVal |= function_namespace0_generated_494_begin(server, ns);
retVal |= function_namespace0_generated_495_begin(server, ns);
retVal |= function_namespace0_generated_496_begin(server, ns);
retVal |= function_namespace0_generated_497_begin(server, ns);
retVal |= function_namespace0_generated_498_begin(server, ns);
retVal |= function_namespace0_generated_499_begin(server, ns);
retVal |= function_namespace0_generated_500_begin(server, ns);
retVal |= function_namespace0_generated_501_begin(server, ns);
retVal |= function_namespace0_generated_502_begin(server, ns);
retVal |= function_namespace0_generated_503_begin(server, ns);
retVal |= function_namespace0_generated_504_begin(server, ns);
retVal |= function_namespace0_generated_505_begin(server, ns);
retVal |= function_namespace0_generated_506_begin(server, ns);
retVal |= function_namespace0_generated_507_begin(server, ns);
retVal |= function_namespace0_generated_508_begin(server, ns);
retVal |= function_namespace0_generated_509_begin(server, ns);
retVal |= function_namespace0_generated_510_begin(server, ns);
retVal |= function_namespace0_generated_511_begin(server, ns);
retVal |= function_namespace0_generated_512_begin(server, ns);
retVal |= function_namespace0_generated_513_begin(server, ns);
retVal |= function_namespace0_generated_514_begin(server, ns);
retVal |= function_namespace0_generated_515_begin(server, ns);
retVal |= function_namespace0_generated_516_begin(server, ns);
retVal |= function_namespace0_generated_517_begin(server, ns);
retVal |= function_namespace0_generated_518_begin(server, ns);
retVal |= function_namespace0_generated_519_begin(server, ns);
retVal |= function_namespace0_generated_520_begin(server, ns);
retVal |= function_namespace0_generated_521_begin(server, ns);
retVal |= function_namespace0_generated_522_begin(server, ns);
retVal |= function_namespace0_generated_523_begin(server, ns);
retVal |= function_namespace0_generated_524_begin(server, ns);
retVal |= function_namespace0_generated_525_begin(server, ns);
retVal |= function_namespace0_generated_526_begin(server, ns);
retVal |= function_namespace0_generated_527_begin(server, ns);
retVal |= function_namespace0_generated_528_begin(server, ns);
retVal |= function_namespace0_generated_529_begin(server, ns);
retVal |= function_namespace0_generated_530_begin(server, ns);
retVal |= function_namespace0_generated_531_begin(server, ns);
retVal |= function_namespace0_generated_532_begin(server, ns);
retVal |= function_namespace0_generated_533_begin(server, ns);
retVal |= function_namespace0_generated_534_begin(server, ns);
retVal |= function_namespace0_generated_535_begin(server, ns);
retVal |= function_namespace0_generated_536_begin(server, ns);
retVal |= function_namespace0_generated_537_begin(server, ns);
retVal |= function_namespace0_generated_538_begin(server, ns);
retVal |= function_namespace0_generated_539_begin(server, ns);
retVal |= function_namespace0_generated_540_begin(server, ns);
retVal |= function_namespace0_generated_541_begin(server, ns);
retVal |= function_namespace0_generated_542_begin(server, ns);
retVal |= function_namespace0_generated_543_begin(server, ns);
retVal |= function_namespace0_generated_544_begin(server, ns);
retVal |= function_namespace0_generated_545_begin(server, ns);
retVal |= function_namespace0_generated_546_begin(server, ns);
retVal |= function_namespace0_generated_547_begin(server, ns);
retVal |= function_namespace0_generated_548_begin(server, ns);
retVal |= function_namespace0_generated_549_begin(server, ns);
retVal |= function_namespace0_generated_550_begin(server, ns);
retVal |= function_namespace0_generated_551_begin(server, ns);
retVal |= function_namespace0_generated_552_begin(server, ns);
retVal |= function_namespace0_generated_553_begin(server, ns);
retVal |= function_namespace0_generated_554_begin(server, ns);
retVal |= function_namespace0_generated_555_begin(server, ns);
retVal |= function_namespace0_generated_556_begin(server, ns);
retVal |= function_namespace0_generated_557_begin(server, ns);
retVal |= function_namespace0_generated_558_begin(server, ns);
retVal |= function_namespace0_generated_558_finish(server, ns);
retVal |= function_namespace0_generated_557_finish(server, ns);
retVal |= function_namespace0_generated_556_finish(server, ns);
retVal |= function_namespace0_generated_555_finish(server, ns);
retVal |= function_namespace0_generated_554_finish(server, ns);
retVal |= function_namespace0_generated_553_finish(server, ns);
retVal |= function_namespace0_generated_552_finish(server, ns);
retVal |= function_namespace0_generated_551_finish(server, ns);
retVal |= function_namespace0_generated_550_finish(server, ns);
retVal |= function_namespace0_generated_549_finish(server, ns);
retVal |= function_namespace0_generated_548_finish(server, ns);
retVal |= function_namespace0_generated_547_finish(server, ns);
retVal |= function_namespace0_generated_546_finish(server, ns);
retVal |= function_namespace0_generated_545_finish(server, ns);
retVal |= function_namespace0_generated_544_finish(server, ns);
retVal |= function_namespace0_generated_543_finish(server, ns);
retVal |= function_namespace0_generated_542_finish(server, ns);
retVal |= function_namespace0_generated_541_finish(server, ns);
retVal |= function_namespace0_generated_540_finish(server, ns);
retVal |= function_namespace0_generated_539_finish(server, ns);
retVal |= function_namespace0_generated_538_finish(server, ns);
retVal |= function_namespace0_generated_537_finish(server, ns);
retVal |= function_namespace0_generated_536_finish(server, ns);
retVal |= function_namespace0_generated_535_finish(server, ns);
retVal |= function_namespace0_generated_534_finish(server, ns);
retVal |= function_namespace0_generated_533_finish(server, ns);
retVal |= function_namespace0_generated_532_finish(server, ns);
retVal |= function_namespace0_generated_531_finish(server, ns);
retVal |= function_namespace0_generated_530_finish(server, ns);
retVal |= function_namespace0_generated_529_finish(server, ns);
retVal |= function_namespace0_generated_528_finish(server, ns);
retVal |= function_namespace0_generated_527_finish(server, ns);
retVal |= function_namespace0_generated_526_finish(server, ns);
retVal |= function_namespace0_generated_525_finish(server, ns);
retVal |= function_namespace0_generated_524_finish(server, ns);
retVal |= function_namespace0_generated_523_finish(server, ns);
retVal |= function_namespace0_generated_522_finish(server, ns);
retVal |= function_namespace0_generated_521_finish(server, ns);
retVal |= function_namespace0_generated_520_finish(server, ns);
retVal |= function_namespace0_generated_519_finish(server, ns);
retVal |= function_namespace0_generated_518_finish(server, ns);
retVal |= function_namespace0_generated_517_finish(server, ns);
retVal |= function_namespace0_generated_516_finish(server, ns);
retVal |= function_namespace0_generated_515_finish(server, ns);
retVal |= function_namespace0_generated_514_finish(server, ns);
retVal |= function_namespace0_generated_513_finish(server, ns);
retVal |= function_namespace0_generated_512_finish(server, ns);
retVal |= function_namespace0_generated_511_finish(server, ns);
retVal |= function_namespace0_generated_510_finish(server, ns);
retVal |= function_namespace0_generated_509_finish(server, ns);
retVal |= function_namespace0_generated_508_finish(server, ns);
retVal |= function_namespace0_generated_507_finish(server, ns);
retVal |= function_namespace0_generated_506_finish(server, ns);
retVal |= function_namespace0_generated_505_finish(server, ns);
retVal |= function_namespace0_generated_504_finish(server, ns);
retVal |= function_namespace0_generated_503_finish(server, ns);
retVal |= function_namespace0_generated_502_finish(server, ns);
retVal |= function_namespace0_generated_501_finish(server, ns);
retVal |= function_namespace0_generated_500_finish(server, ns);
retVal |= function_namespace0_generated_499_finish(server, ns);
retVal |= function_namespace0_generated_498_finish(server, ns);
retVal |= function_namespace0_generated_497_finish(server, ns);
retVal |= function_namespace0_generated_496_finish(server, ns);
retVal |= function_namespace0_generated_495_finish(server, ns);
retVal |= function_namespace0_generated_494_finish(server, ns);
retVal |= function_namespace0_generated_493_finish(server, ns);
retVal |= function_namespace0_generated_492_finish(server, ns);
retVal |= function_namespace0_generated_491_finish(server, ns);
retVal |= function_namespace0_generated_490_finish(server, ns);
retVal |= function_namespace0_generated_489_finish(server, ns);
retVal |= function_namespace0_generated_488_finish(server, ns);
retVal |= function_namespace0_generated_487_finish(server, ns);
retVal |= function_namespace0_generated_486_finish(server, ns);
retVal |= function_namespace0_generated_485_finish(server, ns);
retVal |= function_namespace0_generated_484_finish(server, ns);
retVal |= function_namespace0_generated_483_finish(server, ns);
retVal |= function_namespace0_generated_482_finish(server, ns);
retVal |= function_namespace0_generated_481_finish(server, ns);
retVal |= function_namespace0_generated_480_finish(server, ns);
retVal |= function_namespace0_generated_479_finish(server, ns);
retVal |= function_namespace0_generated_478_finish(server, ns);
retVal |= function_namespace0_generated_477_finish(server, ns);
retVal |= function_namespace0_generated_476_finish(server, ns);
retVal |= function_namespace0_generated_475_finish(server, ns);
retVal |= function_namespace0_generated_474_finish(server, ns);
retVal |= function_namespace0_generated_473_finish(server, ns);
retVal |= function_namespace0_generated_472_finish(server, ns);
retVal |= function_namespace0_generated_471_finish(server, ns);
retVal |= function_namespace0_generated_470_finish(server, ns);
retVal |= function_namespace0_generated_469_finish(server, ns);
retVal |= function_namespace0_generated_468_finish(server, ns);
retVal |= function_namespace0_generated_467_finish(server, ns);
retVal |= function_namespace0_generated_466_finish(server, ns);
retVal |= function_namespace0_generated_465_finish(server, ns);
retVal |= function_namespace0_generated_464_finish(server, ns);
retVal |= function_namespace0_generated_463_finish(server, ns);
retVal |= function_namespace0_generated_462_finish(server, ns);
retVal |= function_namespace0_generated_461_finish(server, ns);
retVal |= function_namespace0_generated_460_finish(server, ns);
retVal |= function_namespace0_generated_459_finish(server, ns);
retVal |= function_namespace0_generated_458_finish(server, ns);
retVal |= function_namespace0_generated_457_finish(server, ns);
retVal |= function_namespace0_generated_456_finish(server, ns);
retVal |= function_namespace0_generated_455_finish(server, ns);
retVal |= function_namespace0_generated_454_finish(server, ns);
retVal |= function_namespace0_generated_453_finish(server, ns);
retVal |= function_namespace0_generated_452_finish(server, ns);
retVal |= function_namespace0_generated_451_finish(server, ns);
retVal |= function_namespace0_generated_450_finish(server, ns);
retVal |= function_namespace0_generated_449_finish(server, ns);
retVal |= function_namespace0_generated_448_finish(server, ns);
retVal |= function_namespace0_generated_447_finish(server, ns);
retVal |= function_namespace0_generated_446_finish(server, ns);
retVal |= function_namespace0_generated_445_finish(server, ns);
retVal |= function_namespace0_generated_444_finish(server, ns);
retVal |= function_namespace0_generated_443_finish(server, ns);
retVal |= function_namespace0_generated_442_finish(server, ns);
retVal |= function_namespace0_generated_441_finish(server, ns);
retVal |= function_namespace0_generated_440_finish(server, ns);
retVal |= function_namespace0_generated_439_finish(server, ns);
retVal |= function_namespace0_generated_438_finish(server, ns);
retVal |= function_namespace0_generated_437_finish(server, ns);
retVal |= function_namespace0_generated_436_finish(server, ns);
retVal |= function_namespace0_generated_435_finish(server, ns);
retVal |= function_namespace0_generated_434_finish(server, ns);
retVal |= function_namespace0_generated_433_finish(server, ns);
retVal |= function_namespace0_generated_432_finish(server, ns);
retVal |= function_namespace0_generated_431_finish(server, ns);
retVal |= function_namespace0_generated_430_finish(server, ns);
retVal |= function_namespace0_generated_429_finish(server, ns);
retVal |= function_namespace0_generated_428_finish(server, ns);
retVal |= function_namespace0_generated_427_finish(server, ns);
retVal |= function_namespace0_generated_426_finish(server, ns);
retVal |= function_namespace0_generated_425_finish(server, ns);
retVal |= function_namespace0_generated_424_finish(server, ns);
retVal |= function_namespace0_generated_423_finish(server, ns);
retVal |= function_namespace0_generated_422_finish(server, ns);
retVal |= function_namespace0_generated_421_finish(server, ns);
retVal |= function_namespace0_generated_420_finish(server, ns);
retVal |= function_namespace0_generated_419_finish(server, ns);
retVal |= function_namespace0_generated_418_finish(server, ns);
retVal |= function_namespace0_generated_417_finish(server, ns);
retVal |= function_namespace0_generated_416_finish(server, ns);
retVal |= function_namespace0_generated_415_finish(server, ns);
retVal |= function_namespace0_generated_414_finish(server, ns);
retVal |= function_namespace0_generated_413_finish(server, ns);
retVal |= function_namespace0_generated_412_finish(server, ns);
retVal |= function_namespace0_generated_411_finish(server, ns);
retVal |= function_namespace0_generated_410_finish(server, ns);
retVal |= function_namespace0_generated_409_finish(server, ns);
retVal |= function_namespace0_generated_408_finish(server, ns);
retVal |= function_namespace0_generated_407_finish(server, ns);
retVal |= function_namespace0_generated_406_finish(server, ns);
retVal |= function_namespace0_generated_405_finish(server, ns);
retVal |= function_namespace0_generated_404_finish(server, ns);
retVal |= function_namespace0_generated_403_finish(server, ns);
retVal |= function_namespace0_generated_402_finish(server, ns);
retVal |= function_namespace0_generated_401_finish(server, ns);
retVal |= function_namespace0_generated_400_finish(server, ns);
retVal |= function_namespace0_generated_399_finish(server, ns);
retVal |= function_namespace0_generated_398_finish(server, ns);
retVal |= function_namespace0_generated_397_finish(server, ns);
retVal |= function_namespace0_generated_396_finish(server, ns);
retVal |= function_namespace0_generated_395_finish(server, ns);
retVal |= function_namespace0_generated_394_finish(server, ns);
retVal |= function_namespace0_generated_393_finish(server, ns);
retVal |= function_namespace0_generated_392_finish(server, ns);
retVal |= function_namespace0_generated_391_finish(server, ns);
retVal |= function_namespace0_generated_390_finish(server, ns);
retVal |= function_namespace0_generated_389_finish(server, ns);
retVal |= function_namespace0_generated_388_finish(server, ns);
retVal |= function_namespace0_generated_387_finish(server, ns);
retVal |= function_namespace0_generated_386_finish(server, ns);
retVal |= function_namespace0_generated_385_finish(server, ns);
retVal |= function_namespace0_generated_384_finish(server, ns);
retVal |= function_namespace0_generated_383_finish(server, ns);
retVal |= function_namespace0_generated_382_finish(server, ns);
retVal |= function_namespace0_generated_381_finish(server, ns);
retVal |= function_namespace0_generated_380_finish(server, ns);
retVal |= function_namespace0_generated_379_finish(server, ns);
retVal |= function_namespace0_generated_378_finish(server, ns);
retVal |= function_namespace0_generated_377_finish(server, ns);
retVal |= function_namespace0_generated_376_finish(server, ns);
retVal |= function_namespace0_generated_375_finish(server, ns);
retVal |= function_namespace0_generated_374_finish(server, ns);
retVal |= function_namespace0_generated_373_finish(server, ns);
retVal |= function_namespace0_generated_372_finish(server, ns);
retVal |= function_namespace0_generated_371_finish(server, ns);
retVal |= function_namespace0_generated_370_finish(server, ns);
retVal |= function_namespace0_generated_369_finish(server, ns);
retVal |= function_namespace0_generated_368_finish(server, ns);
retVal |= function_namespace0_generated_367_finish(server, ns);
retVal |= function_namespace0_generated_366_finish(server, ns);
retVal |= function_namespace0_generated_365_finish(server, ns);
retVal |= function_namespace0_generated_364_finish(server, ns);
retVal |= function_namespace0_generated_363_finish(server, ns);
retVal |= function_namespace0_generated_362_finish(server, ns);
retVal |= function_namespace0_generated_361_finish(server, ns);
retVal |= function_namespace0_generated_360_finish(server, ns);
retVal |= function_namespace0_generated_359_finish(server, ns);
retVal |= function_namespace0_generated_358_finish(server, ns);
retVal |= function_namespace0_generated_357_finish(server, ns);
retVal |= function_namespace0_generated_356_finish(server, ns);
retVal |= function_namespace0_generated_355_finish(server, ns);
retVal |= function_namespace0_generated_354_finish(server, ns);
retVal |= function_namespace0_generated_353_finish(server, ns);
retVal |= function_namespace0_generated_352_finish(server, ns);
retVal |= function_namespace0_generated_351_finish(server, ns);
retVal |= function_namespace0_generated_350_finish(server, ns);
retVal |= function_namespace0_generated_349_finish(server, ns);
retVal |= function_namespace0_generated_348_finish(server, ns);
retVal |= function_namespace0_generated_347_finish(server, ns);
retVal |= function_namespace0_generated_346_finish(server, ns);
retVal |= function_namespace0_generated_345_finish(server, ns);
retVal |= function_namespace0_generated_344_finish(server, ns);
retVal |= function_namespace0_generated_343_finish(server, ns);
retVal |= function_namespace0_generated_342_finish(server, ns);
retVal |= function_namespace0_generated_341_finish(server, ns);
retVal |= function_namespace0_generated_340_finish(server, ns);
retVal |= function_namespace0_generated_339_finish(server, ns);
retVal |= function_namespace0_generated_338_finish(server, ns);
retVal |= function_namespace0_generated_337_finish(server, ns);
retVal |= function_namespace0_generated_336_finish(server, ns);
retVal |= function_namespace0_generated_335_finish(server, ns);
retVal |= function_namespace0_generated_334_finish(server, ns);
retVal |= function_namespace0_generated_333_finish(server, ns);
retVal |= function_namespace0_generated_332_finish(server, ns);
retVal |= function_namespace0_generated_331_finish(server, ns);
retVal |= function_namespace0_generated_330_finish(server, ns);
retVal |= function_namespace0_generated_329_finish(server, ns);
retVal |= function_namespace0_generated_328_finish(server, ns);
retVal |= function_namespace0_generated_327_finish(server, ns);
retVal |= function_namespace0_generated_326_finish(server, ns);
retVal |= function_namespace0_generated_325_finish(server, ns);
retVal |= function_namespace0_generated_324_finish(server, ns);
retVal |= function_namespace0_generated_323_finish(server, ns);
retVal |= function_namespace0_generated_322_finish(server, ns);
retVal |= function_namespace0_generated_321_finish(server, ns);
retVal |= function_namespace0_generated_320_finish(server, ns);
retVal |= function_namespace0_generated_319_finish(server, ns);
retVal |= function_namespace0_generated_318_finish(server, ns);
retVal |= function_namespace0_generated_317_finish(server, ns);
retVal |= function_namespace0_generated_316_finish(server, ns);
retVal |= function_namespace0_generated_315_finish(server, ns);
retVal |= function_namespace0_generated_314_finish(server, ns);
retVal |= function_namespace0_generated_313_finish(server, ns);
retVal |= function_namespace0_generated_312_finish(server, ns);
retVal |= function_namespace0_generated_311_finish(server, ns);
retVal |= function_namespace0_generated_310_finish(server, ns);
retVal |= function_namespace0_generated_309_finish(server, ns);
retVal |= function_namespace0_generated_308_finish(server, ns);
retVal |= function_namespace0_generated_307_finish(server, ns);
retVal |= function_namespace0_generated_306_finish(server, ns);
retVal |= function_namespace0_generated_305_finish(server, ns);
retVal |= function_namespace0_generated_304_finish(server, ns);
retVal |= function_namespace0_generated_303_finish(server, ns);
retVal |= function_namespace0_generated_302_finish(server, ns);
retVal |= function_namespace0_generated_301_finish(server, ns);
retVal |= function_namespace0_generated_300_finish(server, ns);
retVal |= function_namespace0_generated_299_finish(server, ns);
retVal |= function_namespace0_generated_298_finish(server, ns);
retVal |= function_namespace0_generated_297_finish(server, ns);
retVal |= function_namespace0_generated_296_finish(server, ns);
retVal |= function_namespace0_generated_295_finish(server, ns);
retVal |= function_namespace0_generated_294_finish(server, ns);
retVal |= function_namespace0_generated_293_finish(server, ns);
retVal |= function_namespace0_generated_292_finish(server, ns);
retVal |= function_namespace0_generated_291_finish(server, ns);
retVal |= function_namespace0_generated_290_finish(server, ns);
retVal |= function_namespace0_generated_289_finish(server, ns);
retVal |= function_namespace0_generated_288_finish(server, ns);
retVal |= function_namespace0_generated_287_finish(server, ns);
retVal |= function_namespace0_generated_286_finish(server, ns);
retVal |= function_namespace0_generated_285_finish(server, ns);
retVal |= function_namespace0_generated_284_finish(server, ns);
retVal |= function_namespace0_generated_283_finish(server, ns);
retVal |= function_namespace0_generated_282_finish(server, ns);
retVal |= function_namespace0_generated_281_finish(server, ns);
retVal |= function_namespace0_generated_280_finish(server, ns);
retVal |= function_namespace0_generated_279_finish(server, ns);
retVal |= function_namespace0_generated_278_finish(server, ns);
retVal |= function_namespace0_generated_277_finish(server, ns);
retVal |= function_namespace0_generated_276_finish(server, ns);
retVal |= function_namespace0_generated_275_finish(server, ns);
retVal |= function_namespace0_generated_274_finish(server, ns);
retVal |= function_namespace0_generated_273_finish(server, ns);
retVal |= function_namespace0_generated_272_finish(server, ns);
retVal |= function_namespace0_generated_271_finish(server, ns);
retVal |= function_namespace0_generated_270_finish(server, ns);
retVal |= function_namespace0_generated_269_finish(server, ns);
retVal |= function_namespace0_generated_268_finish(server, ns);
retVal |= function_namespace0_generated_267_finish(server, ns);
retVal |= function_namespace0_generated_266_finish(server, ns);
retVal |= function_namespace0_generated_265_finish(server, ns);
retVal |= function_namespace0_generated_264_finish(server, ns);
retVal |= function_namespace0_generated_263_finish(server, ns);
retVal |= function_namespace0_generated_262_finish(server, ns);
retVal |= function_namespace0_generated_261_finish(server, ns);
retVal |= function_namespace0_generated_260_finish(server, ns);
retVal |= function_namespace0_generated_259_finish(server, ns);
retVal |= function_namespace0_generated_258_finish(server, ns);
retVal |= function_namespace0_generated_257_finish(server, ns);
retVal |= function_namespace0_generated_256_finish(server, ns);
retVal |= function_namespace0_generated_255_finish(server, ns);
retVal |= function_namespace0_generated_254_finish(server, ns);
retVal |= function_namespace0_generated_253_finish(server, ns);
retVal |= function_namespace0_generated_252_finish(server, ns);
retVal |= function_namespace0_generated_251_finish(server, ns);
retVal |= function_namespace0_generated_250_finish(server, ns);
retVal |= function_namespace0_generated_249_finish(server, ns);
retVal |= function_namespace0_generated_248_finish(server, ns);
retVal |= function_namespace0_generated_247_finish(server, ns);
retVal |= function_namespace0_generated_246_finish(server, ns);
retVal |= function_namespace0_generated_245_finish(server, ns);
retVal |= function_namespace0_generated_244_finish(server, ns);
retVal |= function_namespace0_generated_243_finish(server, ns);
retVal |= function_namespace0_generated_242_finish(server, ns);
retVal |= function_namespace0_generated_241_finish(server, ns);
retVal |= function_namespace0_generated_240_finish(server, ns);
retVal |= function_namespace0_generated_239_finish(server, ns);
retVal |= function_namespace0_generated_238_finish(server, ns);
retVal |= function_namespace0_generated_237_finish(server, ns);
retVal |= function_namespace0_generated_236_finish(server, ns);
retVal |= function_namespace0_generated_235_finish(server, ns);
retVal |= function_namespace0_generated_234_finish(server, ns);
retVal |= function_namespace0_generated_233_finish(server, ns);
retVal |= function_namespace0_generated_232_finish(server, ns);
retVal |= function_namespace0_generated_231_finish(server, ns);
retVal |= function_namespace0_generated_230_finish(server, ns);
retVal |= function_namespace0_generated_229_finish(server, ns);
retVal |= function_namespace0_generated_228_finish(server, ns);
retVal |= function_namespace0_generated_227_finish(server, ns);
retVal |= function_namespace0_generated_226_finish(server, ns);
retVal |= function_namespace0_generated_225_finish(server, ns);
retVal |= function_namespace0_generated_224_finish(server, ns);
retVal |= function_namespace0_generated_223_finish(server, ns);
retVal |= function_namespace0_generated_222_finish(server, ns);
retVal |= function_namespace0_generated_221_finish(server, ns);
retVal |= function_namespace0_generated_220_finish(server, ns);
retVal |= function_namespace0_generated_219_finish(server, ns);
retVal |= function_namespace0_generated_218_finish(server, ns);
retVal |= function_namespace0_generated_217_finish(server, ns);
retVal |= function_namespace0_generated_216_finish(server, ns);
retVal |= function_namespace0_generated_215_finish(server, ns);
retVal |= function_namespace0_generated_214_finish(server, ns);
retVal |= function_namespace0_generated_213_finish(server, ns);
retVal |= function_namespace0_generated_212_finish(server, ns);
retVal |= function_namespace0_generated_211_finish(server, ns);
retVal |= function_namespace0_generated_210_finish(server, ns);
retVal |= function_namespace0_generated_209_finish(server, ns);
retVal |= function_namespace0_generated_208_finish(server, ns);
retVal |= function_namespace0_generated_207_finish(server, ns);
retVal |= function_namespace0_generated_206_finish(server, ns);
retVal |= function_namespace0_generated_205_finish(server, ns);
retVal |= function_namespace0_generated_204_finish(server, ns);
retVal |= function_namespace0_generated_203_finish(server, ns);
retVal |= function_namespace0_generated_202_finish(server, ns);
retVal |= function_namespace0_generated_201_finish(server, ns);
retVal |= function_namespace0_generated_200_finish(server, ns);
retVal |= function_namespace0_generated_199_finish(server, ns);
retVal |= function_namespace0_generated_198_finish(server, ns);
retVal |= function_namespace0_generated_197_finish(server, ns);
retVal |= function_namespace0_generated_196_finish(server, ns);
retVal |= function_namespace0_generated_195_finish(server, ns);
retVal |= function_namespace0_generated_194_finish(server, ns);
retVal |= function_namespace0_generated_193_finish(server, ns);
retVal |= function_namespace0_generated_192_finish(server, ns);
retVal |= function_namespace0_generated_191_finish(server, ns);
retVal |= function_namespace0_generated_190_finish(server, ns);
retVal |= function_namespace0_generated_189_finish(server, ns);
retVal |= function_namespace0_generated_188_finish(server, ns);
retVal |= function_namespace0_generated_187_finish(server, ns);
retVal |= function_namespace0_generated_186_finish(server, ns);
retVal |= function_namespace0_generated_185_finish(server, ns);
retVal |= function_namespace0_generated_184_finish(server, ns);
retVal |= function_namespace0_generated_183_finish(server, ns);
retVal |= function_namespace0_generated_182_finish(server, ns);
retVal |= function_namespace0_generated_181_finish(server, ns);
retVal |= function_namespace0_generated_180_finish(server, ns);
retVal |= function_namespace0_generated_179_finish(server, ns);
retVal |= function_namespace0_generated_178_finish(server, ns);
retVal |= function_namespace0_generated_177_finish(server, ns);
retVal |= function_namespace0_generated_176_finish(server, ns);
retVal |= function_namespace0_generated_175_finish(server, ns);
retVal |= function_namespace0_generated_174_finish(server, ns);
retVal |= function_namespace0_generated_173_finish(server, ns);
retVal |= function_namespace0_generated_172_finish(server, ns);
retVal |= function_namespace0_generated_171_finish(server, ns);
retVal |= function_namespace0_generated_170_finish(server, ns);
retVal |= function_namespace0_generated_169_finish(server, ns);
retVal |= function_namespace0_generated_168_finish(server, ns);
retVal |= function_namespace0_generated_167_finish(server, ns);
retVal |= function_namespace0_generated_166_finish(server, ns);
retVal |= function_namespace0_generated_165_finish(server, ns);
retVal |= function_namespace0_generated_164_finish(server, ns);
retVal |= function_namespace0_generated_163_finish(server, ns);
retVal |= function_namespace0_generated_162_finish(server, ns);
retVal |= function_namespace0_generated_161_finish(server, ns);
retVal |= function_namespace0_generated_160_finish(server, ns);
retVal |= function_namespace0_generated_159_finish(server, ns);
retVal |= function_namespace0_generated_158_finish(server, ns);
retVal |= function_namespace0_generated_157_finish(server, ns);
retVal |= function_namespace0_generated_156_finish(server, ns);
retVal |= function_namespace0_generated_155_finish(server, ns);
retVal |= function_namespace0_generated_154_finish(server, ns);
retVal |= function_namespace0_generated_153_finish(server, ns);
retVal |= function_namespace0_generated_152_finish(server, ns);
retVal |= function_namespace0_generated_151_finish(server, ns);
retVal |= function_namespace0_generated_150_finish(server, ns);
retVal |= function_namespace0_generated_149_finish(server, ns);
retVal |= function_namespace0_generated_148_finish(server, ns);
retVal |= function_namespace0_generated_147_finish(server, ns);
retVal |= function_namespace0_generated_146_finish(server, ns);
retVal |= function_namespace0_generated_145_finish(server, ns);
retVal |= function_namespace0_generated_144_finish(server, ns);
retVal |= function_namespace0_generated_143_finish(server, ns);
retVal |= function_namespace0_generated_142_finish(server, ns);
retVal |= function_namespace0_generated_141_finish(server, ns);
retVal |= function_namespace0_generated_140_finish(server, ns);
retVal |= function_namespace0_generated_139_finish(server, ns);
retVal |= function_namespace0_generated_138_finish(server, ns);
retVal |= function_namespace0_generated_137_finish(server, ns);
retVal |= function_namespace0_generated_136_finish(server, ns);
retVal |= function_namespace0_generated_135_finish(server, ns);
retVal |= function_namespace0_generated_134_finish(server, ns);
retVal |= function_namespace0_generated_133_finish(server, ns);
retVal |= function_namespace0_generated_132_finish(server, ns);
retVal |= function_namespace0_generated_131_finish(server, ns);
retVal |= function_namespace0_generated_130_finish(server, ns);
retVal |= function_namespace0_generated_129_finish(server, ns);
retVal |= function_namespace0_generated_128_finish(server, ns);
retVal |= function_namespace0_generated_127_finish(server, ns);
retVal |= function_namespace0_generated_126_finish(server, ns);
retVal |= function_namespace0_generated_125_finish(server, ns);
retVal |= function_namespace0_generated_124_finish(server, ns);
retVal |= function_namespace0_generated_123_finish(server, ns);
retVal |= function_namespace0_generated_122_finish(server, ns);
retVal |= function_namespace0_generated_121_finish(server, ns);
retVal |= function_namespace0_generated_120_finish(server, ns);
retVal |= function_namespace0_generated_119_finish(server, ns);
retVal |= function_namespace0_generated_118_finish(server, ns);
retVal |= function_namespace0_generated_117_finish(server, ns);
retVal |= function_namespace0_generated_116_finish(server, ns);
retVal |= function_namespace0_generated_115_finish(server, ns);
retVal |= function_namespace0_generated_114_finish(server, ns);
retVal |= function_namespace0_generated_113_finish(server, ns);
retVal |= function_namespace0_generated_112_finish(server, ns);
retVal |= function_namespace0_generated_111_finish(server, ns);
retVal |= function_namespace0_generated_110_finish(server, ns);
retVal |= function_namespace0_generated_109_finish(server, ns);
retVal |= function_namespace0_generated_108_finish(server, ns);
retVal |= function_namespace0_generated_107_finish(server, ns);
retVal |= function_namespace0_generated_106_finish(server, ns);
retVal |= function_namespace0_generated_105_finish(server, ns);
retVal |= function_namespace0_generated_104_finish(server, ns);
retVal |= function_namespace0_generated_103_finish(server, ns);
retVal |= function_namespace0_generated_102_finish(server, ns);
retVal |= function_namespace0_generated_101_finish(server, ns);
retVal |= function_namespace0_generated_100_finish(server, ns);
retVal |= function_namespace0_generated_99_finish(server, ns);
retVal |= function_namespace0_generated_98_finish(server, ns);
retVal |= function_namespace0_generated_97_finish(server, ns);
retVal |= function_namespace0_generated_96_finish(server, ns);
retVal |= function_namespace0_generated_95_finish(server, ns);
retVal |= function_namespace0_generated_94_finish(server, ns);
retVal |= function_namespace0_generated_93_finish(server, ns);
retVal |= function_namespace0_generated_92_finish(server, ns);
retVal |= function_namespace0_generated_91_finish(server, ns);
retVal |= function_namespace0_generated_90_finish(server, ns);
retVal |= function_namespace0_generated_89_finish(server, ns);
retVal |= function_namespace0_generated_88_finish(server, ns);
retVal |= function_namespace0_generated_87_finish(server, ns);
retVal |= function_namespace0_generated_86_finish(server, ns);
retVal |= function_namespace0_generated_85_finish(server, ns);
retVal |= function_namespace0_generated_84_finish(server, ns);
retVal |= function_namespace0_generated_83_finish(server, ns);
retVal |= function_namespace0_generated_82_finish(server, ns);
retVal |= function_namespace0_generated_81_finish(server, ns);
retVal |= function_namespace0_generated_80_finish(server, ns);
retVal |= function_namespace0_generated_79_finish(server, ns);
retVal |= function_namespace0_generated_78_finish(server, ns);
retVal |= function_namespace0_generated_77_finish(server, ns);
retVal |= function_namespace0_generated_76_finish(server, ns);
retVal |= function_namespace0_generated_75_finish(server, ns);
retVal |= function_namespace0_generated_74_finish(server, ns);
retVal |= function_namespace0_generated_73_finish(server, ns);
retVal |= function_namespace0_generated_72_finish(server, ns);
retVal |= function_namespace0_generated_71_finish(server, ns);
retVal |= function_namespace0_generated_70_finish(server, ns);
retVal |= function_namespace0_generated_69_finish(server, ns);
retVal |= function_namespace0_generated_68_finish(server, ns);
retVal |= function_namespace0_generated_67_finish(server, ns);
retVal |= function_namespace0_generated_66_finish(server, ns);
retVal |= function_namespace0_generated_65_finish(server, ns);
retVal |= function_namespace0_generated_64_finish(server, ns);
retVal |= function_namespace0_generated_63_finish(server, ns);
retVal |= function_namespace0_generated_62_finish(server, ns);
retVal |= function_namespace0_generated_61_finish(server, ns);
retVal |= function_namespace0_generated_60_finish(server, ns);
retVal |= function_namespace0_generated_59_finish(server, ns);
retVal |= function_namespace0_generated_58_finish(server, ns);
retVal |= function_namespace0_generated_57_finish(server, ns);
retVal |= function_namespace0_generated_56_finish(server, ns);
retVal |= function_namespace0_generated_55_finish(server, ns);
retVal |= function_namespace0_generated_54_finish(server, ns);
retVal |= function_namespace0_generated_53_finish(server, ns);
retVal |= function_namespace0_generated_52_finish(server, ns);
retVal |= function_namespace0_generated_51_finish(server, ns);
retVal |= function_namespace0_generated_50_finish(server, ns);
retVal |= function_namespace0_generated_49_finish(server, ns);
retVal |= function_namespace0_generated_48_finish(server, ns);
retVal |= function_namespace0_generated_47_finish(server, ns);
retVal |= function_namespace0_generated_46_finish(server, ns);
retVal |= function_namespace0_generated_45_finish(server, ns);
retVal |= function_namespace0_generated_44_finish(server, ns);
retVal |= function_namespace0_generated_43_finish(server, ns);
retVal |= function_namespace0_generated_42_finish(server, ns);
retVal |= function_namespace0_generated_41_finish(server, ns);
retVal |= function_namespace0_generated_40_finish(server, ns);
retVal |= function_namespace0_generated_39_finish(server, ns);
retVal |= function_namespace0_generated_38_finish(server, ns);
retVal |= function_namespace0_generated_37_finish(server, ns);
retVal |= function_namespace0_generated_36_finish(server, ns);
retVal |= function_namespace0_generated_35_finish(server, ns);
retVal |= function_namespace0_generated_34_finish(server, ns);
retVal |= function_namespace0_generated_33_finish(server, ns);
retVal |= function_namespace0_generated_32_finish(server, ns);
retVal |= function_namespace0_generated_31_finish(server, ns);
retVal |= function_namespace0_generated_30_finish(server, ns);
retVal |= function_namespace0_generated_29_finish(server, ns);
retVal |= function_namespace0_generated_28_finish(server, ns);
retVal |= function_namespace0_generated_27_finish(server, ns);
retVal |= function_namespace0_generated_26_finish(server, ns);
retVal |= function_namespace0_generated_25_finish(server, ns);
retVal |= function_namespace0_generated_24_finish(server, ns);
retVal |= function_namespace0_generated_23_finish(server, ns);
retVal |= function_namespace0_generated_22_finish(server, ns);
retVal |= function_namespace0_generated_21_finish(server, ns);
retVal |= function_namespace0_generated_20_finish(server, ns);
retVal |= function_namespace0_generated_19_finish(server, ns);
retVal |= function_namespace0_generated_18_finish(server, ns);
retVal |= function_namespace0_generated_17_finish(server, ns);
retVal |= function_namespace0_generated_16_finish(server, ns);
retVal |= function_namespace0_generated_15_finish(server, ns);
retVal |= function_namespace0_generated_14_finish(server, ns);
retVal |= function_namespace0_generated_13_finish(server, ns);
retVal |= function_namespace0_generated_12_finish(server, ns);
retVal |= function_namespace0_generated_11_finish(server, ns);
retVal |= function_namespace0_generated_10_finish(server, ns);
retVal |= function_namespace0_generated_9_finish(server, ns);
retVal |= function_namespace0_generated_8_finish(server, ns);
retVal |= function_namespace0_generated_7_finish(server, ns);
retVal |= function_namespace0_generated_6_finish(server, ns);
return retVal;
}

/**** amalgamated original file "/src/util/ua_types_lex.c" ****/

/* Generated by re2c 3.1 */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *
 */


/* Lexing and parsing of builtin data types. These are helper functions that not
 * required by the SDK internally. But they are useful for users who want to use
 * standard-specified humand readable encodings for NodeIds, etc.
 *
 * This compilation unit uses the re2c lexer generator. The final C source is
 * generated with the following script:
 *
 *   re2c -i --no-generation-date ua_types_lex.re > ua_types_lex.c
 *
 * In order that users of the SDK don't need to install re2c, always commit a
 * recent ua_types_lex.c if changes are made to the lexer. */

#define YYCURSOR pos
#define YYMARKER context.marker
#define YYPEEK() (YYCURSOR < end) ? *YYCURSOR : 0 /* The lexer sees a stream of
                                                   * \0 when the input ends*/
#define YYSKIP() ++YYCURSOR;
#define YYBACKUP() YYMARKER = YYCURSOR
#define YYRESTORE() YYCURSOR = YYMARKER
#define YYSTAGP(t) t = YYCURSOR
#define YYSTAGN(t) t = NULL
#define YYSHIFTSTAG(t, shift) t += shift

typedef struct {
    const char *marker;
    const char *yyt1;const char *yyt2;const char *yyt3;const char *yyt4;
} LexContext;



static UA_StatusCode
parse_guid(UA_Guid *guid, const UA_Byte *s, const UA_Byte *e) {
    size_t len = (size_t)(e - s);
    if(len != 36 || s[8] != '-' || s[13] != '-' || s[23] != '-')
        return UA_STATUSCODE_BADDECODINGERROR;

    UA_UInt32 tmp;
    if(UA_readNumberWithBase(s, 8, &tmp, 16) != 8)
        return UA_STATUSCODE_BADDECODINGERROR;
    guid->data1 = tmp;

    if(UA_readNumberWithBase(&s[9], 4, &tmp, 16) != 4)
        return UA_STATUSCODE_BADDECODINGERROR;
    guid->data2 = (UA_UInt16)tmp;

    if(UA_readNumberWithBase(&s[14], 4, &tmp, 16) != 4)
        return UA_STATUSCODE_BADDECODINGERROR;
    guid->data3 = (UA_UInt16)tmp;

    if(UA_readNumberWithBase(&s[19], 2, &tmp, 16) != 2)
        return UA_STATUSCODE_BADDECODINGERROR;
    guid->data4[0] = (UA_Byte)tmp;

    if(UA_readNumberWithBase(&s[21], 2, &tmp, 16) != 2)
        return UA_STATUSCODE_BADDECODINGERROR;
    guid->data4[1] = (UA_Byte)tmp;

    for(size_t pos = 2, spos = 24; pos < 8; pos++, spos += 2) {
        if(UA_readNumberWithBase(&s[spos], 2, &tmp, 16) != 2)
            return UA_STATUSCODE_BADDECODINGERROR;
        guid->data4[pos] = (UA_Byte)tmp;
    }

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Guid_parse(UA_Guid *guid, const UA_String str) {
    UA_StatusCode res = parse_guid(guid, str.data, str.data + str.length);
    if(res != UA_STATUSCODE_GOOD)
        *guid = UA_GUID_NULL;
    return res;
}

static UA_StatusCode
parse_nodeid_body(UA_NodeId *id, const char *body, const char *end) {
    size_t len = (size_t)(end - (body+2));
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    switch(*body) {
    case 'i': {
        if(UA_readNumber((const UA_Byte*)body+2, len, &id->identifier.numeric) != len)
            return UA_STATUSCODE_BADDECODINGERROR;
        id->identifierType = UA_NODEIDTYPE_NUMERIC;
        break;
    }
    case 's': {
        UA_String tmpstr;
        tmpstr.data = (UA_Byte*)(uintptr_t)body+2;
        tmpstr.length = len;
        res = UA_String_copy(&tmpstr, &id->identifier.string);
        if(res != UA_STATUSCODE_GOOD)
            break;
        id->identifierType = UA_NODEIDTYPE_STRING;
        break;
    }
    case 'g':
        res = parse_guid(&id->identifier.guid, (const UA_Byte*)body+2, (const UA_Byte*)end);
        if(res == UA_STATUSCODE_GOOD)
            id->identifierType = UA_NODEIDTYPE_GUID;
        break;
    case 'b':
        id->identifier.byteString.data =
            UA_unbase64((const unsigned char*)body+2, len,
                        &id->identifier.byteString.length);
        if(!id->identifier.byteString.data && len > 0)
            return UA_STATUSCODE_BADDECODINGERROR;
        id->identifierType = UA_NODEIDTYPE_BYTESTRING;
        break;
    default:
        return UA_STATUSCODE_BADDECODINGERROR;
    }
    return res;
}

static UA_StatusCode
parse_nodeid(UA_NodeId *id, const char *pos, const char *end) {
    *id = UA_NODEID_NULL; /* Reset the NodeId */
    LexContext context;
    memset(&context, 0, sizeof(LexContext));
    const char *ns = NULL, *nse= NULL;

    
{
	char yych;
	yych = YYPEEK();
	switch (yych) {
		case 'b':
		case 'g':
		case 'i':
		case 's':
			YYSTAGN(context.yyt1);
			YYSTAGN(context.yyt2);
			goto yy3;
		case 'n': goto yy4;
		default: goto yy1;
	}
yy1:
	YYSKIP();
yy2:
	{ (void)pos; return UA_STATUSCODE_BADDECODINGERROR; }
yy3:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '=': goto yy5;
		default: goto yy2;
	}
yy4:
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 's': goto yy6;
		default: goto yy2;
	}
yy5:
	YYSKIP();
	ns = context.yyt1;
	nse = context.yyt2;
	{
        (void)pos; // Get rid of a dead store clang-analyzer warning
        if(ns) {
            UA_UInt32 tmp;
            size_t len = (size_t)(nse - ns);
            if(UA_readNumber((const UA_Byte*)ns, len, &tmp) != len)
                return UA_STATUSCODE_BADDECODINGERROR;
            id->namespaceIndex = (UA_UInt16)tmp;
        }

        // From the current position until the end
        return parse_nodeid_body(id, &pos[-2], end);
    }
yy6:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '=': goto yy8;
		default: goto yy7;
	}
yy7:
	YYRESTORE();
	goto yy2;
yy8:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			YYSTAGP(context.yyt1);
			goto yy9;
		default: goto yy7;
	}
yy9:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy9;
		case ';':
			YYSTAGP(context.yyt2);
			goto yy10;
		default: goto yy7;
	}
yy10:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'b':
		case 'g':
		case 'i':
		case 's': goto yy11;
		default: goto yy7;
	}
yy11:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '=': goto yy5;
		default: goto yy7;
	}
}

}

UA_StatusCode
UA_NodeId_parse(UA_NodeId *id, const UA_String str) {
    UA_StatusCode res =
        parse_nodeid(id, (const char*)str.data, (const char*)str.data+str.length);
    if(res != UA_STATUSCODE_GOOD)
        UA_NodeId_clear(id);
    return res;
}

static UA_StatusCode
parse_expandednodeid(UA_ExpandedNodeId *id, const char *pos, const char *end) {
    *id = UA_EXPANDEDNODEID_NULL; /* Reset the NodeId */
    LexContext context;
    memset(&context, 0, sizeof(LexContext));
    const char *svr = NULL, *svre = NULL, *nsu = NULL, *ns = NULL, *body = NULL;

    
{
	char yych;
	yych = YYPEEK();
	switch (yych) {
		case 'b':
		case 'g':
		case 'i':
			YYSTAGN(context.yyt1);
			YYSTAGN(context.yyt2);
			YYSTAGN(context.yyt3);
			YYSTAGN(context.yyt4);
			goto yy15;
		case 'n':
			YYSTAGN(context.yyt1);
			YYSTAGN(context.yyt2);
			goto yy16;
		case 's':
			YYSTAGN(context.yyt1);
			YYSTAGN(context.yyt2);
			YYSTAGN(context.yyt3);
			YYSTAGN(context.yyt4);
			goto yy17;
		default: goto yy13;
	}
yy13:
	YYSKIP();
yy14:
	{ (void)pos; return UA_STATUSCODE_BADDECODINGERROR; }
yy15:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '=': goto yy18;
		default: goto yy14;
	}
yy16:
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 's': goto yy19;
		default: goto yy14;
	}
yy17:
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case '=': goto yy18;
		case 'v': goto yy21;
		default: goto yy14;
	}
yy18:
	YYSKIP();
	svr = context.yyt1;
	svre = context.yyt2;
	ns = context.yyt3;
	nsu = context.yyt4;
	YYSTAGP(body);
	YYSHIFTSTAG(body, -2);
	{
        (void)pos; // Get rid of a dead store clang-analyzer warning
        if(svr) {
            size_t len = (size_t)((svre) - svr);
            if(UA_readNumber((const UA_Byte*)svr, len, &id->serverIndex) != len)
                return UA_STATUSCODE_BADDECODINGERROR;
        }

        if(nsu) {
            size_t len = (size_t)((body-1) - nsu);
            UA_String nsuri;
            nsuri.data = (UA_Byte*)(uintptr_t)nsu;
            nsuri.length = len;
            UA_StatusCode res = UA_String_copy(&nsuri, &id->namespaceUri);
            if(res != UA_STATUSCODE_GOOD)
                return res;
        } else if(ns) {
            UA_UInt32 tmp;
            size_t len = (size_t)((body-1) - ns);
            if(UA_readNumber((const UA_Byte*)ns, len, &tmp) != len)
                return UA_STATUSCODE_BADDECODINGERROR;
            id->nodeId.namespaceIndex = (UA_UInt16)tmp;
        }

        // From the current position until the end
        return parse_nodeid_body(&id->nodeId, &pos[-2], end);
    }
yy19:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '=': goto yy22;
		case 'u': goto yy23;
		default: goto yy20;
	}
yy20:
	YYRESTORE();
	goto yy14;
yy21:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'r': goto yy24;
		default: goto yy20;
	}
yy22:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			YYSTAGP(context.yyt3);
			goto yy25;
		default: goto yy20;
	}
yy23:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '=': goto yy26;
		default: goto yy20;
	}
yy24:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '=': goto yy27;
		default: goto yy20;
	}
yy25:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy25;
		case ';': goto yy28;
		default: goto yy20;
	}
yy26:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\n': goto yy20;
		case ';':
			YYSTAGP(context.yyt4);
			goto yy30;
		default:
			YYSTAGP(context.yyt4);
			goto yy29;
	}
yy27:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			YYSTAGP(context.yyt1);
			goto yy31;
		default: goto yy20;
	}
yy28:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'b':
		case 'g':
		case 'i':
		case 's':
			YYSTAGN(context.yyt4);
			goto yy32;
		default: goto yy20;
	}
yy29:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '\n': goto yy20;
		case ';': goto yy30;
		default: goto yy29;
	}
yy30:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'b':
		case 'g':
		case 'i':
		case 's':
			YYSTAGN(context.yyt3);
			goto yy32;
		default: goto yy20;
	}
yy31:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy31;
		case ';':
			YYSTAGP(context.yyt2);
			goto yy33;
		default: goto yy20;
	}
yy32:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case '=': goto yy18;
		default: goto yy20;
	}
yy33:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 'b':
		case 'g':
		case 'i':
		case 's':
			YYSTAGN(context.yyt3);
			YYSTAGN(context.yyt4);
			goto yy32;
		case 'n': goto yy34;
		default: goto yy20;
	}
yy34:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 's': goto yy19;
		default: goto yy20;
	}
}

}

UA_StatusCode
UA_ExpandedNodeId_parse(UA_ExpandedNodeId *id, const UA_String str) {
    UA_StatusCode res =
        parse_expandednodeid(id, (const char*)str.data, (const char*)str.data+str.length);
    if(res != UA_STATUSCODE_GOOD)
        UA_ExpandedNodeId_clear(id);
    return res;
}

static UA_StatusCode
relativepath_addelem(UA_RelativePath *rp, UA_RelativePathElement *el) {
    /* Allocate memory */
    UA_RelativePathElement *newArray = (UA_RelativePathElement*)
        UA_realloc(rp->elements, sizeof(UA_RelativePathElement) * (rp->elementsSize + 1));
    if(!newArray)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    rp->elements = newArray;

    /* Move to the target */
    rp->elements[rp->elementsSize] = *el;
    rp->elementsSize++;
    return UA_STATUSCODE_GOOD;
}

/* Parse name string with '&' as the escape character */
static UA_StatusCode
parse_refpath_qn_name(UA_QualifiedName *qn, const char **pos, const char *end) {
    /* Allocate the max length the name can have */
    size_t maxlen = (size_t)(end - *pos);
    if(maxlen == 0) {
        qn->name.data = (UA_Byte*)UA_EMPTY_ARRAY_SENTINEL;
        return UA_STATUSCODE_GOOD;
    }
    char *name = (char*)UA_malloc(maxlen);
    if(!name)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    size_t index = 0;
    for(; *pos < end; (*pos)++) {
        char c = **pos;
        /* Unescaped special characer: The end of the QualifiedName */
        if(c == '/' || c == '.' || c == '<' || c == '>' ||
           c == ':' || c == '#' || c == '!')
            break;

        /* Escaped character */
        if(c == '&') {
            (*pos)++;
            if(*pos >= end ||
               (**pos != '/' && **pos != '.' && **pos != '<' && **pos != '>' &&
                **pos != ':' && **pos != '#' && **pos != '!' && **pos != '&')) {
                UA_free(name);
                return UA_STATUSCODE_BADDECODINGERROR;
            }
            c = **pos;
        }

        /* Unescaped normal character */
        name[index] = c;
        index++;
    }

    if(index > 0) {
        qn->name.data = (UA_Byte*)name;
        qn->name.length = index;
    } else {
        qn->name.data = (UA_Byte*)UA_EMPTY_ARRAY_SENTINEL;
        UA_free(name);
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
parse_refpath_qn(UA_QualifiedName *qn, const char *pos, const char *end) {
    LexContext context;
    memset(&context, 0, sizeof(LexContext));
    const char *ns = NULL, *nse = NULL;
    UA_QualifiedName_init(qn);

    
{
	char yych;
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			YYSTAGP(context.yyt1);
			goto yy38;
		default: goto yy36;
	}
yy36:
	YYSKIP();
yy37:
	{ pos--; goto parse_qn_name; }
yy38:
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case ':': goto yy40;
		default: goto yy37;
	}
yy39:
	YYSKIP();
	yych = YYPEEK();
yy40:
	switch (yych) {
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9': goto yy39;
		case ':': goto yy42;
		default: goto yy41;
	}
yy41:
	YYRESTORE();
	goto yy37;
yy42:
	YYSKIP();
	ns = context.yyt1;
	YYSTAGP(nse);
	YYSHIFTSTAG(nse, -1);
	{
        UA_UInt32 tmp;
        size_t len = (size_t)(nse - ns);
        if(UA_readNumber((const UA_Byte*)ns, len, &tmp) != len)
            return UA_STATUSCODE_BADDECODINGERROR;
        qn->namespaceIndex = (UA_UInt16)tmp;
        goto parse_qn_name;
    }
}


 parse_qn_name:
    return parse_refpath_qn_name(qn, &pos, end);
}

static UA_StatusCode
parse_relativepath(UA_Server *server, UA_RelativePath *rp, const UA_String str) {
    const char *pos = (const char*)str.data;
    const char *end = (const char*)(str.data + str.length);

    LexContext context;
    memset(&context, 0, sizeof(LexContext));
    const char *begin = NULL, *finish = NULL;
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    UA_RelativePath_init(rp); /* Reset the BrowsePath */

    /* Add one element to the path in every iteration */
    UA_RelativePathElement current;
 loop:
    UA_RelativePathElement_init(&current);
    current.includeSubtypes = true; /* Follow subtypes by default */

    /* Get the ReferenceType and its modifiers */
    
{
	char yych;
	unsigned int yyaccept = 0;
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy44;
		case '.': goto yy47;
		case '/': goto yy48;
		case '<': goto yy49;
		default: goto yy45;
	}
yy44:
	YYSKIP();
	{ (void)pos; return UA_STATUSCODE_GOOD; }
yy45:
	YYSKIP();
yy46:
	{ (void)pos; return UA_STATUSCODE_BADDECODINGERROR; }
yy47:
	YYSKIP();
	{
        current.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_AGGREGATES);
        goto reftype_target;
    }
yy48:
	YYSKIP();
	{
        current.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_HIERARCHICALREFERENCES);
        goto reftype_target;
    }
yy49:
	yyaccept = 0;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '>': goto yy46;
		case '&':
			YYSTAGP(context.yyt1);
			goto yy52;
		default:
			YYSTAGP(context.yyt1);
			goto yy50;
	}
yy50:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy51;
		case '&': goto yy52;
		case '>': goto yy53;
		default: goto yy50;
	}
yy51:
	YYRESTORE();
	if (yyaccept == 0) {
		goto yy46;
	} else {
		goto yy54;
	}
yy52:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy51;
		case '&': goto yy52;
		case '>': goto yy55;
		default: goto yy50;
	}
yy53:
	YYSKIP();
yy54:
	begin = context.yyt1;
	YYSTAGP(finish);
	YYSHIFTSTAG(finish, -1);
	{

        // Process modifier characters
        for(; begin < finish; begin++) {
            if(*begin== '#')
                current.includeSubtypes = false;
            else if(*begin == '!')
                current.isInverse = true;
            else
                break;
        }

        // Try to parse a NodeId for the ReferenceType (non-standard!)
        res = parse_nodeid(&current.referenceTypeId, begin, finish);
        if(res == UA_STATUSCODE_GOOD)
            goto reftype_target;

        // Parse the the ReferenceType from its BrowseName
        UA_QualifiedName refqn;
        res = parse_refpath_qn(&refqn, begin, finish);
        res |= lookupRefType(server, &refqn, &current.referenceTypeId);
        UA_QualifiedName_clear(&refqn);
        goto reftype_target;
    }
yy55:
	yyaccept = 1;
	YYSKIP();
	YYBACKUP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy54;
		case '&': goto yy52;
		case '>': goto yy53;
		default: goto yy50;
	}
}


    /* Get the TargetName component */
 reftype_target:
    if(res != UA_STATUSCODE_GOOD)
        return res;

    
{
	char yych;
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '.':
		case '/':
		case '<': goto yy57;
		case '&':
			YYSTAGP(context.yyt1);
			goto yy60;
		default:
			YYSTAGP(context.yyt1);
			goto yy58;
	}
yy57:
	YYSKIP();
	{ pos--; goto add_element; }
yy58:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00:
		case '.':
		case '/':
		case '<': goto yy59;
		case '&': goto yy60;
		default: goto yy58;
	}
yy59:
	begin = context.yyt1;
	{
        res = parse_refpath_qn(&current.targetName, begin, pos);
        goto add_element;
    }
yy60:
	YYSKIP();
	yych = YYPEEK();
	switch (yych) {
		case 0x00: goto yy59;
		case '&': goto yy60;
		default: goto yy58;
	}
}


    /* Add the current element to the path and continue to the next element */
 add_element:
    res |= relativepath_addelem(rp, &current);
    if(res != UA_STATUSCODE_GOOD) {
        UA_RelativePathElement_clear(&current);
        return res;
    }
    goto loop;
}

UA_StatusCode
UA_RelativePath_parse(UA_RelativePath *rp, const UA_String str) {
    UA_StatusCode res = parse_relativepath(NULL, rp, str);
    if(res != UA_STATUSCODE_GOOD)
        UA_RelativePath_clear(rp);
    return res;
}

UA_StatusCode
UA_RelativePath_parseWithServer(UA_Server *server, UA_RelativePath *rp,
                                const UA_String str) {
    UA_StatusCode res = parse_relativepath(server, rp, str);
    if(res != UA_STATUSCODE_GOOD)
        UA_RelativePath_clear(rp);
    return res;
}

UA_StatusCode
UA_SimpleAttributeOperand_parse(UA_SimpleAttributeOperand *sao,
                                const UA_String str) {
    /* Initialize */
    UA_SimpleAttributeOperand_init(sao);

    /* Make a copy of the input. Used to de-escape the reserved characters. */
    UA_String edit_str;
    UA_StatusCode res = UA_String_copy(&str, &edit_str);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    char *pos = (char*)edit_str.data;
    char *end = (char*)(edit_str.data + edit_str.length);

    /* Parse the TypeDefinitionId */
    if(pos < end && *pos != '/' && *pos != '#' && *pos != '[') {
        char *typedef_pos = pos;
        pos = find_unescaped(pos, end, true);
        UA_String typeString = {(size_t)(pos - typedef_pos), (UA_Byte*)typedef_pos};
        UA_String_unescape(&typeString, true);
        res = UA_NodeId_parse(&sao->typeDefinitionId, typeString);
        if(res != UA_STATUSCODE_GOOD)
            goto cleanup;
    } else {
        /* BaseEventType is the default */
        sao->typeDefinitionId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE);
    }

    /* Parse the BrowsePath */
    while(pos < end && *pos == '/') {
        UA_QualifiedName browseName;
        UA_QualifiedName_init(&browseName);
        char *browsename_pos = ++pos;

        /* Skip namespace index and colon */
        char *browsename_name_pos = pos;
        if(pos < end && *pos >= '0' && *pos <= '9') {
 check_colon:
            pos++;
            if(pos < end) {
                if(*pos >= '0' && *pos <= '9')
                    goto check_colon;
                if(*pos ==':')
                    browsename_name_pos = ++pos;
            }
        }

        /* Find the end of the QualifiedName */
        pos = find_unescaped(browsename_name_pos, end, true);

        /* Unescape the name element of the QualifiedName */
        UA_String bnString = {(size_t)(pos - browsename_name_pos), (UA_Byte*)browsename_name_pos};
        UA_String_unescape(&bnString, true);

        /* Parse the QualifiedName */
        res = parse_refpath_qn(&browseName, browsename_pos, (char*)bnString.data + bnString.length);
        if(res != UA_STATUSCODE_GOOD)
            goto cleanup;

        /* Append to the BrowsePath */
        res = UA_Array_append((void**)&sao->browsePath, &sao->browsePathSize,
                              &browseName, &UA_TYPES[UA_TYPES_QUALIFIEDNAME]);
        if(res != UA_STATUSCODE_GOOD) {
            UA_QualifiedName_clear(&browseName);
            goto cleanup;
        }
    }

    /* Parse the AttributeId */
    if(pos < end && *pos == '#') {
        /* Find the first non-alphabet character */
        char *attr_pos = ++pos;
        while(pos < end && ((*pos >= 'a' && *pos <= 'z') ||
                            (*pos >= 'A' && *pos <= 'Z'))) {
            pos++;
        }
        /* Parse the AttributeId */
        UA_String attrString = {(size_t)(pos - attr_pos), (UA_Byte*)attr_pos};
        sao->attributeId = UA_AttributeId_fromName(attrString);
        if(sao->attributeId == UA_ATTRIBUTEID_INVALID) {
            res = UA_STATUSCODE_BADDECODINGERROR;
            goto cleanup;
        }
    } else {
        /* The value attribute is the default */
        sao->attributeId = UA_ATTRIBUTEID_VALUE;
    }

    /* Check whether the IndexRange can be parsed.
     * But just copy the string. */
    if(pos < end && *pos == '[') {
        /* Find the end character */
        char *range_pos = ++pos;
        while(pos < end && *pos != ']') {
            pos++;
        }
        if(pos == end) {
            res = UA_STATUSCODE_BADDECODINGERROR;
            goto cleanup;
        }
        UA_String rangeString = {(size_t)(pos - range_pos), (UA_Byte*)range_pos};
        UA_NumericRange nr;
        memset(&nr, 0, sizeof(UA_NumericRange));
        res = UA_NumericRange_parse(&nr, rangeString);
        if(res != UA_STATUSCODE_GOOD)
            goto cleanup;
        res = UA_String_copy(&rangeString, &sao->indexRange);
        if(nr.dimensionsSize > 0)
            UA_free(nr.dimensions);
        pos++;
    }

    /* Check that we have parsed the entire string */
    if(pos != end)
        res = UA_STATUSCODE_BADDECODINGERROR;

 cleanup:
    UA_String_clear(&edit_str);
    if(res != UA_STATUSCODE_GOOD)
        UA_SimpleAttributeOperand_clear(sao);
    return res;
}

/**** amalgamated original file "/src/util/ua_eventfilter_parser.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2023-2024 (c) Fraunhofer IOSB (Author: Florian Düwel)
 */



static UA_Parsed_Element_List *
create_next_operator_element(UA_Element_List *elements) {
    UA_Parsed_Element_List *element = (UA_Parsed_Element_List*)
        UA_calloc(1, sizeof(UA_Parsed_Element_List));
    element->identifier = parsed_operator;
    element->element.oper.ContentFilterArrayPosition = 0;
    TAILQ_INSERT_TAIL(&elements->head, element, element_entries);
    return element;
}

void
save_string(char *str, char **local_str) {
    *local_str = (char*) UA_calloc(strlen(str)+1, sizeof(char));
    strcpy(*local_str, str);
}

void
create_next_operand_element(UA_Element_List *elements, UA_Parsed_Operand *operand,
                            char *ref) {
    UA_Parsed_Element_List *element = (UA_Parsed_Element_List*)
        UA_calloc(1, sizeof(UA_Parsed_Element_List));
    element->identifier = PARSEDOPERAND;
    save_string(ref, &element->ref);
    free(ref);
    memcpy(&element->element.operand.identifier, &operand->identifier,
           sizeof(OperandIdentifier));
    if(operand->identifier == EXTENSIONOBJECT) {
        UA_ExtensionObject_copy(&operand->value.extension,
                                &element->element.operand.value.extension);
        UA_ExtensionObject_clear(&operand->value.extension);
    } else {
        save_string(operand->value.element_ref,
                    &element->element.operand.value.element_ref);
        free(operand->value.element_ref);
    }
    TAILQ_INSERT_TAIL(&elements->head, element, element_entries);
}

static UA_Parsed_Element_List *
get_element_by_reference(UA_Element_List *elements, char **reference) {
    UA_Parsed_Element_List *temp;
    TAILQ_FOREACH(temp, &elements->head, element_entries) {
        if(strcmp(temp->ref, *reference) == 0)
            return temp;
    }
    UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                 "Failed to find the element with reference: %s", *reference);
    return temp;
}

static UA_Parsed_Element_List *
get_element_by_idx_position(UA_Element_List *elements, size_t idx) {
    UA_Parsed_Element_List *temp;
    TAILQ_FOREACH(temp, &elements->head, element_entries) {
        if(temp->element.oper.ContentFilterArrayPosition == idx)
            return temp;
    }
    UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                 "Failed to find the element with idx %lu.", (unsigned long) idx);
    return temp;
}

static UA_Parsed_Element_List *
get_last_element_from_list(UA_Element_List *elements) {
    return TAILQ_LAST(&elements->head, parsed_filter_elements);
}

static UA_StatusCode
solve_children_references(UA_Parsed_Element_List *temp, UA_Element_List *elements,
                          size_t *position, size_t *nbr_children, char ***child_references) {
    for(size_t i = 0; i < temp->element.oper.nbr_children; i++) {
        if(temp->element.oper.children[i].identifier == ELEMENTOPERAND) {
            UA_Parsed_Element_List *temp_1 =
                get_element_by_reference(elements, &temp->element.oper.children[i].value.element_ref);
            if(temp_1->identifier == parsed_operator) {
                if(temp_1->element.oper.ContentFilterArrayPosition == 0) {
                    (*nbr_children)++;
                    *child_references = (char**)
                        UA_realloc(*child_references, *nbr_children*sizeof(char*));
                    save_string(temp->element.oper.children[i].value.element_ref,
                                &(*child_references)[*nbr_children-1]);
                    (*position)++;
                    temp_1->element.oper.ContentFilterArrayPosition = *position;
                }
                free(temp->element.oper.children[i].value.element_ref);
                UA_ExtensionObject extension;
                extension.encoding = UA_EXTENSIONOBJECT_DECODED;
                extension.content.decoded.type = &UA_TYPES[UA_TYPES_ELEMENTOPERAND];
                extension.content.decoded.data = &temp_1->element.oper.ContentFilterArrayPosition;
                UA_ExtensionObject_copy(&extension, &temp->element.oper.children[i].value.extension);
                temp->element.oper.children[i].identifier = EXTENSIONOBJECT;
            } else {
                if(temp_1->element.operand.identifier == ELEMENTOPERAND) {
                    UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                                 "Error! Unsolved reference to an ElementOperand");
                    return UA_STATUSCODE_BAD;
                }
                free(temp->element.oper.children[i].value.element_ref);
                temp->element.oper.children[i].identifier = EXTENSIONOBJECT;
                UA_ExtensionObject_copy(&temp_1->element.operand.value.extension,
                                        &temp->element.oper.children[i].value.extension);

            }
        }
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
check_recursion_on_operands(UA_Parsed_Element_List *element, size_t init_element,
                            UA_Element_List *elements, size_t *ctr, UA_StatusCode *status){
    if(*status != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_GOOD;
    for(size_t i = 0; i<element->element.oper.nbr_children; i++) {
        if(element->element.oper.children[i].value.extension.content.decoded.type == &UA_TYPES[UA_TYPES_ELEMENTOPERAND]){
            UA_ElementOperand *temp = (UA_ElementOperand*)
                element->element.oper.children[i].value.extension.content.decoded.data;
            UA_Parsed_Element_List *next_element =
                get_element_by_idx_position(elements, (size_t) temp->index);
            if(next_element->element.oper.ContentFilterArrayPosition == init_element) {
                UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                             "Operator %s has a loop to itself", next_element->ref);
                return UA_STATUSCODE_BAD;
            }
            //when checking an element and a loop exists inside the tree
            //structure, a termination condition is required, otherwise, the
            //loop is detecter, however as it does not involve the current
            //element, the condition based on the element index will never be
            //met
            if(*ctr > 1000) {
                UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                               "Checking Operator on position %lu." PRIu64
                               " Loop within the ContentFilter structure detected",
                               (unsigned long)init_element);
                break;
            }
            (*ctr)++;
            UA_StatusCode retval =
                check_recursion_on_operands(next_element, init_element, elements, ctr, status);
            if(retval != UA_STATUSCODE_GOOD)
                return retval;
        }
    }
    return UA_STATUSCODE_GOOD;
}

static void
handle_filter_structure(char *first_element, UA_Element_List *elements, size_t *position) {
    UA_Parsed_Element_List *temp;
    size_t nbr_children = 0;
    char **children_list = (char**) UA_calloc(0, sizeof(char*));
    temp = get_element_by_reference(elements, &first_element);
    solve_children_references(temp, elements, position, &nbr_children, &children_list);
    while(nbr_children > 0) {
        size_t temp_ctr = nbr_children;
        char **temp_list = (char**) UA_calloc(temp_ctr, sizeof(char*));
        for(size_t i=0; i< temp_ctr; i++){
            temp_list[i] = (char*) UA_calloc(strlen(children_list[i])+1, sizeof(char));
            strcpy(temp_list[i], children_list[i]);
            free(children_list[i]);
        }
        nbr_children = 0;
        children_list = (char**) UA_realloc(children_list, nbr_children);
        for(size_t i=0; i< temp_ctr; i++){
            UA_Parsed_Element_List *child = get_element_by_reference(elements, &temp_list[i]);
            solve_children_references(child, elements, position, &nbr_children, &children_list);
            free(temp_list[i]);
        }
        free(temp_list);
    }
    free(children_list);
    free(first_element);
}

static UA_StatusCode
solve_operand_references(UA_Element_List *elements) {
    size_t current_nbr = 1, last_nbr = 0;
    UA_Parsed_Element_List *temp, *temp1;
    while(current_nbr > 0) {
        current_nbr = 0;
        TAILQ_FOREACH(temp, &elements->head, element_entries) {
            if(temp->identifier == PARSEDOPERAND){
                if(temp->element.operand.identifier == ELEMENTOPERAND) {
                    temp1 = get_element_by_reference(elements,
                                                     &temp->element.operand.value.element_ref);
                    if(temp1->identifier == parsed_operator) {
                        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                                     "Error! An operand references an Operator");
                        return UA_STATUSCODE_BAD;
                    }

                    if(temp1->element.operand.identifier == ELEMENTOPERAND) {
                        current_nbr++;
                    } else {
                        free(temp->element.operand.value.element_ref);
                        temp->element.operand.identifier = EXTENSIONOBJECT;
                        UA_ExtensionObject_copy(&temp1->element.operand.value.extension,
                                                &temp->element.operand.value.extension);
                    }
                }
            }
        }
        if(current_nbr == last_nbr && last_nbr != 0) {
            UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                         "Error! Unable to solve all operand references");
            return UA_STATUSCODE_BAD;
        }
        last_nbr = current_nbr;
    }
    return UA_STATUSCODE_GOOD;
}

static void
clear_operand_list(UA_Parsed_Operand *operand_list, size_t list_size) {
    for(size_t i=0; i< list_size; i++) {
        operand_list[i].identifier == ELEMENTOPERAND ?
            free(operand_list[i].value.element_ref) :
            UA_ExtensionObject_clear(&operand_list[i].value.extension);
    }
}

static void
clear_linked_list(UA_Element_List *elements) {
    UA_Parsed_Element_List *temp, *temp1;
    TAILQ_FOREACH_SAFE(temp, &elements->head, element_entries, temp1) {
        free(temp->ref);
        if(temp->identifier == PARSEDOPERAND) {
            clear_operand_list(&temp->element.operand, 1);
        } else {
            UA_FilterOperator_clear(&temp->element.oper.filter);
            clear_operand_list(temp->element.oper.children, temp->element.oper.nbr_children);
            free(temp->element.oper.children);
        }
        TAILQ_REMOVE(&elements->head, temp, element_entries);
        free(temp);
    }
}

static void
add_content_filter_element(UA_ContentFilterElement *filterElement,
                           UA_Parsed_Operator *parsedElement) {
    UA_ContentFilterElement_init(filterElement);
    filterElement->filterOperandsSize = parsedElement->nbr_children;
    filterElement->filterOperands = (UA_ExtensionObject*)
        UA_calloc(parsedElement->nbr_children, sizeof(UA_ExtensionObject));
    filterElement->filterOperator = parsedElement->filter;
    for(size_t i=0; i< parsedElement->nbr_children; i++) {
        UA_ExtensionObject_copy(&parsedElement->children[i].value.extension,
                                &filterElement->filterOperands[i]);
        UA_ExtensionObject_clear(&parsedElement->children[i].value.extension);
    }
}

UA_StatusCode
create_content_filter(UA_Element_List *elements, UA_ContentFilter *filter,
                      char *first_element, UA_StatusCode status) {
    if(status != UA_STATUSCODE_GOOD) {
        clear_linked_list(elements);
        free(first_element);
        return status;
    }
    size_t position = 0;
    UA_StatusCode retval = solve_operand_references(elements);
    if(retval!= UA_STATUSCODE_GOOD) {
        clear_linked_list(elements);
        free(first_element);
        return retval;
    }
    handle_filter_structure(first_element, elements, &position);
    ////check for loops inside the tree structure
    UA_Parsed_Element_List *temp;
    TAILQ_FOREACH(temp, &elements->head, element_entries) {
        size_t ctr = 0;
        retval = check_recursion_on_operands(temp, temp->element.oper.ContentFilterArrayPosition,
                                             elements, &ctr, &status);
        if(retval != UA_STATUSCODE_GOOD) {
            clear_linked_list(elements);
            return retval;
        }
    }
    //add the elements to the contentFilter based on their array position values
    filter->elementsSize = position+1;
    filter->elements = (UA_ContentFilterElement*)
        UA_Array_new(filter->elementsSize, &UA_TYPES[UA_TYPES_CONTENTFILTERELEMENT]);
    for(size_t i=0; i<=position; i++) {
        temp = get_element_by_idx_position(elements, i);
        add_content_filter_element(&filter->elements[i], &temp->element.oper);
    }
    clear_linked_list(elements);
    return UA_STATUSCODE_GOOD;
}

static void
copy_children(UA_Parsed_Operator element, UA_Parsed_Element_List *temp) {
    for(size_t i=0; i<element.nbr_children; i++) {
        if(element.children[i].identifier == ELEMENTOPERAND) {
            temp->element.oper.children[i].identifier = ELEMENTOPERAND;
            save_string(element.children[i].value.element_ref,
                        &temp->element.oper.children[i].value.element_ref);
        } else {
            temp->element.oper.children[i].identifier = EXTENSIONOBJECT;
            UA_ExtensionObject_copy(&element.children[i].value.extension,
                                    &temp->element.oper.children[i].value.extension);
        }
    }
}

static void
add_operator_children(UA_Element_List *global, UA_Parsed_Operator element) {
    UA_Parsed_Element_List *temp = get_last_element_from_list(global);
    memcpy(&temp->element.oper.nbr_children, &element.nbr_children, sizeof(size_t));
    temp->element.oper.children = (UA_Parsed_Operand*)
        UA_calloc(element.nbr_children, sizeof(UA_Parsed_Operand));
    UA_FilterOperator_copy(&element.filter, &temp->element.oper.filter);
    copy_children(element, temp);
}

void
add_new_operator(UA_Element_List *global, char *operator_ref,
                 UA_Parsed_Operator *element) {
    UA_Parsed_Element_List *temp = create_next_operator_element(global);
    save_string(operator_ref, &temp->ref);
    free(operator_ref);
    add_operator_children(global, *element);
    clear_operand_list(element->children, element->nbr_children);
    free(element->children);
}

static void
check_SAO(UA_SimpleAttributeOperand *sao) {
    if(sao->typeDefinitionId.identifier.numeric == 0 &&
       sao->typeDefinitionId.identifierType == UA_NODEIDTYPE_NUMERIC) {
        sao->typeDefinitionId = UA_NODEID_NUMERIC(0, 2041);}
    if(sao->attributeId == 0)
        sao->attributeId = 13;
    if(sao->attributeId == 1) {
        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                     "Extracting a NodeId from a SimpleAttributeOperand "
                     "is not supported in the current implementation");
    }
    //if(sao->indexRange.length == 0) {sao->indexRange =UA_String_fromChars("");}
}

UA_StatusCode
append_select_clauses(UA_SimpleAttributeOperand **select_clauses, size_t *sao_size,
                      UA_ExtensionObject *extension, UA_StatusCode status) {
    if(status != UA_STATUSCODE_GOOD) {
        UA_ExtensionObject_clear(extension);
        return status;
    }
    if(*sao_size == 0) {
        *sao_size = 1;
        *select_clauses = (UA_SimpleAttributeOperand*)
            UA_Array_new(*sao_size, &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND]);
        UA_SimpleAttributeOperand_init(*select_clauses);
        UA_SimpleAttributeOperand_copy((UA_SimpleAttributeOperand*) extension->content.decoded.data,
                                       select_clauses[0]);
    } else {
        UA_StatusCode ret_val = UA_Array_append((void **)select_clauses, sao_size,
                                                (UA_SimpleAttributeOperand*) extension->content.decoded.data,
                                                &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND]);
        if(ret_val != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                         "Failed to increase the select clauses %s",
                         UA_StatusCode_name(ret_val));
            UA_ExtensionObject_clear(extension);
            return ret_val;
        }
    }
    UA_ExtensionObject_clear(extension);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
set_up_browsepath(UA_QualifiedName **q_name_list, size_t *size, char *str,
                  UA_StatusCode status) {
    if(status != UA_STATUSCODE_GOOD)
        return status;
    UA_RelativePath *path = UA_RelativePath_new();
    UA_String parsed_string = UA_String_fromChars(str);
    UA_StatusCode ret_val = UA_RelativePath_parse(path, parsed_string);
    if(ret_val != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                     "Failed to parse the RelativePath %s", UA_StatusCode_name(ret_val));
        UA_RelativePath_delete(path);
        UA_String_clear(&parsed_string);
        return ret_val;
    }
    memcpy(size, &path->elementsSize, sizeof(size_t));
    *q_name_list = (UA_QualifiedName*) UA_calloc(*size, sizeof(UA_QualifiedName));
    for(size_t i=0; i< path->elementsSize; i++)
        UA_QualifiedName_copy(&path->elements[i].targetName, &(*q_name_list)[i]);
    UA_RelativePath_delete(path);
    UA_String_clear(&parsed_string);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
create_literal_operand(char *string, UA_LiteralOperand *lit,
                       UA_StatusCode status) {
    if(status != UA_STATUSCODE_GOOD)
        return status;
    UA_ByteString input_val = UA_String_fromChars(string);
    UA_StatusCode ret_val = UA_decodeJson(&input_val, (void *)&lit->value,
                                          &UA_TYPES[UA_TYPES_VARIANT], NULL);
    if(ret_val != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                     "Failed to decode the Json %s", UA_StatusCode_name(ret_val));
        UA_ByteString_clear(&input_val);
        return ret_val;
    }
    UA_ByteString_clear(&input_val);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
create_nodeId_from_string(char *identifier, UA_NodeId *id, UA_StatusCode status) {
    if(status != UA_STATUSCODE_GOOD) {
        free(identifier);
        return status;
    }
    UA_String str = UA_String_fromChars(identifier);
    free(identifier);
    UA_NodeId_init(id);
    UA_StatusCode ret_val = UA_NodeId_parse(id, str);
    if(ret_val != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                     "Failed to parse the NodeId %s", UA_StatusCode_name(ret_val));
        UA_String_clear(&str);
        return ret_val;
    }
    UA_String_clear(&str);
    return UA_STATUSCODE_GOOD;
}

void
handle_elementoperand(UA_Parsed_Operand *operand, char *ref) {
    memset(operand, 0, sizeof(UA_Parsed_Operand));
    operand->identifier = ELEMENTOPERAND;
    save_string(ref, &operand->value.element_ref);
}

void handle_sao(UA_SimpleAttributeOperand *simple, UA_Parsed_Operand *operand) {
    UA_SimpleAttributeOperand *sao = UA_SimpleAttributeOperand_new();
    UA_SimpleAttributeOperand_copy(simple, sao);
    for(size_t i=0; i< simple->browsePathSize; i++) {
        UA_QualifiedName_clear(&simple->browsePath[i]);
    }
    UA_NodeId_clear(&simple->typeDefinitionId);
    UA_String_clear(&simple->indexRange);
    UA_SimpleAttributeOperand_clear(simple);
    check_SAO(sao);
    UA_ExtensionObject_init(&operand->value.extension);
    operand->value.extension.encoding = UA_EXTENSIONOBJECT_DECODED;
    operand->value.extension.content.decoded.type = &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND];
    operand->value.extension.content.decoded.data = sao;
    operand->identifier = EXTENSIONOBJECT;
}

static void
create_element_reference(size_t *branch_nbr, char **ref, char *ref_identifier) {
    char ref_nbr[128];
    int ret = mp_snprintf(ref_nbr, 128, "%lu" PRIu64 , (unsigned long) *branch_nbr);
    if(ret == 0) {
        UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "sprintf Failed");
    }
    *ref = (char*) UA_calloc(strlen(ref_identifier)+1+strlen(ref_nbr), sizeof(char));
    strcpy(*ref, ref_identifier);
    strcat(*ref, ref_nbr);
    (*branch_nbr)++;
}

static void
handle_branch_operator(UA_Parsed_Element_List *element, UA_FilterOperator oper,
                       size_t *branch_ctr) {
    element->element.oper.filter = oper;
    create_element_reference(branch_ctr, &element->ref, "operator_reference_");
}

void
add_operand_from_branch(char **ref, size_t *operand_ctr, UA_Parsed_Operand *operand,
                        UA_Element_List *global) {
    char *temp, temp1[100];
    create_element_reference(operand_ctr, &temp, "operand_reference_");
    strcpy(temp1, temp);
    create_next_operand_element(global, operand, temp);
    save_string(temp1, ref);
}

static void
add_child_references(UA_Parsed_Element_List *element, char **ref_1,
                     char **ref_2) {
    element->element.oper.nbr_children = 2;
    element->element.oper.children = (UA_Parsed_Operand *)
        UA_calloc(2, sizeof(UA_Parsed_Operand));
    for(size_t i=0; i<2; i++) {
        element->element.oper.children[i].identifier = ELEMENTOPERAND;
        i == 0 ? save_string(*ref_1, &element->element.oper.children[0].value.element_ref)
               : save_string(*ref_2, &element->element.oper.children[1].value.element_ref);
    }
}

static UA_NodeId
copy_nodeId(UA_NodeId *id) {
    UA_NodeId temp;
    UA_NodeId_copy(id, &temp);
    UA_NodeId_clear(id);
    return temp;
}

static void
set_up_ext_object_from_literal(UA_ExtensionObject *obj,
                               UA_LiteralOperand *value) {
    UA_LiteralOperand *lit = UA_LiteralOperand_new();
    UA_LiteralOperand_copy(value, lit);
    UA_LiteralOperand_clear(value);
    UA_ExtensionObject_init(obj);
    obj->encoding = UA_EXTENSIONOBJECT_DECODED;
    obj->content.decoded.type = &UA_TYPES[UA_TYPES_LITERALOPERAND];
    obj->content.decoded.data = lit;
}

void
set_up_variant_from_nodeId(UA_NodeId *id, UA_Variant *litvalue) {
    UA_NodeId temp = *id;
    UA_Variant_setScalarCopy(litvalue, &temp, &UA_TYPES[UA_TYPES_NODEID]);
}

void
create_nodeid_element(UA_Element_List *elements, UA_NodeId *id, char *ref) {
    UA_Parsed_Operand operand;
    memset(&operand, 0, sizeof(UA_Parsed_Operand));
    UA_LiteralOperand lit;
    set_up_variant_from_nodeId(id, &lit.value);
    UA_NodeId_clear(id);
    set_up_ext_object_from_literal(&operand.value.extension, &lit);
    operand.identifier = EXTENSIONOBJECT;
    create_next_operand_element(elements, &operand, ref);
}

void
handle_oftype_nodeId(UA_Parsed_Operator *element, UA_NodeId *id) {
    UA_FilterOperator_init(&element->filter);
    element->filter = UA_FILTEROPERATOR_OFTYPE;
    element->nbr_children = 1;
    element->children = (UA_Parsed_Operand*) UA_calloc(1, sizeof(UA_Parsed_Operand));
    UA_LiteralOperand lit;
    set_up_variant_from_nodeId(id, &lit.value);
    UA_NodeId_clear(id);
    set_up_ext_object_from_literal(&element->children[0].value.extension, &lit);
    element->children[0].identifier = EXTENSIONOBJECT;
}

void
handle_literal_operand(UA_Parsed_Operand *operand, UA_LiteralOperand *literalValue) {
    set_up_ext_object_from_literal(&operand->value.extension, literalValue);
    operand->identifier = EXTENSIONOBJECT;
    UA_LiteralOperand_clear(literalValue);
}

void
set_up_typeid(UA_Local_Operand *operand) {
    UA_NodeId temp = copy_nodeId(&operand->id);
    operand->sao.typeDefinitionId = copy_nodeId(&temp);
}

void
add_child_operands(UA_Parsed_Operand *operand_list, size_t operand_list_size,
                   UA_Parsed_Operator *element, UA_FilterOperator oper) {
    element->nbr_children = operand_list_size;
    element->filter = oper;
    element->children = (UA_Parsed_Operand*)
        UA_calloc(operand_list_size, sizeof(UA_Parsed_Operand));
    for(size_t i=0; i< operand_list_size; i++) {
        if(operand_list[i].identifier == ELEMENTOPERAND) {
            save_string(operand_list[i].value.element_ref, &element->children[i].value.element_ref);
            element->children[i].identifier = ELEMENTOPERAND;
            free(operand_list[i].value.element_ref);
        } else {
            UA_ExtensionObject_copy(&operand_list[i].value.extension,
                                    &element->children[i].value.extension);
            element->children[i].identifier = EXTENSIONOBJECT;
            UA_ExtensionObject_clear(&operand_list[i].value.extension);
        }
    }
}

void
handle_between_operator(UA_Parsed_Operator *element, UA_Parsed_Operand *operand_1,
                        UA_Parsed_Operand *operand_2, UA_Parsed_Operand *operand_3) {
    UA_Parsed_Operand operand_list[3] = {*operand_1, *operand_2, *operand_3};
    add_child_operands(operand_list, 3, element, UA_FILTEROPERATOR_BETWEEN);
}

void
handle_two_operands_operator(UA_Parsed_Operator *element, UA_Parsed_Operand *operand_1,
                             UA_Parsed_Operand *operand_2, UA_FilterOperator *filter) {
    UA_Parsed_Operand operand_list[2] = {*operand_1, *operand_2};
    add_child_operands(operand_list, 2, element, *filter);
}

void
init_item_list(UA_Element_List *global, UA_Counters *ctr) {
    TAILQ_INIT(&global->head);
    ctr->branch_element_number = 0;
    ctr->for_operator_reference = 0;
    ctr->operand_ctr = 0;
}

void
create_branch_element(UA_Element_List *global, size_t *branch_element_number,
                      UA_FilterOperator filteroperator, char *ref_1, char *ref_2, char **ref) {
    UA_Parsed_Element_List *temp = create_next_operator_element(global);
    handle_branch_operator(temp, filteroperator, branch_element_number);
    add_child_references(temp, &ref_1, &ref_2);
    save_string(temp->ref, ref);
    free(ref_1);
    free(ref_2);
}

void
handle_for_operator(UA_Element_List *global, size_t *for_operator_reference,
                    char **ref, UA_Parsed_Operator *element) {
    UA_Parsed_Element_List *temp = create_next_operator_element(global);
    create_element_reference(for_operator_reference, &temp->ref, "for_reference_");
    memcpy(&temp->element.oper.nbr_children, &element->nbr_children, sizeof(size_t));
    temp->element.oper.filter = element->filter;
    temp->element.oper.children = (UA_Parsed_Operand*)
        UA_calloc(element->nbr_children, sizeof(UA_Parsed_Operand));
    copy_children(*element, temp);
    save_string(temp->ref, ref);
    clear_operand_list(element->children, element->nbr_children);
    free(element->children);
}

void
change_element_reference(UA_Element_List *global, char *element_name,
                         char *new_element_reference) {
    UA_Parsed_Element_List *temp = get_element_by_reference(global, &element_name);
    temp->ref = (char*) UA_realloc(temp->ref, (strlen(new_element_reference)+1)*sizeof(char));
    memset(temp->ref, 0, (strlen(new_element_reference)+1)*sizeof(char));
    strcpy(temp->ref, new_element_reference);
    free(new_element_reference);
    free(element_name);
}

void
add_in_list_children(UA_Element_List *global, UA_Parsed_Operand *oper) {
    UA_Parsed_Element_List *temp = get_last_element_from_list(global);
    temp->element.oper.nbr_children++;
    temp->element.oper.children = (UA_Parsed_Operand*)
        UA_realloc(temp->element.oper.children,
                   temp->element.oper.nbr_children*sizeof(UA_Parsed_Operand));
    memcpy(&temp->element.oper.children[temp->element.oper.nbr_children-1], oper,
           sizeof(UA_Parsed_Operand));
}

void
create_in_list_operator(UA_Element_List *global, UA_Parsed_Operand *oper,
                        char *element_ref) {
    UA_Parsed_Element_List *temp = create_next_operator_element(global);
    save_string(element_ref, &temp->ref);
    temp->element.oper.filter = UA_FILTEROPERATOR_INLIST;
    free(element_ref);
    add_in_list_children(global, oper);
}

void
append_string(char **string, char *yytext) {
    size_t old_size = (*string)? strlen(*string):0;
    size_t new_size = old_size+strlen(yytext)+1;
    *string = (char *)UA_realloc(*string, new_size*sizeof(char));
    memset((void*)((char*)(*string) + old_size),0, (new_size-old_size)*sizeof(char));
    strcat(*string, yytext);
}

void
set_up_variant_from_bool(char *yytext, UA_Variant *litvalue) {
    UA_Boolean val;
    if(strcmp(yytext, "false") == 0 || strcmp(yytext, "False") == 0 ||
       strcmp(yytext, "0") == 0) {
        val = false;
        UA_Variant_setScalarCopy(litvalue, &val, &UA_TYPES[UA_TYPES_BOOLEAN]);
    }
    else if(strcmp(yytext, "true") == 0 || strcmp(yytext, "True") == 0 ||
            strcmp(yytext, "1") == 0) {
        val = true;
        UA_Variant_setScalarCopy(litvalue, &val, &UA_TYPES[UA_TYPES_BOOLEAN]);
    }
}

void
set_up_variant_from_string(char *yytext, UA_Variant *litvalue) {
    UA_String val = UA_String_fromChars(yytext);
    UA_Variant_setScalarCopy(litvalue, &val, &UA_TYPES[UA_TYPES_STRING]);
    UA_String_clear(&val);
}

void
set_up_variant_from_bstring(char *yytext, UA_Variant *litvalue) {
    UA_ByteString val = UA_BYTESTRING(yytext);
    UA_Variant_setScalarCopy(litvalue, &val, &UA_TYPES[UA_TYPES_BYTESTRING]);
}

void
set_up_variant_from_float(char *yytext, UA_Variant *litvalue) {
    UA_Float val = (UA_Float) strtod(yytext, NULL);
    UA_Variant_setScalarCopy(litvalue, &val, &UA_TYPES[UA_TYPES_FLOAT]);
}

void
set_up_variant_from_double(char *yytext, UA_Variant *litvalue) {
    UA_Double val = (UA_Double) strtod(yytext, NULL);
    UA_Variant_setScalarCopy(litvalue, &val, &UA_TYPES[UA_TYPES_DOUBLE]);
}

void
set_up_variant_from_sbyte(char *yytext, UA_Variant *litvalue) {
    UA_SByte val = (UA_SByte) atoi(yytext);
    UA_Variant_setScalarCopy(litvalue, &val, &UA_TYPES[UA_TYPES_SBYTE]);
}

void
set_up_variant_from_statuscode(char *yytext, UA_Variant *litvalue) {
    UA_StatusCode val = (uint32_t) atoi(yytext);
    UA_Variant_setScalarCopy(litvalue, &val, &UA_TYPES[UA_TYPES_STATUSCODE]);
}

UA_StatusCode
set_up_variant_from_expnodeid(char *yytext, UA_Variant *litvalue, UA_StatusCode status) {
    if(status != UA_STATUSCODE_GOOD)
        return status;
    UA_ExpandedNodeId val;
    UA_ExpandedNodeId_init(&val);
    UA_String temp = UA_String_fromChars(yytext);
    UA_StatusCode retval = UA_ExpandedNodeId_parse(&val, temp);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                     "Failed to parse the ExpandedNodeId %s", UA_StatusCode_name(retval));
        UA_ExpandedNodeId_clear(&val);
        UA_String_clear(&temp);
        return retval;
    }
    UA_Variant_setScalarCopy(litvalue, &val, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
    UA_ExpandedNodeId_clear(&val);
    UA_String_clear(&temp);
    return UA_STATUSCODE_GOOD;
}

void
set_up_variant_from_time(const char *yytext, UA_Variant *litvalue) {
    UA_DateTime val;
    UA_String str = UA_STRING((char*)(uintptr_t)yytext);
    UA_StatusCode ret = UA_decodeJson(&str, &val, &UA_TYPES[UA_TYPES_DATETIME], NULL);
    if(ret == UA_STATUSCODE_GOOD)
        UA_Variant_setScalarCopy(litvalue, &val, &UA_TYPES[UA_TYPES_DATETIME]);
}

void
set_up_variant_from_byte(char *yytext, UA_Variant *litvalue) {
    UA_Byte val = (UA_Byte) atoi(yytext);
    UA_Variant_setScalarCopy(litvalue, &val, &UA_TYPES[UA_TYPES_BYTE]);
}

UA_StatusCode
set_up_variant_from_qname(char *str, UA_Variant *litvalue,
                          UA_StatusCode status) {
    if(status != UA_STATUSCODE_GOOD)
        return status;
    UA_RelativePath path;
    UA_String parsed_string = UA_String_fromChars(str);
    UA_StatusCode ret_val = UA_RelativePath_parse(&path, parsed_string);
    if(ret_val != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND,
                       "Failed to parse the RelativePath %s", UA_StatusCode_name(ret_val));
        UA_String_clear(&parsed_string);
        UA_RelativePath_clear(&path);
        return ret_val;
    }
    UA_Variant_setScalarCopy(litvalue, &path.elements[0].targetName,
                             &UA_TYPES[UA_TYPES_QUALIFIEDNAME]);
    UA_String_clear(&parsed_string);
    UA_RelativePath_clear(&path);
    return UA_STATUSCODE_GOOD;
}

void
set_up_variant_from_guid(char *yytext, UA_Variant *litvalue) {
    UA_Guid val;
    UA_String str = UA_String_fromChars(yytext);
    UA_Guid_parse(&val, str);
    UA_Variant_setScalarCopy(litvalue, &val, &UA_TYPES[UA_TYPES_GUID]);
    UA_String_clear(&str);
}

void
set_up_variant_from_int64(char *yytext, UA_Variant *litvalue) {
    UA_Int64 val = (UA_Int64) atoi(yytext);
    UA_Variant_setScalarCopy(litvalue, &val, &UA_TYPES[UA_TYPES_INT64]);
}

void
set_up_variant_from_localized(char *yytext, UA_Variant *litvalue) {
    UA_LocalizedText val = UA_LOCALIZEDTEXT("en-us", yytext);
    UA_Variant_setScalarCopy(litvalue, &val, &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]);
}

void
set_up_variant_from_uint16(char *yytext, UA_Variant *litvalue) {
    UA_UInt16 val = (UA_UInt16) atoi(yytext);
    UA_Variant_setScalarCopy(litvalue, &val, &UA_TYPES[UA_TYPES_UINT16]);
}

void
set_up_variant_from_uint32(char *yytext, UA_Variant *litvalue) {
    UA_UInt32 val = (UA_UInt32) atoi(yytext);
    UA_Variant_setScalarCopy(litvalue, &val, &UA_TYPES[UA_TYPES_UINT32]);
}

void
set_up_variant_from_uint64(char *yytext, UA_Variant *litvalue) {
    UA_UInt64 val = (UA_UInt64) atoi(yytext);
    UA_Variant_setScalarCopy(litvalue, &val, &UA_TYPES[UA_TYPES_INT64]);
}

void
set_up_variant_from_int16(char *yytext, UA_Variant *litvalue) {
    UA_Int16 val = (UA_Int16) atoi(yytext);
    UA_Variant_setScalarCopy(litvalue, &val, &UA_TYPES[UA_TYPES_INT16]);
}

void
set_up_variant_from_int32(char *yytext, UA_Variant *litvalue) {
    UA_Int32 val = (UA_Int32) atoi(yytext);
    UA_Variant_setScalarCopy(litvalue, &val, &UA_TYPES[UA_TYPES_INT32]);
}

/**** amalgamated original file "/src/util/ua_eventfilter_grammar.c" ****/

/* A recursive-descent parser generated by peg 0.1.18 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define YYRULECOUNT 36
#line 1 "ua_eventfilter_grammar.leg"

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2023-2024 (c) Fraunhofer IOSB (Author: Florian Düwel)
 */


/*
 *  Lexing and parsing of OPC UA eventfilter. These are helper functions that
 *  are not required by the SDk internally. But they are useful for users who want to create
 *  eventfilter from human readable strings.
 *
 *  This compilation unit uses the leg parser generators (https://www.piumarta.com/software/peg/peg.1.html).
 *  The final C source is generated with the following script:
 *
 *  leg -Po ua_eventfilter_grammar.c ua_eventfilter_grammar.leg
 *
 *  However, the generated eventfilter_parser_grammar.c file creates some compiler warnings.
 *  Here is an Explanation on how to remove these warnings:
 *  windows build:
 *
 *   1 #define YY_INPUT(yyctx, buf, result, max_size) \
 *   2 {                                              \
 *   3  if(yyctx->input.length <= yyctx->pos) {      \
 *   4      result = 0;                              \
 *   5  } else {                                     \
 *   6      result = ((int) yyctx->input.length) - yyctx->pos;\
 *   7      if(result > max_size)                     \
 *   8          result = max_size;                   \
 *   9      memcpy(buf, &yyctx->input.data[yyctx->pos], result); \
 *   10      yyctx->pos += result;                    \
 *   11  }                                            \
 *   12}
 *   replace: yyctx->input.length with  ((int) yyctx->input.length) in line 6
 *
 *   13 YY_LOCAL(void) yyPush(yycontext *yy, char *text, int count)
 *   14 {
 *   15   yy->__val += count;
 *   16   while (yy->__valslen <= yy->__val - yy->__vals)
 *   17     {
 *   18       long offset= (long)( yy->__val - yy->__vals);
 *   19       yy->__valslen *= 2;
 *   20       yy->__vals= (YYSTYPE *)YY_REALLOC(yy, yy->__vals, sizeof(YYSTYPE) * yy->__valslen);
 *   21       yy->__val= yy->__vals + offset;
 *   22     }
 *   23 }
 *   replace: long offset= yy->__val - yy->__vals; with long offset= (long)( yy->__val - yy->__vals); in line 18
 *
 *   linux build:
 *
 *   replace YY_PARSE(int) YYPARSEFROM(YY_CTX_PARAM_ yyrule yystart) with YY_PARSE(static int) YYPARSEFROM(YY_CTX_PARAM_ yyrule yystart)
 *   replace YY_PARSE(int) YYPARSE(YY_CTX_PARAM) with YY_PARSE(static int) YYPARSE(YY_CTX_PARAM)
 *   replace YY_PARSE(yycontext *) YYRELEASE(yycontext *yyctx) with YY_PARSE(static yycontext *) YYRELEASE(yycontext *yyctx)
 *
 *   remove:
 *   YY_LOCAL(int) yyAccept(yycontext *yy, int tp0)
 *   {
 *     if (tp0)
 *       {
 *         fprintf(stderr, "accept denied at %d\n", tp0);
 *         return 0;
 *       }
 *     else
 *       {
 *         yyDone(yy);
 *         yyCommit(yy);
 *       }
 *     return 1;
 *   }
 *
 *  In order that users of the SDK don't need to use the leg parser, always commit a recent
 *  eventfilter_parser_grammar.c if changes are made to the lexer.
 */


#define YY_CTX_LOCAL 1
#define YY_CTX_MEMBERS                  \
    UA_Parsed_EventFilter parsedFilter; \
    UA_String input;                    \
    UA_UInt32 pos;                      \
    UA_Counters ctr;                    \
    UA_Element_List global;             \
    UA_Local_Operand operand;

#define YY_INPUT(yyctx, buf, result, max_size) \
{                                              \
  if(yyctx->input.length <= yyctx->pos) {      \
      result = 0;                              \
  } else {                                     \
      result = ((int) yyctx->input.length) - yyctx->pos;\
      if(result > max_size)                     \
          result = max_size;                   \
      memcpy(buf, &yyctx->input.data[yyctx->pos], result); \
      yyctx->pos += result;                    \
  }                                            \
}



union value{
    char *str;
    UA_Parsed_Operand operand;
    UA_Parsed_Operator element;
};

# define YYSTYPE union value

#ifndef YY_MALLOC
#define YY_MALLOC(C, N)		malloc(N)
#endif
#ifndef YY_REALLOC
#define YY_REALLOC(C, P, N)	realloc(P, N)
#endif
#ifndef YY_FREE
#define YY_FREE(C, P)		free(P)
#endif
#ifndef YY_LOCAL
#define YY_LOCAL(T)	static T
#endif
#ifndef YY_ACTION
#define YY_ACTION(T)	static T
#endif
#ifndef YY_RULE
#define YY_RULE(T)	static T
#endif
#ifndef YY_PARSE
#define YY_PARSE(T)	T
#endif
#ifndef YYPARSE
#define YYPARSE		yyparse
#endif
#ifndef YYPARSEFROM
#define YYPARSEFROM	yyparsefrom
#endif
#ifndef YYRELEASE
#define YYRELEASE	yyrelease
#endif
#ifndef YY_BEGIN
#define YY_BEGIN	( yy->__begin= yy->__pos, 1)
#endif
#ifndef YY_END
#define YY_END		( yy->__end= yy->__pos, 1)
#endif
#ifdef YY_DEBUG
# define yyprintf(args)	fprintf args
#else
# define yyprintf(args)
#endif
#ifndef YYSTYPE
#define YYSTYPE	int
#endif
#ifndef YY_STACK_SIZE
#define YY_STACK_SIZE 128
#endif

#ifndef YY_BUFFER_SIZE
#define YY_BUFFER_SIZE 1024
#endif

#ifndef YY_PART

typedef struct _yycontext yycontext;
typedef void (*yyaction)(yycontext *yy, char *yytext, int yyleng);
typedef struct _yythunk { int begin, end;  yyaction  action;  struct _yythunk *next; } yythunk;

struct _yycontext {
  char     *__buf;
  int       __buflen;
  int       __pos;
  int       __limit;
  char     *__text;
  int       __textlen;
  int       __begin;
  int       __end;
  int       __textmax;
  yythunk  *__thunks;
  int       __thunkslen;
  int       __thunkpos;
  YYSTYPE   __;
  YYSTYPE  *__val;
  YYSTYPE  *__vals;
  int       __valslen;
#ifdef YY_CTX_MEMBERS
  YY_CTX_MEMBERS
#endif
};

#ifdef YY_CTX_LOCAL
#define YY_CTX_PARAM_	yycontext *yyctx,
#define YY_CTX_PARAM	yycontext *yyctx
#define YY_CTX_ARG_	yyctx,
#define YY_CTX_ARG	yyctx
#ifndef YY_INPUT
#define YY_INPUT(yy, buf, result, max_size)		\
  {							\
    int yyc= getchar();					\
    result= (EOF == yyc) ? 0 : (*(buf)= yyc, 1);	\
    yyprintf((stderr, "<%c>", yyc));			\
  }
#endif
#else
#define YY_CTX_PARAM_
#define YY_CTX_PARAM
#define YY_CTX_ARG_
#define YY_CTX_ARG
yycontext _yyctx= { 0, 0 };
yycontext *yyctx= &_yyctx;
#ifndef YY_INPUT
#define YY_INPUT(buf, result, max_size)			\
  {							\
    int yyc= getchar();					\
    result= (EOF == yyc) ? 0 : (*(buf)= yyc, 1);	\
    yyprintf((stderr, "<%c>", yyc));			\
  }
#endif
#endif

YY_LOCAL(int) yyrefill(yycontext *yy)
{
  int yyn;
  while (yy->__buflen - yy->__pos < 512)
    {
      yy->__buflen *= 2;
      yy->__buf= (char *)YY_REALLOC(yy, yy->__buf, yy->__buflen);
    }
#ifdef YY_CTX_LOCAL
  YY_INPUT(yy, (yy->__buf + yy->__pos), yyn, (yy->__buflen - yy->__pos));
#else
  YY_INPUT((yy->__buf + yy->__pos), yyn, (yy->__buflen - yy->__pos));
#endif
  if (!yyn) return 0;
  yy->__limit += yyn;
  return 1;
}

YY_LOCAL(int) yymatchDot(yycontext *yy)
{
  if (yy->__pos >= yy->__limit && !yyrefill(yy)) return 0;
  ++yy->__pos;
  return 1;
}

YY_LOCAL(int) yymatchChar(yycontext *yy, int c)
{
  if (yy->__pos >= yy->__limit && !yyrefill(yy)) return 0;
  if ((unsigned char)yy->__buf[yy->__pos] == c)
    {
      ++yy->__pos;
      yyprintf((stderr, "  ok   yymatchChar(yy, %c) @ %s\n", c, yy->__buf+yy->__pos));
      return 1;
    }
  yyprintf((stderr, "  fail yymatchChar(yy, %c) @ %s\n", c, yy->__buf+yy->__pos));
  return 0;
}

YY_LOCAL(int) yymatchString(yycontext *yy, const char *s)
{
  int yysav= yy->__pos;
  while (*s)
    {
      if (yy->__pos >= yy->__limit && !yyrefill(yy)) return 0;
      if (yy->__buf[yy->__pos] != *s)
        {
          yy->__pos= yysav;
          return 0;
        }
      ++s;
      ++yy->__pos;
    }
  return 1;
}

YY_LOCAL(int) yymatchClass(yycontext *yy, unsigned char *bits)
{
  int c;
  if (yy->__pos >= yy->__limit && !yyrefill(yy)) return 0;
  c= (unsigned char)yy->__buf[yy->__pos];
  if (bits[c >> 3] & (1 << (c & 7)))
    {
      ++yy->__pos;
      yyprintf((stderr, "  ok   yymatchClass @ %s\n", yy->__buf+yy->__pos));
      return 1;
    }
  yyprintf((stderr, "  fail yymatchClass @ %s\n", yy->__buf+yy->__pos));
  return 0;
}

YY_LOCAL(void) yyDo(yycontext *yy, yyaction action, int begin, int end)
{
  while (yy->__thunkpos >= yy->__thunkslen)
    {
      yy->__thunkslen *= 2;
      yy->__thunks= (yythunk *)YY_REALLOC(yy, yy->__thunks, sizeof(yythunk) * yy->__thunkslen);
    }
  yy->__thunks[yy->__thunkpos].begin=  begin;
  yy->__thunks[yy->__thunkpos].end=    end;
  yy->__thunks[yy->__thunkpos].action= action;
  ++yy->__thunkpos;
}

YY_LOCAL(int) yyText(yycontext *yy, int begin, int end)
{
  int yyleng= end - begin;
  if (yyleng <= 0)
    yyleng= 0;
  else
    {
      while (yy->__textlen < (yyleng + 1))
	{
	  yy->__textlen *= 2;
	  yy->__text= (char *)YY_REALLOC(yy, yy->__text, yy->__textlen);
	}
      memcpy(yy->__text, yy->__buf + begin, yyleng);
    }
  yy->__text[yyleng]= '\0';
  return yyleng;
}

YY_LOCAL(void) yyDone(yycontext *yy)
{
  int pos;
  for (pos= 0;  pos < yy->__thunkpos;  ++pos)
    {
      yythunk *thunk= &yy->__thunks[pos];
      int yyleng= thunk->end ? yyText(yy, thunk->begin, thunk->end) : thunk->begin;
      yyprintf((stderr, "DO [%d] %p %s\n", pos, thunk->action, yy->__text));
      thunk->action(yy, yy->__text, yyleng);
    }
  yy->__thunkpos= 0;
}

YY_LOCAL(void) yyCommit(yycontext *yy)
{
  if ((yy->__limit -= yy->__pos))
    {
      memmove(yy->__buf, yy->__buf + yy->__pos, yy->__limit);
    }
  yy->__begin -= yy->__pos;
  yy->__end -= yy->__pos;
  yy->__pos= yy->__thunkpos= 0;
}

YY_LOCAL(void) yyPush(yycontext *yy, char *text, int count)
{
  yy->__val += count;
  while (yy->__valslen <= yy->__val - yy->__vals)
    {
        long offset= (long)( yy->__val - yy->__vals);
        yy->__valslen *= 2;
      yy->__vals= (YYSTYPE *)YY_REALLOC(yy, yy->__vals, sizeof(YYSTYPE) * yy->__valslen);
      yy->__val= yy->__vals + offset;
    }
}
YY_LOCAL(void) yyPop(yycontext *yy, char *text, int count)   { yy->__val -= count; }
YY_LOCAL(void) yySet(yycontext *yy, char *text, int count)   { yy->__val[count]= yy->__; }

#endif /* YY_PART */

#define	YYACCEPT	yyAccept(yy, yythunkpos0)

YY_RULE(int) yy_Enter(yycontext *yy); /* 36 */
YY_RULE(int) yy_comment(yycontext *yy); /* 35 */
YY_RULE(int) yy_Space(yycontext *yy); /* 34 */
YY_RULE(int) yy_References(yycontext *yy); /* 33 */
YY_RULE(int) yy_StringElement(yycontext *yy); /* 32 */
YY_RULE(int) yy_JsonValue(yycontext *yy); /* 31 */
YY_RULE(int) yy_JsonArray(yycontext *yy); /* 30 */
YY_RULE(int) yy_JsonElement(yycontext *yy); /* 29 */
YY_RULE(int) yy_JsonObject(yycontext *yy); /* 28 */
YY_RULE(int) yy_ReferenceType(yycontext *yy); /* 27 */
YY_RULE(int) yy_Literal(yycontext *yy); /* 26 */
YY_RULE(int) yy_ParsedJsonString(yycontext *yy); /* 25 */
YY_RULE(int) yy_NumericRange(yycontext *yy); /* 24 */
YY_RULE(int) yy_QualifiedName(yycontext *yy); /* 23 */
YY_RULE(int) yy_ParsedString(yycontext *yy); /* 22 */
YY_RULE(int) yy_SingleOperatorType(yycontext *yy); /* 21 */
YY_RULE(int) yy_TwoOperandsOperatorType(yycontext *yy); /* 20 */
YY_RULE(int) yy_NodeId(yycontext *yy); /* 19 */
YY_RULE(int) yy_Operand(yycontext *yy); /* 18 */
YY_RULE(int) yy_ReferenceElement(yycontext *yy); /* 17 */
YY_RULE(int) yy_ReferencedOperator(yycontext *yy); /* 16 */
YY_RULE(int) yy_OperatorInstance(yycontext *yy); /* 15 */
YY_RULE(int) yy_LiteralOperand(yycontext *yy); /* 14 */
YY_RULE(int) yy_ForOperator(yycontext *yy); /* 13 */
YY_RULE(int) yy_ElementOperand(yycontext *yy); /* 12 */
YY_RULE(int) yy_Child_2(yycontext *yy); /* 11 */
YY_RULE(int) yy_Child_1(yycontext *yy); /* 10 */
YY_RULE(int) yy_BranchStructure(yycontext *yy); /* 9 */
YY_RULE(int) yy_ReferencedElement(yycontext *yy); /* 8 */
YY_RULE(int) yy_SingleBranchStructure(yycontext *yy); /* 7 */
YY_RULE(int) yy_SimpleAttributeOperand(yycontext *yy); /* 6 */
YY_RULE(int) yy__(yycontext *yy); /* 5 */
YY_RULE(int) yy_Select(yycontext *yy); /* 4 */
YY_RULE(int) yy_ContentFilter(yycontext *yy); /* 3 */
YY_RULE(int) yy_SelectClauses(yycontext *yy); /* 2 */
YY_RULE(int) yy_EventFilter(yycontext *yy); /* 1 */

YY_ACTION(void) yy_1_ReferenceElement(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_1_ReferenceElement\n"));
  {
  save_string(yytext, &__.str);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_1_ParsedJsonString(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_1_ParsedJsonString\n"));
  {
  yy->parsedFilter.status = create_literal_operand(yytext, &yy->operand.literal, yy->parsedFilter.status);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_26_Literal(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_26_Literal\n"));
  {
  set_up_variant_from_qname(yytext, &yy->operand.literal.value, yy->parsedFilter.status);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_25_Literal(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_25_Literal\n"));
  {
  set_up_variant_from_double(yytext, &yy->operand.literal.value);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_24_Literal(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_24_Literal\n"));
  {
  set_up_variant_from_bool(yytext, &yy->operand.literal.value);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_23_Literal(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_23_Literal\n"));
  {
  set_up_variant_from_string(yytext, &yy->operand.literal.value);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_22_Literal(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_22_Literal\n"));
  {
  set_up_variant_from_int64(yytext, &yy->operand.literal.value);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_21_Literal(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_21_Literal\n"));
  {
  set_up_variant_from_nodeId(&yy->operand.id, &yy->operand.literal.value);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_20_Literal(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_20_Literal\n"));
  {
  set_up_variant_from_localized(yytext, &yy->operand.literal.value);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_19_Literal(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_19_Literal\n"));
  {
  yy->parsedFilter.status = set_up_variant_from_qname(yytext, &yy->operand.literal.value, yy->parsedFilter.status);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_18_Literal(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_18_Literal\n"));
  {
  yy->parsedFilter.status = set_up_variant_from_expnodeid(yytext, &yy->operand.literal.value, yy->parsedFilter.status);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_17_Literal(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_17_Literal\n"));
  {
  set_up_variant_from_statuscode(yytext, &yy->operand.literal.value);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_16_Literal(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_16_Literal\n"));
  {
  set_up_variant_from_bstring(yytext, &yy->operand.literal.value);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_15_Literal(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_15_Literal\n"));
  {
  set_up_variant_from_guid(yytext, &yy->operand.literal.value);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_14_Literal(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_14_Literal\n"));
  {
  set_up_variant_from_time(yytext, &yy->operand.literal.value);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_13_Literal(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_13_Literal\n"));
  {
  set_up_variant_from_byte(yytext, &yy->operand.literal.value);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_12_Literal(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_12_Literal\n"));
  {
  set_up_variant_from_sbyte(yytext, &yy->operand.literal.value);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_11_Literal(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_11_Literal\n"));
  {
  set_up_variant_from_nodeId(&yy->operand.id, &yy->operand.literal.value);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_10_Literal(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_10_Literal\n"));
  {
  set_up_variant_from_float(yytext, &yy->operand.literal.value);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_9_Literal(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_9_Literal\n"));
  {
  set_up_variant_from_double(yytext, &yy->operand.literal.value);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_8_Literal(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_8_Literal\n"));
  {
  set_up_variant_from_uint64(yytext, &yy->operand.literal.value);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_7_Literal(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_7_Literal\n"));
  {
  set_up_variant_from_uint32(yytext, &yy->operand.literal.value);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_6_Literal(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_6_Literal\n"));
  {
  set_up_variant_from_uint16(yytext, &yy->operand.literal.value);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_5_Literal(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_5_Literal\n"));
  {
  set_up_variant_from_int64(yytext, &yy->operand.literal.value);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_4_Literal(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_4_Literal\n"));
  {
  set_up_variant_from_int16(yytext, &yy->operand.literal.value);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_3_Literal(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_3_Literal\n"));
  {
  set_up_variant_from_bool(yytext, &yy->operand.literal.value);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_2_Literal(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_2_Literal\n"));
  {
  set_up_variant_from_string(yytext, &yy->operand.literal.value);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_1_Literal(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_1_Literal\n"));
  {
  set_up_variant_from_int32(yytext, &yy->operand.literal.value);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_1_LiteralOperand(yycontext *yy, char *yytext, int yyleng)
{
#define litValue yy->__val[-1]
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_1_LiteralOperand\n"));
  {
  handle_literal_operand(&__.operand, &yy->operand.literal);;
  }
#undef yythunkpos
#undef yypos
#undef yy
#undef litValue
}
YY_ACTION(void) yy_7_NodeId(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_7_NodeId\n"));
  {
  yy->parsedFilter.status = create_nodeId_from_string(yy->operand.str, &yy->operand.id, yy->parsedFilter.status);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_6_NodeId(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_6_NodeId\n"));
  {
  append_string(&yy->operand.str, yytext);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_5_NodeId(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_5_NodeId\n"));
  {
  append_string(&yy->operand.str, yytext);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_4_NodeId(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_4_NodeId\n"));
  {
  append_string(&yy->operand.str, yytext);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_3_NodeId(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_3_NodeId\n"));
  {
  append_string(&yy->operand.str, yytext);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_2_NodeId(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_2_NodeId\n"));
  {
  append_string(&yy->operand.str, yytext);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_1_NodeId(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_1_NodeId\n"));
  {
  append_string(&yy->operand.str, yytext);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_5_SimpleAttributeOperand(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_5_SimpleAttributeOperand\n"));
  {
  handle_sao(&yy->operand.sao, &__.operand);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_4_SimpleAttributeOperand(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_4_SimpleAttributeOperand\n"));
  {
  yy->operand.sao.indexRange = UA_String_fromChars(yytext); UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Index Range in SimpleAttributeOperands is not supported in the current implementation");;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_3_SimpleAttributeOperand(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_3_SimpleAttributeOperand\n"));
  {
  yy->operand.sao.attributeId = (UA_UInt32) atoi(yytext);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_2_SimpleAttributeOperand(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_2_SimpleAttributeOperand\n"));
  {
  yy->parsedFilter.status = set_up_browsepath(&yy->operand.sao.browsePath, &yy->operand.sao.browsePathSize, yytext, yy->parsedFilter.status);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_1_SimpleAttributeOperand(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_1_SimpleAttributeOperand\n"));
  {
  set_up_typeid(&yy->operand);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_1_Operand(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_1_Operand\n"));
  {
  handle_elementoperand(&__.operand, yytext);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_9_TwoOperandsOperatorType(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_9_TwoOperandsOperatorType\n"));
  {
  __.element.filter = UA_FILTEROPERATOR_BITWISEOR;;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_8_TwoOperandsOperatorType(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_8_TwoOperandsOperatorType\n"));
  {
  __.element.filter = UA_FILTEROPERATOR_BITWISEAND;;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_7_TwoOperandsOperatorType(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_7_TwoOperandsOperatorType\n"));
  {
  __.element.filter = UA_FILTEROPERATOR_CAST;;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_6_TwoOperandsOperatorType(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_6_TwoOperandsOperatorType\n"));
  {
  __.element.filter = UA_FILTEROPERATOR_LIKE;;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_5_TwoOperandsOperatorType(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_5_TwoOperandsOperatorType\n"));
  {
  __.element.filter = UA_FILTEROPERATOR_LESSTHANOREQUAL;;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_4_TwoOperandsOperatorType(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_4_TwoOperandsOperatorType\n"));
  {
  __.element.filter = UA_FILTEROPERATOR_GREATERTHANOREQUAL;;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_3_TwoOperandsOperatorType(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_3_TwoOperandsOperatorType\n"));
  {
  __.element.filter = UA_FILTEROPERATOR_LESSTHAN;;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_2_TwoOperandsOperatorType(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_2_TwoOperandsOperatorType\n"));
  {
  __.element.filter = UA_FILTEROPERATOR_EQUALS;;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_1_TwoOperandsOperatorType(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_1_TwoOperandsOperatorType\n"));
  {
  __.element.filter = UA_FILTEROPERATOR_GREATERTHAN;;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_4_SingleOperatorType(yycontext *yy, char *yytext, int yyleng)
{
#define oper yy->__val[-1]
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_4_SingleOperatorType\n"));
  {
  add_child_operands(&oper.operand, 1, &__.element, UA_FILTEROPERATOR_OFTYPE);;
  }
#undef yythunkpos
#undef yypos
#undef yy
#undef oper
}
YY_ACTION(void) yy_3_SingleOperatorType(yycontext *yy, char *yytext, int yyleng)
{
#define oper yy->__val[-1]
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_3_SingleOperatorType\n"));
  {
  handle_oftype_nodeId(&__.element, &yy->operand.id);;
  }
#undef yythunkpos
#undef yypos
#undef yy
#undef oper
}
YY_ACTION(void) yy_2_SingleOperatorType(yycontext *yy, char *yytext, int yyleng)
{
#define oper yy->__val[-1]
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_2_SingleOperatorType\n"));
  {
  add_child_operands(&oper.operand, 1, &__.element, UA_FILTEROPERATOR_ISNULL);;
  }
#undef yythunkpos
#undef yypos
#undef yy
#undef oper
}
YY_ACTION(void) yy_1_SingleOperatorType(yycontext *yy, char *yytext, int yyleng)
{
#define oper yy->__val[-1]
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_1_SingleOperatorType\n"));
  {
  add_child_operands(&oper.operand, 1, &__.element, UA_FILTEROPERATOR_NOT);;
  }
#undef yythunkpos
#undef yypos
#undef yy
#undef oper
}
YY_ACTION(void) yy_2_OperatorInstance(yycontext *yy, char *yytext, int yyleng)
{
#define oper_3 yy->__val[-1]
#define oper_2 yy->__val[-2]
#define operator yy->__val[-3]
#define oper_1 yy->__val[-4]
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_2_OperatorInstance\n"));
  {
  handle_between_operator(&__.element, &oper_1.operand, &oper_2.operand, &oper_3.operand);;
  }
#undef yythunkpos
#undef yypos
#undef yy
#undef oper_3
#undef oper_2
#undef operator
#undef oper_1
}
YY_ACTION(void) yy_1_OperatorInstance(yycontext *yy, char *yytext, int yyleng)
{
#define oper_3 yy->__val[-1]
#define oper_2 yy->__val[-2]
#define operator yy->__val[-3]
#define oper_1 yy->__val[-4]
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_1_OperatorInstance\n"));
  {
  handle_two_operands_operator(&__.element, &oper_1.operand, &oper_2.operand, &operator.element.filter);;
  }
#undef yythunkpos
#undef yypos
#undef yy
#undef oper_3
#undef oper_2
#undef operator
#undef oper_1
}
YY_ACTION(void) yy_5_ReferencedOperator(yycontext *yy, char *yytext, int yyleng)
{
#define oper yy->__val[-1]
#define op1 yy->__val[-2]
#define operator yy->__val[-3]
#define ref yy->__val[-4]
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_5_ReferencedOperator\n"));
  {
  add_in_list_children(&yy->global, &oper.operand);;
  }
#undef yythunkpos
#undef yypos
#undef yy
#undef oper
#undef op1
#undef operator
#undef ref
}
YY_ACTION(void) yy_4_ReferencedOperator(yycontext *yy, char *yytext, int yyleng)
{
#define oper yy->__val[-1]
#define op1 yy->__val[-2]
#define operator yy->__val[-3]
#define ref yy->__val[-4]
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_4_ReferencedOperator\n"));
  {
  add_in_list_children(&yy->global, &oper.operand);;
  }
#undef yythunkpos
#undef yypos
#undef yy
#undef oper
#undef op1
#undef operator
#undef ref
}
YY_ACTION(void) yy_3_ReferencedOperator(yycontext *yy, char *yytext, int yyleng)
{
#define oper yy->__val[-1]
#define op1 yy->__val[-2]
#define operator yy->__val[-3]
#define ref yy->__val[-4]
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_3_ReferencedOperator\n"));
  {
  create_in_list_operator(&yy->global, &oper.operand, ref.str);;
  }
#undef yythunkpos
#undef yypos
#undef yy
#undef oper
#undef op1
#undef operator
#undef ref
}
YY_ACTION(void) yy_2_ReferencedOperator(yycontext *yy, char *yytext, int yyleng)
{
#define oper yy->__val[-1]
#define op1 yy->__val[-2]
#define operator yy->__val[-3]
#define ref yy->__val[-4]
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_2_ReferencedOperator\n"));
  {
  change_element_reference(&yy->global, op1.str, ref.str);;
  }
#undef yythunkpos
#undef yypos
#undef yy
#undef oper
#undef op1
#undef operator
#undef ref
}
YY_ACTION(void) yy_1_ReferencedOperator(yycontext *yy, char *yytext, int yyleng)
{
#define oper yy->__val[-1]
#define op1 yy->__val[-2]
#define operator yy->__val[-3]
#define ref yy->__val[-4]
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_1_ReferencedOperator\n"));
  {
  add_new_operator(&yy->global, ref.str, &operator.element);;
  }
#undef yythunkpos
#undef yypos
#undef yy
#undef oper
#undef op1
#undef operator
#undef ref
}
YY_ACTION(void) yy_2_ReferencedElement(yycontext *yy, char *yytext, int yyleng)
{
#define oper yy->__val[-1]
#define ref yy->__val[-2]
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_2_ReferencedElement\n"));
  {
  create_nodeid_element(&yy->global, &yy->operand.id, ref.str);;
  }
#undef yythunkpos
#undef yypos
#undef yy
#undef oper
#undef ref
}
YY_ACTION(void) yy_1_ReferencedElement(yycontext *yy, char *yytext, int yyleng)
{
#define oper yy->__val[-1]
#define ref yy->__val[-2]
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_1_ReferencedElement\n"));
  {
  create_next_operand_element(&yy->global, &oper.operand, ref.str);;
  }
#undef yythunkpos
#undef yypos
#undef yy
#undef oper
#undef ref
}
YY_ACTION(void) yy_1_ForOperator(yycontext *yy, char *yytext, int yyleng)
{
#define operator yy->__val[-1]
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_1_ForOperator\n"));
  {
  handle_for_operator(&yy->global, &yy->ctr.for_operator_reference, &__.str, &operator.element);;
  }
#undef yythunkpos
#undef yypos
#undef yy
#undef operator
}
YY_ACTION(void) yy_3_Child_2(yycontext *yy, char *yytext, int yyleng)
{
#define oper yy->__val[-1]
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_3_Child_2\n"));
  {
  add_operand_from_branch(&__.str, &yy->ctr.operand_ctr, &oper.operand, &yy->global);;
  }
#undef yythunkpos
#undef yypos
#undef yy
#undef oper
}
YY_ACTION(void) yy_2_Child_2(yycontext *yy, char *yytext, int yyleng)
{
#define oper yy->__val[-1]
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_2_Child_2\n"));
  {
  add_operand_from_branch(&__.str, &yy->ctr.operand_ctr, &oper.operand, &yy->global);;
  }
#undef yythunkpos
#undef yypos
#undef yy
#undef oper
}
YY_ACTION(void) yy_1_Child_2(yycontext *yy, char *yytext, int yyleng)
{
#define oper yy->__val[-1]
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_1_Child_2\n"));
  {
  save_string(yytext, &__.str);;
  }
#undef yythunkpos
#undef yypos
#undef yy
#undef oper
}
YY_ACTION(void) yy_3_Child_1(yycontext *yy, char *yytext, int yyleng)
{
#define oper yy->__val[-1]
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_3_Child_1\n"));
  {
  add_operand_from_branch(&__.str, &yy->ctr.operand_ctr, &oper.operand, &yy->global);;
  }
#undef yythunkpos
#undef yypos
#undef yy
#undef oper
}
YY_ACTION(void) yy_2_Child_1(yycontext *yy, char *yytext, int yyleng)
{
#define oper yy->__val[-1]
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_2_Child_1\n"));
  {
  add_operand_from_branch(&__.str, &yy->ctr.operand_ctr, &oper.operand, &yy->global);;
  }
#undef yythunkpos
#undef yypos
#undef yy
#undef oper
}
YY_ACTION(void) yy_1_Child_1(yycontext *yy, char *yytext, int yyleng)
{
#define oper yy->__val[-1]
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_1_Child_1\n"));
  {
  save_string(yytext, &__.str);;
  }
#undef yythunkpos
#undef yypos
#undef yy
#undef oper
}
YY_ACTION(void) yy_1_SingleBranchStructure(yycontext *yy, char *yytext, int yyleng)
{
#define oper yy->__val[-1]
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_1_SingleBranchStructure\n"));
  {
  save_string(yytext, &__.str);;
  }
#undef yythunkpos
#undef yypos
#undef yy
#undef oper
}
YY_ACTION(void) yy_2_BranchStructure(yycontext *yy, char *yytext, int yyleng)
{
#define op2 yy->__val[-1]
#define op1 yy->__val[-2]
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_2_BranchStructure\n"));
  {
  create_branch_element(&yy->global, &yy->ctr.branch_element_number, UA_FILTEROPERATOR_AND, op1.str, op2.str, &__.str);;
  }
#undef yythunkpos
#undef yypos
#undef yy
#undef op2
#undef op1
}
YY_ACTION(void) yy_1_BranchStructure(yycontext *yy, char *yytext, int yyleng)
{
#define op2 yy->__val[-1]
#define op1 yy->__val[-2]
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_1_BranchStructure\n"));
  {
  create_branch_element(&yy->global, &yy->ctr.branch_element_number, UA_FILTEROPERATOR_OR, op1.str, op2.str, &__.str);;
  }
#undef yythunkpos
#undef yypos
#undef yy
#undef op2
#undef op1
}
YY_ACTION(void) yy_1_ContentFilter(yycontext *yy, char *yytext, int yyleng)
{
#define element yy->__val[-1]
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_1_ContentFilter\n"));
  {
  yy->parsedFilter.status = create_content_filter(&yy->global, &yy->parsedFilter.filter.whereClause, element.str, yy->parsedFilter.status);;
  }
#undef yythunkpos
#undef yypos
#undef yy
#undef element
}
YY_ACTION(void) yy_1_Select(yycontext *yy, char *yytext, int yyleng)
{
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_1_Select\n"));
  {
  init_item_list(&yy->global, &yy->ctr);;
  }
#undef yythunkpos
#undef yypos
#undef yy
}
YY_ACTION(void) yy_2_SelectClauses(yycontext *yy, char *yytext, int yyleng)
{
#define oper yy->__val[-1]
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_2_SelectClauses\n"));
  {
  yy->parsedFilter.status = append_select_clauses(&yy->parsedFilter.filter.selectClauses, &yy->parsedFilter.filter.selectClausesSize, &oper.operand.value.extension, yy->parsedFilter.status);;
  }
#undef yythunkpos
#undef yypos
#undef yy
#undef oper
}
YY_ACTION(void) yy_1_SelectClauses(yycontext *yy, char *yytext, int yyleng)
{
#define oper yy->__val[-1]
#define __ yy->__
#define yypos yy->__pos
#define yythunkpos yy->__thunkpos
  yyprintf((stderr, "do yy_1_SelectClauses\n"));
  {
  yy->parsedFilter.status = append_select_clauses(&yy->parsedFilter.filter.selectClauses, &yy->parsedFilter.filter.selectClausesSize, &oper.operand.value.extension, yy->parsedFilter.status);;
  }
#undef yythunkpos
#undef yypos
#undef yy
#undef oper
}

YY_RULE(int) yy_Enter(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;
  yyprintf((stderr, "%s\n", "Enter"));
  {  int yypos2= yy->__pos, yythunkpos2= yy->__thunkpos;  if (!yymatchString(yy, "\r\n")) goto l3;  goto l2;
  l3:;	  yy->__pos= yypos2; yy->__thunkpos= yythunkpos2;  if (!yymatchChar(yy, '\n')) goto l4;  goto l2;
  l4:;	  yy->__pos= yypos2; yy->__thunkpos= yythunkpos2;  if (!yymatchChar(yy, '\r')) goto l1;
  }
  l2:;	
  yyprintf((stderr, "  ok   %s @ %s\n", "Enter", yy->__buf+yy->__pos));
  return 1;
  l1:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "Enter", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_comment(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;
  yyprintf((stderr, "%s\n", "comment"));
  {  int yypos6= yy->__pos, yythunkpos6= yy->__thunkpos;  if (!yymatchChar(yy, '#')) goto l7;
  l8:;	
  {  int yypos9= yy->__pos, yythunkpos9= yy->__thunkpos;
  {  int yypos10= yy->__pos, yythunkpos10= yy->__thunkpos;  if (!yy_Enter(yy)) goto l10;  goto l9;
  l10:;	  yy->__pos= yypos10; yy->__thunkpos= yythunkpos10;
  }  if (!yymatchDot(yy)) goto l9;  goto l8;
  l9:;	  yy->__pos= yypos9; yy->__thunkpos= yythunkpos9;
  }  if (!yy_Enter(yy)) goto l7;  goto l6;
  l7:;	  yy->__pos= yypos6; yy->__thunkpos= yythunkpos6;  if (!yymatchString(yy, "/*")) goto l5;
  l11:;	
  {  int yypos12= yy->__pos, yythunkpos12= yy->__thunkpos;
  {  int yypos13= yy->__pos, yythunkpos13= yy->__thunkpos;
  {  int yypos15= yy->__pos, yythunkpos15= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\204\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l15;  goto l14;
  l15:;	  yy->__pos= yypos15; yy->__thunkpos= yythunkpos15;
  }  if (!yymatchDot(yy)) goto l14;  goto l13;
  l14:;	  yy->__pos= yypos13; yy->__thunkpos= yythunkpos13;  if (!yymatchChar(yy, '/')) goto l12;
  }
  l13:;	  goto l11;
  l12:;	  yy->__pos= yypos12; yy->__thunkpos= yythunkpos12;
  }  if (!yymatchString(yy, "*/")) goto l5;
  }
  l6:;	
  yyprintf((stderr, "  ok   %s @ %s\n", "comment", yy->__buf+yy->__pos));
  return 1;
  l5:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "comment", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_Space(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;
  yyprintf((stderr, "%s\n", "Space"));
  {  int yypos17= yy->__pos, yythunkpos17= yy->__thunkpos;  if (!yymatchChar(yy, ' ')) goto l18;  goto l17;
  l18:;	  yy->__pos= yypos17; yy->__thunkpos= yythunkpos17;  if (!yymatchChar(yy, '\t')) goto l19;  goto l17;
  l19:;	  yy->__pos= yypos17; yy->__thunkpos= yythunkpos17;  if (!yy_Enter(yy)) goto l16;
  }
  l17:;	
  yyprintf((stderr, "  ok   %s @ %s\n", "Space", yy->__buf+yy->__pos));
  return 1;
  l16:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "Space", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_References(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;
  yyprintf((stderr, "%s\n", "References"));
  {  int yypos21= yy->__pos, yythunkpos21= yy->__thunkpos;  if (!yymatchChar(yy, '/')) goto l22;  goto l21;
  l22:;	  yy->__pos= yypos21; yy->__thunkpos= yythunkpos21;  if (!yymatchChar(yy, '.')) goto l20;
  }
  l21:;	
  yyprintf((stderr, "  ok   %s @ %s\n", "References", yy->__buf+yy->__pos));
  return 1;
  l20:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "References", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_StringElement(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;
  yyprintf((stderr, "%s\n", "StringElement"));
  {  int yypos24= yy->__pos, yythunkpos24= yy->__thunkpos;  if (!yymatchString(yy, "\\\"")) goto l25;  goto l24;
  l25:;	  yy->__pos= yypos24; yy->__thunkpos= yythunkpos24;
  {  int yypos26= yy->__pos, yythunkpos26= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\004\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l26;  goto l23;
  l26:;	  yy->__pos= yypos26; yy->__thunkpos= yythunkpos26;
  }  if (!yymatchDot(yy)) goto l23;
  }
  l24:;	
  yyprintf((stderr, "  ok   %s @ %s\n", "StringElement", yy->__buf+yy->__pos));
  return 1;
  l23:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "StringElement", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_JsonValue(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;
  yyprintf((stderr, "%s\n", "JsonValue"));
  {  int yypos28= yy->__pos, yythunkpos28= yy->__thunkpos;  if (!yy_JsonArray(yy)) goto l29;  goto l28;
  l29:;	  yy->__pos= yypos28; yy->__thunkpos= yythunkpos28;  if (!yymatchChar(yy, '"')) goto l30;  if (!yy_StringElement(yy)) goto l30;
  l31:;	
  {  int yypos32= yy->__pos, yythunkpos32= yy->__thunkpos;  if (!yy_StringElement(yy)) goto l32;  goto l31;
  l32:;	  yy->__pos= yypos32; yy->__thunkpos= yythunkpos32;
  }  if (!yymatchChar(yy, '"')) goto l30;  goto l28;
  l30:;	  yy->__pos= yypos28; yy->__thunkpos= yythunkpos28;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l33;
  l34:;	
  {  int yypos35= yy->__pos, yythunkpos35= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l35;  goto l34;
  l35:;	  yy->__pos= yypos35; yy->__thunkpos= yythunkpos35;
  }  goto l28;
  l33:;	  yy->__pos= yypos28; yy->__thunkpos= yythunkpos28;  if (!yymatchString(yy, "true")) goto l36;  goto l28;
  l36:;	  yy->__pos= yypos28; yy->__thunkpos= yythunkpos28;  if (!yymatchString(yy, "false")) goto l37;  goto l28;
  l37:;	  yy->__pos= yypos28; yy->__thunkpos= yythunkpos28;  if (!yymatchString(yy, "null")) goto l27;
  }
  l28:;	
  yyprintf((stderr, "  ok   %s @ %s\n", "JsonValue", yy->__buf+yy->__pos));
  return 1;
  l27:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "JsonValue", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_JsonArray(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;
  yyprintf((stderr, "%s\n", "JsonArray"));  if (!yymatchChar(yy, '[')) goto l38;  if (!yy__(yy)) goto l38;
  l39:;	
  {  int yypos40= yy->__pos, yythunkpos40= yy->__thunkpos;  if (!yy_JsonValue(yy)) goto l40;  if (!yy__(yy)) goto l40;  if (!yymatchChar(yy, ',')) goto l40;  if (!yy__(yy)) goto l40;  goto l39;
  l40:;	  yy->__pos= yypos40; yy->__thunkpos= yythunkpos40;
  }  if (!yy_JsonValue(yy)) goto l38;  if (!yy__(yy)) goto l38;  if (!yymatchChar(yy, ']')) goto l38;
  yyprintf((stderr, "  ok   %s @ %s\n", "JsonArray", yy->__buf+yy->__pos));
  return 1;
  l38:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "JsonArray", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_JsonElement(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;
  yyprintf((stderr, "%s\n", "JsonElement"));  if (!yy__(yy)) goto l41;  if (!yymatchChar(yy, '"')) goto l41;  if (!yy_StringElement(yy)) goto l41;
  l42:;	
  {  int yypos43= yy->__pos, yythunkpos43= yy->__thunkpos;  if (!yy_StringElement(yy)) goto l43;  goto l42;
  l43:;	  yy->__pos= yypos43; yy->__thunkpos= yythunkpos43;
  }  if (!yymatchChar(yy, '"')) goto l41;  if (!yy__(yy)) goto l41;  if (!yymatchChar(yy, ':')) goto l41;  if (!yy__(yy)) goto l41;  if (!yy_JsonValue(yy)) goto l41;  if (!yy__(yy)) goto l41;
  yyprintf((stderr, "  ok   %s @ %s\n", "JsonElement", yy->__buf+yy->__pos));
  return 1;
  l41:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "JsonElement", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_JsonObject(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;
  yyprintf((stderr, "%s\n", "JsonObject"));  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l44;
#undef yytext
#undef yyleng
  }  if (!yymatchChar(yy, '{')) goto l44;  if (!yy__(yy)) goto l44;
  l45:;	
  {  int yypos46= yy->__pos, yythunkpos46= yy->__thunkpos;  if (!yy_JsonElement(yy)) goto l46;  if (!yy__(yy)) goto l46;  if (!yymatchChar(yy, ',')) goto l46;  if (!yy__(yy)) goto l46;  goto l45;
  l46:;	  yy->__pos= yypos46; yy->__thunkpos= yythunkpos46;
  }  if (!yy_JsonElement(yy)) goto l44;  if (!yy__(yy)) goto l44;  if (!yymatchChar(yy, '}')) goto l44;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l44;
#undef yytext
#undef yyleng
  }
  yyprintf((stderr, "  ok   %s @ %s\n", "JsonObject", yy->__buf+yy->__pos));
  return 1;
  l44:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "JsonObject", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_ReferenceType(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;
  yyprintf((stderr, "%s\n", "ReferenceType"));
  {  int yypos48= yy->__pos, yythunkpos48= yy->__thunkpos;  if (!yy_References(yy)) goto l49;  goto l48;
  l49:;	  yy->__pos= yypos48; yy->__thunkpos= yythunkpos48;  if (!yymatchChar(yy, '<')) goto l47;
  {  int yypos50= yy->__pos, yythunkpos50= yy->__thunkpos;
  {  int yypos52= yy->__pos, yythunkpos52= yy->__thunkpos;  if (!yymatchChar(yy, '!')) goto l53;  goto l52;
  l53:;	  yy->__pos= yypos52; yy->__thunkpos= yythunkpos52;  if (!yymatchChar(yy, '#')) goto l50;
  }
  l52:;	  goto l51;
  l50:;	  yy->__pos= yypos50; yy->__thunkpos= yythunkpos50;
  }
  l51:;	
  {  int yypos54= yy->__pos, yythunkpos54= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l54;
  l56:;	
  {  int yypos57= yy->__pos, yythunkpos57= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l57;  goto l56;
  l57:;	  yy->__pos= yypos57; yy->__thunkpos= yythunkpos57;
  }  if (!yy__(yy)) goto l54;  if (!yymatchChar(yy, ':')) goto l54;  goto l55;
  l54:;	  yy->__pos= yypos54; yy->__thunkpos= yythunkpos54;
  }
  l55:;	  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\000\000\376\377\377\207\376\377\377\007\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l47;
  l58:;	
  {  int yypos59= yy->__pos, yythunkpos59= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\000\000\376\377\377\207\376\377\377\007\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l59;  goto l58;
  l59:;	  yy->__pos= yypos59; yy->__thunkpos= yythunkpos59;
  }  if (!yymatchChar(yy, '>')) goto l47;
  }
  l48:;	
  yyprintf((stderr, "  ok   %s @ %s\n", "ReferenceType", yy->__buf+yy->__pos));
  return 1;
  l47:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "ReferenceType", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_Literal(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;
  yyprintf((stderr, "%s\n", "Literal"));
  {  int yypos61= yy->__pos, yythunkpos61= yy->__thunkpos;  if (!yymatchString(yy, "INT32")) goto l62;  if (!yy__(yy)) goto l62;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l62;
#undef yytext
#undef yyleng
  }
  {  int yypos63= yy->__pos, yythunkpos63= yy->__thunkpos;  if (!yymatchChar(yy, '-')) goto l63;  goto l64;
  l63:;	  yy->__pos= yypos63; yy->__thunkpos= yythunkpos63;
  }
  l64:;	  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l62;
  l65:;	
  {  int yypos66= yy->__pos, yythunkpos66= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l66;  goto l65;
  l66:;	  yy->__pos= yypos66; yy->__thunkpos= yythunkpos66;
  }  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l62;
#undef yytext
#undef yyleng
  }  yyDo(yy, yy_1_Literal, yy->__begin, yy->__end);  goto l61;
  l62:;	  yy->__pos= yypos61; yy->__thunkpos= yythunkpos61;  if (!yymatchString(yy, "STRING")) goto l67;  if (!yy__(yy)) goto l67;  if (!yy_ParsedString(yy)) goto l67;  yyDo(yy, yy_2_Literal, yy->__begin, yy->__end);  goto l61;
  l67:;	  yy->__pos= yypos61; yy->__thunkpos= yythunkpos61;  if (!yymatchString(yy, "BOOL")) goto l68;  if (!yy__(yy)) goto l68;
  {  int yypos69= yy->__pos, yythunkpos69= yy->__thunkpos;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l70;
#undef yytext
#undef yyleng
  }
  {  int yypos71= yy->__pos, yythunkpos71= yy->__thunkpos;  if (!yymatchString(yy, "true")) goto l72;  goto l71;
  l72:;	  yy->__pos= yypos71; yy->__thunkpos= yythunkpos71;  if (!yymatchString(yy, "True")) goto l73;  goto l71;
  l73:;	  yy->__pos= yypos71; yy->__thunkpos= yythunkpos71;  if (!yymatchString(yy, "false")) goto l74;  goto l71;
  l74:;	  yy->__pos= yypos71; yy->__thunkpos= yythunkpos71;  if (!yymatchString(yy, "False")) goto l70;
  }
  l71:;	  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l70;
#undef yytext
#undef yyleng
  }  goto l69;
  l70:;	  yy->__pos= yypos69; yy->__thunkpos= yythunkpos69;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l68;
#undef yytext
#undef yyleng
  }  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l68;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l68;
#undef yytext
#undef yyleng
  }
  }
  l69:;	  yyDo(yy, yy_3_Literal, yy->__begin, yy->__end);  goto l61;
  l68:;	  yy->__pos= yypos61; yy->__thunkpos= yythunkpos61;  if (!yymatchString(yy, "INT16")) goto l75;  if (!yy__(yy)) goto l75;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l75;
#undef yytext
#undef yyleng
  }
  {  int yypos76= yy->__pos, yythunkpos76= yy->__thunkpos;  if (!yymatchChar(yy, '-')) goto l76;  goto l77;
  l76:;	  yy->__pos= yypos76; yy->__thunkpos= yythunkpos76;
  }
  l77:;	  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l75;
  l78:;	
  {  int yypos79= yy->__pos, yythunkpos79= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l79;  goto l78;
  l79:;	  yy->__pos= yypos79; yy->__thunkpos= yythunkpos79;
  }  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l75;
#undef yytext
#undef yyleng
  }  yyDo(yy, yy_4_Literal, yy->__begin, yy->__end);  goto l61;
  l75:;	  yy->__pos= yypos61; yy->__thunkpos= yythunkpos61;  if (!yymatchString(yy, "INT64")) goto l80;  if (!yy__(yy)) goto l80;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l80;
#undef yytext
#undef yyleng
  }
  {  int yypos81= yy->__pos, yythunkpos81= yy->__thunkpos;  if (!yymatchChar(yy, '-')) goto l81;  goto l82;
  l81:;	  yy->__pos= yypos81; yy->__thunkpos= yythunkpos81;
  }
  l82:;	  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l80;
  l83:;	
  {  int yypos84= yy->__pos, yythunkpos84= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l84;  goto l83;
  l84:;	  yy->__pos= yypos84; yy->__thunkpos= yythunkpos84;
  }  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l80;
#undef yytext
#undef yyleng
  }  yyDo(yy, yy_5_Literal, yy->__begin, yy->__end);  goto l61;
  l80:;	  yy->__pos= yypos61; yy->__thunkpos= yythunkpos61;  if (!yymatchString(yy, "UINT16")) goto l85;  if (!yy__(yy)) goto l85;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l85;
#undef yytext
#undef yyleng
  }  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l85;
  l86:;	
  {  int yypos87= yy->__pos, yythunkpos87= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l87;  goto l86;
  l87:;	  yy->__pos= yypos87; yy->__thunkpos= yythunkpos87;
  }  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l85;
#undef yytext
#undef yyleng
  }  yyDo(yy, yy_6_Literal, yy->__begin, yy->__end);  goto l61;
  l85:;	  yy->__pos= yypos61; yy->__thunkpos= yythunkpos61;  if (!yymatchString(yy, "UINT32")) goto l88;  if (!yy__(yy)) goto l88;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l88;
#undef yytext
#undef yyleng
  }  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l88;
  l89:;	
  {  int yypos90= yy->__pos, yythunkpos90= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l90;  goto l89;
  l90:;	  yy->__pos= yypos90; yy->__thunkpos= yythunkpos90;
  }  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l88;
#undef yytext
#undef yyleng
  }  yyDo(yy, yy_7_Literal, yy->__begin, yy->__end);  goto l61;
  l88:;	  yy->__pos= yypos61; yy->__thunkpos= yythunkpos61;  if (!yymatchString(yy, "UINT64")) goto l91;  if (!yy__(yy)) goto l91;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l91;
#undef yytext
#undef yyleng
  }  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l91;
  l92:;	
  {  int yypos93= yy->__pos, yythunkpos93= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l93;  goto l92;
  l93:;	  yy->__pos= yypos93; yy->__thunkpos= yythunkpos93;
  }  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l91;
#undef yytext
#undef yyleng
  }  yyDo(yy, yy_8_Literal, yy->__begin, yy->__end);  goto l61;
  l91:;	  yy->__pos= yypos61; yy->__thunkpos= yythunkpos61;  if (!yymatchString(yy, "DOUBLE")) goto l94;  if (!yy__(yy)) goto l94;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l94;
#undef yytext
#undef yyleng
  }
  {  int yypos95= yy->__pos, yythunkpos95= yy->__thunkpos;  if (!yymatchChar(yy, '-')) goto l95;  goto l96;
  l95:;	  yy->__pos= yypos95; yy->__thunkpos= yythunkpos95;
  }
  l96:;	  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l94;
  l97:;	
  {  int yypos98= yy->__pos, yythunkpos98= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l98;  goto l97;
  l98:;	  yy->__pos= yypos98; yy->__thunkpos= yythunkpos98;
  }
  {  int yypos99= yy->__pos, yythunkpos99= yy->__thunkpos;  if (!yymatchChar(yy, '.')) goto l99;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l99;
  l101:;	
  {  int yypos102= yy->__pos, yythunkpos102= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l102;  goto l101;
  l102:;	  yy->__pos= yypos102; yy->__thunkpos= yythunkpos102;
  }  goto l100;
  l99:;	  yy->__pos= yypos99; yy->__thunkpos= yythunkpos99;
  }
  l100:;	  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l94;
#undef yytext
#undef yyleng
  }  yyDo(yy, yy_9_Literal, yy->__begin, yy->__end);  goto l61;
  l94:;	  yy->__pos= yypos61; yy->__thunkpos= yythunkpos61;  if (!yymatchString(yy, "FLOAT")) goto l103;  if (!yy__(yy)) goto l103;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l103;
#undef yytext
#undef yyleng
  }
  {  int yypos104= yy->__pos, yythunkpos104= yy->__thunkpos;  if (!yymatchChar(yy, '-')) goto l104;  goto l105;
  l104:;	  yy->__pos= yypos104; yy->__thunkpos= yythunkpos104;
  }
  l105:;	  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l103;
  l106:;	
  {  int yypos107= yy->__pos, yythunkpos107= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l107;  goto l106;
  l107:;	  yy->__pos= yypos107; yy->__thunkpos= yythunkpos107;
  }
  {  int yypos108= yy->__pos, yythunkpos108= yy->__thunkpos;  if (!yymatchChar(yy, '.')) goto l108;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l108;
  l110:;	
  {  int yypos111= yy->__pos, yythunkpos111= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l111;  goto l110;
  l111:;	  yy->__pos= yypos111; yy->__thunkpos= yythunkpos111;
  }  goto l109;
  l108:;	  yy->__pos= yypos108; yy->__thunkpos= yythunkpos108;
  }
  l109:;	  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l103;
#undef yytext
#undef yyleng
  }  yyDo(yy, yy_10_Literal, yy->__begin, yy->__end);  goto l61;
  l103:;	  yy->__pos= yypos61; yy->__thunkpos= yythunkpos61;  if (!yymatchString(yy, "NODEID")) goto l112;  if (!yy__(yy)) goto l112;  if (!yy_NodeId(yy)) goto l112;  yyDo(yy, yy_11_Literal, yy->__begin, yy->__end);  goto l61;
  l112:;	  yy->__pos= yypos61; yy->__thunkpos= yythunkpos61;  if (!yymatchString(yy, "SBYTE")) goto l113;  if (!yy__(yy)) goto l113;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l113;
#undef yytext
#undef yyleng
  }
  {  int yypos114= yy->__pos, yythunkpos114= yy->__thunkpos;  if (!yymatchChar(yy, '-')) goto l114;  goto l115;
  l114:;	  yy->__pos= yypos114; yy->__thunkpos= yythunkpos114;
  }
  l115:;	  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l113;
  l116:;	
  {  int yypos117= yy->__pos, yythunkpos117= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l117;  goto l116;
  l117:;	  yy->__pos= yypos117; yy->__thunkpos= yythunkpos117;
  }  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l113;
#undef yytext
#undef yyleng
  }  yyDo(yy, yy_12_Literal, yy->__begin, yy->__end);  goto l61;
  l113:;	  yy->__pos= yypos61; yy->__thunkpos= yythunkpos61;  if (!yymatchString(yy, "BYTE")) goto l118;  if (!yy__(yy)) goto l118;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l118;
#undef yytext
#undef yyleng
  }  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l118;
  l119:;	
  {  int yypos120= yy->__pos, yythunkpos120= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l120;  goto l119;
  l120:;	  yy->__pos= yypos120; yy->__thunkpos= yythunkpos120;
  }  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l118;
#undef yytext
#undef yyleng
  }  yyDo(yy, yy_13_Literal, yy->__begin, yy->__end);  goto l61;
  l118:;	  yy->__pos= yypos61; yy->__thunkpos= yythunkpos61;  if (!yymatchString(yy, "TIME")) goto l121;  if (!yy__(yy)) goto l121;  if (!yymatchChar(yy, '"')) goto l121;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l121;
#undef yytext
#undef yyleng
  }
  {  int yypos124= yy->__pos, yythunkpos124= yy->__thunkpos;  if (!yymatchChar(yy, '-')) goto l125;  goto l124;
  l125:;	  yy->__pos= yypos124; yy->__thunkpos= yythunkpos124;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l126;  goto l124;
  l126:;	  yy->__pos= yypos124; yy->__thunkpos= yythunkpos124;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\000\000\376\377\377\007\376\377\377\007\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l127;  goto l124;
  l127:;	  yy->__pos= yypos124; yy->__thunkpos= yythunkpos124;  if (!yymatchChar(yy, '.')) goto l128;  goto l124;
  l128:;	  yy->__pos= yypos124; yy->__thunkpos= yythunkpos124;  if (!yymatchChar(yy, ':')) goto l121;
  }
  l124:;	
  l122:;	
  {  int yypos123= yy->__pos, yythunkpos123= yy->__thunkpos;
  {  int yypos129= yy->__pos, yythunkpos129= yy->__thunkpos;  if (!yymatchChar(yy, '-')) goto l130;  goto l129;
  l130:;	  yy->__pos= yypos129; yy->__thunkpos= yythunkpos129;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l131;  goto l129;
  l131:;	  yy->__pos= yypos129; yy->__thunkpos= yythunkpos129;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\000\000\376\377\377\007\376\377\377\007\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l132;  goto l129;
  l132:;	  yy->__pos= yypos129; yy->__thunkpos= yythunkpos129;  if (!yymatchChar(yy, '.')) goto l133;  goto l129;
  l133:;	  yy->__pos= yypos129; yy->__thunkpos= yythunkpos129;  if (!yymatchChar(yy, ':')) goto l123;
  }
  l129:;	  goto l122;
  l123:;	  yy->__pos= yypos123; yy->__thunkpos= yythunkpos123;
  }  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l121;
#undef yytext
#undef yyleng
  }  if (!yymatchChar(yy, '"')) goto l121;  yyDo(yy, yy_14_Literal, yy->__begin, yy->__end);  goto l61;
  l121:;	  yy->__pos= yypos61; yy->__thunkpos= yythunkpos61;  if (!yymatchString(yy, "GUID")) goto l134;  if (!yy__(yy)) goto l134;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l134;
#undef yytext
#undef yyleng
  }
  {  int yypos137= yy->__pos, yythunkpos137= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\000\000\376\377\377\207\376\377\377\007\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l138;  goto l137;
  l138:;	  yy->__pos= yypos137; yy->__thunkpos= yythunkpos137;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l139;  goto l137;
  l139:;	  yy->__pos= yypos137; yy->__thunkpos= yythunkpos137;  if (!yymatchChar(yy, '-')) goto l134;
  }
  l137:;	
  l135:;	
  {  int yypos136= yy->__pos, yythunkpos136= yy->__thunkpos;
  {  int yypos140= yy->__pos, yythunkpos140= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\000\000\376\377\377\207\376\377\377\007\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l141;  goto l140;
  l141:;	  yy->__pos= yypos140; yy->__thunkpos= yythunkpos140;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l142;  goto l140;
  l142:;	  yy->__pos= yypos140; yy->__thunkpos= yythunkpos140;  if (!yymatchChar(yy, '-')) goto l136;
  }
  l140:;	  goto l135;
  l136:;	  yy->__pos= yypos136; yy->__thunkpos= yythunkpos136;
  }  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l134;
#undef yytext
#undef yyleng
  }  yyDo(yy, yy_15_Literal, yy->__begin, yy->__end);  goto l61;
  l134:;	  yy->__pos= yypos61; yy->__thunkpos= yythunkpos61;  if (!yymatchString(yy, "BSTRING")) goto l143;  if (!yy__(yy)) goto l143;  if (!yy_ParsedString(yy)) goto l143;  yyDo(yy, yy_16_Literal, yy->__begin, yy->__end);  goto l61;
  l143:;	  yy->__pos= yypos61; yy->__thunkpos= yythunkpos61;  if (!yymatchString(yy, "STATUSCODE")) goto l144;  if (!yy__(yy)) goto l144;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l144;
#undef yytext
#undef yyleng
  }
  {  int yypos147= yy->__pos, yythunkpos147= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\000\000\376\377\377\207\376\377\377\007\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l148;  goto l147;
  l148:;	  yy->__pos= yypos147; yy->__thunkpos= yythunkpos147;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l144;
  }
  l147:;	
  l145:;	
  {  int yypos146= yy->__pos, yythunkpos146= yy->__thunkpos;
  {  int yypos149= yy->__pos, yythunkpos149= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\000\000\376\377\377\207\376\377\377\007\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l150;  goto l149;
  l150:;	  yy->__pos= yypos149; yy->__thunkpos= yythunkpos149;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l146;
  }
  l149:;	  goto l145;
  l146:;	  yy->__pos= yypos146; yy->__thunkpos= yythunkpos146;
  }  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l144;
#undef yytext
#undef yyleng
  }  yyDo(yy, yy_17_Literal, yy->__begin, yy->__end);  goto l61;
  l144:;	  yy->__pos= yypos61; yy->__thunkpos= yythunkpos61;  if (!yymatchString(yy, "EXPNODEID")) goto l151;  if (!yy__(yy)) goto l151;  if (!yy_ParsedString(yy)) goto l151;  yyDo(yy, yy_18_Literal, yy->__begin, yy->__end);  goto l61;
  l151:;	  yy->__pos= yypos61; yy->__thunkpos= yythunkpos61;  if (!yymatchString(yy, "QNAME")) goto l152;  if (!yy__(yy)) goto l152;  if (!yymatchChar(yy, '"')) goto l152;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l152;
#undef yytext
#undef yyleng
  }  if (!yy_QualifiedName(yy)) goto l152;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l152;
#undef yytext
#undef yyleng
  }  if (!yymatchChar(yy, '"')) goto l152;  yyDo(yy, yy_19_Literal, yy->__begin, yy->__end);  goto l61;
  l152:;	  yy->__pos= yypos61; yy->__thunkpos= yythunkpos61;  if (!yymatchString(yy, "LOCALIZED")) goto l153;  if (!yy__(yy)) goto l153;  if (!yy_ParsedString(yy)) goto l153;  yyDo(yy, yy_20_Literal, yy->__begin, yy->__end);  goto l61;
  l153:;	  yy->__pos= yypos61; yy->__thunkpos= yythunkpos61;
  {  int yypos154= yy->__pos, yythunkpos154= yy->__thunkpos;  if (!yy__(yy)) goto l155;  if (!yy_NodeId(yy)) goto l155;  yyDo(yy, yy_21_Literal, yy->__begin, yy->__end);  goto l154;
  l155:;	  yy->__pos= yypos154; yy->__thunkpos= yythunkpos154;  if (!yy__(yy)) goto l156;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l156;
#undef yytext
#undef yyleng
  }
  {  int yypos157= yy->__pos, yythunkpos157= yy->__thunkpos;  if (!yymatchChar(yy, '-')) goto l157;  goto l158;
  l157:;	  yy->__pos= yypos157; yy->__thunkpos= yythunkpos157;
  }
  l158:;	  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l156;
  l159:;	
  {  int yypos160= yy->__pos, yythunkpos160= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l160;  goto l159;
  l160:;	  yy->__pos= yypos160; yy->__thunkpos= yythunkpos160;
  }  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l156;
#undef yytext
#undef yyleng
  }
  {  int yypos161= yy->__pos, yythunkpos161= yy->__thunkpos;  if (!yymatchChar(yy, '.')) goto l161;  goto l156;
  l161:;	  yy->__pos= yypos161; yy->__thunkpos= yythunkpos161;
  }  yyDo(yy, yy_22_Literal, yy->__begin, yy->__end);  goto l154;
  l156:;	  yy->__pos= yypos154; yy->__thunkpos= yythunkpos154;  if (!yy__(yy)) goto l162;
  {  int yypos163= yy->__pos, yythunkpos163= yy->__thunkpos;  if (!yymatchChar(yy, '"')) goto l163;  if (!yy__(yy)) goto l163;  if (!yy_ReferenceType(yy)) goto l163;  goto l162;
  l163:;	  yy->__pos= yypos163; yy->__thunkpos= yythunkpos163;
  }  if (!yy_ParsedString(yy)) goto l162;  yyDo(yy, yy_23_Literal, yy->__begin, yy->__end);  goto l154;
  l162:;	  yy->__pos= yypos154; yy->__thunkpos= yythunkpos154;  if (!yy__(yy)) goto l164;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l164;
#undef yytext
#undef yyleng
  }
  {  int yypos165= yy->__pos, yythunkpos165= yy->__thunkpos;  if (!yymatchString(yy, "true")) goto l166;  goto l165;
  l166:;	  yy->__pos= yypos165; yy->__thunkpos= yythunkpos165;  if (!yymatchString(yy, "True")) goto l167;  goto l165;
  l167:;	  yy->__pos= yypos165; yy->__thunkpos= yythunkpos165;  if (!yymatchString(yy, "false")) goto l168;  goto l165;
  l168:;	  yy->__pos= yypos165; yy->__thunkpos= yythunkpos165;  if (!yymatchString(yy, "False")) goto l164;
  }
  l165:;	  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l164;
#undef yytext
#undef yyleng
  }  yyDo(yy, yy_24_Literal, yy->__begin, yy->__end);  goto l154;
  l164:;	  yy->__pos= yypos154; yy->__thunkpos= yythunkpos154;  if (!yy__(yy)) goto l169;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l169;
#undef yytext
#undef yyleng
  }
  {  int yypos170= yy->__pos, yythunkpos170= yy->__thunkpos;  if (!yymatchChar(yy, '-')) goto l170;  goto l171;
  l170:;	  yy->__pos= yypos170; yy->__thunkpos= yythunkpos170;
  }
  l171:;	  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l169;
  l172:;	
  {  int yypos173= yy->__pos, yythunkpos173= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l173;  goto l172;
  l173:;	  yy->__pos= yypos173; yy->__thunkpos= yythunkpos173;
  }  if (!yymatchChar(yy, '.')) goto l169;
  l174:;	
  {  int yypos175= yy->__pos, yythunkpos175= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l175;  goto l174;
  l175:;	  yy->__pos= yypos175; yy->__thunkpos= yythunkpos175;
  }  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l169;
#undef yytext
#undef yyleng
  }  if (!yy__(yy)) goto l169;  yyDo(yy, yy_25_Literal, yy->__begin, yy->__end);  goto l154;
  l169:;	  yy->__pos= yypos154; yy->__thunkpos= yythunkpos154;  if (!yy__(yy)) goto l60;  if (!yymatchChar(yy, '"')) goto l60;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l60;
#undef yytext
#undef yyleng
  }  if (!yy_QualifiedName(yy)) goto l60;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l60;
#undef yytext
#undef yyleng
  }  if (!yymatchChar(yy, '"')) goto l60;
  {  int yypos176= yy->__pos, yythunkpos176= yy->__thunkpos;
  {  int yypos177= yy->__pos, yythunkpos177= yy->__thunkpos;  if (!yymatchString(yy, "true")) goto l178;  goto l177;
  l178:;	  yy->__pos= yypos177; yy->__thunkpos= yythunkpos177;  if (!yymatchString(yy, "True")) goto l179;  goto l177;
  l179:;	  yy->__pos= yypos177; yy->__thunkpos= yythunkpos177;  if (!yymatchString(yy, "false")) goto l180;  goto l177;
  l180:;	  yy->__pos= yypos177; yy->__thunkpos= yythunkpos177;  if (!yymatchString(yy, "False")) goto l176;
  }
  l177:;	  goto l60;
  l176:;	  yy->__pos= yypos176; yy->__thunkpos= yythunkpos176;
  }  yyDo(yy, yy_26_Literal, yy->__begin, yy->__end);
  }
  l154:;	
  }
  l61:;	
  yyprintf((stderr, "  ok   %s @ %s\n", "Literal", yy->__buf+yy->__pos));
  return 1;
  l60:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "Literal", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_ParsedJsonString(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;
  yyprintf((stderr, "%s\n", "ParsedJsonString"));
  {  int yypos182= yy->__pos, yythunkpos182= yy->__thunkpos;  if (!yy_JsonObject(yy)) goto l183;  goto l182;
  l183:;	  yy->__pos= yypos182; yy->__thunkpos= yythunkpos182;  if (!yymatchChar(yy, '(')) goto l181;  if (!yy_JsonObject(yy)) goto l181;  if (!yymatchChar(yy, ')')) goto l181;
  }
  l182:;	  if (!yy__(yy)) goto l181;  yyDo(yy, yy_1_ParsedJsonString, yy->__begin, yy->__end);
  yyprintf((stderr, "  ok   %s @ %s\n", "ParsedJsonString", yy->__buf+yy->__pos));
  return 1;
  l181:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "ParsedJsonString", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_NumericRange(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;
  yyprintf((stderr, "%s\n", "NumericRange"));  if (!yymatchChar(yy, '[')) goto l184;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l184;
#undef yytext
#undef yyleng
  }  if (!yy__(yy)) goto l184;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l184;
  l185:;	
  {  int yypos186= yy->__pos, yythunkpos186= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l186;  goto l185;
  l186:;	  yy->__pos= yypos186; yy->__thunkpos= yythunkpos186;
  }  if (!yy__(yy)) goto l184;
  {  int yypos187= yy->__pos, yythunkpos187= yy->__thunkpos;  if (!yymatchChar(yy, ':')) goto l187;  if (!yy__(yy)) goto l187;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l187;
  l189:;	
  {  int yypos190= yy->__pos, yythunkpos190= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l190;  goto l189;
  l190:;	  yy->__pos= yypos190; yy->__thunkpos= yythunkpos190;
  }  goto l188;
  l187:;	  yy->__pos= yypos187; yy->__thunkpos= yythunkpos187;
  }
  l188:;	
  l191:;	
  {  int yypos192= yy->__pos, yythunkpos192= yy->__thunkpos;  if (!yymatchChar(yy, ',')) goto l192;  if (!yy__(yy)) goto l192;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l192;
  l193:;	
  {  int yypos194= yy->__pos, yythunkpos194= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l194;  goto l193;
  l194:;	  yy->__pos= yypos194; yy->__thunkpos= yythunkpos194;
  }  if (!yy__(yy)) goto l192;
  {  int yypos195= yy->__pos, yythunkpos195= yy->__thunkpos;  if (!yymatchChar(yy, ':')) goto l195;  if (!yy__(yy)) goto l195;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l195;
  l197:;	
  {  int yypos198= yy->__pos, yythunkpos198= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l198;  goto l197;
  l198:;	  yy->__pos= yypos198; yy->__thunkpos= yythunkpos198;
  }  goto l196;
  l195:;	  yy->__pos= yypos195; yy->__thunkpos= yythunkpos195;
  }
  l196:;	  goto l191;
  l192:;	  yy->__pos= yypos192; yy->__thunkpos= yythunkpos192;
  }  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l184;
#undef yytext
#undef yyleng
  }  if (!yymatchChar(yy, ']')) goto l184;
  yyprintf((stderr, "  ok   %s @ %s\n", "NumericRange", yy->__buf+yy->__pos));
  return 1;
  l184:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "NumericRange", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_QualifiedName(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;
  yyprintf((stderr, "%s\n", "QualifiedName"));  if (!yy_ReferenceType(yy)) goto l199;
  {  int yypos200= yy->__pos, yythunkpos200= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l200;
  l202:;	
  {  int yypos203= yy->__pos, yythunkpos203= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l203;  goto l202;
  l203:;	  yy->__pos= yypos203; yy->__thunkpos= yythunkpos203;
  }  if (!yy__(yy)) goto l200;  if (!yymatchChar(yy, ':')) goto l200;  goto l201;
  l200:;	  yy->__pos= yypos200; yy->__thunkpos= yythunkpos200;
  }
  l201:;	
  {  int yypos204= yy->__pos, yythunkpos204= yy->__thunkpos;  if (!yy_StringElement(yy)) goto l204;
  l206:;	
  {  int yypos207= yy->__pos, yythunkpos207= yy->__thunkpos;  if (!yy_StringElement(yy)) goto l207;  goto l206;
  l207:;	  yy->__pos= yypos207; yy->__thunkpos= yythunkpos207;
  }  goto l205;
  l204:;	  yy->__pos= yypos204; yy->__thunkpos= yythunkpos204;
  }
  l205:;	
  yyprintf((stderr, "  ok   %s @ %s\n", "QualifiedName", yy->__buf+yy->__pos));
  return 1;
  l199:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "QualifiedName", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_ParsedString(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;
  yyprintf((stderr, "%s\n", "ParsedString"));  if (!yymatchChar(yy, '"')) goto l208;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l208;
#undef yytext
#undef yyleng
  }  if (!yy_StringElement(yy)) goto l208;
  l209:;	
  {  int yypos210= yy->__pos, yythunkpos210= yy->__thunkpos;  if (!yy_StringElement(yy)) goto l210;  goto l209;
  l210:;	  yy->__pos= yypos210; yy->__thunkpos= yythunkpos210;
  }  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l208;
#undef yytext
#undef yyleng
  }  if (!yymatchChar(yy, '"')) goto l208;
  yyprintf((stderr, "  ok   %s @ %s\n", "ParsedString", yy->__buf+yy->__pos));
  return 1;
  l208:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "ParsedString", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_SingleOperatorType(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;  yyDo(yy, yyPush, 1, 0);
  yyprintf((stderr, "%s\n", "SingleOperatorType"));
  {  int yypos212= yy->__pos, yythunkpos212= yy->__thunkpos;
  {  int yypos214= yy->__pos, yythunkpos214= yy->__thunkpos;  if (!yymatchString(yy, "NOT")) goto l215;  goto l214;
  l215:;	  yy->__pos= yypos214; yy->__thunkpos= yythunkpos214;  if (!yymatchChar(yy, '!')) goto l213;
  }
  l214:;	  if (!yy__(yy)) goto l213;  if (!yy_Operand(yy)) goto l213;  yyDo(yy, yySet, -1, 0);  if (!yy__(yy)) goto l213;  yyDo(yy, yy_1_SingleOperatorType, yy->__begin, yy->__end);  goto l212;
  l213:;	  yy->__pos= yypos212; yy->__thunkpos= yythunkpos212;
  {  int yypos217= yy->__pos, yythunkpos217= yy->__thunkpos;  if (!yymatchString(yy, "ISNULL")) goto l218;  goto l217;
  l218:;	  yy->__pos= yypos217; yy->__thunkpos= yythunkpos217;  if (!yymatchString(yy, "0=")) goto l219;  goto l217;
  l219:;	  yy->__pos= yypos217; yy->__thunkpos= yythunkpos217;  if (!yymatchChar(yy, '0')) goto l216;  if (!yy__(yy)) goto l216;  if (!yymatchChar(yy, '=')) goto l216;
  }
  l217:;	  if (!yy__(yy)) goto l216;  if (!yy_Operand(yy)) goto l216;  yyDo(yy, yySet, -1, 0);  if (!yy__(yy)) goto l216;  yyDo(yy, yy_2_SingleOperatorType, yy->__begin, yy->__end);  goto l212;
  l216:;	  yy->__pos= yypos212; yy->__thunkpos= yythunkpos212;  if (!yymatchString(yy, "OFTYPE")) goto l211;  if (!yy__(yy)) goto l211;
  {  int yypos220= yy->__pos, yythunkpos220= yy->__thunkpos;
  {  int yypos222= yy->__pos, yythunkpos222= yy->__thunkpos;  if (!yy_NodeId(yy)) goto l223;  goto l222;
  l223:;	  yy->__pos= yypos222; yy->__thunkpos= yythunkpos222;  if (!yymatchChar(yy, '(')) goto l221;  if (!yy__(yy)) goto l221;  if (!yy_NodeId(yy)) goto l221;  if (!yy__(yy)) goto l221;  if (!yymatchChar(yy, ')')) goto l221;
  }
  l222:;	  yyDo(yy, yy_3_SingleOperatorType, yy->__begin, yy->__end);  goto l220;
  l221:;	  yy->__pos= yypos220; yy->__thunkpos= yythunkpos220;  if (!yy_Operand(yy)) goto l211;  yyDo(yy, yySet, -1, 0);  yyDo(yy, yy_4_SingleOperatorType, yy->__begin, yy->__end);
  }
  l220:;	  if (!yy__(yy)) goto l211;
  }
  l212:;	
  yyprintf((stderr, "  ok   %s @ %s\n", "SingleOperatorType", yy->__buf+yy->__pos));  yyDo(yy, yyPop, 1, 0);
  return 1;
  l211:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "SingleOperatorType", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_TwoOperandsOperatorType(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;
  yyprintf((stderr, "%s\n", "TwoOperandsOperatorType"));
  {  int yypos225= yy->__pos, yythunkpos225= yy->__thunkpos;
  {  int yypos227= yy->__pos, yythunkpos227= yy->__thunkpos;  if (!yymatchString(yy, "GREATERTHAN")) goto l228;  goto l227;
  l228:;	  yy->__pos= yypos227; yy->__thunkpos= yythunkpos227;  if (!yymatchChar(yy, '>')) goto l229;
  {  int yypos230= yy->__pos, yythunkpos230= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\000\140\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l230;  goto l229;
  l230:;	  yy->__pos= yypos230; yy->__thunkpos= yythunkpos230;
  }  goto l227;
  l229:;	  yy->__pos= yypos227; yy->__thunkpos= yythunkpos227;  if (!yymatchString(yy, "GT")) goto l226;
  }
  l227:;	  yyDo(yy, yy_1_TwoOperandsOperatorType, yy->__begin, yy->__end);  goto l225;
  l226:;	  yy->__pos= yypos225; yy->__thunkpos= yythunkpos225;
  {  int yypos232= yy->__pos, yythunkpos232= yy->__thunkpos;  if (!yymatchString(yy, "EQUALS")) goto l233;  goto l232;
  l233:;	  yy->__pos= yypos232; yy->__thunkpos= yythunkpos232;  if (!yymatchString(yy, "==")) goto l234;  goto l232;
  l234:;	  yy->__pos= yypos232; yy->__thunkpos= yythunkpos232;  if (!yymatchString(yy, "EQ")) goto l231;
  }
  l232:;	  yyDo(yy, yy_2_TwoOperandsOperatorType, yy->__begin, yy->__end);  goto l225;
  l231:;	  yy->__pos= yypos225; yy->__thunkpos= yythunkpos225;
  {  int yypos236= yy->__pos, yythunkpos236= yy->__thunkpos;  if (!yymatchString(yy, "LESSTHAN")) goto l237;  goto l236;
  l237:;	  yy->__pos= yypos236; yy->__thunkpos= yythunkpos236;  if (!yymatchChar(yy, '<')) goto l238;
  {  int yypos239= yy->__pos, yythunkpos239= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\000\060\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l239;  goto l238;
  l239:;	  yy->__pos= yypos239; yy->__thunkpos= yythunkpos239;
  }
  {  int yypos240= yy->__pos, yythunkpos240= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\000\160\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l240;  goto l238;
  l240:;	  yy->__pos= yypos240; yy->__thunkpos= yythunkpos240;
  }  goto l236;
  l238:;	  yy->__pos= yypos236; yy->__thunkpos= yythunkpos236;  if (!yymatchString(yy, "LT")) goto l235;
  }
  l236:;	  yyDo(yy, yy_3_TwoOperandsOperatorType, yy->__begin, yy->__end);  goto l225;
  l235:;	  yy->__pos= yypos225; yy->__thunkpos= yythunkpos225;
  {  int yypos242= yy->__pos, yythunkpos242= yy->__thunkpos;  if (!yymatchString(yy, "GREATEROREQUAL")) goto l243;  goto l242;
  l243:;	  yy->__pos= yypos242; yy->__thunkpos= yythunkpos242;  if (!yymatchString(yy, ">=")) goto l244;  goto l242;
  l244:;	  yy->__pos= yypos242; yy->__thunkpos= yythunkpos242;  if (!yymatchString(yy, "GE")) goto l241;
  }
  l242:;	  yyDo(yy, yy_4_TwoOperandsOperatorType, yy->__begin, yy->__end);  goto l225;
  l241:;	  yy->__pos= yypos225; yy->__thunkpos= yythunkpos225;
  {  int yypos246= yy->__pos, yythunkpos246= yy->__thunkpos;  if (!yymatchString(yy, "LESSOREQUAL")) goto l247;  goto l246;
  l247:;	  yy->__pos= yypos246; yy->__thunkpos= yythunkpos246;  if (!yymatchString(yy, "<=")) goto l248;
  {  int yypos249= yy->__pos, yythunkpos249= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\000\160\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l249;  goto l248;
  l249:;	  yy->__pos= yypos249; yy->__thunkpos= yythunkpos249;
  }  goto l246;
  l248:;	  yy->__pos= yypos246; yy->__thunkpos= yythunkpos246;  if (!yymatchString(yy, "LE")) goto l245;
  }
  l246:;	  yyDo(yy, yy_5_TwoOperandsOperatorType, yy->__begin, yy->__end);  goto l225;
  l245:;	  yy->__pos= yypos225; yy->__thunkpos= yythunkpos225;
  {  int yypos251= yy->__pos, yythunkpos251= yy->__thunkpos;  if (!yymatchString(yy, "LIKE")) goto l252;  goto l251;
  l252:;	  yy->__pos= yypos251; yy->__thunkpos= yythunkpos251;  if (!yymatchString(yy, "<=>")) goto l250;
  }
  l251:;	  yyDo(yy, yy_6_TwoOperandsOperatorType, yy->__begin, yy->__end);  goto l225;
  l250:;	  yy->__pos= yypos225; yy->__thunkpos= yythunkpos225;
  {  int yypos254= yy->__pos, yythunkpos254= yy->__thunkpos;  if (!yymatchString(yy, "CAST")) goto l255;  goto l254;
  l255:;	  yy->__pos= yypos254; yy->__thunkpos= yythunkpos254;  if (!yymatchString(yy, "->")) goto l253;
  }
  l254:;	  yyDo(yy, yy_7_TwoOperandsOperatorType, yy->__begin, yy->__end);  goto l225;
  l253:;	  yy->__pos= yypos225; yy->__thunkpos= yythunkpos225;
  {  int yypos257= yy->__pos, yythunkpos257= yy->__thunkpos;  if (!yymatchString(yy, "BITAND")) goto l258;  goto l257;
  l258:;	  yy->__pos= yypos257; yy->__thunkpos= yythunkpos257;  if (!yymatchChar(yy, '&')) goto l256;
  }
  l257:;	  yyDo(yy, yy_8_TwoOperandsOperatorType, yy->__begin, yy->__end);  goto l225;
  l256:;	  yy->__pos= yypos225; yy->__thunkpos= yythunkpos225;
  {  int yypos259= yy->__pos, yythunkpos259= yy->__thunkpos;  if (!yymatchString(yy, "BITOR")) goto l260;  goto l259;
  l260:;	  yy->__pos= yypos259; yy->__thunkpos= yythunkpos259;  if (!yymatchChar(yy, '|')) goto l224;
  }
  l259:;	  yyDo(yy, yy_9_TwoOperandsOperatorType, yy->__begin, yy->__end);
  }
  l225:;	
  yyprintf((stderr, "  ok   %s @ %s\n", "TwoOperandsOperatorType", yy->__buf+yy->__pos));
  return 1;
  l224:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "TwoOperandsOperatorType", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_NodeId(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;
  yyprintf((stderr, "%s\n", "NodeId"));
  {  int yypos262= yy->__pos, yythunkpos262= yy->__thunkpos;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l263;
#undef yytext
#undef yyleng
  }
  {  int yypos264= yy->__pos, yythunkpos264= yy->__thunkpos;  if (!yymatchString(yy, "ns=")) goto l264;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l264;
  l266:;	
  {  int yypos267= yy->__pos, yythunkpos267= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l267;  goto l266;
  l267:;	  yy->__pos= yypos267; yy->__thunkpos= yythunkpos267;
  }  if (!yymatchChar(yy, ';')) goto l264;  goto l265;
  l264:;	  yy->__pos= yypos264; yy->__thunkpos= yythunkpos264;
  }
  l265:;	  if (!yymatchString(yy, "i=")) goto l263;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l263;
  l268:;	
  {  int yypos269= yy->__pos, yythunkpos269= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l269;  goto l268;
  l269:;	  yy->__pos= yypos269; yy->__thunkpos= yythunkpos269;
  }  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l263;
#undef yytext
#undef yyleng
  }  yyDo(yy, yy_1_NodeId, yy->__begin, yy->__end);  goto l262;
  l263:;	  yy->__pos= yypos262; yy->__thunkpos= yythunkpos262;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l270;
#undef yytext
#undef yyleng
  }
  {  int yypos271= yy->__pos, yythunkpos271= yy->__thunkpos;  if (!yymatchString(yy, "ns=")) goto l271;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l271;
  l273:;	
  {  int yypos274= yy->__pos, yythunkpos274= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l274;  goto l273;
  l274:;	  yy->__pos= yypos274; yy->__thunkpos= yythunkpos274;
  }  if (!yymatchChar(yy, ';')) goto l271;  goto l272;
  l271:;	  yy->__pos= yypos271; yy->__thunkpos= yythunkpos271;
  }
  l272:;	  if (!yymatchString(yy, "s=")) goto l270;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l270;
#undef yytext
#undef yyleng
  }  yyDo(yy, yy_2_NodeId, yy->__begin, yy->__end);  if (!yy_ParsedString(yy)) goto l270;  yyDo(yy, yy_3_NodeId, yy->__begin, yy->__end);  goto l262;
  l270:;	  yy->__pos= yypos262; yy->__thunkpos= yythunkpos262;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l275;
#undef yytext
#undef yyleng
  }
  {  int yypos276= yy->__pos, yythunkpos276= yy->__thunkpos;  if (!yymatchString(yy, "ns=")) goto l276;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l276;
  l278:;	
  {  int yypos279= yy->__pos, yythunkpos279= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l279;  goto l278;
  l279:;	  yy->__pos= yypos279; yy->__thunkpos= yythunkpos279;
  }  if (!yymatchChar(yy, ';')) goto l276;  goto l277;
  l276:;	  yy->__pos= yypos276; yy->__thunkpos= yythunkpos276;
  }
  l277:;	  if (!yymatchString(yy, "g=")) goto l275;
  {  int yypos282= yy->__pos, yythunkpos282= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\000\000\376\377\377\207\376\377\377\007\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l283;  goto l282;
  l283:;	  yy->__pos= yypos282; yy->__thunkpos= yythunkpos282;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l284;  goto l282;
  l284:;	  yy->__pos= yypos282; yy->__thunkpos= yythunkpos282;  if (!yymatchChar(yy, '-')) goto l275;
  }
  l282:;	
  l280:;	
  {  int yypos281= yy->__pos, yythunkpos281= yy->__thunkpos;
  {  int yypos285= yy->__pos, yythunkpos285= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\000\000\376\377\377\207\376\377\377\007\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l286;  goto l285;
  l286:;	  yy->__pos= yypos285; yy->__thunkpos= yythunkpos285;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l287;  goto l285;
  l287:;	  yy->__pos= yypos285; yy->__thunkpos= yythunkpos285;  if (!yymatchChar(yy, '-')) goto l281;
  }
  l285:;	  goto l280;
  l281:;	  yy->__pos= yypos281; yy->__thunkpos= yythunkpos281;
  }  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l275;
#undef yytext
#undef yyleng
  }  yyDo(yy, yy_4_NodeId, yy->__begin, yy->__end);  goto l262;
  l275:;	  yy->__pos= yypos262; yy->__thunkpos= yythunkpos262;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l261;
#undef yytext
#undef yyleng
  }
  {  int yypos288= yy->__pos, yythunkpos288= yy->__thunkpos;  if (!yymatchString(yy, "ns=")) goto l288;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l288;
  l290:;	
  {  int yypos291= yy->__pos, yythunkpos291= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l291;  goto l290;
  l291:;	  yy->__pos= yypos291; yy->__thunkpos= yythunkpos291;
  }  if (!yymatchChar(yy, ';')) goto l288;  goto l289;
  l288:;	  yy->__pos= yypos288; yy->__thunkpos= yythunkpos288;
  }
  l289:;	  if (!yymatchString(yy, "b=")) goto l261;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l261;
#undef yytext
#undef yyleng
  }  yyDo(yy, yy_5_NodeId, yy->__begin, yy->__end);  if (!yy_ParsedString(yy)) goto l261;  yyDo(yy, yy_6_NodeId, yy->__begin, yy->__end);
  }
  l262:;	  yyDo(yy, yy_7_NodeId, yy->__begin, yy->__end);
  yyprintf((stderr, "  ok   %s @ %s\n", "NodeId", yy->__buf+yy->__pos));
  return 1;
  l261:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "NodeId", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_Operand(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;
  yyprintf((stderr, "%s\n", "Operand"));  if (!yy__(yy)) goto l292;
  {  int yypos293= yy->__pos, yythunkpos293= yy->__thunkpos;  if (!yy_LiteralOperand(yy)) goto l294;  goto l293;
  l294:;	  yy->__pos= yypos293; yy->__thunkpos= yythunkpos293;  if (!yymatchChar(yy, '(')) goto l295;  if (!yy__(yy)) goto l295;  if (!yy_LiteralOperand(yy)) goto l295;  if (!yy__(yy)) goto l295;  if (!yymatchChar(yy, ')')) goto l295;  goto l293;
  l295:;	  yy->__pos= yypos293; yy->__thunkpos= yythunkpos293;
  {  int yypos297= yy->__pos, yythunkpos297= yy->__thunkpos;  if (!yy_ElementOperand(yy)) goto l298;  goto l297;
  l298:;	  yy->__pos= yypos297; yy->__thunkpos= yythunkpos297;  if (!yymatchChar(yy, '(')) goto l296;  if (!yy__(yy)) goto l296;  if (!yy_ElementOperand(yy)) goto l296;  if (!yy__(yy)) goto l296;  if (!yymatchChar(yy, ')')) goto l296;
  }
  l297:;	  yyDo(yy, yy_1_Operand, yy->__begin, yy->__end);  goto l293;
  l296:;	  yy->__pos= yypos293; yy->__thunkpos= yythunkpos293;
  {  int yypos299= yy->__pos, yythunkpos299= yy->__thunkpos;  if (!yymatchChar(yy, '(')) goto l300;  if (!yy__(yy)) goto l300;  if (!yy_SimpleAttributeOperand(yy)) goto l300;  if (!yy__(yy)) goto l300;  if (!yymatchChar(yy, ')')) goto l300;  goto l299;
  l300:;	  yy->__pos= yypos299; yy->__thunkpos= yythunkpos299;  if (!yy_SimpleAttributeOperand(yy)) goto l292;
  }
  l299:;	
  }
  l293:;	  if (!yy__(yy)) goto l292;
  yyprintf((stderr, "  ok   %s @ %s\n", "Operand", yy->__buf+yy->__pos));
  return 1;
  l292:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "Operand", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_ReferenceElement(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;
  yyprintf((stderr, "%s\n", "ReferenceElement"));  if (!yy_ElementOperand(yy)) goto l301;  if (!yymatchString(yy, ":=")) goto l301;  yyDo(yy, yy_1_ReferenceElement, yy->__begin, yy->__end);
  yyprintf((stderr, "  ok   %s @ %s\n", "ReferenceElement", yy->__buf+yy->__pos));
  return 1;
  l301:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "ReferenceElement", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_ReferencedOperator(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;  yyDo(yy, yyPush, 4, 0);
  yyprintf((stderr, "%s\n", "ReferencedOperator"));
  {  int yypos303= yy->__pos, yythunkpos303= yy->__thunkpos;  if (!yy_ReferenceElement(yy)) goto l304;  yyDo(yy, yySet, -4, 0);  if (!yy__(yy)) goto l304;  if (!yy_OperatorInstance(yy)) goto l304;  yyDo(yy, yySet, -3, 0);  if (!yy__(yy)) goto l304;  yyDo(yy, yy_1_ReferencedOperator, yy->__begin, yy->__end);  goto l303;
  l304:;	  yy->__pos= yypos303; yy->__thunkpos= yythunkpos303;  if (!yy_ReferenceElement(yy)) goto l305;  yyDo(yy, yySet, -4, 0);  if (!yy__(yy)) goto l305;  if (!yy_BranchStructure(yy)) goto l305;  yyDo(yy, yySet, -2, 0);  if (!yy__(yy)) goto l305;  yyDo(yy, yy_2_ReferencedOperator, yy->__begin, yy->__end);  goto l303;
  l305:;	  yy->__pos= yypos303; yy->__thunkpos= yythunkpos303;  if (!yy_ReferenceElement(yy)) goto l302;  yyDo(yy, yySet, -4, 0);  if (!yy__(yy)) goto l302;  if (!yy_Operand(yy)) goto l302;  yyDo(yy, yySet, -1, 0);  if (!yy__(yy)) goto l302;  yyDo(yy, yy_3_ReferencedOperator, yy->__begin, yy->__end);  if (!yy__(yy)) goto l302;  if (!yymatchString(yy, "INLIST")) goto l302;  if (!yy__(yy)) goto l302;  if (!yymatchChar(yy, '[')) goto l302;  if (!yy__(yy)) goto l302;
  l306:;	
  {  int yypos307= yy->__pos, yythunkpos307= yy->__thunkpos;  if (!yy_Operand(yy)) goto l307;  yyDo(yy, yySet, -1, 0);  if (!yy__(yy)) goto l307;  if (!yymatchChar(yy, ',')) goto l307;  if (!yy__(yy)) goto l307;  yyDo(yy, yy_4_ReferencedOperator, yy->__begin, yy->__end);  goto l306;
  l307:;	  yy->__pos= yypos307; yy->__thunkpos= yythunkpos307;
  }  if (!yy__(yy)) goto l302;  if (!yy_Operand(yy)) goto l302;  yyDo(yy, yySet, -1, 0);  if (!yy__(yy)) goto l302;  if (!yymatchChar(yy, ']')) goto l302;  if (!yy__(yy)) goto l302;  yyDo(yy, yy_5_ReferencedOperator, yy->__begin, yy->__end);
  }
  l303:;	
  yyprintf((stderr, "  ok   %s @ %s\n", "ReferencedOperator", yy->__buf+yy->__pos));  yyDo(yy, yyPop, 4, 0);
  return 1;
  l302:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "ReferencedOperator", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_OperatorInstance(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;  yyDo(yy, yyPush, 4, 0);
  yyprintf((stderr, "%s\n", "OperatorInstance"));
  {  int yypos309= yy->__pos, yythunkpos309= yy->__thunkpos;  if (!yy_Operand(yy)) goto l310;  yyDo(yy, yySet, -4, 0);  if (!yy_TwoOperandsOperatorType(yy)) goto l310;  yyDo(yy, yySet, -3, 0);  if (!yy_Operand(yy)) goto l310;  yyDo(yy, yySet, -2, 0);  yyDo(yy, yy_1_OperatorInstance, yy->__begin, yy->__end);  goto l309;
  l310:;	  yy->__pos= yypos309; yy->__thunkpos= yythunkpos309;  if (!yy_Operand(yy)) goto l311;  yyDo(yy, yySet, -4, 0);  if (!yy__(yy)) goto l311;  if (!yymatchString(yy, "BETWEEN")) goto l311;  if (!yy__(yy)) goto l311;  if (!yymatchChar(yy, '[')) goto l311;  if (!yy__(yy)) goto l311;  if (!yy_Operand(yy)) goto l311;  yyDo(yy, yySet, -2, 0);  if (!yy__(yy)) goto l311;  if (!yymatchChar(yy, ',')) goto l311;  if (!yy__(yy)) goto l311;  if (!yy_Operand(yy)) goto l311;  yyDo(yy, yySet, -1, 0);  if (!yy__(yy)) goto l311;  if (!yymatchChar(yy, ']')) goto l311;  yyDo(yy, yy_2_OperatorInstance, yy->__begin, yy->__end);  goto l309;
  l311:;	  yy->__pos= yypos309; yy->__thunkpos= yythunkpos309;  if (!yy__(yy)) goto l308;  if (!yy_SingleOperatorType(yy)) goto l308;  yyDo(yy, yySet, -3, 0);
  }
  l309:;	  if (!yy__(yy)) goto l308;
  yyprintf((stderr, "  ok   %s @ %s\n", "OperatorInstance", yy->__buf+yy->__pos));  yyDo(yy, yyPop, 4, 0);
  return 1;
  l308:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "OperatorInstance", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_LiteralOperand(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;  yyDo(yy, yyPush, 1, 0);
  yyprintf((stderr, "%s\n", "LiteralOperand"));
  {  int yypos313= yy->__pos, yythunkpos313= yy->__thunkpos;  if (!yy_ParsedJsonString(yy)) goto l314;  yyDo(yy, yySet, -1, 0);  goto l313;
  l314:;	  yy->__pos= yypos313; yy->__thunkpos= yythunkpos313;  if (!yy_Literal(yy)) goto l312;  yyDo(yy, yySet, -1, 0);
  }
  l313:;	  yyDo(yy, yy_1_LiteralOperand, yy->__begin, yy->__end);
  yyprintf((stderr, "  ok   %s @ %s\n", "LiteralOperand", yy->__buf+yy->__pos));  yyDo(yy, yyPop, 1, 0);
  return 1;
  l312:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "LiteralOperand", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_ForOperator(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;  yyDo(yy, yyPush, 1, 0);
  yyprintf((stderr, "%s\n", "ForOperator"));
  {  int yypos316= yy->__pos, yythunkpos316= yy->__thunkpos;  if (!yy_OperatorInstance(yy)) goto l317;  yyDo(yy, yySet, -1, 0);  goto l316;
  l317:;	  yy->__pos= yypos316; yy->__thunkpos= yythunkpos316;  if (!yymatchChar(yy, '(')) goto l315;  if (!yy__(yy)) goto l315;  if (!yy_OperatorInstance(yy)) goto l315;  yyDo(yy, yySet, -1, 0);  if (!yy__(yy)) goto l315;  if (!yymatchChar(yy, ')')) goto l315;
  }
  l316:;	  yyDo(yy, yy_1_ForOperator, yy->__begin, yy->__end);
  yyprintf((stderr, "  ok   %s @ %s\n", "ForOperator", yy->__buf+yy->__pos));  yyDo(yy, yyPop, 1, 0);
  return 1;
  l315:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "ForOperator", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_ElementOperand(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;
  yyprintf((stderr, "%s\n", "ElementOperand"));  if (!yy__(yy)) goto l318;  if (!yymatchChar(yy, '$')) goto l318;
  {  int yypos319= yy->__pos, yythunkpos319= yy->__thunkpos;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l320;
#undef yytext
#undef yyleng
  }  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l320;
  l321:;	
  {  int yypos322= yy->__pos, yythunkpos322= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l322;  goto l321;
  l322:;	  yy->__pos= yypos322; yy->__thunkpos= yythunkpos322;
  }  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l320;
#undef yytext
#undef yyleng
  }  goto l319;
  l320:;	  yy->__pos= yypos319; yy->__thunkpos= yythunkpos319;  if (!yy_ParsedString(yy)) goto l318;
  }
  l319:;	  if (!yy__(yy)) goto l318;
  yyprintf((stderr, "  ok   %s @ %s\n", "ElementOperand", yy->__buf+yy->__pos));
  return 1;
  l318:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "ElementOperand", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_Child_2(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;  yyDo(yy, yyPush, 1, 0);
  yyprintf((stderr, "%s\n", "Child_2"));
  {  int yypos324= yy->__pos, yythunkpos324= yy->__thunkpos;  if (!yy_ElementOperand(yy)) goto l325;  if (!yy__(yy)) goto l325;  if (!yymatchChar(yy, ')')) goto l325;  yyDo(yy, yy_1_Child_2, yy->__begin, yy->__end);  goto l324;
  l325:;	  yy->__pos= yypos324; yy->__thunkpos= yythunkpos324;  if (!yy_SimpleAttributeOperand(yy)) goto l326;  yyDo(yy, yySet, -1, 0);  if (!yy__(yy)) goto l326;  if (!yymatchChar(yy, ')')) goto l326;  yyDo(yy, yy_2_Child_2, yy->__begin, yy->__end);  goto l324;
  l326:;	  yy->__pos= yypos324; yy->__thunkpos= yythunkpos324;  if (!yy_LiteralOperand(yy)) goto l327;  yyDo(yy, yySet, -1, 0);  if (!yy__(yy)) goto l327;  if (!yymatchChar(yy, ')')) goto l327;  yyDo(yy, yy_3_Child_2, yy->__begin, yy->__end);  goto l324;
  l327:;	  yy->__pos= yypos324; yy->__thunkpos= yythunkpos324;  if (!yy_BranchStructure(yy)) goto l328;  if (!yy__(yy)) goto l328;  if (!yymatchChar(yy, ')')) goto l328;  goto l324;
  l328:;	  yy->__pos= yypos324; yy->__thunkpos= yythunkpos324;  if (!yy_ForOperator(yy)) goto l323;  if (!yy__(yy)) goto l323;  if (!yymatchChar(yy, ')')) goto l323;
  }
  l324:;	
  yyprintf((stderr, "  ok   %s @ %s\n", "Child_2", yy->__buf+yy->__pos));  yyDo(yy, yyPop, 1, 0);
  return 1;
  l323:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "Child_2", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_Child_1(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;  yyDo(yy, yyPush, 1, 0);
  yyprintf((stderr, "%s\n", "Child_1"));
  {  int yypos330= yy->__pos, yythunkpos330= yy->__thunkpos;  if (!yymatchChar(yy, '(')) goto l331;  if (!yy__(yy)) goto l331;  if (!yy_ElementOperand(yy)) goto l331;  if (!yy__(yy)) goto l331;  if (!yymatchChar(yy, ',')) goto l331;  if (!yy__(yy)) goto l331;  yyDo(yy, yy_1_Child_1, yy->__begin, yy->__end);  goto l330;
  l331:;	  yy->__pos= yypos330; yy->__thunkpos= yythunkpos330;  if (!yymatchChar(yy, '(')) goto l332;  if (!yy__(yy)) goto l332;  if (!yy_SimpleAttributeOperand(yy)) goto l332;  yyDo(yy, yySet, -1, 0);  if (!yy__(yy)) goto l332;  if (!yymatchChar(yy, ',')) goto l332;  if (!yy__(yy)) goto l332;  yyDo(yy, yy_2_Child_1, yy->__begin, yy->__end);  goto l330;
  l332:;	  yy->__pos= yypos330; yy->__thunkpos= yythunkpos330;  if (!yymatchChar(yy, '(')) goto l333;  if (!yy__(yy)) goto l333;  if (!yy_LiteralOperand(yy)) goto l333;  yyDo(yy, yySet, -1, 0);  if (!yy__(yy)) goto l333;  if (!yymatchChar(yy, ',')) goto l333;  if (!yy__(yy)) goto l333;  yyDo(yy, yy_3_Child_1, yy->__begin, yy->__end);  goto l330;
  l333:;	  yy->__pos= yypos330; yy->__thunkpos= yythunkpos330;  if (!yymatchChar(yy, '(')) goto l334;  if (!yy__(yy)) goto l334;  if (!yy_BranchStructure(yy)) goto l334;  if (!yy__(yy)) goto l334;  if (!yymatchChar(yy, ',')) goto l334;  if (!yy__(yy)) goto l334;  goto l330;
  l334:;	  yy->__pos= yypos330; yy->__thunkpos= yythunkpos330;  if (!yymatchChar(yy, '(')) goto l329;  if (!yy__(yy)) goto l329;  if (!yy_ForOperator(yy)) goto l329;  if (!yy__(yy)) goto l329;  if (!yymatchChar(yy, ',')) goto l329;  if (!yy__(yy)) goto l329;
  }
  l330:;	
  yyprintf((stderr, "  ok   %s @ %s\n", "Child_1", yy->__buf+yy->__pos));  yyDo(yy, yyPop, 1, 0);
  return 1;
  l329:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "Child_1", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_BranchStructure(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;  yyDo(yy, yyPush, 2, 0);
  yyprintf((stderr, "%s\n", "BranchStructure"));
  {  int yypos336= yy->__pos, yythunkpos336= yy->__thunkpos;  if (!yymatchString(yy, "OR")) goto l337;  if (!yy__(yy)) goto l337;  if (!yy_Child_1(yy)) goto l337;  yyDo(yy, yySet, -2, 0);  if (!yy_Child_2(yy)) goto l337;  yyDo(yy, yySet, -1, 0);  yyDo(yy, yy_1_BranchStructure, yy->__begin, yy->__end);  goto l336;
  l337:;	  yy->__pos= yypos336; yy->__thunkpos= yythunkpos336;  if (!yymatchString(yy, "AND")) goto l335;  if (!yy__(yy)) goto l335;  if (!yy_Child_1(yy)) goto l335;  yyDo(yy, yySet, -2, 0);  if (!yy_Child_2(yy)) goto l335;  yyDo(yy, yySet, -1, 0);  yyDo(yy, yy_2_BranchStructure, yy->__begin, yy->__end);
  }
  l336:;	
  yyprintf((stderr, "  ok   %s @ %s\n", "BranchStructure", yy->__buf+yy->__pos));  yyDo(yy, yyPop, 2, 0);
  return 1;
  l335:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "BranchStructure", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_ReferencedElement(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;  yyDo(yy, yyPush, 2, 0);
  yyprintf((stderr, "%s\n", "ReferencedElement"));
  {  int yypos339= yy->__pos, yythunkpos339= yy->__thunkpos;  if (!yy_ReferencedOperator(yy)) goto l340;  goto l339;
  l340:;	  yy->__pos= yypos339; yy->__thunkpos= yythunkpos339;  if (!yy_ReferenceElement(yy)) goto l341;  yyDo(yy, yySet, -2, 0);  if (!yy_Operand(yy)) goto l341;  yyDo(yy, yySet, -1, 0);  if (!yy__(yy)) goto l341;  yyDo(yy, yy_1_ReferencedElement, yy->__begin, yy->__end);  goto l339;
  l341:;	  yy->__pos= yypos339; yy->__thunkpos= yythunkpos339;  if (!yy_ReferenceElement(yy)) goto l338;  yyDo(yy, yySet, -2, 0);  if (!yy__(yy)) goto l338;  if (!yy_NodeId(yy)) goto l338;  if (!yy__(yy)) goto l338;  yyDo(yy, yy_2_ReferencedElement, yy->__begin, yy->__end);
  }
  l339:;	
  yyprintf((stderr, "  ok   %s @ %s\n", "ReferencedElement", yy->__buf+yy->__pos));  yyDo(yy, yyPop, 2, 0);
  return 1;
  l338:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "ReferencedElement", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_SingleBranchStructure(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;  yyDo(yy, yyPush, 1, 0);
  yyprintf((stderr, "%s\n", "SingleBranchStructure"));
  {  int yypos343= yy->__pos, yythunkpos343= yy->__thunkpos;  if (!yy_ElementOperand(yy)) goto l344;  yyDo(yy, yy_1_SingleBranchStructure, yy->__begin, yy->__end);  goto l343;
  l344:;	  yy->__pos= yypos343; yy->__thunkpos= yythunkpos343;  if (!yy_ForOperator(yy)) goto l342;  yyDo(yy, yySet, -1, 0);
  }
  l343:;	
  yyprintf((stderr, "  ok   %s @ %s\n", "SingleBranchStructure", yy->__buf+yy->__pos));  yyDo(yy, yyPop, 1, 0);
  return 1;
  l342:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "SingleBranchStructure", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_SimpleAttributeOperand(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;
  yyprintf((stderr, "%s\n", "SimpleAttributeOperand"));  if (!yy__(yy)) goto l345;
  {  int yypos346= yy->__pos, yythunkpos346= yy->__thunkpos;  if (!yy__(yy)) goto l346;  if (!yymatchString(yy, "TYPEID")) goto l346;  if (!yy__(yy)) goto l346;  if (!yy_NodeId(yy)) goto l346;  goto l347;
  l346:;	  yy->__pos= yypos346; yy->__thunkpos= yythunkpos346;
  }
  l347:;	  yyDo(yy, yy_1_SimpleAttributeOperand, yy->__begin, yy->__end);  if (!yy__(yy)) goto l345;  if (!yymatchString(yy, "PATH")) goto l345;  if (!yy__(yy)) goto l345;  if (!yymatchChar(yy, '"')) goto l345;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l345;
#undef yytext
#undef yyleng
  }  if (!yy_QualifiedName(yy)) goto l345;
  l348:;	
  {  int yypos349= yy->__pos, yythunkpos349= yy->__thunkpos;  if (!yy_QualifiedName(yy)) goto l349;  goto l348;
  l349:;	  yy->__pos= yypos349; yy->__thunkpos= yythunkpos349;
  }  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l345;
#undef yytext
#undef yyleng
  }  if (!yymatchChar(yy, '"')) goto l345;  yyDo(yy, yy_2_SimpleAttributeOperand, yy->__begin, yy->__end);
  {  int yypos350= yy->__pos, yythunkpos350= yy->__thunkpos;  if (!yy__(yy)) goto l350;  if (!yymatchString(yy, "ATTRIBUTE")) goto l350;  if (!yy__(yy)) goto l350;  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_BEGIN)) goto l350;
#undef yytext
#undef yyleng
  }  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l350;
  l352:;	
  {  int yypos353= yy->__pos, yythunkpos353= yy->__thunkpos;  if (!yymatchClass(yy, (unsigned char *)"\000\000\000\000\000\000\377\003\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000")) goto l353;  goto l352;
  l353:;	  yy->__pos= yypos353; yy->__thunkpos= yythunkpos353;
  }  yyText(yy, yy->__begin, yy->__end);  {
#define yytext yy->__text
#define yyleng yy->__textlen
if (!(YY_END)) goto l350;
#undef yytext
#undef yyleng
  }  goto l351;
  l350:;	  yy->__pos= yypos350; yy->__thunkpos= yythunkpos350;
  }
  l351:;	  yyDo(yy, yy_3_SimpleAttributeOperand, yy->__begin, yy->__end);
  {  int yypos354= yy->__pos, yythunkpos354= yy->__thunkpos;  if (!yy__(yy)) goto l354;  if (!yymatchString(yy, "INDEX")) goto l354;  if (!yy__(yy)) goto l354;  if (!yy_NumericRange(yy)) goto l354;  yyDo(yy, yy_4_SimpleAttributeOperand, yy->__begin, yy->__end);  goto l355;
  l354:;	  yy->__pos= yypos354; yy->__thunkpos= yythunkpos354;
  }
  l355:;	  if (!yy__(yy)) goto l345;  yyDo(yy, yy_5_SimpleAttributeOperand, yy->__begin, yy->__end);
  yyprintf((stderr, "  ok   %s @ %s\n", "SimpleAttributeOperand", yy->__buf+yy->__pos));
  return 1;
  l345:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "SimpleAttributeOperand", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy__(yycontext *yy)
{
  yyprintf((stderr, "%s\n", "_"));
  l357:;	
  {  int yypos358= yy->__pos, yythunkpos358= yy->__thunkpos;
  {  int yypos359= yy->__pos, yythunkpos359= yy->__thunkpos;  if (!yy_Space(yy)) goto l360;  goto l359;
  l360:;	  yy->__pos= yypos359; yy->__thunkpos= yythunkpos359;  if (!yy_comment(yy)) goto l358;
  }
  l359:;	  goto l357;
  l358:;	  yy->__pos= yypos358; yy->__thunkpos= yythunkpos358;
  }
  yyprintf((stderr, "  ok   %s @ %s\n", "_", yy->__buf+yy->__pos));
  return 1;
}
YY_RULE(int) yy_Select(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;
  yyprintf((stderr, "%s\n", "Select"));  if (!yy__(yy)) goto l361;  if (!yymatchString(yy, "SELECT")) goto l361;  if (!yy__(yy)) goto l361;  yyDo(yy, yy_1_Select, yy->__begin, yy->__end);
  yyprintf((stderr, "  ok   %s @ %s\n", "Select", yy->__buf+yy->__pos));
  return 1;
  l361:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "Select", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_ContentFilter(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;  yyDo(yy, yyPush, 1, 0);
  yyprintf((stderr, "%s\n", "ContentFilter"));  if (!yy__(yy)) goto l362;  if (!yymatchString(yy, "WHERE")) goto l362;  if (!yy__(yy)) goto l362;
  {  int yypos363= yy->__pos, yythunkpos363= yy->__thunkpos;  if (!yy_SingleBranchStructure(yy)) goto l364;  yyDo(yy, yySet, -1, 0);  if (!yy__(yy)) goto l364;
  {  int yypos365= yy->__pos, yythunkpos365= yy->__thunkpos;  if (!yymatchString(yy, "FOR")) goto l365;  if (!yy__(yy)) goto l365;  if (!yy_ReferencedElement(yy)) goto l365;
  l367:;	
  {  int yypos368= yy->__pos, yythunkpos368= yy->__thunkpos;  if (!yy_ReferencedElement(yy)) goto l368;  goto l367;
  l368:;	  yy->__pos= yypos368; yy->__thunkpos= yythunkpos368;
  }  goto l366;
  l365:;	  yy->__pos= yypos365; yy->__thunkpos= yythunkpos365;
  }
  l366:;	  goto l363;
  l364:;	  yy->__pos= yypos363; yy->__thunkpos= yythunkpos363;  if (!yy_BranchStructure(yy)) goto l362;  yyDo(yy, yySet, -1, 0);  if (!yy__(yy)) goto l362;
  {  int yypos369= yy->__pos, yythunkpos369= yy->__thunkpos;  if (!yymatchString(yy, "FOR")) goto l369;  if (!yy__(yy)) goto l369;  if (!yy_ReferencedElement(yy)) goto l369;
  l371:;	
  {  int yypos372= yy->__pos, yythunkpos372= yy->__thunkpos;  if (!yy_ReferencedElement(yy)) goto l372;  goto l371;
  l372:;	  yy->__pos= yypos372; yy->__thunkpos= yythunkpos372;
  }  goto l370;
  l369:;	  yy->__pos= yypos369; yy->__thunkpos= yythunkpos369;
  }
  l370:;	
  }
  l363:;	  yyDo(yy, yy_1_ContentFilter, yy->__begin, yy->__end);
  yyprintf((stderr, "  ok   %s @ %s\n", "ContentFilter", yy->__buf+yy->__pos));  yyDo(yy, yyPop, 1, 0);
  return 1;
  l362:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "ContentFilter", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_SelectClauses(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;  yyDo(yy, yyPush, 1, 0);
  yyprintf((stderr, "%s\n", "SelectClauses"));  if (!yy_Select(yy)) goto l373;  if (!yy__(yy)) goto l373;
  l374:;	
  {  int yypos375= yy->__pos, yythunkpos375= yy->__thunkpos;
  {  int yypos376= yy->__pos, yythunkpos376= yy->__thunkpos;  if (!yy_SimpleAttributeOperand(yy)) goto l377;  yyDo(yy, yySet, -1, 0);  goto l376;
  l377:;	  yy->__pos= yypos376; yy->__thunkpos= yythunkpos376;  if (!yymatchChar(yy, '(')) goto l375;  if (!yy__(yy)) goto l375;  if (!yy_SimpleAttributeOperand(yy)) goto l375;  yyDo(yy, yySet, -1, 0);  if (!yy__(yy)) goto l375;  if (!yymatchChar(yy, ')')) goto l375;
  }
  l376:;	  if (!yy__(yy)) goto l375;  if (!yymatchChar(yy, ',')) goto l375;  if (!yy__(yy)) goto l375;  yyDo(yy, yy_1_SelectClauses, yy->__begin, yy->__end);  goto l374;
  l375:;	  yy->__pos= yypos375; yy->__thunkpos= yythunkpos375;
  }
  {  int yypos378= yy->__pos, yythunkpos378= yy->__thunkpos;  if (!yy_SimpleAttributeOperand(yy)) goto l379;  yyDo(yy, yySet, -1, 0);  goto l378;
  l379:;	  yy->__pos= yypos378; yy->__thunkpos= yythunkpos378;  if (!yymatchChar(yy, '(')) goto l373;  if (!yy__(yy)) goto l373;  if (!yy_SimpleAttributeOperand(yy)) goto l373;  yyDo(yy, yySet, -1, 0);  if (!yy__(yy)) goto l373;  if (!yymatchChar(yy, ')')) goto l373;
  }
  l378:;	  if (!yy__(yy)) goto l373;  yyDo(yy, yy_2_SelectClauses, yy->__begin, yy->__end);
  yyprintf((stderr, "  ok   %s @ %s\n", "SelectClauses", yy->__buf+yy->__pos));  yyDo(yy, yyPop, 1, 0);
  return 1;
  l373:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "SelectClauses", yy->__buf+yy->__pos));
  return 0;
}
YY_RULE(int) yy_EventFilter(yycontext *yy)
{  int yypos0= yy->__pos, yythunkpos0= yy->__thunkpos;
  yyprintf((stderr, "%s\n", "EventFilter"));  if (!yy_SelectClauses(yy)) goto l380;  if (!yy_ContentFilter(yy)) goto l380;
  yyprintf((stderr, "  ok   %s @ %s\n", "EventFilter", yy->__buf+yy->__pos));
  return 1;
  l380:;	  yy->__pos= yypos0; yy->__thunkpos= yythunkpos0;
  yyprintf((stderr, "  fail %s @ %s\n", "EventFilter", yy->__buf+yy->__pos));
  return 0;
}

#ifndef YY_PART

typedef int (*yyrule)(yycontext *yy);

YY_PARSE(static int) YYPARSEFROM(YY_CTX_PARAM_ yyrule yystart)
{
  int yyok;
  if (!yyctx->__buflen)
    {
      yyctx->__buflen= YY_BUFFER_SIZE;
      yyctx->__buf= (char *)YY_MALLOC(yyctx, yyctx->__buflen);
      yyctx->__textlen= YY_BUFFER_SIZE;
      yyctx->__text= (char *)YY_MALLOC(yyctx, yyctx->__textlen);
      yyctx->__thunkslen= YY_STACK_SIZE;
      yyctx->__thunks= (yythunk *)YY_MALLOC(yyctx, sizeof(yythunk) * yyctx->__thunkslen);
      yyctx->__valslen= YY_STACK_SIZE;
      yyctx->__vals= (YYSTYPE *)YY_MALLOC(yyctx, sizeof(YYSTYPE) * yyctx->__valslen);
      yyctx->__begin= yyctx->__end= yyctx->__pos= yyctx->__limit= yyctx->__thunkpos= 0;
    }
  yyctx->__begin= yyctx->__end= yyctx->__pos;
  yyctx->__thunkpos= 0;
  yyctx->__val= yyctx->__vals;
  yyok= yystart(yyctx);
  if (yyok) yyDone(yyctx);
  yyCommit(yyctx);
  return yyok;
}

YY_PARSE(static int) YYPARSE(YY_CTX_PARAM)
{
  return YYPARSEFROM(YY_CTX_ARG_ yy_EventFilter);
}

YY_PARSE(static yycontext *) YYRELEASE(yycontext *yyctx)
{
  if (yyctx->__buflen)
    {
      yyctx->__buflen= 0;
      YY_FREE(yyctx, yyctx->__buf);
      YY_FREE(yyctx, yyctx->__text);
      YY_FREE(yyctx, yyctx->__thunks);
      YY_FREE(yyctx, yyctx->__vals);
    }
  return yyctx;
}

#endif



UA_StatusCode UA_EventFilter_parse(UA_EventFilter *filter, UA_ByteString *content) {
    yycontext ctx;
    memset(&ctx, 0, sizeof(yycontext));
    ctx.input = *content;
    while (yyparse(&ctx));
    UA_StatusCode retval;
    if(ctx.parsedFilter.status != UA_STATUSCODE_GOOD){
        UA_StatusCode_copy(&ctx.parsedFilter.status ,&retval);
        UA_EventFilter_clear(&ctx.parsedFilter.filter);
        yyrelease(&ctx);
        return retval;
    }
    UA_EventFilter_copy(&ctx.parsedFilter.filter, filter);
    UA_EventFilter_clear(&ctx.parsedFilter.filter);
    yyrelease(&ctx);
    return UA_STATUSCODE_GOOD;
}

/**** amalgamated original file "/deps/cj5.c" ****/

// MIT License
//
// Copyright (c) 2020 Sepehr Taghdisian
// Copyright (c) 2022 Julius Pfrommer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.


#include <math.h>
#include <float.h>
#include <string.h>

#if defined(_MSC_VER)
# define CJ5_INLINE __inline
#else
# define CJ5_INLINE inline
#endif

/* vs2008 does not have INFINITY and NAN defined */
#ifndef INFINITY
# define INFINITY ((double)(DBL_MAX+DBL_MAX))
#endif
#ifndef NAN
# define NAN ((double)(INFINITY-INFINITY))
#endif

#if defined(_MSC_VER)
# pragma warning(disable: 4056)
# pragma warning(disable: 4756)
#endif

/* Max nesting depth of objects and arrays */
#define CJ5_MAX_NESTING 32

#define CJ5__FOURCC(_a, _b, _c, _d)                         \
    (((uint32_t)(_a) | ((uint32_t)(_b) << 8) |              \
      ((uint32_t)(_c) << 16) | ((uint32_t)(_d) << 24)))

static const uint32_t CJ5__NULL_FOURCC  = CJ5__FOURCC('n', 'u', 'l', 'l');
static const uint32_t CJ5__TRUE_FOURCC  = CJ5__FOURCC('t', 'r', 'u', 'e');
static const uint32_t CJ5__FALSE_FOURCC = CJ5__FOURCC('f', 'a', 'l', 's');

typedef struct {
    unsigned int pos;
    unsigned int line_start;
    unsigned int line;
    cj5_error_code error;

    const char *json5;
    unsigned int len;

    unsigned int curr_tok_idx;

    cj5_token *tokens;
    unsigned int token_count;
    unsigned int max_tokens;

    bool stop_early;
} cj5__parser;

static CJ5_INLINE bool
cj5__isrange(char ch, char from, char to) {
    return (uint8_t)(ch - from) <= (uint8_t)(to - from);
}

#define cj5__isupperchar(ch) cj5__isrange(ch, 'A', 'Z')
#define cj5__islowerchar(ch) cj5__isrange(ch, 'a', 'z')
#define cj5__isnum(ch)       cj5__isrange(ch, '0', '9')

static cj5_token *
cj5__alloc_token(cj5__parser *parser) {
    cj5_token* token = NULL;
    if(parser->token_count < parser->max_tokens) {
        token = &parser->tokens[parser->token_count];
        memset(token, 0x0, sizeof(cj5_token));
    } else {
        parser->error = CJ5_ERROR_OVERFLOW;
    }

    // Always increase the index. So we know eventually how many token would be
    // required (if there are not enough).
    parser->token_count++;
    return token;
}

static void
cj5__parse_string(cj5__parser *parser) {
    const char *json5 = parser->json5;
    unsigned int len = parser->len;
    unsigned int start = parser->pos;
    char str_open = json5[start];

    parser->pos++;
    for(; parser->pos < len; parser->pos++) {
        char c = json5[parser->pos];

        // End of string
        if(str_open == c) {
            cj5_token *token = cj5__alloc_token(parser);
            if(token) {
                token->type = CJ5_TOKEN_STRING;
                token->start = start + 1;
                token->end = parser->pos - 1;
                token->size = token->end - token->start + 1;
                token->parent_id = parser->curr_tok_idx;
            } 
            return;
        }

        // Unescaped newlines are forbidden
        if(c == '\n') {
            parser->error = CJ5_ERROR_INVALID;
            return;
        }

        // Escape char
        if(c == '\\') {
            if(parser->pos + 1 >= len) {
                parser->error = CJ5_ERROR_INCOMPLETE;
                return;
            }
            parser->pos++;
            switch(json5[parser->pos]) {
            case '\"':
            case '/':
            case '\\':
            case 'b':
            case 'f':
            case 'r':
            case 'n':
            case 't':
                break;
            case 'u': // The next four characters are an utf8 code
                parser->pos++;
                if(parser->pos + 4 >= len) {
                    parser->error = CJ5_ERROR_INVALID;
                    return;
                }
                for(unsigned int i = 0; i < 4; i++) {
                    // If it isn't a hex character we have an error
                    if(!(json5[parser->pos] >= 48 && json5[parser->pos] <= 57) && /* 0-9 */
                       !(json5[parser->pos] >= 65 && json5[parser->pos] <= 70) && /* A-F */
                       !(json5[parser->pos] >= 97 && json5[parser->pos] <= 102))  /* a-f */
                        {
                            parser->error = CJ5_ERROR_INVALID;
                            return;
                        }
                    parser->pos++;
                }
                parser->pos--;
                break;
            case '\n': // Escape break line
                parser->line++;
                parser->line_start = parser->pos;
                break;
            default:
                parser->error = CJ5_ERROR_INVALID;
                return;
            }
        }
    }

    // The file has ended before the string terminates
    parser->error = CJ5_ERROR_INCOMPLETE;
}

// parser->pos is advanced a last time in the next iteration of the main
// parse-loop. So we leave parse-primitive in a state where parse->pos points to
// the last character of the primitive value (or the quote-character of the
// string).
static void
cj5__parse_primitive(cj5__parser* parser) {
    const char* json5 = parser->json5;
    unsigned int len = parser->len;
    unsigned int start = parser->pos;

    // String value
    if(json5[start] == '\"' ||
       json5[start] == '\'') {
        cj5__parse_string(parser);
        return;
    }

    // Fast comparison of bool, and null.
    // We have to use memcpy here or we can get unaligned accesses
    uint32_t fourcc = 0;
    if(start + 4 < len)
        memcpy(&fourcc, &json5[start], 4);
    
    cj5_token_type type;
    if(fourcc == CJ5__NULL_FOURCC) {
        type = CJ5_TOKEN_NULL;
        parser->pos += 3;
    } else if(fourcc == CJ5__TRUE_FOURCC) {
        type = CJ5_TOKEN_BOOL;
        parser->pos += 3;
    } else if(fourcc == CJ5__FALSE_FOURCC) {
        // "false" has five characters
        type = CJ5_TOKEN_BOOL;
        if(start + 4 >= len || json5[start+4] != 'e') {
            parser->error = CJ5_ERROR_INVALID;
            return;
        }
        parser->pos += 4;
    } else {
        // Numbers are checked for basic compatibility.
        // But they are fully parsed only in the cj5_get_XXX functions.
        type = CJ5_TOKEN_NUMBER;
        for(; parser->pos < len; parser->pos++) {
            if(!cj5__isnum(json5[parser->pos]) &&
               !(json5[parser->pos] == '.') &&
               !cj5__islowerchar(json5[parser->pos]) && 
               !cj5__isupperchar(json5[parser->pos]) &&
               !(json5[parser->pos] == '+') && !(json5[parser->pos] == '-')) {
                break;
            }
        }
        parser->pos--; // Point to the last character that is still inside the
                       // primitive value
    }

    cj5_token *token = cj5__alloc_token(parser);
    if(token) {
        token->type = type;
        token->start = start;
        token->end = parser->pos;
        token->size = parser->pos - start + 1;
        token->parent_id = parser->curr_tok_idx;
    }
}

static void
cj5__parse_key(cj5__parser* parser) {
    const char* json5 = parser->json5;
    unsigned int start = parser->pos;
    cj5_token* token;

    // Key is a a normal string
    if(json5[start] == '\"' || json5[start] == '\'') {
        cj5__parse_string(parser);
        return;
    }

    // An unquoted key. Must start with a-ZA-Z_$. Can contain numbers later on.
    unsigned int len = parser->len;
    for(; parser->pos < len; parser->pos++) {
        if(cj5__islowerchar(json5[parser->pos]) ||
           cj5__isupperchar(json5[parser->pos]) ||
           json5[parser->pos] == '_' || json5[parser->pos] == '$')
            continue;
        if(cj5__isnum(json5[parser->pos]) && parser->pos != start)
            continue;
        break;
    }

    // An empty key is not allowed
    if(parser->pos <= start) {
        parser->error = CJ5_ERROR_INVALID;
        return;
    }

    // Move pos to the last character within the unquoted key
    parser->pos--;

    token = cj5__alloc_token(parser);
    if(token) {
        token->type = CJ5_TOKEN_STRING;
        token->start = start;
        token->end = parser->pos;
        token->size = parser->pos - start + 1;
        token->parent_id = parser->curr_tok_idx;
    }
}

static void
cj5__skip_comment(cj5__parser* parser) {
    const char* json5 = parser->json5;

    // Single-line comment
    if(json5[parser->pos] == '#') {
    skip_line:
        while(parser->pos < parser->len) {
            if(json5[parser->pos] == '\n') {
                parser->pos--; // Reparse the newline in the main parse loop
                return;
            }
            parser->pos++;
        }
        return;
    }

    // Comment begins with '/' but not enough space for another character
    if(parser->pos + 1 >= parser->len) {
        parser->error = CJ5_ERROR_INVALID;
        return;
    }
    parser->pos++;

    // Comment begins with '//' -> single-line comment
    if(json5[parser->pos] == '/')
        goto skip_line;

    // Multi-line comments begin with '/*' and end with '*/'
    if(json5[parser->pos] == '*') {
        parser->pos++;
        for(; parser->pos + 1 < parser->len; parser->pos++) {
            if(json5[parser->pos] == '*' && json5[parser->pos + 1] == '/') {
                parser->pos++;
                return;
            }
            // Remember we passed a newline
            if(json5[parser->pos] == '\n') {
                parser->line++;
                parser->line_start = parser->pos;
            }
        }
    }

    // Unknown comment type or the multi-line comment is not terminated
    parser->error = CJ5_ERROR_INCOMPLETE;
}

cj5_result
cj5_parse(const char *json5, unsigned int len,
          cj5_token *tokens, unsigned int max_tokens,
          cj5_options *options) {
    cj5_result r;
    cj5__parser parser;
    memset(&parser, 0x0, sizeof(parser));
    parser.curr_tok_idx = 0;
    parser.json5 = json5;
    parser.len = len;
    parser.tokens = tokens;
    parser.max_tokens = max_tokens;

    if(options)
        parser.stop_early = options->stop_early;

    unsigned short depth = 0; // Nesting depth zero means "outside the root object"
    char nesting[CJ5_MAX_NESTING]; // Contains either '\0', '{' or '[' for the
                                   // type of nesting at each depth. '\0'
                                   // indicates we are out of the root object.
    char next[CJ5_MAX_NESTING];    // Next content to parse: 'k' (key), ':', 'v'
                                   // (value) or ',' (comma).
    next[0] = 'v';  // The root is a "value" (object, array or primitive). If we
                    // detect a colon after the first value then everything is
                    // wrapped into a "virtual root object" and the parsing is
                    // restarted.
    nesting[0] = 0; // Becomes '{' if there is a virtual root object

    cj5_token *token = NULL; // The current token

 start_parsing:
    for(; parser.pos < len; parser.pos++) {
        char c = json5[parser.pos];
        switch(c) {
        case '\n': // Skip newline
            parser.line++;
            parser.line_start = parser.pos;
            break;

        case '\r': // Skip whitespace
        case '\t':
        case ' ':
            break;

        case '#': // Skip comment
        case '/':
            cj5__skip_comment(&parser);
            if(parser.error != CJ5_ERROR_NONE &&
               parser.error != CJ5_ERROR_OVERFLOW)
                goto finish;
            break;

        case '{': // Open an object or array
        case '[':
            // Check the nesting depth
            if(depth + 1 >= CJ5_MAX_NESTING) {
                parser.error = CJ5_ERROR_INVALID;
                goto finish;
            }

            // Correct next?
            if(next[depth] != 'v') {
                parser.error = CJ5_ERROR_INVALID;
                goto finish;
            }

            depth++; // Increase the nesting depth
            nesting[depth] = c; // Set the nesting type
            next[depth] = (c == '{') ? 'k' : 'v'; // next is either a key or a value

            // Create a token for the object or array
            token = cj5__alloc_token(&parser);
            if(token) {
                token->parent_id = parser.curr_tok_idx;
                token->type = (c == '{') ? CJ5_TOKEN_OBJECT : CJ5_TOKEN_ARRAY;
                token->start = parser.pos;
                token->size = 0;
                parser.curr_tok_idx = parser.token_count - 1; // The new curr_tok_idx
                                                              // is for this token
            }
            break;

        case '}': // Close an object or array
        case ']':
            // Check the nesting depth. Note that a "virtual root object" at
            // depth zero must not be closed.
            if(depth == 0) {
                parser.error = CJ5_ERROR_INVALID;
                goto finish;
            }

            // Check and adjust the nesting. Note that ']' - '[' == 2 and '}' -
            // '{' == 2. Arrays can always be closed. Objects can only close
            // when a key or a comma is expected.
            if(c - nesting[depth] != 2 ||
               (c == '}' && next[depth] != 'k' && next[depth] != ',')) {
                parser.error = CJ5_ERROR_INVALID;
                goto finish;
            }

            if(token) {
                // Finalize the current token
                token->end = parser.pos;

                // Move to the parent and increase the parent size. Omit this
                // when we leave the root (parent the same as the current
                // token).
                if(parser.curr_tok_idx != token->parent_id) {
                    parser.curr_tok_idx = token->parent_id;
                    token = &tokens[token->parent_id];
                    token->size++;
                }
            }

            // Step one level up
            depth--;
            next[depth] = (depth == 0) ? 0 : ','; // zero if we step out the root
                                                  // object. then we do not look for
                                                  // another element.

            // The first element was successfully parsed. Stop early or try to
            // parse the full input string?
            if(depth == 0 && parser.stop_early)
                goto finish;

            break;

        case ':': // Colon (between key and value)
            if(next[depth] != ':') {
                parser.error = CJ5_ERROR_INVALID;
                goto finish;
            }
            next[depth] = 'v';
            break;

        case ',': // Comma
            if(next[depth] != ',') {
                parser.error = CJ5_ERROR_INVALID;
                goto finish;
            }
            next[depth] = (nesting[depth] == '{') ? 'k' : 'v';
            break;

        default: // Value or key
            if(next[depth] == 'v') {
                cj5__parse_primitive(&parser); // Parse primitive value
                if(nesting[depth] != 0) {
                    // Parent is object or array
                    if(token)
                        token->size++;
                    next[depth] = ',';
                } else {
                    // The current value was the root element. Don't look for
                    // any next element.
                    next[depth] = 0;

                    // The first element was successfully parsed. Stop early or try to
                    // parse the full input string?
                    if(parser.stop_early)
                        goto finish;
                }
            } else if(next[depth] == 'k') {
                cj5__parse_key(&parser);
                if(token)
                    token->size++; // Keys count towards the length
                next[depth] = ':';
            } else {
                parser.error = CJ5_ERROR_INVALID;
            }

            if(parser.error && parser.error != CJ5_ERROR_OVERFLOW)
                goto finish;

            break;
        }
    }

    // Are we back to the initial nesting depth?
    if(depth != 0) {
        parser.error = CJ5_ERROR_INCOMPLETE;
        goto finish;
    }

    // Close the virtual root object if there is one
    if(nesting[0] == '{' && parser.error != CJ5_ERROR_OVERFLOW) {
        // Check the we end after a complete key-value pair (or dangling comma)
        if(next[0] != 'k' && next[0] != ',')
            parser.error = CJ5_ERROR_INVALID;
        tokens[0].end = parser.pos - 1;
    }

 finish:
    // If parsing failed at the initial nesting depth, create a virtual root object
    // and restart parsing.
    if(parser.error != CJ5_ERROR_NONE &&
       parser.error != CJ5_ERROR_OVERFLOW &&
       depth == 0 && nesting[0] != '{') {
        parser.token_count = 0;
        token = cj5__alloc_token(&parser);
        if(token) {
            token->parent_id = 0;
            token->type = CJ5_TOKEN_OBJECT;
            token->start = 0;
            token->size = 0;

            nesting[0] = '{';
            next[0] = 'k';

            parser.curr_tok_idx = 0;
            parser.pos = 0;
            parser.error = CJ5_ERROR_NONE;
            goto start_parsing;
        }
    }

    memset(&r, 0x0, sizeof(r));
    r.error = parser.error;
    r.error_line = parser.line;
    r.error_col = parser.pos - parser.line_start;
    r.num_tokens = parser.token_count; // How many tokens (would) have been
                                       // consumed by the parser?

    // Not a single token was parsed -> return an error
    if(r.num_tokens == 0)
        r.error = CJ5_ERROR_INCOMPLETE;

    // Set the tokens and original string only if successfully parsed
    if(r.error == CJ5_ERROR_NONE) {
        r.tokens = tokens;
        r.json5 = json5;
    }

    return r;
}

cj5_error_code
cj5_get_bool(const cj5_result *r, unsigned int tok_index, bool *out) {
    const cj5_token *token = &r->tokens[tok_index];
    if(token->type != CJ5_TOKEN_BOOL)
        return CJ5_ERROR_INVALID;
    *out = (r->json5[token->start] == 't');
    return CJ5_ERROR_NONE;
}

cj5_error_code
cj5_get_float(const cj5_result *r, unsigned int tok_index, double *out) {
    const cj5_token *token = &r->tokens[tok_index];
    if(token->type != CJ5_TOKEN_NUMBER)
        return CJ5_ERROR_INVALID;

    const char *tokstr = &r->json5[token->start];
    size_t toksize = token->end - token->start + 1;
    if(toksize == 0)
        return CJ5_ERROR_INVALID;

    // Skip prefixed +/-
    bool neg = false;
    if(tokstr[0] == '+' || tokstr[0] == '-') {
        neg = (tokstr[0] == '-');
        tokstr++;
        toksize--;
    }

    // Detect prefixed inf/nan
    if(strncmp(tokstr, "Infinity", toksize) == 0) {
        *out = neg ? -INFINITY : INFINITY;
        return CJ5_ERROR_NONE;
    } else if(strncmp(tokstr, "NaN", toksize) == 0) {
        *out = NAN;
        return CJ5_ERROR_NONE;
    }

    // reset the +/- detection and parse
    tokstr = &r->json5[token->start];
    toksize = token->end - token->start + 1;
    size_t parsed = parseDouble(tokstr, toksize, out);

    // There must only be whitespace between the end of the parsed number and
    // the end of the token
    for(size_t i = parsed; i < toksize; i++) {
        if(tokstr[i] != ' ' && tokstr[i] -'\t' >= 5)
            return CJ5_ERROR_INVALID;
    }

    return (parsed != 0) ? CJ5_ERROR_NONE : CJ5_ERROR_INVALID;
}

cj5_error_code
cj5_get_int(const cj5_result *r, unsigned int tok_index,
            int64_t *out) {
    const cj5_token *token = &r->tokens[tok_index];
    if(token->type != CJ5_TOKEN_NUMBER)
        return CJ5_ERROR_INVALID;
    size_t parsed = parseInt64(&r->json5[token->start], token->size, out);
    return (parsed != 0) ? CJ5_ERROR_NONE : CJ5_ERROR_INVALID;
}

cj5_error_code
cj5_get_uint(const cj5_result *r, unsigned int tok_index,
             uint64_t *out) {
    const cj5_token *token = &r->tokens[tok_index];
    if(token->type != CJ5_TOKEN_NUMBER)
        return CJ5_ERROR_INVALID;
    size_t parsed = parseUInt64(&r->json5[token->start], token->size, out);
    return (parsed != 0) ? CJ5_ERROR_NONE : CJ5_ERROR_INVALID;
}

static const uint32_t SURROGATE_OFFSET = 0x10000u - (0xD800u << 10) - 0xDC00;

static cj5_error_code
parse_codepoint(const char *pos, uint32_t *out_utf) {
    uint32_t utf = 0;
    for(unsigned int i = 0; i < 4; i++) {
        char byte = pos[i];
        if(cj5__isnum(byte)) {
            byte = (char)(byte - '0');
        } else if(cj5__isrange(byte, 'a', 'f')) {
            byte = (char)(byte - ('a' - 10));
        } else if(cj5__isrange(byte, 'A', 'F')) {
            byte = (char)(byte - ('A' - 10));
        } else {
            return CJ5_ERROR_INVALID;
        }
        utf = (utf << 4) | ((uint8_t)byte & 0xF);
    }
    *out_utf = utf;
    return CJ5_ERROR_NONE;
}

cj5_error_code
cj5_get_str(const cj5_result *r, unsigned int tok_index,
            char *buf, unsigned int *buflen) {
    const cj5_token *token = &r->tokens[tok_index];
    if(token->type != CJ5_TOKEN_STRING)
        return CJ5_ERROR_INVALID;

    const char *pos = &r->json5[token->start];
    const char *end = &r->json5[token->end + 1];
    unsigned int outpos = 0;
    for(; pos < end; pos++) {
        uint8_t c = (uint8_t)*pos;

        // Process an escape character
        if(c == '\\') {
            if(pos + 1 >= end)
                return CJ5_ERROR_INCOMPLETE;
            pos++;
            c = (uint8_t)*pos;
            switch(c) {
            case '\"': buf[outpos++] = '\"'; break;
            case '\\': buf[outpos++] = '\\'; break;
            case '\n': buf[outpos++] = '\n'; break; // escape newline
            case '/':  buf[outpos++] = '/';  break;
            case 'b':  buf[outpos++] = '\b'; break;
            case 'f':  buf[outpos++] = '\f'; break;
            case 'r':  buf[outpos++] = '\r'; break;
            case 'n':  buf[outpos++] = '\n'; break;
            case 't':  buf[outpos++] = '\t'; break;
            case 'u': {
                // Parse the unicode code point
                if(pos + 4 >= end)
                    return CJ5_ERROR_INCOMPLETE;
                pos++;
                uint32_t utf;
                cj5_error_code err = parse_codepoint(pos, &utf);
                if(err != CJ5_ERROR_NONE)
                    return err;
                pos += 3;

                if(0xD800 <= utf && utf <= 0xDBFF) {
                    // Parse a surrogate pair
                    if(pos + 6 >= end)
                        return CJ5_ERROR_INVALID;
                    if(pos[1] != '\\' && pos[3] != 'u')
                        return CJ5_ERROR_INVALID;
                    pos += 3;
                    uint32_t trail;
                    err = parse_codepoint(pos, &trail);
                    if(err != CJ5_ERROR_NONE)
                        return err;
                    pos += 3;
                    utf = (utf << 10) + trail + SURROGATE_OFFSET;
                } else if(0xDC00 <= utf && utf <= 0xDFFF) {
                    // Invalid Unicode '\\u%04X'
                    return CJ5_ERROR_INVALID;
                }
                
                // Write the utf8 bytes of the code point
                if(utf <= 0x7F) { // Plain ASCII
                    buf[outpos++] = (char)utf;
                } else if(utf <= 0x07FF) { // 2-byte unicode
                    buf[outpos++] = (char)(((utf >> 6) & 0x1F) | 0xC0);
                    buf[outpos++] = (char)(((utf >> 0) & 0x3F) | 0x80);
                } else if(utf <= 0xFFFF) { // 3-byte unicode
                    buf[outpos++] = (char)(((utf >> 12) & 0x0F) | 0xE0);
                    buf[outpos++] = (char)(((utf >>  6) & 0x3F) | 0x80);
                    buf[outpos++] = (char)(((utf >>  0) & 0x3F) | 0x80);
                } else if(utf <= 0x10FFFF) { // 4-byte unicode
                    buf[outpos++] = (char)(((utf >> 18) & 0x07) | 0xF0);
                    buf[outpos++] = (char)(((utf >> 12) & 0x3F) | 0x80);
                    buf[outpos++] = (char)(((utf >>  6) & 0x3F) | 0x80);
                    buf[outpos++] = (char)(((utf >>  0) & 0x3F) | 0x80);
                } else {
                    return CJ5_ERROR_INVALID; // Not a utf8 string
                }
                break;
            }
            default:
                return CJ5_ERROR_INVALID;
            }
            continue;
        }

        // Unprintable ascii characters must be escaped. JSON5 allows nested
        // quotes if the quote character is not the same as the surrounding
        // quote character, e.g. 'this is my "quote"'. This logic is in the
        // token parsing code and not in this "string extraction" method.
        if(c < ' '   || c == 127)
            return CJ5_ERROR_INVALID;

        // Ascii character or utf8 byte
        buf[outpos++] = (char)c;
    }

    // Terminate with \0
    buf[outpos] = 0;

    // Set the output length
    if(buflen)
        *buflen = outpos;
    return CJ5_ERROR_NONE;
}

void
cj5_skip(const cj5_result *r, unsigned int *tok_index) {
    unsigned int idx = *tok_index;
    unsigned int end = r->tokens[idx].end;
    do { idx++; } while(idx < r->num_tokens &&
                        r->tokens[idx].start < end);
    *tok_index = idx;
}

cj5_error_code
cj5_find(const cj5_result *r, unsigned int *tok_index,
         const char *key) {
    // It has to be an object
    unsigned int idx = *tok_index;
    if(r->tokens[idx].type != CJ5_TOKEN_OBJECT)
        return CJ5_ERROR_INVALID;
    unsigned int size = r->tokens[idx].size;

    // Skip to the first key
    idx++;

    // Size is number of keys + number of values
    for(unsigned int i = 0; i < size; i += 2) {
        // Key has to be a string
        if(r->tokens[idx].type != CJ5_TOKEN_STRING)
            return CJ5_ERROR_INVALID;

        // Return the index to the value if the key matches
        const char *keystart = &r->json5[r->tokens[idx].start];
        size_t keysize = r->tokens[idx].end - r->tokens[idx].start + 1;
        if(strncmp(key, keystart, keysize) == 0) {
            *tok_index = idx + 1;
            return CJ5_ERROR_NONE;
        }

        // Skip over the value
        idx++;
        cj5_skip(r, &idx);
    }
    return CJ5_ERROR_NOTFOUND;
}

/**** amalgamated original file "/deps/parse_num.c" ****/

/* Originally released by the musl project (http://www.musl-libc.org/) under the
 * MIT license. Taken and adapted from the file src/stdlib/atoi.c 
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */


#include <string.h>
#include <stdlib.h>
#include <errno.h>

size_t
parseUInt64(const char *str, size_t size, uint64_t *result) {
    size_t i = 0;
    uint64_t n = 0, prev = 0;

    /* Hex */
    if(size > 2 && str[0] == '0' && (str[1] | 32) == 'x') {
        i = 2;
        for(; i < size; i++) {
            uint8_t c = (uint8_t)str[i] | 32;
            if(c >= '0' && c <= '9')
                c = (uint8_t)(c - '0');
            else if(c >= 'a' && c <='f')
                c = (uint8_t)(c - 'a' + 10);
            else if(c >= 'A' && c <='F')
                c = (uint8_t)(c - 'A' + 10);
            else
                break;
            n = (n << 4) | (c & 0xF);
            if(n < prev) /* Check for overflow */
                return 0;
            prev = n;
        }
        *result = n;
        return (i > 2) ? i : 0; /* 2 -> No digit was parsed */
    }

    /* Decimal */
    for(; i < size; i++) {
        if(str[i] < '0' || str[i] > '9')
            break;
        /* Fast multiplication: n*10 == (n*8) + (n*2) */
        n = (n << 3) + (n << 1) + (uint8_t)(str[i] - '0');
        if(n < prev) /* Check for overflow */
            return 0;
        prev = n;
    }
    *result = n;
    return i;
}

size_t
parseInt64(const char *str, size_t size, int64_t *result) {
    /* Negative value? */
    size_t i = 0;
    bool neg = false;
    if(*str == '-' || *str == '+') {
        neg = (*str == '-');
        i++;
    }

    /* Parse as unsigned */
    uint64_t n = 0;
    size_t len = parseUInt64(&str[i], size - i, &n);
    if(len == 0)
        return 0;

    /* Check for overflow, adjust and return */
    if(!neg) {
        if(n > 9223372036854775807UL)
            return 0;
        *result = (int64_t)n;
    } else {
        if(n > 9223372036854775808UL)
            return 0;
        *result = -(int64_t)n;
    }
    return len + i;
}

size_t parseDouble(const char *str, size_t size, double *result) {
    char buf[2000];
    if(size >= 2000)
        return 0;
    memcpy(buf, str, size);
    buf[size] = 0;
    errno = 0;
    char *endptr;
    *result = strtod(str, &endptr);
    if(errno != 0 && errno != ERANGE)
        return 0;
    return (uintptr_t)endptr - (uintptr_t)str;
}

/**** amalgamated original file "/src/ua_types_encoding_json.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2018 (c) Fraunhofer IOSB (Author: Lukas Meling)
 */


#ifdef UA_ENABLE_JSON_ENCODING


#include <float.h>
#include <math.h>


#ifndef UA_ENABLE_PARSING
#error UA_ENABLE_PARSING required for JSON encoding
#endif

#ifndef UA_ENABLE_TYPEDESCRIPTION
#error UA_ENABLE_TYPEDESCRIPTION required for JSON encoding
#endif

/* vs2008 does not have INFINITY and NAN defined */
#ifndef INFINITY
# define INFINITY ((UA_Double)(DBL_MAX+DBL_MAX))
#endif
#ifndef NAN
# define NAN ((UA_Double)(INFINITY-INFINITY))
#endif

#if defined(_MSC_VER)
# pragma warning(disable: 4756)
# pragma warning(disable: 4056)
#endif

/* Have some slack at the end. E.g. for negative and very long years. */
#define UA_JSON_DATETIME_LENGTH 40

/************/
/* Encoding */
/************/

#define ENCODE_JSON(TYPE) static status \
    TYPE##_encodeJson(CtxJson *ctx, const UA_##TYPE *src, const UA_DataType *type)

#define ENCODE_DIRECT_JSON(SRC, TYPE) \
    TYPE##_encodeJson(ctx, (const UA_##TYPE*)SRC, NULL)

static status UA_FUNC_ATTR_WARN_UNUSED_RESULT
writeChar(CtxJson *ctx, char c) {
    if(ctx->pos >= ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
    if(!ctx->calcOnly)
        *ctx->pos = (UA_Byte)c;
    ctx->pos++;
    return UA_STATUSCODE_GOOD;
}

static status UA_FUNC_ATTR_WARN_UNUSED_RESULT
writeChars(CtxJson *ctx, const char *c, size_t len) {
    if(ctx->pos + len > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
    if(!ctx->calcOnly)
        memcpy(ctx->pos, c, len);
    ctx->pos += len;
    return UA_STATUSCODE_GOOD;
}

#define WRITE_JSON_ELEMENT(ELEM)                            \
    UA_FUNC_ATTR_WARN_UNUSED_RESULT status                  \
    writeJson##ELEM(CtxJson *ctx)

static WRITE_JSON_ELEMENT(Quote) {
    return writeChar(ctx, '\"');
}

UA_StatusCode
writeJsonBeforeElement(CtxJson *ctx, UA_Boolean distinct) {
    /* Comma if needed */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(ctx->commaNeeded[ctx->depth])
        res |= writeChar(ctx, ',');

    if(ctx->prettyPrint) {
        if(distinct) {
            /* Newline and indent if needed */
            res |= writeChar(ctx, '\n');
            for(size_t i = 0; i < ctx->depth; i++)
                res |= writeChar(ctx, '\t');
        } else if(ctx->commaNeeded[ctx->depth]) {
            /* Space after the comma if no newline */
            res |= writeChar(ctx, ' ');
        }
    }

    return res;
}

WRITE_JSON_ELEMENT(ObjStart) {
    /* increase depth, save: before first key-value no comma needed. */
    if(ctx->depth >= UA_JSON_ENCODING_MAX_RECURSION - 1)
        return UA_STATUSCODE_BADENCODINGERROR;
    ctx->depth++;
    ctx->commaNeeded[ctx->depth] = false;
    return writeChar(ctx, '{');
}

WRITE_JSON_ELEMENT(ObjEnd) {
    if(ctx->depth == 0)
        return UA_STATUSCODE_BADENCODINGERROR;

    UA_Boolean have_elem = ctx->commaNeeded[ctx->depth];
    ctx->depth--;
    ctx->commaNeeded[ctx->depth] = true;

    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(ctx->prettyPrint && have_elem) {
        res |= writeChar(ctx, '\n');
        for(size_t i = 0; i < ctx->depth; i++)
            res |= writeChar(ctx, '\t');
    }
    res |= writeChar(ctx, '}');
    return res;
}

WRITE_JSON_ELEMENT(ArrStart) {
    /* increase depth, save: before first array entry no comma needed. */
    if(ctx->depth >= UA_JSON_ENCODING_MAX_RECURSION - 1)
        return UA_STATUSCODE_BADENCODINGERROR;
    ctx->depth++;
    ctx->commaNeeded[ctx->depth] = false;
    return writeChar(ctx, '[');
}

WRITE_JSON_ELEMENT(ArrEnd) {
    if(ctx->depth == 0)
        return UA_STATUSCODE_BADENCODINGERROR;
    UA_Boolean have_elem = ctx->commaNeeded[ctx->depth];
    ctx->depth--;
    ctx->commaNeeded[ctx->depth] = true;
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(ctx->prettyPrint && have_elem) {
        res |= writeChar(ctx, '\n');
        for(size_t i = 0; i < ctx->depth; i++)
            res |= writeChar(ctx, '\t');
    }
    res |= writeChar(ctx, ']');
    return res;
}

status
writeJsonArrElm(CtxJson *ctx, const void *value,
                const UA_DataType *type) {
    UA_Boolean distinct = (type->typeKind > UA_DATATYPEKIND_DOUBLE);
    status ret = writeJsonBeforeElement(ctx, distinct);
    ctx->commaNeeded[ctx->depth] = true;
    ret |= encodeJsonJumpTable[type->typeKind](ctx, value, type);
    return ret;
}

status
writeJsonObjElm(CtxJson *ctx, const char *key,
                const void *value, const UA_DataType *type) {
    return writeJsonKey(ctx, key) | encodeJsonJumpTable[type->typeKind](ctx, value, type);
}

/* Keys for JSON */

/* LocalizedText */
static const char* UA_JSONKEY_LOCALE = "Locale";
static const char* UA_JSONKEY_TEXT = "Text";

/* QualifiedName */
static const char* UA_JSONKEY_NAME = "Name";
static const char* UA_JSONKEY_URI = "Uri";

/* NodeId */
static const char* UA_JSONKEY_ID = "Id";
static const char* UA_JSONKEY_IDTYPE = "IdType";
static const char* UA_JSONKEY_NAMESPACE = "Namespace";

/* ExpandedNodeId */
static const char* UA_JSONKEY_SERVERURI = "ServerUri";

/* Variant */
static const char* UA_JSONKEY_TYPE = "Type";
static const char* UA_JSONKEY_BODY = "Body";
static const char* UA_JSONKEY_DIMENSION = "Dimension";

/* DataValue */
static const char* UA_JSONKEY_VALUE = "Value";
static const char* UA_JSONKEY_STATUS = "Status";
static const char* UA_JSONKEY_SOURCETIMESTAMP = "SourceTimestamp";
static const char* UA_JSONKEY_SOURCEPICOSECONDS = "SourcePicoseconds";
static const char* UA_JSONKEY_SERVERTIMESTAMP = "ServerTimestamp";
static const char* UA_JSONKEY_SERVERPICOSECONDS = "ServerPicoseconds";

/* ExtensionObject */
static const char* UA_JSONKEY_ENCODING = "Encoding";
static const char* UA_JSONKEY_TYPEID = "TypeId";

/* StatusCode */
static const char* UA_JSONKEY_CODE = "Code";
static const char* UA_JSONKEY_SYMBOL = "Symbol";

/* DiagnosticInfo */
static const char* UA_JSONKEY_SYMBOLICID = "SymbolicId";
static const char* UA_JSONKEY_NAMESPACEURI = "NamespaceUri";
static const char* UA_JSONKEY_LOCALIZEDTEXT = "LocalizedText";
static const char* UA_JSONKEY_ADDITIONALINFO = "AdditionalInfo";
static const char* UA_JSONKEY_INNERSTATUSCODE = "InnerStatusCode";
static const char* UA_JSONKEY_INNERDIAGNOSTICINFO = "InnerDiagnosticInfo";

/* Writes null terminated string to output buffer (current ctx->pos). Writes
 * comma in front of key if needed. Encapsulates key in quotes. */
status UA_FUNC_ATTR_WARN_UNUSED_RESULT
writeJsonKey(CtxJson *ctx, const char* key) {
    status ret = writeJsonBeforeElement(ctx, true);
    ctx->commaNeeded[ctx->depth] = true;
    if(!ctx->unquotedKeys)
        ret |= writeChar(ctx, '\"');
    ret |= writeChars(ctx, key, strlen(key));
    if(!ctx->unquotedKeys)
        ret |= writeChar(ctx, '\"');
    ret |= writeChar(ctx, ':');
    if(ctx->prettyPrint)
        ret |= writeChar(ctx, ' ');
    return ret;
}

static bool
isNull(const void *p, const UA_DataType *type) {
    if(UA_DataType_isNumeric(type) || type->typeKind == UA_DATATYPEKIND_BOOLEAN)
        return false;
    UA_STACKARRAY(char, buf, type->memSize);
    memset(buf, 0, type->memSize);
    return UA_equal(buf, p, type);
}

/* Boolean */
ENCODE_JSON(Boolean) {
    if(*src == true)
        return writeChars(ctx, "true", 4);
    return writeChars(ctx, "false", 5);
}

/* Byte */
ENCODE_JSON(Byte) {
    char buf[4];
    UA_UInt16 digits = itoaUnsigned(*src, buf, 10);

    /* Ensure destination can hold the data- */
    if(ctx->pos + digits > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;

    /* Copy digits to the output string/buffer. */
    if(!ctx->calcOnly)
        memcpy(ctx->pos, buf, digits);
    ctx->pos += digits;
    return UA_STATUSCODE_GOOD;
}

/* signed Byte */
ENCODE_JSON(SByte) {
    char buf[5];
    UA_UInt16 digits = itoaSigned(*src, buf);
    if(ctx->pos + digits > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
    if(!ctx->calcOnly)
        memcpy(ctx->pos, buf, digits);
    ctx->pos += digits;
    return UA_STATUSCODE_GOOD;
}

/* UInt16 */
ENCODE_JSON(UInt16) {
    char buf[6];
    UA_UInt16 digits = itoaUnsigned(*src, buf, 10);

    if(ctx->pos + digits > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;

    if(!ctx->calcOnly)
        memcpy(ctx->pos, buf, digits);
    ctx->pos += digits;
    return UA_STATUSCODE_GOOD;
}

/* Int16 */
ENCODE_JSON(Int16) {
    char buf[7];
    UA_UInt16 digits = itoaSigned(*src, buf);

    if(ctx->pos + digits > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;

    if(!ctx->calcOnly)
        memcpy(ctx->pos, buf, digits);
    ctx->pos += digits;
    return UA_STATUSCODE_GOOD;
}

/* UInt32 */
ENCODE_JSON(UInt32) {
    char buf[11];
    UA_UInt16 digits = itoaUnsigned(*src, buf, 10);

    if(ctx->pos + digits > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;

    if(!ctx->calcOnly)
        memcpy(ctx->pos, buf, digits);
    ctx->pos += digits;
    return UA_STATUSCODE_GOOD;
}

/* Int32 */
ENCODE_JSON(Int32) {
    char buf[12];
    UA_UInt16 digits = itoaSigned(*src, buf);

    if(ctx->pos + digits > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;

    if(!ctx->calcOnly)
        memcpy(ctx->pos, buf, digits);
    ctx->pos += digits;
    return UA_STATUSCODE_GOOD;
}

/* UInt64 */
ENCODE_JSON(UInt64) {
    char buf[23];
    buf[0] = '\"';
    UA_UInt16 digits = itoaUnsigned(*src, buf + 1, 10);
    buf[digits + 1] = '\"';
    UA_UInt16 length = (UA_UInt16)(digits + 2);

    if(ctx->pos + length > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;

    if(!ctx->calcOnly)
        memcpy(ctx->pos, buf, length);
    ctx->pos += length;
    return UA_STATUSCODE_GOOD;
}

/* Int64 */
ENCODE_JSON(Int64) {
    char buf[23];
    buf[0] = '\"';
    UA_UInt16 digits = itoaSigned(*src, buf + 1);
    buf[digits + 1] = '\"';
    UA_UInt16 length = (UA_UInt16)(digits + 2);

    if(ctx->pos + length > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;

    if(!ctx->calcOnly)
        memcpy(ctx->pos, buf, length);
    ctx->pos += length;
    return UA_STATUSCODE_GOOD;
}

ENCODE_JSON(Float) {
    char buffer[32];
    size_t len;
    if(*src != *src) {
        strcpy(buffer, "\"NaN\"");
        len = strlen(buffer);
    } else if(*src == INFINITY) {
        strcpy(buffer, "\"Infinity\"");
        len = strlen(buffer);
    } else if(*src == -INFINITY) {
        strcpy(buffer, "\"-Infinity\"");
        len = strlen(buffer);
    } else {
        len = dtoa((UA_Double)*src, buffer);
    }

    if(ctx->pos + len > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;

    if(!ctx->calcOnly)
        memcpy(ctx->pos, buffer, len);
    ctx->pos += len;
    return UA_STATUSCODE_GOOD;
}

ENCODE_JSON(Double) {
    char buffer[32];
    size_t len;
    if(*src != *src) {
        strcpy(buffer, "\"NaN\"");
        len = strlen(buffer);
    } else if(*src == INFINITY) {
        strcpy(buffer, "\"Infinity\"");
        len = strlen(buffer);
    } else if(*src == -INFINITY) {
        strcpy(buffer, "\"-Infinity\"");
        len = strlen(buffer);
    } else {
        len = dtoa(*src, buffer);
    }

    if(ctx->pos + len > ctx->end)
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;

    if(!ctx->calcOnly)
        memcpy(ctx->pos, buffer, len);
    ctx->pos += len;
    return UA_STATUSCODE_GOOD;
}

static status
encodeJsonArray(CtxJson *ctx, const void *ptr, size_t length,
                const UA_DataType *type) {
    /* Null-arrays (length -1) are written as empty arrays '[]'.
     * TODO: Clarify the difference between length -1 and length 0 in JSON. */
    status ret = writeJsonArrStart(ctx);
    if(!ptr)
        return ret | writeJsonArrEnd(ctx);

    uintptr_t uptr = (uintptr_t)ptr;
    encodeJsonSignature encodeType = encodeJsonJumpTable[type->typeKind];
    UA_Boolean distinct = (type->typeKind > UA_DATATYPEKIND_DOUBLE);
    for(size_t i = 0; i < length && ret == UA_STATUSCODE_GOOD; ++i) {
        ret |= writeJsonBeforeElement(ctx, distinct);
        if(isNull((const void*)uptr, type))
            ret |= writeChars(ctx, "null", 4);
        else
            ret |= encodeType(ctx, (const void*)uptr, type);
        ctx->commaNeeded[ctx->depth] = true;
        uptr += type->memSize;
    }
    ret |= writeJsonArrEnd(ctx);
    return ret;
}

static const uint32_t min_codepoints[5] = {0x00, 0x00, 0x80, 0x800, 0x10000};
static const u8 hexmap[16] =
    {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

/* Extract the next utf8 codepoint from the buffer. Return the next position in
 * the buffer or NULL upon an error. */
static const unsigned char *
extract_codepoint(const unsigned char *pos, size_t len, uint32_t *codepoint) {
    UA_assert(len > 0);

    *codepoint = pos[0];
    if(UA_LIKELY(*codepoint < 0x80))
        return pos + 1; /* Normal ASCII */

    if(UA_UNLIKELY(*codepoint <= 0xC1))
        return NULL; /* Continuation byte not allowed here */

    unsigned char count;
    if(*codepoint <= 0xDF) {
        count = 2; /* 2-byte sequence */
        *codepoint &= 0x1F;
    } else if(*codepoint <= 0xEF) {
        count = 3; /* 3-byte sequence */
        *codepoint &= 0xF;
    } else if(*codepoint <= 0xF4) {
        count = 4; /* 4-byte sequence */
        *codepoint &= 0x7;
    } else {
        return NULL; /* invalid utf8 */
    }

    if(UA_UNLIKELY(count > len))
        return NULL; /* Not enough bytes left */

    for(unsigned char i = 1; i < count; i++) {
        unsigned char byte = pos[i];
        if(UA_UNLIKELY(byte < 0x80 || byte > 0xBF))
            return NULL; /* Not a continuation byte */
        *codepoint = (*codepoint << 6) + (byte & 0x3F);
    }

    /* Not in Unicode range or too small for the encoding length */
    if(UA_UNLIKELY(*codepoint > 0x10FFFF || *codepoint < min_codepoints[count]))
        return NULL;

    return pos + count; /* Return the new position in the pos */
}

ENCODE_JSON(String) {
    if(!src->data)
        return writeChars(ctx, "null", 4);

    if(src->length == 0)
        return writeJsonQuote(ctx) | writeJsonQuote(ctx);

    UA_StatusCode ret = writeJsonQuote(ctx);

    const unsigned char *str = src->data;
    const unsigned char *pos = str;
    const unsigned char *end = str;
    const unsigned char *lim = str + src->length;
    uint32_t codepoint = 0;
    while(1) {
        /* Iterate over codepoints in the utf8 encoding. Until the first
         * character that needs to be escaped. */
        while(end < lim) {
            end = extract_codepoint(pos, (size_t)(lim - pos), &codepoint);
            if(!end)  {
                /* A malformed utf8 character. Print anyway and let the
                 * receiving side choose how to handle it. */
                pos++;
                end = pos;
                continue;
            }

            /* Escape unprintable ASCII and escape characters */
            if(codepoint < ' '   || codepoint == 127  ||
               codepoint == '\\' || codepoint == '\"')
                break;

            pos = end;
        }

        /* Write out the characters that don't need escaping */
        if(pos != str) {
            if(ctx->pos + (pos - str) > ctx->end)
                return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
            if(!ctx->calcOnly)
                memcpy(ctx->pos, str, (size_t)(pos - str));
            ctx->pos += pos - str;
        }

        /* Reached the end of the utf8 encoding */
        if(end == pos)
            break;

        /* Handle an escaped character */
        size_t length = 2;
        u8 seq[13];
        const char *text;

        switch(codepoint) {
        case '\\': text = "\\\\"; break;
        case '\"': text = "\\\""; break;
        case '\b': text = "\\b"; break;
        case '\f': text = "\\f"; break;
        case '\n': text = "\\n"; break;
        case '\r': text = "\\r"; break;
        case '\t': text = "\\t"; break;
        default:
            text = (char*)seq;
            if(codepoint < 0x10000) {
                /* codepoint is in BMP */
                seq[0] = '\\';
                seq[1] = 'u';
                UA_Byte b1 = (UA_Byte)(codepoint >> 8u);
                UA_Byte b2 = (UA_Byte)(codepoint >> 0u);
                seq[2] = hexmap[(b1 & 0xF0u) >> 4u];
                seq[3] = hexmap[b1 & 0x0Fu];
                seq[4] = hexmap[(b2 & 0xF0u) >> 4u];
                seq[5] = hexmap[b2 & 0x0Fu];
                length = 6;
            } else {
                /* not in BMP -> construct a UTF-16 surrogate pair */
                codepoint -= 0x10000;
                UA_UInt32 first = 0xD800u | ((codepoint & 0xffc00u) >> 10u);
                UA_UInt32 last = 0xDC00u | (codepoint & 0x003ffu);
                UA_Byte fb1 = (UA_Byte)(first >> 8u);
                UA_Byte fb2 = (UA_Byte)(first >> 0u);
                UA_Byte lb1 = (UA_Byte)(last >> 8u);
                UA_Byte lb2 = (UA_Byte)(last >> 0u);
                seq[0] = '\\';
                seq[1] = 'u';
                seq[2] = hexmap[(fb1 & 0xF0u) >> 4u];
                seq[3] = hexmap[fb1 & 0x0Fu];
                seq[4] = hexmap[(fb2 & 0xF0u) >> 4u];
                seq[5] = hexmap[fb2 & 0x0Fu];
                seq[6] = '\\';
                seq[7] = 'u';
                seq[8] = hexmap[(lb1 & 0xF0u) >> 4u];
                seq[9] = hexmap[lb1 & 0x0Fu];
                seq[10] = hexmap[(lb2 & 0xF0u) >> 4u];
                seq[11] = hexmap[lb2 & 0x0Fu];
                length = 12;
            }
            break;
        }
        if(ctx->pos + length > ctx->end)
            return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
        if(!ctx->calcOnly)
            memcpy(ctx->pos, text, length);
        ctx->pos += length;
        str = pos = end;
    }

    ret |= writeJsonQuote(ctx);
    return ret;
}

ENCODE_JSON(ByteString) {
    if(!src->data)
        return writeChars(ctx, "null", 4);

    if(src->length == 0) {
        status retval = writeJsonQuote(ctx);
        retval |= writeJsonQuote(ctx);
        return retval;
    }

    status ret = writeJsonQuote(ctx);
    size_t flen = 0;
    unsigned char *ba64 = UA_base64(src->data, src->length, &flen);

    /* Not converted, no mem */
    if(!ba64)
        return UA_STATUSCODE_BADENCODINGERROR;

    if(ctx->pos + flen > ctx->end) {
        UA_free(ba64);
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
    }

    /* Copy flen bytes to output stream. */
    if(!ctx->calcOnly)
        memcpy(ctx->pos, ba64, flen);
    ctx->pos += flen;

    /* Base64 result no longer needed */
    UA_free(ba64);

    ret |= writeJsonQuote(ctx);
    return ret;
}

/* Guid */
ENCODE_JSON(Guid) {
    if(ctx->pos + 38 > ctx->end) /* 36 + 2 (") */
        return UA_STATUSCODE_BADENCODINGLIMITSEXCEEDED;
    status ret = writeJsonQuote(ctx);
    if(!ctx->calcOnly)
        UA_Guid_to_hex(src, ctx->pos, false);
    ctx->pos += 36;
    ret |= writeJsonQuote(ctx);
    return ret;
}

static u8
printNumber(i32 n, char *pos, u8 min_digits) {
    char digits[10];
    u8 len = 0;
    /* Handle negative values */
    if(n < 0) {
        pos[len++] = '-';
        n = -n;
    }

    /* Extract the digits */
    u8 i = 0;
    for(; i < min_digits || n > 0; i++) {
        digits[i] = (char)((n % 10) + '0');
        n /= 10;
    }

    /* Print in reverse order and return */
    for(; i > 0; i--)
        pos[len++] = digits[i-1];
    return len;
}

ENCODE_JSON(DateTime) {
    UA_DateTimeStruct tSt = UA_DateTime_toStruct(*src);

    /* Format: -yyyy-MM-dd'T'HH:mm:ss.SSSSSSSSS'Z' is used. max 31 bytes.
     * Note the optional minus for negative years. */
    char buffer[UA_JSON_DATETIME_LENGTH];
    char *pos = buffer;
    pos += printNumber(tSt.year, pos, 4);
    *(pos++) = '-';
    pos += printNumber(tSt.month, pos, 2);
    *(pos++) = '-';
    pos += printNumber(tSt.day, pos, 2);
    *(pos++) = 'T';
    pos += printNumber(tSt.hour, pos, 2);
    *(pos++) = ':';
    pos += printNumber(tSt.min, pos, 2);
    *(pos++) = ':';
    pos += printNumber(tSt.sec, pos, 2);
    *(pos++) = '.';
    pos += printNumber(tSt.milliSec, pos, 3);
    pos += printNumber(tSt.microSec, pos, 3);
    pos += printNumber(tSt.nanoSec, pos, 3);

    UA_assert(pos <= &buffer[UA_JSON_DATETIME_LENGTH]);

    /* Remove trailing zeros */
    pos--;
    while(*pos == '0')
        pos--;
    if(*pos == '.')
        pos--;

    *(++pos) = 'Z';
    UA_String str = {((uintptr_t)pos - (uintptr_t)buffer)+1, (UA_Byte*)buffer};
    return ENCODE_DIRECT_JSON(&str, String);
}

/* NodeId */
static status
NodeId_encodeJsonInternal(CtxJson *ctx, UA_NodeId const *src) {
    status ret = UA_STATUSCODE_GOOD;
    switch(src->identifierType) {
    case UA_NODEIDTYPE_NUMERIC:
        ret |= writeJsonKey(ctx, UA_JSONKEY_ID);
        ret |= ENCODE_DIRECT_JSON(&src->identifier.numeric, UInt32);
        break;
    case UA_NODEIDTYPE_STRING:
        ret |= writeJsonKey(ctx, UA_JSONKEY_IDTYPE);
        ret |= writeChar(ctx, '1');
        ret |= writeJsonKey(ctx, UA_JSONKEY_ID);
        ret |= ENCODE_DIRECT_JSON(&src->identifier.string, String);
        break;
    case UA_NODEIDTYPE_GUID:
        ret |= writeJsonKey(ctx, UA_JSONKEY_IDTYPE);
        ret |= writeChar(ctx, '2');
        ret |= writeJsonKey(ctx, UA_JSONKEY_ID); /* Id */
        ret |= ENCODE_DIRECT_JSON(&src->identifier.guid, Guid);
        break;
    case UA_NODEIDTYPE_BYTESTRING:
        ret |= writeJsonKey(ctx, UA_JSONKEY_IDTYPE);
        ret |= writeChar(ctx, '3');
        ret |= writeJsonKey(ctx, UA_JSONKEY_ID); /* Id */
        ret |= ENCODE_DIRECT_JSON(&src->identifier.byteString, ByteString);
        break;
    default:
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return ret;
}

ENCODE_JSON(NodeId) {
    /* Encode as string (non-standard). Encode with the standard utf8 escaping.
     * As the NodeId can contain quote characters, etc. */
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    if(ctx->stringNodeIds) {
        UA_String out = UA_STRING_NULL;
        ret |= UA_NodeId_print(src, &out);
        ret |= encodeJsonJumpTable[UA_DATATYPEKIND_STRING](ctx, &out, NULL);
        UA_String_clear(&out);
        return ret;
    }

    /* Encode as object */
    ret |= writeJsonObjStart(ctx);
    ret |= NodeId_encodeJsonInternal(ctx, src);
    if(ctx->useReversible) {
        if(src->namespaceIndex > 0) {
            ret |= writeJsonKey(ctx, UA_JSONKEY_NAMESPACE);
            ret |= ENCODE_DIRECT_JSON(&src->namespaceIndex, UInt16);
        }
    } else {
        /* For the non-reversible encoding, the field is the NamespaceUri
         * associated with the NamespaceIndex, encoded as a JSON string.
         * A NamespaceIndex of 1 is always encoded as a JSON number. */
        if(src->namespaceIndex == 1) {
            ret |= writeJsonKey(ctx, UA_JSONKEY_NAMESPACE);
            ret |= ENCODE_DIRECT_JSON(&src->namespaceIndex, UInt16);
        } else {
            ret |= writeJsonKey(ctx, UA_JSONKEY_NAMESPACE);

            /* Check if Namespace given and in range */
            if(src->namespaceIndex < ctx->namespacesSize && ctx->namespaces != NULL) {
                UA_String namespaceEntry = ctx->namespaces[src->namespaceIndex];
                ret |= ENCODE_DIRECT_JSON(&namespaceEntry, String);
            } else {
                return UA_STATUSCODE_BADNOTFOUND;
            }
        }
    }

    ret |= writeJsonObjEnd(ctx);
    return ret;
}

/* ExpandedNodeId */
ENCODE_JSON(ExpandedNodeId) {
    /* Encode as string (non-standard). Encode with utf8 escaping as the NodeId
     * can contain quote characters, etc. */
    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    if(ctx->stringNodeIds) {
        UA_String out = UA_STRING_NULL;
        ret |= UA_ExpandedNodeId_print(src, &out);
        ret |= encodeJsonJumpTable[UA_DATATYPEKIND_STRING](ctx, &out, NULL);
        UA_String_clear(&out);
        return ret;
    }

    /* Encode as object */
    ret |= writeJsonObjStart(ctx);

    /* Encode the identifier portion */
    ret |= NodeId_encodeJsonInternal(ctx, &src->nodeId);

    if(ctx->useReversible) {
        /* Reversible Case */

        if(src->namespaceUri.data) {
            /* If the NamespaceUri is specified it is encoded as a JSON string
             * in this field */
            ret |= writeJsonKey(ctx, UA_JSONKEY_NAMESPACE);
            ret |= ENCODE_DIRECT_JSON(&src->namespaceUri, String);
        } else if(src->nodeId.namespaceIndex > 0) {
            /* If the NamespaceUri is not specified, the NamespaceIndex is
             * encoded. Encoded as a JSON number for the reversible encoding.
             * Omitted if the NamespaceIndex equals 0. */
            ret |= writeJsonKey(ctx, UA_JSONKEY_NAMESPACE);
            ret |= ENCODE_DIRECT_JSON(&src->nodeId.namespaceIndex, UInt16);
        }

        /* Encode the serverIndex/Url. As a JSON number for the reversible
         * encoding. Omitted if the ServerIndex equals 0. */
        if(src->serverIndex > 0) {
            ret |= writeJsonKey(ctx, UA_JSONKEY_SERVERURI);
            ret |= ENCODE_DIRECT_JSON(&src->serverIndex, UInt32);
        }
    } else {
        /* Non-Reversible Case */

        /* If the NamespaceUri is not specified, the NamespaceIndex is encoded
         * with these rules: For the non-reversible encoding the field is the
         * NamespaceUri associated with the NamespaceIndex encoded as a JSON
         * string. A NamespaceIndex of 1 is always encoded as a JSON number. */

        if(src->namespaceUri.data) {
            ret |= writeJsonKey(ctx, UA_JSONKEY_NAMESPACE);
            ret |= ENCODE_DIRECT_JSON(&src->namespaceUri, String);
        } else {
            if(src->nodeId.namespaceIndex == 1) {
                ret |= writeJsonKey(ctx, UA_JSONKEY_NAMESPACE);
                ret |= ENCODE_DIRECT_JSON(&src->nodeId.namespaceIndex, UInt16);
            } else {
                /* Check if Namespace given and in range */
                if(src->nodeId.namespaceIndex >= ctx->namespacesSize || !ctx->namespaces)
                    return UA_STATUSCODE_BADNOTFOUND;
                UA_String namespaceEntry = ctx->namespaces[src->nodeId.namespaceIndex];
                ret |= writeJsonKey(ctx, UA_JSONKEY_NAMESPACE);
                ret |= ENCODE_DIRECT_JSON(&namespaceEntry, String);
            }
        }

        /* For the non-reversible encoding, this field is the ServerUri
         * associated with the ServerIndex portion of the ExpandedNodeId,
         * encoded as a JSON string. */

        /* Check if server given and in range */
        if(src->serverIndex >= ctx->serverUrisSize || !ctx->serverUris)
            return UA_STATUSCODE_BADNOTFOUND;

        UA_String serverUriEntry = ctx->serverUris[src->serverIndex];
        ret |= writeJsonKey(ctx, UA_JSONKEY_SERVERURI);
        ret |= ENCODE_DIRECT_JSON(&serverUriEntry, String);
    }

    ret |= writeJsonObjEnd(ctx);
    return ret;
}

/* LocalizedText */
ENCODE_JSON(LocalizedText) {
    if(ctx->useReversible) {
        status ret = writeJsonObjStart(ctx);
        ret |= writeJsonKey(ctx, UA_JSONKEY_LOCALE);
        ret |= ENCODE_DIRECT_JSON(&src->locale, String);
        ret |= writeJsonKey(ctx, UA_JSONKEY_TEXT);
        ret |= ENCODE_DIRECT_JSON(&src->text, String);
        ret |= writeJsonObjEnd(ctx);
        return ret;
    }

    /* For the non-reversible form, LocalizedText value shall be encoded as a
     * JSON string containing the Text component.*/
    return ENCODE_DIRECT_JSON(&src->text, String);
}

ENCODE_JSON(QualifiedName) {
    status ret = writeJsonObjStart(ctx);
    ret |= writeJsonKey(ctx, UA_JSONKEY_NAME);
    ret |= ENCODE_DIRECT_JSON(&src->name, String);

    if(ctx->useReversible) {
        if(src->namespaceIndex != 0) {
            ret |= writeJsonKey(ctx, UA_JSONKEY_URI);
            ret |= ENCODE_DIRECT_JSON(&src->namespaceIndex, UInt16);
        }
    } else {
        /* For the non-reversible form, the NamespaceUri associated with the
         * NamespaceIndex portion of the QualifiedName is encoded as JSON string
         * unless the NamespaceIndex is 1 or if NamespaceUri is unknown. In
         * these cases, the NamespaceIndex is encoded as a JSON number. */
        if(src->namespaceIndex == 1) {
            ret |= writeJsonKey(ctx, UA_JSONKEY_URI);
            ret |= ENCODE_DIRECT_JSON(&src->namespaceIndex, UInt16);
        } else {
            ret |= writeJsonKey(ctx, UA_JSONKEY_URI);

             /* Check if Namespace given and in range */
            if(src->namespaceIndex < ctx->namespacesSize && ctx->namespaces != NULL) {
                UA_String namespaceEntry = ctx->namespaces[src->namespaceIndex];
                ret |= ENCODE_DIRECT_JSON(&namespaceEntry, String);
            } else {
                /* If not encode as number */
                ret |= ENCODE_DIRECT_JSON(&src->namespaceIndex, UInt16);
            }
        }
    }

    return ret | writeJsonObjEnd(ctx);
}

ENCODE_JSON(StatusCode) {
    if(ctx->useReversible)
        return ENCODE_DIRECT_JSON(src, UInt32);

    const char *codename = UA_StatusCode_name(*src);
    UA_String statusDescription = UA_STRING((char*)(uintptr_t)codename);

    status ret = UA_STATUSCODE_GOOD;
    ret |= writeJsonObjStart(ctx);
    ret |= writeJsonKey(ctx, UA_JSONKEY_CODE);
    ret |= ENCODE_DIRECT_JSON(src, UInt32);
    ret |= writeJsonKey(ctx, UA_JSONKEY_SYMBOL);
    ret |= ENCODE_DIRECT_JSON(&statusDescription, String);
    ret |= writeJsonObjEnd(ctx);
    return ret;
}

/* ExtensionObject */
ENCODE_JSON(ExtensionObject) {
    if(src->encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY)
        return writeChars(ctx, "null", 4);

    /* Must have a type set if data is decoded */
    if(src->encoding != UA_EXTENSIONOBJECT_ENCODED_BYTESTRING &&
       src->encoding != UA_EXTENSIONOBJECT_ENCODED_XML &&
       !src->content.decoded.type)
        return UA_STATUSCODE_BADENCODINGERROR;

    status ret = writeJsonObjStart(ctx);

    /* Reversible encoding */
    if(ctx->useReversible) {
        /* Write the type NodeId */
        ret |= writeJsonKey(ctx, UA_JSONKEY_TYPEID);
        if(src->encoding == UA_EXTENSIONOBJECT_ENCODED_BYTESTRING ||
           src->encoding == UA_EXTENSIONOBJECT_ENCODED_XML)
            ret |= ENCODE_DIRECT_JSON(&src->content.encoded.typeId, NodeId);
        else
            ret |= ENCODE_DIRECT_JSON(&src->content.decoded.type->typeId, NodeId);

        /* Write the encoding */
        if(src->encoding == UA_EXTENSIONOBJECT_ENCODED_BYTESTRING) {
            ret |= writeJsonKey(ctx, UA_JSONKEY_ENCODING);
            ret |= writeChar(ctx, '1');
        } else if(src->encoding == UA_EXTENSIONOBJECT_ENCODED_XML) {
            ret |= writeJsonKey(ctx, UA_JSONKEY_ENCODING);
            ret |= writeChar(ctx, '2');
        }
    }

    /* Write the body */
    ret |= writeJsonKey(ctx, UA_JSONKEY_BODY);
    if(src->encoding == UA_EXTENSIONOBJECT_ENCODED_BYTESTRING ||
       src->encoding == UA_EXTENSIONOBJECT_ENCODED_XML) {
        ret |= ENCODE_DIRECT_JSON(&src->content.encoded.body, String);
    } else {
        const UA_DataType *t = src->content.decoded.type;
        ret |= encodeJsonJumpTable[t->typeKind]
            (ctx, src->content.decoded.data, t);
    }

    ret |= writeJsonObjEnd(ctx);
    return ret;
}

static status
Variant_encodeJsonWrapExtensionObject(const UA_Variant *src, const bool isArray,
                                      CtxJson *ctx) {
    size_t length = 1;
    if(isArray) {
        if(src->arrayLength > UA_INT32_MAX)
            return UA_STATUSCODE_BADENCODINGERROR;

        length = src->arrayLength;
    }

    /* Set up a temporary ExtensionObject to wrap the data */
    UA_ExtensionObject eo;
    UA_ExtensionObject_init(&eo);
    eo.encoding = UA_EXTENSIONOBJECT_DECODED;
    eo.content.decoded.type = src->type;

    if(isArray) {
        u16 memSize = src->type->memSize;
        uintptr_t ptr = (uintptr_t)src->data;
        status ret = writeJsonArrStart(ctx);
        for(size_t i = 0; i < length && ret == UA_STATUSCODE_GOOD; ++i) {
            eo.content.decoded.data = (void*)ptr;
            ret |= writeJsonArrElm(ctx, &eo, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]);
            ptr += memSize;
        }
        return ret | writeJsonArrEnd(ctx);
    }

    eo.content.decoded.data = src->data;
    return ExtensionObject_encodeJson(ctx, &eo, NULL);
}

static status
addMultiArrayContentJSON(CtxJson *ctx, void* array, const UA_DataType *type,
                         size_t *index, UA_UInt32 *arrayDimensions, size_t dimensionIndex,
                         size_t dimensionSize) {
    /* Stop recursion: The inner Arrays are written */
    status ret;
    if(dimensionIndex == (dimensionSize - 1)) {
        ret = encodeJsonArray(ctx, ((u8*)array) + (type->memSize * *index),
                              arrayDimensions[dimensionIndex], type);
        (*index) += arrayDimensions[dimensionIndex];
        return ret;
    }

    /* Recurse to the next dimension */
    ret = writeJsonArrStart(ctx);
    if(ret != UA_STATUSCODE_GOOD)
        return ret;
    for(size_t i = 0; i < arrayDimensions[dimensionIndex]; i++) {
        ret |= writeJsonBeforeElement(ctx, true);
        ret |= addMultiArrayContentJSON(ctx, array, type, index, arrayDimensions,
                                        dimensionIndex + 1, dimensionSize);
        ctx->commaNeeded[ctx->depth] = true;
        if(ret != UA_STATUSCODE_GOOD)
            return ret;
    }
    ret |= writeJsonArrEnd(ctx);
    return ret;
}

ENCODE_JSON(Variant) {
    /* If type is 0 (NULL) the Variant contains a NULL value and the containing
     * JSON object shall be omitted or replaced by the JSON literal ‘null’ (when
     * an element of a JSON array). */
    if(!src->type)
        return writeJsonObjStart(ctx) | writeJsonObjEnd(ctx);

    /* Set the content type in the encoding mask */
    const UA_Boolean isBuiltin = (src->type->typeKind <= UA_DATATYPEKIND_DIAGNOSTICINFO);

    /* Set the array type in the encoding mask */
    const bool isArray = src->arrayLength > 0 || src->data <= UA_EMPTY_ARRAY_SENTINEL;
    const bool hasDimensions = isArray && src->arrayDimensionsSize > 0;

    /* We cannot directly encode a variant inside a variant (but arrays of
     * variant are possible) */
    UA_Boolean wrapEO = !isBuiltin;
    if(src->type == &UA_TYPES[UA_TYPES_VARIANT] && !isArray)
        wrapEO = true;
    if(ctx->prettyPrint)
        wrapEO = false; /* Don't wrap values in ExtensionObjects for pretty-printing */

    status ret = writeJsonObjStart(ctx);

    if(ctx->useReversible) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_TYPE);
        if(ctx->prettyPrint) {
            ret |= writeChars(ctx, src->type->typeName, strlen(src->type->typeName));
        } else {
            /* Write the NodeId for the reversible form */
            UA_UInt32 typeId = src->type->typeId.identifier.numeric;
            if(wrapEO)
                typeId = UA_TYPES[UA_TYPES_EXTENSIONOBJECT].typeId.identifier.numeric;
            ret |= ENCODE_DIRECT_JSON(&typeId, UInt32);
        }
    }

    if(wrapEO) {
        /* Not builtin. Can it be encoded? Wrap in extension object. */
        if(src->arrayDimensionsSize > 1)
            return UA_STATUSCODE_BADNOTIMPLEMENTED;
        ret |= writeJsonKey(ctx, UA_JSONKEY_BODY);
        ret |= Variant_encodeJsonWrapExtensionObject(src, isArray, ctx);
    } else if(!isArray) {
        /* Unwrapped scalar */
        ret |= writeJsonKey(ctx, UA_JSONKEY_BODY);
        ret |= encodeJsonJumpTable[src->type->typeKind](ctx, src->data, src->type);
    } else if(ctx->useReversible) {
        /* Reversible array */
        ret |= writeJsonKey(ctx, UA_JSONKEY_BODY);
        ret |= encodeJsonArray(ctx, src->data, src->arrayLength, src->type);
        if(hasDimensions) {
            ret |= writeJsonKey(ctx, UA_JSONKEY_DIMENSION);
            ret |= encodeJsonArray(ctx, src->arrayDimensions, src->arrayDimensionsSize,
                                   &UA_TYPES[UA_TYPES_INT32]);
        }
    } else {
        /* Non-Reversible array */
        ret |= writeJsonKey(ctx, UA_JSONKEY_BODY);
        if(src->arrayDimensionsSize > 1) {
            size_t index = 0;
            size_t dimensionIndex = 0;
            ret |= addMultiArrayContentJSON(ctx, src->data, src->type, &index,
                                            src->arrayDimensions, dimensionIndex,
                                            src->arrayDimensionsSize);
        } else {
            ret |= encodeJsonArray(ctx, src->data, src->arrayLength, src->type);
        }
    }

    ret |= writeJsonObjEnd(ctx);
    return ret;
}

/* DataValue */
ENCODE_JSON(DataValue) {
    UA_Boolean hasValue = src->hasValue;
    UA_Boolean hasStatus = src->hasStatus;
    UA_Boolean hasSourceTimestamp = src->hasSourceTimestamp;
    UA_Boolean hasSourcePicoseconds = src->hasSourcePicoseconds;
    UA_Boolean hasServerTimestamp = src->hasServerTimestamp;
    UA_Boolean hasServerPicoseconds = src->hasServerPicoseconds;

    status ret = writeJsonObjStart(ctx);

    if(hasValue) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_VALUE);
        ret |= ENCODE_DIRECT_JSON(&src->value, Variant);
    }

    if(hasStatus) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_STATUS);
        ret |= ENCODE_DIRECT_JSON(&src->status, StatusCode);
    }

    if(hasSourceTimestamp) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_SOURCETIMESTAMP);
        ret |= ENCODE_DIRECT_JSON(&src->sourceTimestamp, DateTime);
    }

    if(hasSourcePicoseconds) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_SOURCEPICOSECONDS);
        ret |= ENCODE_DIRECT_JSON(&src->sourcePicoseconds, UInt16);
    }

    if(hasServerTimestamp) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_SERVERTIMESTAMP);
        ret |= ENCODE_DIRECT_JSON(&src->serverTimestamp, DateTime);
    }

    if(hasServerPicoseconds) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_SERVERPICOSECONDS);
        ret |= ENCODE_DIRECT_JSON(&src->serverPicoseconds, UInt16);
    }

    return ret | writeJsonObjEnd(ctx);
}

/* DiagnosticInfo */
ENCODE_JSON(DiagnosticInfo) {
    status ret = writeJsonObjStart(ctx);

    if(src->hasSymbolicId) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_SYMBOLICID);
        ret |= ENCODE_DIRECT_JSON(&src->symbolicId, Int32);
    }

    if(src->hasNamespaceUri) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_NAMESPACEURI);
        ret |= ENCODE_DIRECT_JSON(&src->namespaceUri, Int32);
    }

    if(src->hasLocalizedText) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_LOCALIZEDTEXT);
        ret |= ENCODE_DIRECT_JSON(&src->localizedText, Int32);
    }

    if(src->hasLocale) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_LOCALE);
        ret |= ENCODE_DIRECT_JSON(&src->locale, Int32);
    }

    if(src->hasAdditionalInfo) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_ADDITIONALINFO);
        ret |= ENCODE_DIRECT_JSON(&src->additionalInfo, String);
    }

    if(src->hasInnerStatusCode) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_INNERSTATUSCODE);
        ret |= ENCODE_DIRECT_JSON(&src->innerStatusCode, StatusCode);
    }

    if(src->hasInnerDiagnosticInfo && src->innerDiagnosticInfo) {
        ret |= writeJsonKey(ctx, UA_JSONKEY_INNERDIAGNOSTICINFO);
        ret |= encodeJsonJumpTable[UA_DATATYPEKIND_DIAGNOSTICINFO]
            (ctx, src->innerDiagnosticInfo, NULL);
    }

    return ret | writeJsonObjEnd(ctx);
}

static status
encodeJsonStructure(CtxJson *ctx, const void *src, const UA_DataType *type) {
    status ret = writeJsonObjStart(ctx);
    if(ret != UA_STATUSCODE_GOOD)
        return ret;

    uintptr_t ptr = (uintptr_t) src;
    u8 membersSize = type->membersSize;
    for(size_t i = 0; i < membersSize && ret == UA_STATUSCODE_GOOD; ++i) {
        const UA_DataTypeMember *m = &type->members[i];
        const UA_DataType *mt = m->memberType;

        if(m->memberName != NULL && *m->memberName != 0)
            ret |= writeJsonKey(ctx, m->memberName);

        if(!m->isArray) {
            ptr += m->padding;
            size_t memSize = mt->memSize;
            ret |= encodeJsonJumpTable[mt->typeKind](ctx, (const void*) ptr, mt);
            ptr += memSize;
        } else {
            ptr += m->padding;
            const size_t length = *((const size_t*) ptr);
            ptr += sizeof (size_t);
            ret |= encodeJsonArray(ctx, *(void * const *)ptr, length, mt);
            ptr += sizeof (void*);
        }
    }

    ret |= writeJsonObjEnd(ctx);
    return ret;
}

static status
encodeJsonNotImplemented(const void *src, const UA_DataType *type, CtxJson *ctx) {
    (void) src, (void) type, (void)ctx;
    return UA_STATUSCODE_BADNOTIMPLEMENTED;
}

const encodeJsonSignature encodeJsonJumpTable[UA_DATATYPEKINDS] = {
    (encodeJsonSignature)Boolean_encodeJson,
    (encodeJsonSignature)SByte_encodeJson, /* SByte */
    (encodeJsonSignature)Byte_encodeJson,
    (encodeJsonSignature)Int16_encodeJson, /* Int16 */
    (encodeJsonSignature)UInt16_encodeJson,
    (encodeJsonSignature)Int32_encodeJson, /* Int32 */
    (encodeJsonSignature)UInt32_encodeJson,
    (encodeJsonSignature)Int64_encodeJson, /* Int64 */
    (encodeJsonSignature)UInt64_encodeJson,
    (encodeJsonSignature)Float_encodeJson,
    (encodeJsonSignature)Double_encodeJson,
    (encodeJsonSignature)String_encodeJson,
    (encodeJsonSignature)DateTime_encodeJson, /* DateTime */
    (encodeJsonSignature)Guid_encodeJson,
    (encodeJsonSignature)ByteString_encodeJson, /* ByteString */
    (encodeJsonSignature)String_encodeJson, /* XmlElement */
    (encodeJsonSignature)NodeId_encodeJson,
    (encodeJsonSignature)ExpandedNodeId_encodeJson,
    (encodeJsonSignature)StatusCode_encodeJson, /* StatusCode */
    (encodeJsonSignature)QualifiedName_encodeJson, /* QualifiedName */
    (encodeJsonSignature)LocalizedText_encodeJson,
    (encodeJsonSignature)ExtensionObject_encodeJson,
    (encodeJsonSignature)DataValue_encodeJson,
    (encodeJsonSignature)Variant_encodeJson,
    (encodeJsonSignature)DiagnosticInfo_encodeJson,
    (encodeJsonSignature)encodeJsonNotImplemented, /* Decimal */
    (encodeJsonSignature)Int32_encodeJson, /* Enum */
    (encodeJsonSignature)encodeJsonStructure,
    (encodeJsonSignature)encodeJsonNotImplemented, /* Structure with optional fields */
    (encodeJsonSignature)encodeJsonNotImplemented, /* Union */
    (encodeJsonSignature)encodeJsonNotImplemented /* BitfieldCluster */
};

UA_StatusCode
UA_encodeJson(const void *src, const UA_DataType *type, UA_ByteString *outBuf,
              const UA_EncodeJsonOptions *options) {
    if(!src || !type)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Allocate buffer */
    UA_Boolean allocated = false;
    status res = UA_STATUSCODE_GOOD;
    if(outBuf->length == 0) {
        size_t len = UA_calcSizeJson(src, type, options);
        res = UA_ByteString_allocBuffer(outBuf, len);
        if(res != UA_STATUSCODE_GOOD)
            return res;
        allocated = true;
    }

    /* Set up the context */
    CtxJson ctx;
    memset(&ctx, 0, sizeof(ctx));
    ctx.pos = outBuf->data;
    ctx.end = &outBuf->data[outBuf->length];
    ctx.depth = 0;
    ctx.calcOnly = false;
    ctx.useReversible = true; /* default */
    if(options) {
        ctx.namespaces = options->namespaces;
        ctx.namespacesSize = options->namespacesSize;
        ctx.serverUris = options->serverUris;
        ctx.serverUrisSize = options->serverUrisSize;
        ctx.useReversible = options->useReversible;
        ctx.prettyPrint = options->prettyPrint;
        ctx.unquotedKeys = options->unquotedKeys;
        ctx.stringNodeIds = options->stringNodeIds;
    }

    /* Encode */
    res = encodeJsonJumpTable[type->typeKind](&ctx, src, type);

    /* Clean up */
    if(res == UA_STATUSCODE_GOOD) {
        outBuf->length = (size_t)((uintptr_t)ctx.pos - (uintptr_t)outBuf->data);
    } else if(allocated) {
        UA_ByteString_clear(outBuf);
    }
    return res;
}

UA_StatusCode
UA_print(const void *p, const UA_DataType *type, UA_String *output) {
    if(!p || !type || !output)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_EncodeJsonOptions options;
    memset(&options, 0, sizeof(UA_EncodeJsonOptions));
    options.useReversible = true;
    options.prettyPrint = true;
    options.unquotedKeys = true;
    options.stringNodeIds = true;

    return UA_encodeJson(p, type, output, &options);
}

/************/
/* CalcSize */
/************/

size_t
UA_calcSizeJson(const void *src, const UA_DataType *type,
                const UA_EncodeJsonOptions *options) {
    if(!src || !type)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Set up the context */
    CtxJson ctx;
    memset(&ctx, 0, sizeof(ctx));
    ctx.pos = NULL;
    ctx.end = (const UA_Byte*)(uintptr_t)SIZE_MAX;
    ctx.depth = 0;
    ctx.useReversible = true; /* default */
    if(options) {
        ctx.namespaces = options->namespaces;
        ctx.namespacesSize = options->namespacesSize;
        ctx.serverUris = options->serverUris;
        ctx.serverUrisSize = options->serverUrisSize;
        ctx.useReversible = options->useReversible;
        ctx.prettyPrint = options->prettyPrint;
        ctx.unquotedKeys = options->unquotedKeys;
        ctx.stringNodeIds = options->stringNodeIds;
    }

    ctx.calcOnly = true;

    /* Encode */
    status ret = encodeJsonJumpTable[type->typeKind](&ctx, src, type);
    if(ret != UA_STATUSCODE_GOOD)
        return 0;
    return (size_t)ctx.pos;
}

/**********/
/* Decode */
/**********/

#define GET_TOKEN                                                       \
    size_t tokenSize = getTokenLength(&ctx->tokens[ctx->index]);        \
    const char* tokenData = &ctx->json5[ctx->tokens[ctx->index].start]; \
    do {} while(0)

#define CHECK_TOKEN_BOUNDS do {                   \
    if(ctx->index >= ctx->tokensSize)             \
        return UA_STATUSCODE_BADDECODINGERROR;    \
    } while(0)

#define CHECK_NUMBER do {                                \
    if(currentTokenType(ctx) != CJ5_TOKEN_NUMBER) {      \
        return UA_STATUSCODE_BADDECODINGERROR;           \
    }} while(0)

#define CHECK_BOOL do {                                \
    if(currentTokenType(ctx) != CJ5_TOKEN_BOOL) {      \
        return UA_STATUSCODE_BADDECODINGERROR;         \
    }} while(0)

#define CHECK_STRING do {                                \
    if(currentTokenType(ctx) != CJ5_TOKEN_STRING) {      \
        return UA_STATUSCODE_BADDECODINGERROR;           \
    }} while(0)

#define CHECK_OBJECT do {                                \
    if(currentTokenType(ctx) != CJ5_TOKEN_OBJECT) {      \
        return UA_STATUSCODE_BADDECODINGERROR;           \
    }} while(0)

#define CHECK_NULL_SKIP do {                         \
    if(currentTokenType(ctx) == CJ5_TOKEN_NULL) {    \
        ctx->index++;                                \
        return UA_STATUSCODE_GOOD;                   \
    }} while(0)

/* Forward declarations*/
#define DECODE_JSON(TYPE) static status                   \
    TYPE##_decodeJson(ParseCtx *ctx, UA_##TYPE *dst,      \
                      const UA_DataType *type)

/* If ctx->index points to the beginning of an object, move the index to the
 * next token after this object. Attention! The index can be moved after the
 * last parsed token. So the array length has to be checked afterwards. */
static void
skipObject(ParseCtx *ctx) {
    unsigned int end = ctx->tokens[ctx->index].end;
    do {
        ctx->index++;
    } while(ctx->index < ctx->tokensSize &&
            ctx->tokens[ctx->index].start < end);
}

static status
Array_decodeJson(ParseCtx *ctx, void **dst, const UA_DataType *type);

static status
Variant_decodeJsonUnwrapExtensionObject(ParseCtx *ctx, void *p, const UA_DataType *type);

static UA_SByte
jsoneq(const char *json, const cj5_token *tok, const char *searchKey) {
    /* TODO: necessary?
       if(json == NULL
            || tok == NULL
            || searchKey == NULL) {
        return -1;
    } */

    size_t len = getTokenLength(tok);
    if(tok->type == CJ5_TOKEN_STRING &&
       strlen(searchKey) ==  len &&
       strncmp(json + tok->start, (const char*)searchKey, len) == 0)
        return 0;

    return -1;
}

DECODE_JSON(Boolean) {
    CHECK_TOKEN_BOUNDS;
    CHECK_BOOL;
    GET_TOKEN;

    if(tokenSize == 4 &&
       tokenData[0] == 't' && tokenData[1] == 'r' &&
       tokenData[2] == 'u' && tokenData[3] == 'e') {
        *dst = true;
    } else if(tokenSize == 5 &&
              tokenData[0] == 'f' && tokenData[1] == 'a' &&
              tokenData[2] == 'l' && tokenData[3] == 's' &&
              tokenData[4] == 'e') {
        *dst = false;
    } else {
        return UA_STATUSCODE_BADDECODINGERROR;
    }

    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
parseUnsignedInteger(const char *tokenData, size_t tokenSize, UA_UInt64 *dst) {
    size_t len = parseUInt64(tokenData, tokenSize, dst);
    if(len == 0)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* There must only be whitespace between the end of the parsed number and
     * the end of the token */
    for(size_t i = len; i < tokenSize; i++) {
        if(tokenData[i] != ' ' && tokenData[i] -'\t' >= 5)
            return UA_STATUSCODE_BADDECODINGERROR;
    }

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
parseSignedInteger(const char *tokenData, size_t tokenSize, UA_Int64 *dst) {
    size_t len = parseInt64(tokenData, tokenSize, dst);
    if(len == 0)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* There must only be whitespace between the end of the parsed number and
     * the end of the token */
    for(size_t i = len; i < tokenSize; i++) {
        if(tokenData[i] != ' ' && tokenData[i] -'\t' >= 5)
            return UA_STATUSCODE_BADDECODINGERROR;
    }

    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(Byte) {
    CHECK_TOKEN_BOUNDS;
    CHECK_NUMBER;
    GET_TOKEN;

    UA_UInt64 out = 0;
    UA_StatusCode s = parseUnsignedInteger(tokenData, tokenSize, &out);
    if(s != UA_STATUSCODE_GOOD || out > UA_BYTE_MAX)
        return UA_STATUSCODE_BADDECODINGERROR;
    *dst = (UA_Byte)out;
    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(UInt16) {
    CHECK_TOKEN_BOUNDS;
    CHECK_NUMBER;
    GET_TOKEN;

    UA_UInt64 out = 0;
    UA_StatusCode s = parseUnsignedInteger(tokenData, tokenSize, &out);
    if(s != UA_STATUSCODE_GOOD || out > UA_UINT16_MAX)
        return UA_STATUSCODE_BADDECODINGERROR;
    *dst = (UA_UInt16)out;
    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(UInt32) {
    CHECK_TOKEN_BOUNDS;
    CHECK_NUMBER;
    GET_TOKEN;

    UA_UInt64 out = 0;
    UA_StatusCode s = parseUnsignedInteger(tokenData, tokenSize, &out);
    if(s != UA_STATUSCODE_GOOD || out > UA_UINT32_MAX)
        return UA_STATUSCODE_BADDECODINGERROR;
    *dst = (UA_UInt32)out;
    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(UInt64) {
    CHECK_TOKEN_BOUNDS;
    GET_TOKEN;

    UA_StatusCode s = parseUnsignedInteger(tokenData, tokenSize, dst);
    if(s != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADDECODINGERROR;
    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(SByte) {
    CHECK_TOKEN_BOUNDS;
    CHECK_NUMBER;
    GET_TOKEN;

    UA_Int64 out = 0;
    UA_StatusCode s = parseSignedInteger(tokenData, tokenSize, &out);
    if(s != UA_STATUSCODE_GOOD || out < UA_SBYTE_MIN || out > UA_SBYTE_MAX)
        return UA_STATUSCODE_BADDECODINGERROR;
    *dst = (UA_SByte)out;
    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(Int16) {
    CHECK_TOKEN_BOUNDS;
    CHECK_NUMBER;
    GET_TOKEN;

    UA_Int64 out = 0;
    UA_StatusCode s = parseSignedInteger(tokenData, tokenSize, &out);
    if(s != UA_STATUSCODE_GOOD || out < UA_INT16_MIN || out > UA_INT16_MAX)
        return UA_STATUSCODE_BADDECODINGERROR;
    *dst = (UA_Int16)out;
    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(Int32) {
    CHECK_TOKEN_BOUNDS;
    CHECK_NUMBER;
    GET_TOKEN;

    UA_Int64 out = 0;
    UA_StatusCode s = parseSignedInteger(tokenData, tokenSize, &out);
    if(s != UA_STATUSCODE_GOOD || out < UA_INT32_MIN || out > UA_INT32_MAX)
        return UA_STATUSCODE_BADDECODINGERROR;
    *dst = (UA_Int32)out;
    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(Int64) {
    CHECK_TOKEN_BOUNDS;
    GET_TOKEN;

    UA_StatusCode s = parseSignedInteger(tokenData, tokenSize, dst);
    if(s != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADDECODINGERROR;
    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

/* Either a STRING or NUMBER token */
DECODE_JSON(Double) {
    CHECK_TOKEN_BOUNDS;
    GET_TOKEN;

    /* https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/
     * Maximum digit counts for select IEEE floating-point formats: 1074
     * Sanity check.
     */
    if(tokenSize > 2000)
        return UA_STATUSCODE_BADDECODINGERROR;

    cj5_token_type tokenType = currentTokenType(ctx);

    /* It could be a String with Nan, Infinity */
    if(tokenType == CJ5_TOKEN_STRING) {
        ctx->index++;

        if(tokenSize == 8 && memcmp(tokenData, "Infinity", 8) == 0) {
            *dst = INFINITY;
            return UA_STATUSCODE_GOOD;
        }

        if(tokenSize == 9 && memcmp(tokenData, "-Infinity", 9) == 0) {
            /* workaround an MSVC 2013 issue */
            *dst = -INFINITY;
            return UA_STATUSCODE_GOOD;
        }

        if(tokenSize == 3 && memcmp(tokenData, "NaN", 3) == 0) {
            *dst = NAN;
            return UA_STATUSCODE_GOOD;
        }

        if(tokenSize == 4 && memcmp(tokenData, "-NaN", 4) == 0) {
            *dst = NAN;
            return UA_STATUSCODE_GOOD;
        }

        return UA_STATUSCODE_BADDECODINGERROR;
    }

    if(tokenType != CJ5_TOKEN_NUMBER)
        return UA_STATUSCODE_BADDECODINGERROR;

    size_t len = parseDouble(tokenData, tokenSize, dst);
    if(len == 0)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* There must only be whitespace between the end of the parsed number and
     * the end of the token */
    for(size_t i = len; i < tokenSize; i++) {
        if(tokenData[i] != ' ' && tokenData[i] -'\t' >= 5)
            return UA_STATUSCODE_BADDECODINGERROR;
    }

    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(Float) {
    UA_Double v = 0.0;
    UA_StatusCode res = Double_decodeJson(ctx, &v, NULL);
    *dst = (UA_Float)v;
    return res;
}

DECODE_JSON(Guid) {
    CHECK_TOKEN_BOUNDS;
    CHECK_STRING;
    GET_TOKEN;

    /* Use the existing parsing routine if available */
    UA_String str = {tokenSize, (UA_Byte*)(uintptr_t)tokenData};
    ctx->index++;
    return UA_Guid_parse(dst, str);
}

DECODE_JSON(String) {
    CHECK_TOKEN_BOUNDS;
    CHECK_STRING;
    GET_TOKEN;
    (void)tokenData;

    /* Empty string? */
    if(tokenSize == 0) {
        dst->data = (UA_Byte*)UA_EMPTY_ARRAY_SENTINEL;
        dst->length = 0;
        ctx->index++;
        return UA_STATUSCODE_GOOD;
    }

    /* The decoded utf8 is at most of the same length as the source string */
    char *outBuf = (char*)UA_malloc(tokenSize+1);
    if(!outBuf)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Decode the string */
    cj5_result r;
    r.tokens = ctx->tokens;
    r.num_tokens = (unsigned int)ctx->tokensSize;
    r.json5 = ctx->json5;
    unsigned int len = 0;
    cj5_error_code err = cj5_get_str(&r, (unsigned int)ctx->index, outBuf, &len);
    if(err != CJ5_ERROR_NONE) {
        UA_free(outBuf);
        return UA_STATUSCODE_BADDECODINGERROR;
    }

    /* Set the output */
    dst->length = len;
    if(dst->length > 0) {
        dst->data = (UA_Byte*)outBuf;
    } else {
        dst->data = (UA_Byte*)UA_EMPTY_ARRAY_SENTINEL;
        UA_free(outBuf);
    }

    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(ByteString) {
    CHECK_TOKEN_BOUNDS;
    CHECK_STRING;
    GET_TOKEN;

    /* Empty bytestring? */
    if(tokenSize == 0) {
        dst->data = (UA_Byte*)UA_EMPTY_ARRAY_SENTINEL;
        dst->length = 0;
    } else {
        size_t flen = 0;
        unsigned char* unB64 =
            UA_unbase64((const unsigned char*)tokenData, tokenSize, &flen);
        if(unB64 == 0)
            return UA_STATUSCODE_BADDECODINGERROR;
        dst->data = (u8*)unB64;
        dst->length = flen;
    }

    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(LocalizedText) {
    CHECK_OBJECT;

    DecodeEntry entries[2] = {
        {UA_JSONKEY_LOCALE, &dst->locale, NULL, false, &UA_TYPES[UA_TYPES_STRING]},
        {UA_JSONKEY_TEXT, &dst->text, NULL, false, &UA_TYPES[UA_TYPES_STRING]}
    };

    return decodeFields(ctx, entries, 2);
}

DECODE_JSON(QualifiedName) {
    CHECK_OBJECT;

    DecodeEntry entries[2] = {
        {UA_JSONKEY_NAME, &dst->name, NULL, false, &UA_TYPES[UA_TYPES_STRING]},
        {UA_JSONKEY_URI, &dst->namespaceIndex, NULL, false, &UA_TYPES[UA_TYPES_UINT16]}
    };

    return decodeFields(ctx, entries, 2);
}

UA_FUNC_ATTR_WARN_UNUSED_RESULT status
lookAheadForKey(ParseCtx *ctx, const char *key, size_t *resultIndex) {
    /* The current index must point to the beginning of an object.
     * This has to be ensured by the caller. */
    UA_assert(currentTokenType(ctx) == CJ5_TOKEN_OBJECT);

    status ret = UA_STATUSCODE_BADNOTFOUND;
    size_t oldIndex = ctx->index; /* Save index for later restore */
    unsigned int end = ctx->tokens[ctx->index].end;
    ctx->index++; /* Move to the first key */
    while(ctx->index < ctx->tokensSize &&
          ctx->tokens[ctx->index].start < end) {
        /* Key must be a string */
        UA_assert(currentTokenType(ctx) == CJ5_TOKEN_STRING);

        /* Move index to the value */
        ctx->index++;

        /* Value for the key must exist */
        UA_assert(ctx->index < ctx->tokensSize);

        /* Compare the key (previous index) */
        if(jsoneq(ctx->json5, &ctx->tokens[ctx->index-1], key) == 0) {
            *resultIndex = ctx->index; /* Point result to the current index */
            ret = UA_STATUSCODE_GOOD;
            break;
        }

        skipObject(ctx); /* Jump over the value (can also be an array or object) */
    }
    ctx->index = oldIndex; /* Restore the old index */
    return ret;
}

static status
prepareDecodeNodeIdJson(ParseCtx *ctx, UA_NodeId *dst,
                        u8 *fieldCount, DecodeEntry *entries) {
    UA_assert(currentTokenType(ctx) == CJ5_TOKEN_OBJECT);

    /* possible keys: Id, IdType, NamespaceIndex */
    /* Id must always be present */
    entries[*fieldCount].fieldName = UA_JSONKEY_ID;
    entries[*fieldCount].found = false;
    entries[*fieldCount].type = NULL;
    entries[*fieldCount].function = NULL;

    /* IdType */
    size_t idIndex = 0;
    status ret = lookAheadForKey(ctx, UA_JSONKEY_IDTYPE, &idIndex);
    if(ret == UA_STATUSCODE_GOOD) {
        size_t size = getTokenLength(&ctx->tokens[idIndex]);
        if(size < 1)
            return UA_STATUSCODE_BADDECODINGERROR;

        const char *idType = &ctx->json5[ctx->tokens[idIndex].start];

        if(idType[0] == '2') {
            dst->identifierType = UA_NODEIDTYPE_GUID;
            entries[*fieldCount].fieldPointer = &dst->identifier.guid;
            entries[*fieldCount].type = &UA_TYPES[UA_TYPES_GUID];
        } else if(idType[0] == '1') {
            dst->identifierType = UA_NODEIDTYPE_STRING;
            entries[*fieldCount].fieldPointer = &dst->identifier.string;
            entries[*fieldCount].type = &UA_TYPES[UA_TYPES_STRING];
        } else if(idType[0] == '3') {
            dst->identifierType = UA_NODEIDTYPE_BYTESTRING;
            entries[*fieldCount].fieldPointer = &dst->identifier.byteString;
            entries[*fieldCount].type = &UA_TYPES[UA_TYPES_BYTESTRING];
        } else {
            return UA_STATUSCODE_BADDECODINGERROR;
        }

        /* Id always present */
        (*fieldCount)++;

        entries[*fieldCount].fieldName = UA_JSONKEY_IDTYPE;
        entries[*fieldCount].fieldPointer = NULL;
        entries[*fieldCount].function = NULL;
        entries[*fieldCount].found = false;
        entries[*fieldCount].type = NULL;

        /* IdType */
        (*fieldCount)++;
    } else {
        dst->identifierType = UA_NODEIDTYPE_NUMERIC;
        entries[*fieldCount].fieldPointer = &dst->identifier.numeric;
        entries[*fieldCount].function = NULL;
        entries[*fieldCount].found = false;
        entries[*fieldCount].type = &UA_TYPES[UA_TYPES_UINT32];
        (*fieldCount)++;
    }

    /* NodeId has a NamespaceIndex (the ExpandedNodeId specialization may
     * overwrite this) */
    entries[*fieldCount].fieldName = UA_JSONKEY_NAMESPACE;
    entries[*fieldCount].fieldPointer = &dst->namespaceIndex;
    entries[*fieldCount].function = NULL;
    entries[*fieldCount].found = false;
    entries[*fieldCount].type = &UA_TYPES[UA_TYPES_UINT16];
    (*fieldCount)++;

    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(NodeId) {
    /* Non-standard decoding of NodeIds from the string representation */
    if(currentTokenType(ctx) == CJ5_TOKEN_STRING) {
        GET_TOKEN;
        UA_String str = {tokenSize, (UA_Byte*)(uintptr_t)tokenData};
        ctx->index++;
        return UA_NodeId_parse(dst, str);
    }

    /* Object representation */
    CHECK_OBJECT;

    u8 fieldCount = 0;
    DecodeEntry entries[3];
    status ret = prepareDecodeNodeIdJson(ctx, dst, &fieldCount, entries);
    if(ret != UA_STATUSCODE_GOOD)
        return ret;
    return decodeFields(ctx, entries, fieldCount);
}

static status
decodeExpandedNodeIdNamespace(ParseCtx *ctx, void *dst, const UA_DataType *type) {
    UA_ExpandedNodeId *en = (UA_ExpandedNodeId*)dst;

    /* Parse as a number */
    size_t oldIndex = ctx->index;
    status ret = UInt16_decodeJson(ctx, &en->nodeId.namespaceIndex, NULL);
    if(ret == UA_STATUSCODE_GOOD)
        return ret;

    /* Parse as a string */
    ctx->index = oldIndex; /* Reset the index */
    ret = String_decodeJson(ctx, &en->namespaceUri, NULL);
    if(ret != UA_STATUSCODE_GOOD)
        return ret;

    /* Replace with the index if the URI is found. Otherwise keep the string. */
    for(size_t i = 0; i < ctx->namespacesSize; i++) {
        if(UA_String_equal(&en->namespaceUri, &ctx->namespaces[i])) {
            UA_String_clear(&en->namespaceUri);
            en->nodeId.namespaceIndex = (UA_UInt16)i;
            break;
        }
    }
    return UA_STATUSCODE_GOOD;
}

static status
decodeExpandedNodeIdServerUri(ParseCtx *ctx, void *dst, const UA_DataType *type) {
    UA_ExpandedNodeId *en = (UA_ExpandedNodeId*)dst;

    /* Parse as a number */
    size_t oldIndex = ctx->index;
    status ret = UInt32_decodeJson(ctx, &en->serverIndex, NULL);
    if(ret == UA_STATUSCODE_GOOD)
        return ret;

    /* Parse as a string */
    UA_String uri = UA_STRING_NULL;
    ctx->index = oldIndex; /* Reset the index */
    ret = String_decodeJson(ctx, &uri, NULL);
    if(ret != UA_STATUSCODE_GOOD)
        return ret;

    /* Try to translate the URI into an index */
    ret = UA_STATUSCODE_BADDECODINGERROR;
    for(size_t i = 0; i < ctx->serverUrisSize; i++) {
        if(UA_String_equal(&uri, &ctx->serverUris[i])) {
            en->serverIndex = (UA_UInt32)i;
            ret = UA_STATUSCODE_GOOD;
            break;
        }
    }
    UA_String_clear(&uri);
    return ret;
}

DECODE_JSON(ExpandedNodeId) {
    /* Non-standard decoding of ExpandedNodeIds from the string representation */
    if(currentTokenType(ctx) == CJ5_TOKEN_STRING) {
        GET_TOKEN;
        UA_String str = {tokenSize, (UA_Byte*)(uintptr_t)tokenData};
        ctx->index++;
        return UA_ExpandedNodeId_parse(dst, str);
    }

    /* Object representation */
    CHECK_OBJECT;

    u8 fieldCount = 0;
    DecodeEntry entries[4];
    status ret = prepareDecodeNodeIdJson(ctx, &dst->nodeId, &fieldCount, entries);
    if(ret != UA_STATUSCODE_GOOD)
        return ret;

    /* Overwrite the namespace entry */
    fieldCount--;
    entries[fieldCount].fieldPointer = dst;
    entries[fieldCount].function = decodeExpandedNodeIdNamespace;
    entries[fieldCount].type = NULL;
    fieldCount++;

    entries[fieldCount].fieldName = UA_JSONKEY_SERVERURI;
    entries[fieldCount].fieldPointer = dst;
    entries[fieldCount].function = decodeExpandedNodeIdServerUri;
    entries[fieldCount].found = false;
    entries[fieldCount].type = NULL;
    fieldCount++;

    return decodeFields(ctx, entries, fieldCount);
}

DECODE_JSON(DateTime) {
    CHECK_TOKEN_BOUNDS;
    CHECK_STRING;
    GET_TOKEN;

    /* The last character has to be 'Z'. We can omit some length checks later on
     * because we know the atoi functions stop before the 'Z'. */
    if(tokenSize == 0 || tokenData[tokenSize-1] != 'Z')
        return UA_STATUSCODE_BADDECODINGERROR;

    struct mytm dts;
    memset(&dts, 0, sizeof(dts));

    size_t pos = 0;
    size_t len;

    /* Parse the year. The ISO standard asks for four digits. But we accept up
     * to five with an optional plus or minus in front due to the range of the
     * DateTime 64bit integer. But in that case we require the year and the
     * month to be separated by a '-'. Otherwise we cannot know where the month
     * starts. */
    if(tokenData[0] == '-' || tokenData[0] == '+')
        pos++;
    UA_Int64 year = 0;
    len = parseInt64(&tokenData[pos], 5, &year);
    pos += len;
    if(len != 4 && tokenData[pos] != '-')
        return UA_STATUSCODE_BADDECODINGERROR;
    if(tokenData[0] == '-')
        year = -year;
    dts.tm_year = (UA_Int16)year - 1900;
    if(tokenData[pos] == '-')
        pos++;

    /* Parse the month */
    UA_UInt64 month = 0;
    len = parseUInt64(&tokenData[pos], 2, &month);
    pos += len;
    UA_CHECK(len == 2, return UA_STATUSCODE_BADDECODINGERROR);
    dts.tm_mon = (UA_UInt16)month - 1;
    if(tokenData[pos] == '-')
        pos++;

    /* Parse the day and check the T between date and time */
    UA_UInt64 day = 0;
    len = parseUInt64(&tokenData[pos], 2, &day);
    pos += len;
    UA_CHECK(len == 2 || tokenData[pos] != 'T',
             return UA_STATUSCODE_BADDECODINGERROR);
    dts.tm_mday = (UA_UInt16)day;
    pos++;

    /* Parse the hour */
    UA_UInt64 hour = 0;
    len = parseUInt64(&tokenData[pos], 2, &hour);
    pos += len;
    UA_CHECK(len == 2, return UA_STATUSCODE_BADDECODINGERROR);
    dts.tm_hour = (UA_UInt16)hour;
    if(tokenData[pos] == ':')
        pos++;

    /* Parse the minute */
    UA_UInt64 min = 0;
    len = parseUInt64(&tokenData[pos], 2, &min);
    pos += len;
    UA_CHECK(len == 2, return UA_STATUSCODE_BADDECODINGERROR);
    dts.tm_min = (UA_UInt16)min;
    if(tokenData[pos] == ':')
        pos++;

    /* Parse the second */
    UA_UInt64 sec = 0;
    len = parseUInt64(&tokenData[pos], 2, &sec);
    pos += len;
    UA_CHECK(len == 2, return UA_STATUSCODE_BADDECODINGERROR);
    dts.tm_sec = (UA_UInt16)sec;

    /* Compute the seconds since the Unix epoch */
    long long sinceunix = __tm_to_secs(&dts);

    /* Are we within the range that can be represented? */
    long long sinceunix_min =
        (long long)(UA_INT64_MIN / UA_DATETIME_SEC) -
        (long long)(UA_DATETIME_UNIX_EPOCH / UA_DATETIME_SEC) -
        (long long)1; /* manual correction due to rounding */
    long long sinceunix_max = (long long)
        ((UA_INT64_MAX - UA_DATETIME_UNIX_EPOCH) / UA_DATETIME_SEC);
    if(sinceunix < sinceunix_min || sinceunix > sinceunix_max)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* Convert to DateTime. Add or subtract one extra second here to prevent
     * underflow/overflow. This is reverted once the fractional part has been
     * added. */
    sinceunix -= (sinceunix > 0) ? 1 : -1;
    UA_DateTime dt = (UA_DateTime)
        (sinceunix + (UA_DATETIME_UNIX_EPOCH / UA_DATETIME_SEC)) * UA_DATETIME_SEC;

    /* Parse the fraction of the second if defined */
    if(tokenData[pos] == ',' || tokenData[pos] == '.') {
        pos++;
        double frac = 0.0;
        double denom = 0.1;
        while(pos < tokenSize &&
              tokenData[pos] >= '0' && tokenData[pos] <= '9') {
            frac += denom * (tokenData[pos] - '0');
            denom *= 0.1;
            pos++;
        }
        frac += 0.00000005; /* Correct rounding when converting to integer */
        dt += (UA_DateTime)(frac * UA_DATETIME_SEC);
    }

    /* Remove the underflow/overflow protection (see above) */
    if(sinceunix > 0) {
        if(dt > UA_INT64_MAX - UA_DATETIME_SEC)
            return UA_STATUSCODE_BADDECODINGERROR;
        dt += UA_DATETIME_SEC;
    } else {
        if(dt < UA_INT64_MIN + UA_DATETIME_SEC)
            return UA_STATUSCODE_BADDECODINGERROR;
        dt -= UA_DATETIME_SEC;
    }

    /* We must be at the end of the string (ending with 'Z' as checked above) */
    if(pos != tokenSize - 1)
        return UA_STATUSCODE_BADDECODINGERROR;

    *dst = dt;

    ctx->index++;
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(StatusCode) {
    return UInt32_decodeJson(ctx, dst, NULL);
}

static status
VariantDimension_decodeJson(ParseCtx *ctx, void *dst, const UA_DataType *type) {
    (void) type;
    const UA_DataType *dimType = &UA_TYPES[UA_TYPES_UINT32];
    return Array_decodeJson(ctx, (void**)dst, dimType);
}

/* Get type type encoded by the ExtensionObject at ctx->index.
 * Returns NULL if that fails (type unknown or otherwise). */
static const UA_DataType *
getExtensionObjectType(ParseCtx *ctx) {
    if(currentTokenType(ctx) != CJ5_TOKEN_OBJECT)
        return NULL;

    /* Get the type NodeId index */
    size_t typeIdIndex = 0;
    UA_StatusCode ret = lookAheadForKey(ctx, UA_JSONKEY_TYPEID, &typeIdIndex);
    if(ret != UA_STATUSCODE_GOOD)
        return NULL;

    size_t oldIndex = ctx->index;
    ctx->index = (UA_UInt16)typeIdIndex;

    /* Decode the type NodeId */
    UA_NodeId typeId;
    UA_NodeId_init(&typeId);
    ret = NodeId_decodeJson(ctx, &typeId, &UA_TYPES[UA_TYPES_NODEID]);
    ctx->index = oldIndex;
    if(ret != UA_STATUSCODE_GOOD)
        return NULL;

    /* Lookup an return */
    const UA_DataType *type = UA_findDataTypeWithCustom(&typeId, ctx->customTypes);
    UA_NodeId_clear(&typeId);
    return type;
}

/* Check if all array members are ExtensionObjects of the same type. Return this
 * type or NULL. */
static const UA_DataType *
getArrayUnwrapType(ParseCtx *ctx, size_t arrayIndex) {
    UA_assert(ctx->tokens[arrayIndex].type == CJ5_TOKEN_ARRAY);

    /* Save index to restore later */
    size_t oldIndex = ctx->index;
    ctx->index = arrayIndex;

    /* Return early for empty arrays */
    size_t length = (size_t)ctx->tokens[ctx->index].size;
    if(length == 0) {
        ctx->index = oldIndex; /* Restore the index */
        return NULL;
    }

    /* Go to first array member */
    ctx->index++;

    /* Lookup the type for the first array member */
    UA_NodeId typeId;
    UA_NodeId_init(&typeId);
    const UA_DataType *typeOfBody = getExtensionObjectType(ctx);
    if(!typeOfBody) {
        ctx->index = oldIndex; /* Restore the index */
        return NULL;
    }

    /* The content is a builtin type that could have been directly encoded in
     * the Variant, there was no need to wrap in an ExtensionObject. But this
     * means for us, that somebody made an extra effort to explicitly get an
     * ExtensionObject. So we keep it. As an added advantage we will generate
     * the same JSON again when encoding again. */
    UA_Boolean isBuiltin = (typeOfBody->typeKind <= UA_DATATYPEKIND_DIAGNOSTICINFO);
    if(isBuiltin) {
        ctx->index = oldIndex; /* Restore the index */
        return NULL;
    }

    /* Get the typeId index for faster comparison below.
     * Cannot fail as getExtensionObjectType already looked this up. */
    size_t typeIdIndex = 0;
    UA_StatusCode ret = lookAheadForKey(ctx, UA_JSONKEY_TYPEID, &typeIdIndex);
    (void)ret;
    UA_assert(ret == UA_STATUSCODE_GOOD);
    const char* typeIdData = &ctx->json5[ctx->tokens[typeIdIndex].start];
    size_t typeIdSize = getTokenLength(&ctx->tokens[typeIdIndex]);

    /* Loop over all members and check whether they can be unwrapped */
    for(size_t i = 0; i < length; i++) {
        /* Array element must be an object */
        if(currentTokenType(ctx) != CJ5_TOKEN_OBJECT) {
            ctx->index = oldIndex; /* Restore the index */
            return NULL;
        }

        /* Check for non-JSON encoding */
        size_t encIndex = 0;
        ret = lookAheadForKey(ctx, UA_JSONKEY_ENCODING, &encIndex);
        if(ret == UA_STATUSCODE_GOOD) {
            ctx->index = oldIndex; /* Restore the index */
            return NULL;
        }

        /* Get the type NodeId index */
        size_t memberTypeIdIndex = 0;
        ret = lookAheadForKey(ctx, UA_JSONKEY_TYPEID, &memberTypeIdIndex);
        if(ret != UA_STATUSCODE_GOOD) {
            ctx->index = oldIndex; /* Restore the index */
            return NULL;
        }

        /* Is it the same type? Compare raw NodeId string */
        const char* memberTypeIdData = &ctx->json5[ctx->tokens[memberTypeIdIndex].start];
        size_t memberTypeIdSize = getTokenLength(&ctx->tokens[memberTypeIdIndex]);
        if(typeIdSize != memberTypeIdSize ||
           memcmp(typeIdData, memberTypeIdData, typeIdSize) != 0) {
            ctx->index = oldIndex; /* Restore the index */
            return NULL;
        }

        /* Skip to the next array member */
        skipObject(ctx);
    }

    ctx->index = oldIndex; /* Restore the index */
    return typeOfBody;
}

static status
Array_decodeJsonUnwrapExtensionObject(ParseCtx *ctx, void **dst, const UA_DataType *type) {
    size_t *size_ptr = (size_t*) dst - 1; /* Save the length pointer of the array */
    size_t length = (size_t)ctx->tokens[ctx->index].size;

    /* Known from the previous unwrapping-check */
    UA_assert(currentTokenType(ctx) == CJ5_TOKEN_ARRAY);
    UA_assert(length > 0);

    ctx->index++; /* Go to first array member */

    /* Allocate memory */
    *dst = UA_calloc(length, type->memSize);
    if(*dst == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Decode array members */
    uintptr_t ptr = (uintptr_t)*dst;
    for(size_t i = 0; i < length; i++) {
        UA_assert(ctx->tokens[ctx->index].type == CJ5_TOKEN_OBJECT);

        /* Get the body field and decode it */
        DecodeEntry entries[3] = {
            {UA_JSONKEY_TYPEID, NULL, NULL, false, NULL},
            {UA_JSONKEY_BODY, (void*)ptr, NULL, false, type},
            {UA_JSONKEY_ENCODING, NULL, NULL, false, NULL}
        };
        status ret = decodeFields(ctx, entries, 3); /* Also skips to the next object */
        if(ret != UA_STATUSCODE_GOOD) {
            UA_Array_delete(*dst, i+1, type);
            *dst = NULL;
            return ret;
        }
        ptr += type->memSize;
    }

    *size_ptr = length; /* All good, set the size */
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(Variant) {
    CHECK_NULL_SKIP; /* Treat null as an empty variant */
    CHECK_OBJECT;

    /* First search for the variant type in the json object. */
    size_t typeIndex = 0;
    status ret = lookAheadForKey(ctx, UA_JSONKEY_TYPE, &typeIndex);
    if(ret != UA_STATUSCODE_GOOD) {
        skipObject(ctx);
        return UA_STATUSCODE_GOOD;
    }

    /* Parse the type */
    if(ctx->tokens[typeIndex].type != CJ5_TOKEN_NUMBER)
        return UA_STATUSCODE_BADDECODINGERROR;
    UA_UInt64 idType = 0;
    size_t len = parseUInt64(&ctx->json5[ctx->tokens[typeIndex].start],
                             getTokenLength(&ctx->tokens[typeIndex]), &idType);
    if(len == 0)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* A NULL Variant */
    if(idType == 0) {
        skipObject(ctx);
        return UA_STATUSCODE_GOOD;
    }

    /* Set the type */
    UA_NodeId typeNodeId = UA_NODEID_NUMERIC(0, (UA_UInt32)idType);
    dst->type = UA_findDataTypeWithCustom(&typeNodeId, ctx->customTypes);
    if(!dst->type)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* Search for body */
    size_t bodyIndex = 0;
    ret = lookAheadForKey(ctx, UA_JSONKEY_BODY, &bodyIndex);
    if(ret != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* Value is an array? */
    UA_Boolean isArray = (ctx->tokens[bodyIndex].type == CJ5_TOKEN_ARRAY);

    /* TODO: Handling of null-arrays (length -1) needs to be clarified
     *
     * if(tokenIsNull(ctx, bodyIndex)) {
     *     isArray = true;
     *     dst->arrayLength = 0;
     * } */

    /* Has the variant dimension? */
    UA_Boolean hasDimension = false;
    size_t dimIndex = 0;
    ret = lookAheadForKey(ctx, UA_JSONKEY_DIMENSION, &dimIndex);
    if(ret == UA_STATUSCODE_GOOD)
        hasDimension = (ctx->tokens[dimIndex].size > 0);

    /* No array but has dimension -> error */
    if(!isArray && hasDimension)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* Get the datatype of the content. The type must be a builtin data type.
     * All not-builtin types are wrapped in an ExtensionObject. */
    if(dst->type->typeKind > UA_DATATYPEKIND_DIAGNOSTICINFO)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* A variant cannot contain a variant. But it can contain an array of
     * variants */
    if(dst->type->typeKind == UA_DATATYPEKIND_VARIANT && !isArray)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* Decode an array */
    if(isArray) {
        DecodeEntry entries[3] = {
            {UA_JSONKEY_TYPE, NULL, NULL, false, NULL},
            {UA_JSONKEY_BODY, &dst->data, (decodeJsonSignature)Array_decodeJson, false, dst->type},
            {UA_JSONKEY_DIMENSION, &dst->arrayDimensions, VariantDimension_decodeJson, false, NULL}
        };

        /* Try to unwrap ExtensionObjects in the array.
         * The members must all have the same type. */
        if(dst->type == &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]) {
            const UA_DataType *unwrapType = getArrayUnwrapType(ctx, bodyIndex);
            if(unwrapType) {
                dst->type = unwrapType;
                entries[1].type = unwrapType;
                entries[1].function = (decodeJsonSignature)
                    Array_decodeJsonUnwrapExtensionObject;
            }
        }

        return decodeFields(ctx, entries, (hasDimension) ? 3 : 2);
    }

    /* Decode a value wrapped in an ExtensionObject */
    if(dst->type->typeKind == UA_DATATYPEKIND_EXTENSIONOBJECT) {
        DecodeEntry entries[2] = {
            {UA_JSONKEY_TYPE, NULL, NULL, false, NULL},
            {UA_JSONKEY_BODY, dst, Variant_decodeJsonUnwrapExtensionObject, false, NULL}
        };
        return decodeFields(ctx, entries, 2);
    }

    /* Allocate Memory for Body */
    dst->data = UA_new(dst->type);
    if(!dst->data)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    DecodeEntry entries[2] = {
        {UA_JSONKEY_TYPE, NULL, NULL, false, NULL},
        {UA_JSONKEY_BODY, dst->data, NULL, false, dst->type}
    };
    return decodeFields(ctx, entries, 2);
}

DECODE_JSON(DataValue) {
    CHECK_NULL_SKIP; /* Treat a null value as an empty DataValue */
    CHECK_OBJECT;

    DecodeEntry entries[6] = {
        {UA_JSONKEY_VALUE, &dst->value, NULL, false, &UA_TYPES[UA_TYPES_VARIANT]},
        {UA_JSONKEY_STATUS, &dst->status, NULL, false, &UA_TYPES[UA_TYPES_STATUSCODE]},
        {UA_JSONKEY_SOURCETIMESTAMP, &dst->sourceTimestamp, NULL, false, &UA_TYPES[UA_TYPES_DATETIME]},
        {UA_JSONKEY_SOURCEPICOSECONDS, &dst->sourcePicoseconds, NULL, false, &UA_TYPES[UA_TYPES_UINT16]},
        {UA_JSONKEY_SERVERTIMESTAMP, &dst->serverTimestamp, NULL, false, &UA_TYPES[UA_TYPES_DATETIME]},
        {UA_JSONKEY_SERVERPICOSECONDS, &dst->serverPicoseconds, NULL, false, &UA_TYPES[UA_TYPES_UINT16]}
    };

    status ret = decodeFields(ctx, entries, 6);
    dst->hasValue = entries[0].found;
    dst->hasStatus = entries[1].found;
    dst->hasSourceTimestamp = entries[2].found;
    dst->hasSourcePicoseconds = entries[3].found;
    dst->hasServerTimestamp = entries[4].found;
    dst->hasServerPicoseconds = entries[5].found;
    return ret;
}

/* Move the entire current token into the target bytestring */
static UA_StatusCode
tokenToByteString(ParseCtx *ctx, UA_ByteString *p, const UA_DataType *type) {
    GET_TOKEN;
    UA_StatusCode res = UA_ByteString_allocBuffer(p, tokenSize);
    if(res != UA_STATUSCODE_GOOD)
        return res;
    memcpy(p->data, tokenData, tokenSize);
    skipObject(ctx);
    return UA_STATUSCODE_GOOD;
}

DECODE_JSON(ExtensionObject) {
    CHECK_NULL_SKIP; /* Treat a null value as an empty DataValue */
    CHECK_OBJECT;

    /* Empty object -> Null ExtensionObject */
    if(ctx->tokens[ctx->index].size == 0) {
        ctx->index++; /* Skip the empty ExtensionObject */
        return UA_STATUSCODE_GOOD;
    }

    /* Search for non-JSON encoding */
    UA_UInt64 encoding = 0;
    size_t encIndex = 0;
    status ret = lookAheadForKey(ctx, UA_JSONKEY_ENCODING, &encIndex);
    if(ret == UA_STATUSCODE_GOOD) {
        const char *extObjEncoding = &ctx->json5[ctx->tokens[encIndex].start];
        size_t len = parseUInt64(extObjEncoding, getTokenLength(&ctx->tokens[encIndex]),
                                 &encoding);
        if(len == 0)
            return UA_STATUSCODE_BADDECODINGERROR;
    }

    /* Lookup the DataType for the ExtensionObject if the body can be decoded */
    const UA_DataType *typeOfBody = (encoding == 0) ? getExtensionObjectType(ctx) : NULL;

    /* Keep the encoded body */
    if(!typeOfBody) {
        DecodeEntry entries[3] = {
            {UA_JSONKEY_ENCODING, NULL, NULL, false, NULL},
            {UA_JSONKEY_TYPEID, &dst->content.encoded.typeId, NULL, false, &UA_TYPES[UA_TYPES_NODEID]},
            {UA_JSONKEY_BODY, &dst->content.encoded.body, NULL, false, &UA_TYPES[UA_TYPES_STRING]}
        };

        if(encoding == 0) {
            entries[2].function = (decodeJsonSignature)tokenToByteString;
            dst->encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING; /* ByteString in Json Body */
        } else if(encoding == 1) {
            dst->encoding = UA_EXTENSIONOBJECT_ENCODED_BYTESTRING; /* ByteString in Json Body */
        } else if(encoding == 2) {
            dst->encoding = UA_EXTENSIONOBJECT_ENCODED_XML; /* XmlElement in Json Body */
        } else {
            return UA_STATUSCODE_BADDECODINGERROR;
        }

        return decodeFields(ctx, entries, 3);
    }

    /* Allocate memory for the decoded data */
    dst->content.decoded.data = UA_new(typeOfBody);
    if(!dst->content.decoded.data)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Set type */
    dst->content.decoded.type = typeOfBody;
    dst->encoding = UA_EXTENSIONOBJECT_DECODED;

    /* Decode body */
    DecodeEntry entries[3] = {
        {UA_JSONKEY_ENCODING, NULL, NULL, false, NULL},
        {UA_JSONKEY_TYPEID, NULL, NULL, false, NULL},
        {UA_JSONKEY_BODY, dst->content.decoded.data, NULL, false, typeOfBody}
    };
    return decodeFields(ctx, entries, 3);
}

static status
Variant_decodeJsonUnwrapExtensionObject(ParseCtx *ctx, void *p, const UA_DataType *type) {
    (void) type;
    UA_Variant *dst = (UA_Variant*)p;

    /* ExtensionObject with null body */
    if(currentTokenType(ctx) == CJ5_TOKEN_NULL) {
        dst->data = UA_ExtensionObject_new();
        dst->type = &UA_TYPES[UA_TYPES_EXTENSIONOBJECT];
        ctx->index++;
        return UA_STATUSCODE_GOOD;
    }

    /* Decode the ExtensionObject */
    UA_ExtensionObject eo;
    UA_ExtensionObject_init(&eo);
    UA_StatusCode ret = ExtensionObject_decodeJson(ctx, &eo, NULL);
    if(ret != UA_STATUSCODE_GOOD) {
        UA_ExtensionObject_clear(&eo); /* We don't have the global cleanup */
        return ret;
    }

    /* The content is still encoded, cannot unwrap */
    if(eo.encoding != UA_EXTENSIONOBJECT_DECODED)
        goto use_eo;

    /* The content is a builtin type that could have been directly encoded in
     * the Variant, there was no need to wrap in an ExtensionObject. But this
     * means for us, that somebody made an extra effort to explicitly get an
     * ExtensionObject. So we keep it. As an added advantage we will generate
     * the same JSON again when encoding again. */
    UA_Boolean isBuiltin =
        (eo.content.decoded.type->typeKind <= UA_DATATYPEKIND_DIAGNOSTICINFO);
    if(isBuiltin)
        goto use_eo;

    /* Unwrap the ExtensionObject */
    dst->data = eo.content.decoded.data;
    dst->type = eo.content.decoded.type;
    return UA_STATUSCODE_GOOD;

 use_eo:
    /* Don't unwrap */
    dst->data = UA_new(&UA_TYPES[UA_TYPES_EXTENSIONOBJECT]);
    if(!dst->data) {
        UA_ExtensionObject_clear(&eo);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    dst->type = &UA_TYPES[UA_TYPES_EXTENSIONOBJECT];
    *(UA_ExtensionObject*)dst->data = eo;
    return UA_STATUSCODE_GOOD;
}

status
DiagnosticInfoInner_decodeJson(ParseCtx* ctx, void* dst, const UA_DataType* type);

DECODE_JSON(DiagnosticInfo) {
    CHECK_NULL_SKIP; /* Treat a null value as an empty DiagnosticInfo */
    CHECK_OBJECT;

    DecodeEntry entries[7] = {
        {UA_JSONKEY_SYMBOLICID, &dst->symbolicId, NULL, false, &UA_TYPES[UA_TYPES_INT32]},
        {UA_JSONKEY_NAMESPACEURI, &dst->namespaceUri, NULL, false, &UA_TYPES[UA_TYPES_INT32]},
        {UA_JSONKEY_LOCALIZEDTEXT, &dst->localizedText, NULL, false, &UA_TYPES[UA_TYPES_INT32]},
        {UA_JSONKEY_LOCALE, &dst->locale, NULL, false, &UA_TYPES[UA_TYPES_INT32]},
        {UA_JSONKEY_ADDITIONALINFO, &dst->additionalInfo, NULL, false, &UA_TYPES[UA_TYPES_STRING]},
        {UA_JSONKEY_INNERSTATUSCODE, &dst->innerStatusCode, NULL, false, &UA_TYPES[UA_TYPES_STATUSCODE]},
        {UA_JSONKEY_INNERDIAGNOSTICINFO, &dst->innerDiagnosticInfo, DiagnosticInfoInner_decodeJson, false, NULL}
    };
    status ret = decodeFields(ctx, entries, 7);

    dst->hasSymbolicId = entries[0].found;
    dst->hasNamespaceUri = entries[1].found;
    dst->hasLocalizedText = entries[2].found;
    dst->hasLocale = entries[3].found;
    dst->hasAdditionalInfo = entries[4].found;
    dst->hasInnerStatusCode = entries[5].found;
    dst->hasInnerDiagnosticInfo = entries[6].found;
    return ret;
}

status
DiagnosticInfoInner_decodeJson(ParseCtx* ctx, void* dst, const UA_DataType* type) {
    UA_DiagnosticInfo *inner = (UA_DiagnosticInfo*)
        UA_calloc(1, sizeof(UA_DiagnosticInfo));
    if(!inner)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    UA_DiagnosticInfo **dst2 = (UA_DiagnosticInfo**)dst;
    *dst2 = inner;  /* Copy new Pointer do dest */
    return DiagnosticInfo_decodeJson(ctx, inner, type);
}

status
decodeFields(ParseCtx *ctx, DecodeEntry *entries, size_t entryCount) {
    CHECK_TOKEN_BOUNDS;
    CHECK_NULL_SKIP; /* null is treated like an empty object */

    if(ctx->depth >= UA_JSON_ENCODING_MAX_RECURSION - 1)
        return UA_STATUSCODE_BADENCODINGERROR;

    /* Keys and values are counted separately */
    CHECK_OBJECT;
    UA_assert(ctx->tokens[ctx->index].size % 2 == 0);
    size_t keyCount = (size_t)(ctx->tokens[ctx->index].size) / 2;

    ctx->index++; /* Go to first key - or jump after the empty object */
    ctx->depth++;

    status ret = UA_STATUSCODE_GOOD;
    for(size_t key = 0; key < keyCount; key++) {
        /* Key must be a string */
        UA_assert(ctx->index < ctx->tokensSize);
        UA_assert(currentTokenType(ctx) == CJ5_TOKEN_STRING);

        /* Search for the decoding entry matching the key. Start at the key
         * index to speed-up the case where they key-order is the same as the
         * entry-order. */
        DecodeEntry *entry = NULL;
        for(size_t i = key; i < key + entryCount; i++) {
            size_t ii = i;
            while(ii >= entryCount)
                ii -= entryCount;

            /* Compare the key */
            if(jsoneq(ctx->json5, &ctx->tokens[ctx->index],
                      entries[ii].fieldName) != 0)
                continue;

            /* Key was already used -> duplicate, abort */
            if(entries[ii].found) {
                ctx->depth--;
                return UA_STATUSCODE_BADDECODINGERROR;
            }

            /* Found the key */
            entries[ii].found = true;
            entry = &entries[ii];
            break;
        }

        /* The key is unknown */
        if(!entry) {
            ret = UA_STATUSCODE_BADDECODINGERROR;
            break;
        }

        /* Go from key to value */
        ctx->index++;
        UA_assert(ctx->index < ctx->tokensSize);

        /* An entry that was expected but shall not be decoded.
         * Jump over the value. */
        if(!entry->function && !entry->type) {
            skipObject(ctx);
            continue;
        }

        /* A null-value, skip the decoding (the value is already initialized) */
        if(currentTokenType(ctx) == CJ5_TOKEN_NULL && !entry->function) {
            ctx->index++; /* skip null value */
            continue;
        }

        /* Decode. This also moves to the next key or right after the object for
         * the last value. */
        decodeJsonSignature decodeFunc = (entry->function) ?
            entry->function : decodeJsonJumpTable[entry->type->typeKind];
        ret = decodeFunc(ctx, entry->fieldPointer, entry->type);
        if(ret != UA_STATUSCODE_GOOD)
            break;
    }

    ctx->depth--;
    return ret;
}

static status
Array_decodeJson(ParseCtx *ctx, void **dst, const UA_DataType *type) {
    /* Save the length of the array */
    size_t *size_ptr = (size_t*) dst - 1;

    if(currentTokenType(ctx) != CJ5_TOKEN_ARRAY)
        return UA_STATUSCODE_BADDECODINGERROR;

    size_t length = (size_t)ctx->tokens[ctx->index].size;

    ctx->index++; /* Go to first array member or to the first element after
                   * the array (if empty) */

    /* Return early for empty arrays */
    if(length == 0) {
        *size_ptr = length;
        *dst = UA_EMPTY_ARRAY_SENTINEL;
        return UA_STATUSCODE_GOOD;
    }

    /* Allocate memory */
    *dst = UA_calloc(length, type->memSize);
    if(*dst == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Decode array members */
    uintptr_t ptr = (uintptr_t)*dst;
    for(size_t i = 0; i < length; ++i) {
        if(ctx->tokens[ctx->index].type != CJ5_TOKEN_NULL) {
            status ret = decodeJsonJumpTable[type->typeKind](ctx, (void*)ptr, type);
            if(ret != UA_STATUSCODE_GOOD) {
                UA_Array_delete(*dst, i+1, type);
                *dst = NULL;
                return ret;
            }
        } else {
            ctx->index++;
        }
        ptr += type->memSize;
    }

    *size_ptr = length; /* All good, set the size */
    return UA_STATUSCODE_GOOD;
}

static status
decodeJsonStructure(ParseCtx *ctx, void *dst, const UA_DataType *type) {
    /* Check the recursion limit */
    if(ctx->depth >= UA_JSON_ENCODING_MAX_RECURSION - 1)
        return UA_STATUSCODE_BADENCODINGERROR;
    ctx->depth++;

    uintptr_t ptr = (uintptr_t)dst;
    status ret = UA_STATUSCODE_GOOD;
    u8 membersSize = type->membersSize;
    UA_STACKARRAY(DecodeEntry, entries, membersSize);
    for(size_t i = 0; i < membersSize; ++i) {
        const UA_DataTypeMember *m = &type->members[i];
        const UA_DataType *mt = m->memberType;
        entries[i].type = mt;
        entries[i].fieldName = m->memberName;
        entries[i].found = false;
        if(!m->isArray) {
            ptr += m->padding;
            entries[i].fieldPointer = (void*)ptr;
            entries[i].function = NULL;
            ptr += mt->memSize;
        } else {
            ptr += m->padding;
            ptr += sizeof(size_t);
            entries[i].fieldPointer = (void*)ptr;
            entries[i].function = (decodeJsonSignature)Array_decodeJson;
            ptr += sizeof(void*);
        }
    }

    ret = decodeFields(ctx, entries, membersSize);

    if(ctx->depth == 0)
        return UA_STATUSCODE_BADENCODINGERROR;
    ctx->depth--;
    return ret;
}

static status
decodeJsonNotImplemented(ParseCtx *ctx, void *dst, const UA_DataType *type) {
    (void)dst, (void)type, (void)ctx;
    return UA_STATUSCODE_BADNOTIMPLEMENTED;
}

const decodeJsonSignature decodeJsonJumpTable[UA_DATATYPEKINDS] = {
    (decodeJsonSignature)Boolean_decodeJson,
    (decodeJsonSignature)SByte_decodeJson, /* SByte */
    (decodeJsonSignature)Byte_decodeJson,
    (decodeJsonSignature)Int16_decodeJson, /* Int16 */
    (decodeJsonSignature)UInt16_decodeJson,
    (decodeJsonSignature)Int32_decodeJson, /* Int32 */
    (decodeJsonSignature)UInt32_decodeJson,
    (decodeJsonSignature)Int64_decodeJson, /* Int64 */
    (decodeJsonSignature)UInt64_decodeJson,
    (decodeJsonSignature)Float_decodeJson,
    (decodeJsonSignature)Double_decodeJson,
    (decodeJsonSignature)String_decodeJson,
    (decodeJsonSignature)DateTime_decodeJson, /* DateTime */
    (decodeJsonSignature)Guid_decodeJson,
    (decodeJsonSignature)ByteString_decodeJson, /* ByteString */
    (decodeJsonSignature)String_decodeJson, /* XmlElement */
    (decodeJsonSignature)NodeId_decodeJson,
    (decodeJsonSignature)ExpandedNodeId_decodeJson,
    (decodeJsonSignature)StatusCode_decodeJson, /* StatusCode */
    (decodeJsonSignature)QualifiedName_decodeJson, /* QualifiedName */
    (decodeJsonSignature)LocalizedText_decodeJson,
    (decodeJsonSignature)ExtensionObject_decodeJson,
    (decodeJsonSignature)DataValue_decodeJson,
    (decodeJsonSignature)Variant_decodeJson,
    (decodeJsonSignature)DiagnosticInfo_decodeJson,
    (decodeJsonSignature)decodeJsonNotImplemented, /* Decimal */
    (decodeJsonSignature)Int32_decodeJson, /* Enum */
    (decodeJsonSignature)decodeJsonStructure,
    (decodeJsonSignature)decodeJsonNotImplemented, /* Structure with optional fields */
    (decodeJsonSignature)decodeJsonNotImplemented, /* Union */
    (decodeJsonSignature)decodeJsonNotImplemented /* BitfieldCluster */
};

status
tokenize(ParseCtx *ctx, const UA_ByteString *src, size_t tokensSize) {
    /* Tokenize */
    cj5_result r = cj5_parse((char*)src->data, (unsigned int)src->length,
                             ctx->tokens, (unsigned int)tokensSize, NULL);

    /* Handle overflow error by allocating the number of tokens the parser would
     * have needed */
    if(r.error == CJ5_ERROR_OVERFLOW &&
       tokensSize != r.num_tokens) {
        ctx->tokens = (cj5_token*)
            UA_malloc(sizeof(cj5_token) * r.num_tokens);
        if(!ctx->tokens)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        return tokenize(ctx, src, r.num_tokens);
    }

    /* Cannot recover from other errors */
    if(r.error != CJ5_ERROR_NONE)
        return UA_STATUSCODE_BADDECODINGERROR;

    /* Set up the context */
    ctx->json5 = (char*)src->data;
    ctx->depth = 0;
    ctx->tokensSize = r.num_tokens;
    ctx->index = 0;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_decodeJson(const UA_ByteString *src, void *dst, const UA_DataType *type,
              const UA_DecodeJsonOptions *options) {
    if(!dst || !src || !type)
        return UA_STATUSCODE_BADARGUMENTSMISSING;

    /* Set up the context */
    cj5_token tokens[UA_JSON_MAXTOKENCOUNT];
    ParseCtx ctx;
    memset(&ctx, 0, sizeof(ParseCtx));
    ctx.tokens = tokens;

    if(options) {
        ctx.namespaces = options->namespaces;
        ctx.namespacesSize = options->namespacesSize;
        ctx.serverUris = options->serverUris;
        ctx.serverUrisSize = options->serverUrisSize;
        ctx.customTypes = options->customTypes;
    }

    /* Decode */
    status ret = tokenize(&ctx, src, UA_JSON_MAXTOKENCOUNT);
    if(ret != UA_STATUSCODE_GOOD)
        goto cleanup;

    memset(dst, 0, type->memSize); /* Initialize the value */
    ret = decodeJsonJumpTable[type->typeKind](&ctx, dst, type);

    /* Sanity check if all tokens were processed */
    if(ctx.index != ctx.tokensSize &&
       ctx.index != ctx.tokensSize - 1)
        ret = UA_STATUSCODE_BADDECODINGERROR;

 cleanup:

    /* Free token array on the heap */
    if(ctx.tokens != tokens)
        UA_free((void*)(uintptr_t)ctx.tokens);

    if(ret != UA_STATUSCODE_GOOD)
        UA_clear(dst, type);
    return ret;
}

#endif /* UA_ENABLE_JSON_ENCODING */

/**** amalgamated original file "/src/server/ua_subscription.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2015-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015-2016 (c) Sten Grüner
 *    Copyright 2017-2018 (c) Thomas Stalder, Blue Time Concept SA
 *    Copyright 2015 (c) Joakim L. Gilje
 *    Copyright 2016-2017 (c) Florian Palm
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2017 (c) frax2222
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Ari Breitkreuz, fortiss GmbH
 *    Copyright 2017 (c) Mattias Bornhager
 *    Copyright 2018 (c) Hilscher Gesellschaft für Systemautomation mbH (Author: Martin Lang)
 *    Copyright 2019 (c) HMS Industrial Networks AB (Author: Jonas Green)
 */


#ifdef UA_ENABLE_SUBSCRIPTIONS /* conditional compilation */

#define UA_MAX_RETRANSMISSIONQUEUESIZE 256

UA_Subscription *
UA_Subscription_new(void) {
    /* Allocate the memory */
    UA_Subscription *newSub = (UA_Subscription*)UA_calloc(1, sizeof(UA_Subscription));
    if(!newSub)
        return NULL;

    /* The first publish response is sent immediately */
    newSub->state = UA_SUBSCRIPTIONSTATE_STOPPED;

    /* Even if the first publish response is a keepalive the sequence number is 1.
     * This can happen by a subscription without a monitored item (see CTT test scripts). */
    newSub->nextSequenceNumber = 1;

    TAILQ_INIT(&newSub->retransmissionQueue);
    TAILQ_INIT(&newSub->notificationQueue);
    return newSub;
}

static void
delayedFreeSubscription(void *app, void *context) {
    UA_free(context);
}

void
UA_Subscription_delete(UA_Server *server, UA_Subscription *sub) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_EventLoop *el = server->config.eventLoop;

    /* Unregister the publish callback and possible delayed callback */
    Subscription_setState(server, sub, UA_SUBSCRIPTIONSTATE_REMOVING);

    /* Remove delayed callbacks for processing remaining notifications */
    if(sub->delayedCallbackRegistered) {
        el->removeDelayedCallback(el, &sub->delayedMoreNotifications);
        sub->delayedCallbackRegistered = false;
    }

    /* Remove the diagnostics object for the subscription */
#ifdef UA_ENABLE_DIAGNOSTICS
    if(!UA_NodeId_isNull(&sub->ns0Id))
        deleteNode(server, sub->ns0Id, true);
    UA_NodeId_clear(&sub->ns0Id);
#endif

    UA_LOG_INFO_SUBSCRIPTION(server->config.logging, sub, "Subscription deleted");

    /* Detach from the session if necessary */
    if(sub->session)
        UA_Session_detachSubscription(server, sub->session, sub, true);

    /* Remove from the server if not previously registered */
    if(sub->serverListEntry.le_prev) {
        LIST_REMOVE(sub, serverListEntry);
        UA_assert(server->subscriptionsSize > 0);
        server->subscriptionsSize--;
        server->serverDiagnosticsSummary.currentSubscriptionCount--;
    }

    /* Delete monitored Items */
    UA_assert(server->monitoredItemsSize >= sub->monitoredItemsSize);
    UA_MonitoredItem *mon, *tmp_mon;
    LIST_FOREACH_SAFE(mon, &sub->monitoredItems, listEntry, tmp_mon) {
        UA_MonitoredItem_delete(server, mon);
    }
    UA_assert(sub->monitoredItemsSize == 0);

    /* Delete Retransmission Queue */
    UA_NotificationMessageEntry *nme, *nme_tmp;
    TAILQ_FOREACH_SAFE(nme, &sub->retransmissionQueue, listEntry, nme_tmp) {
        TAILQ_REMOVE(&sub->retransmissionQueue, nme, listEntry);
        UA_NotificationMessage_clear(&nme->message);
        UA_free(nme);
        if(sub->session)
            --sub->session->totalRetransmissionQueueSize;
        --sub->retransmissionQueueSize;
    }
    UA_assert(sub->retransmissionQueueSize == 0);

    /* Pointers to the subscription may still exist upwards in the call stack.
     * Add a delayed callback to remove the Subscription when the current jobs
     * have completed. */
    sub->delayedFreePointers.callback = delayedFreeSubscription;
    sub->delayedFreePointers.application = NULL;
    sub->delayedFreePointers.context = sub;
    el->addDelayedCallback(el, &sub->delayedFreePointers);
}

void
Subscription_resetLifetime(UA_Subscription *sub) {
    sub->currentLifetimeCount = 0;
}

UA_MonitoredItem *
UA_Subscription_getMonitoredItem(UA_Subscription *sub, UA_UInt32 monitoredItemId) {
    UA_MonitoredItem *mon;
    LIST_FOREACH(mon, &sub->monitoredItems, listEntry) {
        if(mon->monitoredItemId == monitoredItemId)
            break;
    }
    return mon;
}

static void
removeOldestRetransmissionMessageFromSub(UA_Subscription *sub) {
    UA_NotificationMessageEntry *oldestEntry =
        TAILQ_LAST(&sub->retransmissionQueue, NotificationMessageQueue);
    TAILQ_REMOVE(&sub->retransmissionQueue, oldestEntry, listEntry);
    UA_NotificationMessage_clear(&oldestEntry->message);
    UA_free(oldestEntry);
    --sub->retransmissionQueueSize;
    if(sub->session)
        --sub->session->totalRetransmissionQueueSize;

#ifdef UA_ENABLE_DIAGNOSTICS
    sub->discardedMessageCount++;
#endif
}

static void
removeOldestRetransmissionMessageFromSession(UA_Session *session) {
    UA_NotificationMessageEntry *oldestEntry = NULL;
    UA_Subscription *oldestSub = NULL;
    UA_Subscription *sub;
    TAILQ_FOREACH(sub, &session->subscriptions, sessionListEntry) {
        UA_NotificationMessageEntry *first =
            TAILQ_LAST(&sub->retransmissionQueue, NotificationMessageQueue);
        if(!first)
            continue;
        if(!oldestEntry || oldestEntry->message.publishTime > first->message.publishTime) {
            oldestEntry = first;
            oldestSub = sub;
        }
    }
    UA_assert(oldestEntry);
    UA_assert(oldestSub);

    removeOldestRetransmissionMessageFromSub(oldestSub);
}

static void
UA_Subscription_addRetransmissionMessage(UA_Server *server, UA_Subscription *sub,
                                         UA_NotificationMessageEntry *entry) {
    /* Release the oldest entry if there is not enough space */
    UA_Session *session = sub->session;
    if(sub->retransmissionQueueSize >= UA_MAX_RETRANSMISSIONQUEUESIZE) {
        UA_LOG_WARNING_SUBSCRIPTION(server->config.logging, sub,
                                    "Subscription retransmission queue overflow");
        removeOldestRetransmissionMessageFromSub(sub);
    } else if(session && server->config.maxRetransmissionQueueSize > 0 &&
              session->totalRetransmissionQueueSize >=
              server->config.maxRetransmissionQueueSize) {
        UA_LOG_WARNING_SUBSCRIPTION(server->config.logging, sub,
                                    "Session-wide retransmission queue overflow");
        removeOldestRetransmissionMessageFromSession(sub->session);
    }

    /* Add entry */
    TAILQ_INSERT_TAIL(&sub->retransmissionQueue, entry, listEntry);
    ++sub->retransmissionQueueSize;
    if(session)
        ++session->totalRetransmissionQueueSize;
}

UA_StatusCode
UA_Subscription_removeRetransmissionMessage(UA_Subscription *sub, UA_UInt32 sequenceNumber) {
    /* Find the retransmission message */
    UA_NotificationMessageEntry *entry;
    TAILQ_FOREACH(entry, &sub->retransmissionQueue, listEntry) {
        if(entry->message.sequenceNumber == sequenceNumber)
            break;
    }
    if(!entry)
        return UA_STATUSCODE_BADSEQUENCENUMBERUNKNOWN;

    /* Remove the retransmission message */
    TAILQ_REMOVE(&sub->retransmissionQueue, entry, listEntry);
    --sub->retransmissionQueueSize;
    UA_NotificationMessage_clear(&entry->message);
    UA_free(entry);

    if(sub->session)
        --sub->session->totalRetransmissionQueueSize;

    return UA_STATUSCODE_GOOD;
}

/* The output counters are only set when the preparation is successful */
static UA_StatusCode
prepareNotificationMessage(UA_Server *server, UA_Subscription *sub,
                           UA_NotificationMessage *message,
                           size_t maxNotifications) {
    UA_assert(maxNotifications > 0);

    /* Allocate an ExtensionObject for Event- and DataChange-Notifications. Also
     * there can be StatusChange-Notifications. The standard says in Part 4,
     * 7.2.1:
     *
     * If a Subscription contains MonitoredItems for events and data, this array
     * should have not more than 2 elements. */
    message->notificationData = (UA_ExtensionObject*)
        UA_Array_new(2, &UA_TYPES[UA_TYPES_EXTENSIONOBJECT]);
    if(!message->notificationData)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    message->notificationDataSize = 2;

    /* Pre-allocate DataChangeNotifications */
    size_t notificationDataIdx = 0;
    size_t dcnPos = 0; /* How many DataChangeNotifications? */
    UA_DataChangeNotification *dcn = NULL;
    if(sub->dataChangeNotifications > 0) {
        dcn = UA_DataChangeNotification_new();
        if(!dcn) {
            UA_NotificationMessage_clear(message);
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }
        UA_ExtensionObject_setValue(message->notificationData, dcn,
                                    &UA_TYPES[UA_TYPES_DATACHANGENOTIFICATION]);
        size_t dcnSize = sub->dataChangeNotifications;
        if(dcnSize > maxNotifications)
            dcnSize = maxNotifications;
        dcn->monitoredItems = (UA_MonitoredItemNotification*)
            UA_Array_new(dcnSize, &UA_TYPES[UA_TYPES_MONITOREDITEMNOTIFICATION]);
        if(!dcn->monitoredItems) {
            UA_NotificationMessage_clear(message);
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }
        dcn->monitoredItemsSize = dcnSize;
        notificationDataIdx++;
    }

#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
    size_t enlPos = 0; /* How many EventNotifications? */
    UA_EventNotificationList *enl = NULL;
    if(sub->eventNotifications > 0) {
        enl = UA_EventNotificationList_new();
        if(!enl) {
            UA_NotificationMessage_clear(message);
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }
        UA_ExtensionObject_setValue(&message->notificationData[notificationDataIdx],
                                    enl, &UA_TYPES[UA_TYPES_EVENTNOTIFICATIONLIST]);
        size_t enlSize = sub->eventNotifications;
        if(enlSize > maxNotifications)
            enlSize = maxNotifications;
        enl->events = (UA_EventFieldList*)
            UA_Array_new(enlSize, &UA_TYPES[UA_TYPES_EVENTFIELDLIST]);
        if(!enl->events) {
            UA_NotificationMessage_clear(message);
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }
        enl->eventsSize = enlSize;
        notificationDataIdx++;
    }
#endif

    UA_assert(notificationDataIdx > 0);
    message->notificationDataSize = notificationDataIdx;

    /* <-- The point of no return --> */

    /* How many notifications were moved to the response overall? */
    size_t totalNotifications = 0;
    UA_Notification *notification, *notification_tmp;
    TAILQ_FOREACH_SAFE(notification, &sub->notificationQueue,
                       globalEntry, notification_tmp) {
        if(totalNotifications >= maxNotifications)
            break;

        /* Move the content to the response */
        switch(notification->mon->itemToMonitor.attributeId) {
#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
        case UA_ATTRIBUTEID_EVENTNOTIFIER:
            UA_assert(enl != NULL); /* Have at least one event notification */
            enl->events[enlPos] = notification->data.event;
            UA_EventFieldList_init(&notification->data.event);
            enlPos++;
            break;
#endif
        default:
            UA_assert(dcn != NULL); /* Have at least one change notification */
            dcn->monitoredItems[dcnPos] = notification->data.dataChange;
            UA_DataValue_init(&notification->data.dataChange.value);
            dcnPos++;
            break;
        }

        /* If there are Notifications *before this one* in the MonitoredItem-
         * local queue, remove all of them. These are earlier Notifications that
         * are non-reporting. And we don't want them to show up after the
         * current Notification has been sent out. */
        UA_Notification *prev;
        while((prev = TAILQ_PREV(notification, NotificationQueue, localEntry))) {
            UA_Notification_delete(prev);
        }

        /* Delete the notification, remove from the queues and decrease the counters */
        UA_Notification_delete(notification);

        totalNotifications++;
    }

    /* Set sizes */
    if(dcn) {
        dcn->monitoredItemsSize = dcnPos;
        if(dcnPos == 0) {
            UA_free(dcn->monitoredItems);
            dcn->monitoredItems = NULL;
        }
    }

#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
    if(enl) {
        enl->eventsSize = enlPos;
        if(enlPos == 0) {
            UA_free(enl->events);
            enl->events = NULL;
        }
    }
#endif

    return UA_STATUSCODE_GOOD;
}

/* According to OPC Unified Architecture, Part 4 5.13.1.1 i) The value 0 is
 * never used for the sequence number */
static UA_UInt32
UA_Subscription_nextSequenceNumber(UA_UInt32 sequenceNumber) {
    UA_UInt32 nextSequenceNumber = sequenceNumber + 1;
    if(nextSequenceNumber == 0)
        nextSequenceNumber = 1;
    return nextSequenceNumber;
}

static void
sendStatusChangeDelete(UA_Server *server, UA_Subscription *sub,
                       UA_PublishResponseEntry *pre) {
    /* Cannot send out the StatusChange because no response is queued.
     * Delete the Subscription without sending the StatusChange, if the statusChange is Bad*/
    if(!pre) {
        UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, sub,
                                  "Cannot send the StatusChange notification because no response is queued.");
        if(UA_StatusCode_isBad(sub->statusChange)) {
            UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, sub, "Removing the subscription.");
            UA_Subscription_delete(server, sub);
        }
        return;
    }

    UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, sub,
                              "Sending out a StatusChange "
                              "notification and removing the subscription");

    UA_EventLoop *el = server->config.eventLoop;

    /* Populate the response */
    UA_PublishResponse *response = &pre->response;

    UA_StatusChangeNotification scn;
    UA_StatusChangeNotification_init(&scn);
    scn.status = sub->statusChange;

    UA_ExtensionObject notificationData;
    UA_ExtensionObject_setValue(&notificationData, &scn,
                                &UA_TYPES[UA_TYPES_STATUSCHANGENOTIFICATION]);

    response->notificationMessage.notificationData = &notificationData;
    response->notificationMessage.notificationDataSize = 1;
    response->subscriptionId = sub->subscriptionId;
    response->notificationMessage.publishTime = el->dateTime_now(el);
    response->notificationMessage.sequenceNumber = sub->nextSequenceNumber;

    /* Send the response */
    UA_assert(sub->session); /* Otherwise pre is NULL */
    UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, sub,
                              "Sending out a publish response");
    sendResponse(server, sub->session->channel, pre->requestId,
                 (UA_Response *)response, &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]);

    /* Clean up */
    response->notificationMessage.notificationData = NULL;
    response->notificationMessage.notificationDataSize = 0;
    UA_PublishResponse_clear(&pre->response);
    UA_free(pre);

    /* Delete the subscription */
    UA_Subscription_delete(server, sub);
}

/* The local adminSubscription forwards notifications to a registered callback
 * method. This is done async from a delayed callback registered in the
 * EventLoop. */
void
UA_Subscription_localPublish(UA_Server *server, UA_Subscription *sub) {
    UA_LOCK(&server->serviceMutex);
    sub->delayedCallbackRegistered = false;

    UA_Notification *n, *n_tmp;
    TAILQ_FOREACH_SAFE(n, &sub->notificationQueue, globalEntry, n_tmp) {
        UA_MonitoredItem *mon = n->mon;
        UA_LocalMonitoredItem *localMon = (UA_LocalMonitoredItem*)mon;

        /* Move the content to the response */
        void *nodeContext = NULL;
        switch(mon->itemToMonitor.attributeId) {
#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
        case UA_ATTRIBUTEID_EVENTNOTIFIER:
            /* Set the fields in the key-value map */
            UA_assert(n->data.event.eventFieldsSize == localMon->eventFields.mapSize);
            for(size_t i = 0; i < localMon->eventFields.mapSize; i++) {
                localMon->eventFields.map[i].value = n->data.event.eventFields[i];
            }

            /* Call the callback */
            UA_UNLOCK(&server->serviceMutex);
            localMon->callback.
                eventCallback(server, mon->monitoredItemId, localMon->context,
                              localMon->eventFields);
            UA_LOCK(&server->serviceMutex);
            break;
#endif
        default:
            getNodeContext(server, mon->itemToMonitor.nodeId, &nodeContext);
            UA_UNLOCK(&server->serviceMutex);
            localMon->callback.
                dataChangeCallback(server, mon->monitoredItemId, localMon->context,
                                   &mon->itemToMonitor.nodeId, nodeContext,
                                   mon->itemToMonitor.attributeId,
                                   &n->data.dataChange.value);
            UA_LOCK(&server->serviceMutex);
            break;
        }

        /* If there are Notifications *before this one* in the MonitoredItem-
         * local queue, remove all of them. These are earlier Notifications that
         * are non-reporting. And we don't want them to show up after the
         * current Notification has been sent out. */
        UA_Notification *prev;
        while((prev = TAILQ_PREV(n, NotificationQueue, localEntry))) {
            UA_Notification_delete(prev);
        }

        /* Delete the notification, remove from the queues and decrease the counters */
        UA_Notification_delete(n);
    }

    UA_UNLOCK(&server->serviceMutex);
}

static void
delayedPublishNotifications(UA_Server *server, UA_Subscription *sub) {
    UA_LOCK(&server->serviceMutex);
    sub->delayedCallbackRegistered = false;
    UA_Subscription_publish(server, sub);
    UA_UNLOCK(&server->serviceMutex);
}

/* Try to publish now. Enqueue a "next publish" as a delayed callback if not
 * done. */
void
UA_Subscription_publish(UA_Server *server, UA_Subscription *sub) {
    UA_EventLoop *el = server->config.eventLoop;

    /* Get a response */
    UA_PublishResponseEntry *pre = NULL;
    if(sub->session) {
        UA_DateTime nowMonotonic = el->dateTime_nowMonotonic(el);
        do {
            /* Dequeue the oldest response */
            pre = UA_Session_dequeuePublishReq(sub->session);
            if(!pre)
                break;

            /* Check if the TimeoutHint is still valid. Otherwise return with a bad
             * statuscode and continue. */
            if(pre->maxTime < nowMonotonic) {
                UA_LOG_DEBUG_SESSION(server->config.logging, sub->session,
                                     "Publish request %u has timed out", pre->requestId);
                pre->response.responseHeader.serviceResult = UA_STATUSCODE_BADTIMEOUT;
                sendResponse(server, sub->session->channel, pre->requestId,
                             (UA_Response *)&pre->response, &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]);
                UA_PublishResponse_clear(&pre->response);
                UA_free(pre);
                pre = NULL;
            }
        } while(!pre);
    }

    /* Update the LifetimeCounter */
    if(pre) {
        Subscription_resetLifetime(sub);
    } else {
        UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, sub,
                                  "The publish queue is empty");
        ++sub->currentLifetimeCount;
        if(sub->currentLifetimeCount > sub->lifeTimeCount) {
            UA_LOG_WARNING_SUBSCRIPTION(server->config.logging, sub,
                                        "End of subscription lifetime");
            /* Set the StatusChange to delete the subscription. */
            sub->statusChange = UA_STATUSCODE_BADTIMEOUT;
        }
    }

    /* Send a StatusChange notification if possible and delete the
     * Subscription */
    if(sub->statusChange != UA_STATUSCODE_GOOD) {
        sendStatusChangeDelete(server, sub, pre);
        return;
    }

    /* Dsiabled subscriptions do not send notifications */
    UA_UInt32 notifications = (sub->state == UA_SUBSCRIPTIONSTATE_ENABLED) ?
        sub->notificationQueueSize : 0;

    /* Limit the number of notifications to the configured maximum */
    if(notifications > sub->notificationsPerPublish)
        notifications = sub->notificationsPerPublish;

    /* Return if no notifications and no keepalive */
    if(notifications == 0) {
        ++sub->currentKeepAliveCount;
        if(sub->currentKeepAliveCount < sub->maxKeepAliveCount) {
            if(pre)
                UA_Session_queuePublishReq(sub->session, pre, true); /* Re-enqueue */
            return;
        }
        UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, sub, "Sending a KeepAlive");
    }

    /* We want to send a response, but cannot. Either because there is no queued
     * response or because the Subscription is detached from a Session or because
     * the SecureChannel for the Session is closed. */
    if(!pre || !sub->session || !sub->session->channel) {
        UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, sub,
                                  "Want to send a publish response but cannot. "
                                  "The subscription is late.");
        sub->late = true;
        if(pre)
            UA_Session_queuePublishReq(sub->session, pre, true); /* Re-enqueue */
        return;
    }

    UA_assert(pre);
    UA_assert(sub->session); /* Otherwise pre is NULL */

    /* Prepare the response */
    UA_PublishResponse *response = &pre->response;
    UA_NotificationMessage *message = &response->notificationMessage;
    UA_NotificationMessageEntry *retransmission = NULL;
#ifdef UA_ENABLE_DIAGNOSTICS
    size_t priorDataChangeNotifications = sub->dataChangeNotifications;
    size_t priorEventNotifications = sub->eventNotifications;
#endif
    if(notifications > 0) {
        if(server->config.enableRetransmissionQueue) {
            /* Allocate the retransmission entry */
            retransmission = (UA_NotificationMessageEntry*)
                UA_malloc(sizeof(UA_NotificationMessageEntry));
            if(!retransmission) {
                UA_LOG_WARNING_SUBSCRIPTION(server->config.logging, sub,
                                            "Could not allocate memory for retransmission. "
                                            "The subscription is late.");
                sub->late = true;
                UA_Session_queuePublishReq(sub->session, pre, true); /* Re-enqueue */
                return;
            }
        }

        /* Prepare the response */
        UA_StatusCode retval =
            prepareNotificationMessage(server, sub, message, notifications);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING_SUBSCRIPTION(server->config.logging, sub,
                                        "Could not prepare the notification message. "
                                        "The subscription is late.");
            /* If the retransmission queue is enabled a retransmission message is allocated */
            if(retransmission)
                UA_free(retransmission);
            sub->late = true;
            UA_Session_queuePublishReq(sub->session, pre, true); /* Re-enqueue */
            return;
        }
    }

    /* <-- The point of no return --> */

    /* Set up the response */
    response->subscriptionId = sub->subscriptionId;
    response->moreNotifications = (sub->notificationQueueSize > 0);
    message->publishTime = el->dateTime_now(el);

    /* Set sequence number to message. Started at 1 which is given during
     * creating a new subscription. The 1 is required for initial publish
     * response with or without an monitored item. */
    message->sequenceNumber = sub->nextSequenceNumber;

    if(notifications > 0) {
        /* If the retransmission queue is enabled a retransmission message is
         * allocated */
        if(retransmission) {
            /* Put the notification message into the retransmission queue. This
             * needs to be done here, so that the message itself is included in
             * the available sequence numbers for acknowledgement. */
            retransmission->message = response->notificationMessage;
            UA_Subscription_addRetransmissionMessage(server, sub, retransmission);
        }
        /* Only if a notification was created, the sequence number must be
         * increased. For a keepalive the sequence number can be reused. */
        sub->nextSequenceNumber =
            UA_Subscription_nextSequenceNumber(sub->nextSequenceNumber);
    }

    /* Get the available sequence numbers from the retransmission queue */
    UA_assert(sub->retransmissionQueueSize <= UA_MAX_RETRANSMISSIONQUEUESIZE);
    UA_UInt32 seqNumbers[UA_MAX_RETRANSMISSIONQUEUESIZE];
    response->availableSequenceNumbers = seqNumbers;
    response->availableSequenceNumbersSize = sub->retransmissionQueueSize;
    size_t i = 0;
    UA_NotificationMessageEntry *nme;
    TAILQ_FOREACH(nme, &sub->retransmissionQueue, listEntry) {
        response->availableSequenceNumbers[i] = nme->message.sequenceNumber;
        ++i;
    }
    UA_assert(i == sub->retransmissionQueueSize);

    /* Send the response */
    UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, sub,
                              "Sending out a publish response with %" PRIu32
                              " notifications", notifications);
    sendResponse(server, sub->session->channel, pre->requestId,
                 (UA_Response*)response, &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]);

    /* Reset the Subscription state to NORMAL. But only if all notifications
     * have been sent out. Otherwise keep the Subscription in the LATE state. So
     * we immediately answer incoming Publish requests.
     *
     * (We also check that session->responseQueueSize > 0 in Service_Publish. To
     * avoid answering Publish requests out of order. As we additionally may have
     * scheduled a publish callback as a delayed callback. */
    if(sub->notificationQueueSize == 0)
        sub->late = false;

    /* Reset the KeepAlive after publishing */
    sub->currentKeepAliveCount = 0;

    /* Free the response */
    if(retransmission) {
        /* NotificationMessage was moved into retransmission queue */
        UA_NotificationMessage_init(&response->notificationMessage);
    }
    response->availableSequenceNumbers = NULL;
    response->availableSequenceNumbersSize = 0;
    UA_PublishResponse_clear(&pre->response);
    UA_free(pre);

    /* Update the diagnostics statistics */
#ifdef UA_ENABLE_DIAGNOSTICS
    sub->publishRequestCount++;

    UA_UInt32 sentDCN = (UA_UInt32)
        (priorDataChangeNotifications - sub->dataChangeNotifications);
    UA_UInt32 sentEN = (UA_UInt32)(priorEventNotifications - sub->eventNotifications);
    sub->dataChangeNotificationsCount += sentDCN;
    sub->eventNotificationsCount += sentEN;
    sub->notificationsCount += (sentDCN + sentEN);
#endif

    /* Repeat sending notifications if there are more notifications to send. But
     * only call monitoredItem_sampleCallback in the regular publish
     * callback. */
    UA_Boolean done = (sub->notificationQueueSize == 0);
    if(!done && !sub->delayedCallbackRegistered) {
        sub->delayedCallbackRegistered = true;

        sub->delayedMoreNotifications.callback = (UA_Callback)delayedPublishNotifications;
        sub->delayedMoreNotifications.application = server;
        sub->delayedMoreNotifications.context = sub;

        el = server->config.eventLoop;
        el->addDelayedCallback(el, &sub->delayedMoreNotifications);
    }
}

void
UA_Subscription_resendData(UA_Server *server, UA_Subscription *sub) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    UA_assert(server);
    UA_assert(sub);

    /* Part 4, §6.7: If this Method is called, subsequent Publish responses
     * shall contain the current values of all data MonitoredItems in the
     * Subscription where the MonitoringMode is set to Reporting. If a value is
     * queued for a data MonitoredItem, the next value in the queue is sent in
     * the Publish response. If no value is queued for a data MonitoredItem, the
     * last value sent is repeated in the Publish response. */
    UA_MonitoredItem *mon;
    LIST_FOREACH(mon, &sub->monitoredItems, listEntry) {
        /* Create only DataChange notifications */
        if(mon->itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER)
            continue;

        /* Only if the mode is monitoring */
        if(mon->monitoringMode != UA_MONITORINGMODE_REPORTING)
            continue;

        /* If a value is queued for a data MonitoredItem, the next value in
         * the queue is sent in the Publish response. */
        if(mon->queueSize > 0)
            continue;

        /* Create a notification with the last sampled value */
        UA_MonitoredItem_createDataChangeNotification(server, mon, &mon->lastValue);
    }
}

void
UA_Session_ensurePublishQueueSpace(UA_Server* server, UA_Session* session) {
    if(server->config.maxPublishReqPerSession == 0)
        return;

    while(session->responseQueueSize >= server->config.maxPublishReqPerSession) {
        /* Dequeue a response */
        UA_PublishResponseEntry *pre = UA_Session_dequeuePublishReq(session);
        UA_assert(pre != NULL); /* There must be a pre as session->responseQueueSize > 0 */

        UA_LOG_DEBUG_SESSION(server->config.logging, session,
                             "Sending out a publish response triggered by too many publish requests");

        /* Send the response. This response has no related subscription id */
        UA_PublishResponse *response = &pre->response;
        response->responseHeader.serviceResult = UA_STATUSCODE_BADTOOMANYPUBLISHREQUESTS;
        sendResponse(server, session->channel, pre->requestId,
                     (UA_Response *)response, &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]);

        /* Free the response */
        UA_PublishResponse_clear(response);
        UA_free(pre);
    }
}

static void
sampleAndPublishCallback(UA_Server *server, UA_Subscription *sub) {
    UA_LOCK(&server->serviceMutex);
    UA_assert(sub);

    UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, sub,
                              "Sample and Publish Callback");

    /* Sample the MonitoredItems with sampling interval <0 (which implies
     * sampling in the same interval as the subscription) */
    UA_MonitoredItem *mon;
    LIST_FOREACH(mon, &sub->samplingMonitoredItems, sampling.subscriptionSampling) {
        monitoredItem_sampleCallback(server, mon);
    }

    /* Publish the queued notifications */
    UA_Subscription_publish(server, sub);

    UA_UNLOCK(&server->serviceMutex);
}

UA_StatusCode
Subscription_setState(UA_Server *server, UA_Subscription *sub,
                      UA_SubscriptionState state) {
    if(state <= UA_SUBSCRIPTIONSTATE_REMOVING) {
        if(sub->publishCallbackId != 0) {
            removeCallback(server, sub->publishCallbackId);
            sub->publishCallbackId = 0;
#ifdef UA_ENABLE_DIAGNOSTICS
            sub->disableCount++;
#endif
        }
    } else if(sub->publishCallbackId == 0) {
        UA_StatusCode res =
            addRepeatedCallback(server, (UA_ServerCallback)sampleAndPublishCallback,
                                sub, sub->publishingInterval, &sub->publishCallbackId);
        if(res != UA_STATUSCODE_GOOD) {
            sub->state = UA_SUBSCRIPTIONSTATE_STOPPED;
            return res;
        }

        /* Send (at least a) keepalive after the next publish interval */
        sub->currentKeepAliveCount = sub->maxKeepAliveCount;

#ifdef UA_ENABLE_DIAGNOSTICS
        sub->enableCount++;
#endif
    }

    sub->state = state;
    return UA_STATUSCODE_GOOD;
}

#endif /* UA_ENABLE_SUBSCRIPTIONS */

/**** amalgamated original file "/src/server/ua_subscription_monitoreditem.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2017-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2018 (c) Ari Breitkreuz, fortiss GmbH
 *    Copyright 2018 (c) Thomas Stalder, Blue Time Concept SA
 *    Copyright 2018 (c) Fabian Arndt, Root-Core
 *    Copyright 2020-2021 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati)
 */


#ifdef UA_ENABLE_SUBSCRIPTIONS /* conditional compilation */

/****************/
/* Notification */
/****************/

#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS

static const UA_NodeId eventQueueOverflowEventType =
    {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_EVENTQUEUEOVERFLOWEVENTTYPE}};

/* The specification states in Part 4 5.12.1.5 that an EventQueueOverflowEvent
 * "is generated when the first Event has to be discarded [...] without
 * discarding any other event". So only generate one for all deleted events. */
static UA_StatusCode
createEventOverflowNotification(UA_Server *server, UA_Subscription *sub,
                                UA_MonitoredItem *mon) {
    /* Avoid creating two adjacent overflow events */
    UA_Notification *indicator = NULL;
    if(mon->parameters.discardOldest) {
        indicator = TAILQ_FIRST(&mon->queue);
        UA_assert(indicator); /* must exist */
        if(indicator->isOverflowEvent)
            return UA_STATUSCODE_GOOD;
    } else {
        indicator = TAILQ_LAST(&mon->queue, NotificationQueue);
        UA_assert(indicator); /* must exist */
        /* Skip the last element. It is the recently added notification that
         * shall be kept. We know it is not an OverflowEvent. */
        UA_Notification *before = TAILQ_PREV(indicator, NotificationQueue, localEntry);
        if(before && before->isOverflowEvent)
            return UA_STATUSCODE_GOOD;
    }

    /* A Notification is inserted into the queue which includes only the
     * NodeId of the OverflowEventType. */

    /* Allocate the notification */
    UA_Notification *overflowNotification = UA_Notification_new();
    if(!overflowNotification)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Set the notification fields */
    overflowNotification->isOverflowEvent = true;
    overflowNotification->mon = mon;
    overflowNotification->data.event.clientHandle = mon->parameters.clientHandle;
    overflowNotification->data.event.eventFields = UA_Variant_new();
    if(!overflowNotification->data.event.eventFields) {
        UA_free(overflowNotification);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    overflowNotification->data.event.eventFieldsSize = 1;
    UA_StatusCode retval =
        UA_Variant_setScalarCopy(overflowNotification->data.event.eventFields,
                                 &eventQueueOverflowEventType, &UA_TYPES[UA_TYPES_NODEID]);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_Notification_delete(overflowNotification);
        return retval;
    }

    /* Insert before the removed notification. This is either first in the
     * queue (if the oldest notification was removed) or before the new event
     * that remains the last element of the queue.
     *
     * Ensure that the following is consistent with UA_Notification_enqueueMon
     * and UA_Notification_enqueueSub! */
    TAILQ_INSERT_BEFORE(indicator, overflowNotification, localEntry);
    ++mon->eventOverflows;
    ++mon->queueSize;

    /* Test for consistency */
    UA_assert(mon->queueSize >= mon->eventOverflows);
    UA_assert(mon->eventOverflows <= mon->queueSize - mon->eventOverflows + 1);

    if(TAILQ_NEXT(indicator, globalEntry) != UA_SUBSCRIPTION_QUEUE_SENTINEL) {
        /* Insert just before the indicator */
        TAILQ_INSERT_BEFORE(indicator, overflowNotification, globalEntry);
    } else {
        /* The indicator was not reporting or not added yet. */
        if(!mon->parameters.discardOldest) {
            /* Add last to the per-Subscription queue */
            TAILQ_INSERT_TAIL(&mon->subscription->notificationQueue,
                              overflowNotification, globalEntry);
        } else {
            /* Find the oldest reported element. Add before that. */
            while(indicator) {
                indicator = TAILQ_PREV(indicator, NotificationQueue, localEntry);
                if(!indicator) {
                    TAILQ_INSERT_TAIL(&mon->subscription->notificationQueue,
                                      overflowNotification, globalEntry);
                    break;
                }
                if(TAILQ_NEXT(indicator, globalEntry) != UA_SUBSCRIPTION_QUEUE_SENTINEL) {
                    TAILQ_INSERT_BEFORE(indicator, overflowNotification, globalEntry);
                    break;
                }
            }
        }
    }

    ++sub->notificationQueueSize;
    ++sub->eventNotifications;

    /* Update the diagnostics statistics */
#ifdef UA_ENABLE_DIAGNOSTICS
    sub->eventQueueOverFlowCount++;
#endif

    return UA_STATUSCODE_GOOD;
}

#endif

/* Set the InfoBits that a datachange notification was removed */
static void
setOverflowInfoBits(UA_MonitoredItem *mon) {
    /* Only for queues with more than one element */
    if(mon->parameters.queueSize == 1)
        return;

    UA_Notification *indicator = NULL;
    if(mon->parameters.discardOldest) {
        indicator = TAILQ_FIRST(&mon->queue);
    } else {
        indicator = TAILQ_LAST(&mon->queue, NotificationQueue);
    }
    UA_assert(indicator); /* must exist */

    indicator->data.dataChange.value.hasStatus = true;
    indicator->data.dataChange.value.status |=
        (UA_STATUSCODE_INFOTYPE_DATAVALUE | UA_STATUSCODE_INFOBITS_OVERFLOW);
}

/* Remove the InfoBits when the queueSize was reduced to 1 */
void
UA_MonitoredItem_removeOverflowInfoBits(UA_MonitoredItem *mon) {
    /* Don't consider queue size > 1 and Event MonitoredItems */
    if(mon->parameters.queueSize > 1 ||
       mon->itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER)
        return;

    /* Get the first notification */
    UA_Notification *n = TAILQ_FIRST(&mon->queue);
    if(!n)
        return;

    /* Assertion that at most one notification is in the queue */
    UA_assert(n == TAILQ_LAST(&mon->queue, NotificationQueue));

    /* Remve the Infobits */
    n->data.dataChange.value.status &= ~(UA_StatusCode)
        (UA_STATUSCODE_INFOTYPE_DATAVALUE | UA_STATUSCODE_INFOBITS_OVERFLOW);
}

UA_Notification *
UA_Notification_new(void) {
    UA_Notification *n = (UA_Notification*)UA_calloc(1, sizeof(UA_Notification));
    if(n) {
        /* Set the sentinel for a notification that is not enqueued */
        TAILQ_NEXT(n, globalEntry) = UA_SUBSCRIPTION_QUEUE_SENTINEL;
        TAILQ_NEXT(n, localEntry) = UA_SUBSCRIPTION_QUEUE_SENTINEL;
    }
    return n;
}

static void UA_Notification_dequeueMon(UA_Notification *n);
static void UA_Notification_enqueueSub(UA_Notification *n);
static void UA_Notification_dequeueSub(UA_Notification *n);

void
UA_Notification_delete(UA_Notification *n) {
    UA_assert(n != UA_SUBSCRIPTION_QUEUE_SENTINEL);
    if(n->mon) {
        UA_Notification_dequeueMon(n);
        UA_Notification_dequeueSub(n);
        switch(n->mon->itemToMonitor.attributeId) {
#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
        case UA_ATTRIBUTEID_EVENTNOTIFIER:
            UA_EventFieldList_clear(&n->data.event);
            break;
#endif
        default:
            UA_MonitoredItemNotification_clear(&n->data.dataChange);
            break;
        }
    }
    UA_free(n);
}

/* Add to the MonitoredItem queue, update all counters and then handle overflow */
static void
UA_Notification_enqueueMon(UA_Server *server, UA_Notification *n) {
    UA_MonitoredItem *mon = n->mon;
    UA_assert(mon);
    UA_assert(TAILQ_NEXT(n, localEntry) == UA_SUBSCRIPTION_QUEUE_SENTINEL);

    /* Add to the MonitoredItem */
    TAILQ_INSERT_TAIL(&mon->queue, n, localEntry);
    ++mon->queueSize;

#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
    if(n->isOverflowEvent)
        ++mon->eventOverflows;
#endif

    /* Test for consistency */
    UA_assert(mon->queueSize >= mon->eventOverflows);
    UA_assert(mon->eventOverflows <= mon->queueSize - mon->eventOverflows + 1);

    /* Ensure enough space is available in the MonitoredItem. Do this only after
     * adding the new Notification. */
    UA_MonitoredItem_ensureQueueSpace(server, mon);

    UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, mon->subscription,
                              "MonitoredItem %" PRIi32 " | "
                              "Notification enqueued (Queue size %lu / %lu)",
                              mon->monitoredItemId,
                              (long unsigned)mon->queueSize,
                              (long unsigned)mon->parameters.queueSize);
}

static void
UA_Notification_enqueueSub(UA_Notification *n) {
    UA_MonitoredItem *mon = n->mon;
    UA_assert(mon);

    UA_Subscription *sub = mon->subscription;
    UA_assert(sub);

    if(TAILQ_NEXT(n, globalEntry) != UA_SUBSCRIPTION_QUEUE_SENTINEL)
        return;

    /* Add to the subscription if reporting is enabled */
    TAILQ_INSERT_TAIL(&sub->notificationQueue, n, globalEntry);
    ++sub->notificationQueueSize;

    switch(mon->itemToMonitor.attributeId) {
#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
    case UA_ATTRIBUTEID_EVENTNOTIFIER:
        ++sub->eventNotifications;
        break;
#endif
    default:
        ++sub->dataChangeNotifications;
        break;
    }
}

void
UA_Notification_enqueueAndTrigger(UA_Server *server, UA_Notification *n) {
    UA_MonitoredItem *mon = n->mon;
    UA_Subscription *sub = mon->subscription;
    UA_assert(sub); /* This function is never called for local MonitoredItems */

    /* If reporting or (sampled+triggered), enqueue into the Subscription first
     * and then into the MonitoredItem. UA_MonitoredItem_ensureQueueSpace
     * (called within UA_Notification_enqueueMon) assumes the notification is
     * already in the Subscription's publishing queue. */
    UA_EventLoop *el = server->config.eventLoop;
    UA_DateTime nowMonotonic = el->dateTime_nowMonotonic(el);
    if(mon->monitoringMode == UA_MONITORINGMODE_REPORTING ||
       (mon->monitoringMode == UA_MONITORINGMODE_SAMPLING &&
        mon->triggeredUntil > nowMonotonic)) {
        UA_Notification_enqueueSub(n);
        mon->triggeredUntil = UA_INT64_MIN;
        UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, mon->subscription,
                                  "Notification enqueued (Queue size %lu)",
                                  (long unsigned)mon->subscription->notificationQueueSize);
    }

    /* Insert into the MonitoredItem. This checks the queue size and
     * handles overflow. */
    UA_Notification_enqueueMon(server, n);

    for(size_t i = mon->triggeringLinksSize - 1; i < mon->triggeringLinksSize; i--) {
        /* Get the triggered MonitoredItem. Remove the link if the MI doesn't exist. */
        UA_MonitoredItem *triggeredMon =
            UA_Subscription_getMonitoredItem(sub, mon->triggeringLinks[i]);
        if(!triggeredMon) {
            UA_MonitoredItem_removeLink(sub, mon, mon->triggeringLinks[i]);
            continue;
        }

        /* Only sampling MonitoredItems receive a trigger. Reporting
         * MonitoredItems send out Notifications anyway and disabled
         * MonitoredItems don't create samples to send. */
        if(triggeredMon->monitoringMode != UA_MONITORINGMODE_SAMPLING)
            continue;

        /* Get the latest sampled Notification from the triggered MonitoredItem.
         * Enqueue for publication. */
        UA_Notification *n2 = TAILQ_LAST(&triggeredMon->queue, NotificationQueue);
        if(n2)
            UA_Notification_enqueueSub(n2);

        /* The next Notification within the publishing interval is going to be
         * published as well. (Falsely) assume that the publishing cycle has
         * started right now, so that we don't have to loop over MonitoredItems
         * to deactivate the triggering after the publishing cycle. */
        triggeredMon->triggeredUntil = nowMonotonic +
            (UA_DateTime)(sub->publishingInterval * (UA_Double)UA_DATETIME_MSEC);

        UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, sub,
                                  "MonitoredItem %u triggers MonitoredItem %u",
                                  mon->monitoredItemId, triggeredMon->monitoredItemId);
    }

    /* If we just enqueued a notification into the local adminSubscription, then
     * register a delayed callback for "local publishing". */
    if(sub == server->adminSubscription && !sub->delayedCallbackRegistered) {
        sub->delayedCallbackRegistered = true;
        sub->delayedMoreNotifications.callback =
            (UA_Callback)UA_Subscription_localPublish;
        sub->delayedMoreNotifications.application = server;
        sub->delayedMoreNotifications.context = sub;

        el = server->config.eventLoop;
        el->addDelayedCallback(el, &sub->delayedMoreNotifications);
    }
}

/* Remove from the MonitoredItem queue and adjust all counters */
static void
UA_Notification_dequeueMon(UA_Notification *n) {
    UA_MonitoredItem *mon = n->mon;
    UA_assert(mon);

    if(TAILQ_NEXT(n, localEntry) == UA_SUBSCRIPTION_QUEUE_SENTINEL)
        return;

    /* Remove from the MonitoredItem queue */
#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
    if(n->isOverflowEvent)
        --mon->eventOverflows;
#endif

    TAILQ_REMOVE(&mon->queue, n, localEntry);
    --mon->queueSize;

    /* Test for consistency */
    UA_assert(mon->queueSize >= mon->eventOverflows);
    UA_assert(mon->eventOverflows <= mon->queueSize - mon->eventOverflows + 1);

    /* Reset the sentintel */
    TAILQ_NEXT(n, localEntry) = UA_SUBSCRIPTION_QUEUE_SENTINEL;
}

void
UA_Notification_dequeueSub(UA_Notification *n) {
    if(TAILQ_NEXT(n, globalEntry) == UA_SUBSCRIPTION_QUEUE_SENTINEL)
        return;

    UA_MonitoredItem *mon = n->mon;
    UA_assert(mon);
    UA_Subscription *sub = mon->subscription;
    UA_assert(sub);

    switch(mon->itemToMonitor.attributeId) {
#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
    case UA_ATTRIBUTEID_EVENTNOTIFIER:
        --sub->eventNotifications;
        break;
#endif
    default:
        --sub->dataChangeNotifications;
        break;
    }

    TAILQ_REMOVE(&sub->notificationQueue, n, globalEntry);
    --sub->notificationQueueSize;

    /* Reset the sentinel */
    TAILQ_NEXT(n, globalEntry) = UA_SUBSCRIPTION_QUEUE_SENTINEL;
}

/*****************/
/* MonitoredItem */
/*****************/

void
UA_MonitoredItem_init(UA_MonitoredItem *mon) {
    memset(mon, 0, sizeof(UA_MonitoredItem));
    TAILQ_INIT(&mon->queue);
    mon->triggeredUntil = UA_INT64_MIN;
}

static UA_StatusCode
addMonitoredItemBackpointer(UA_Server *server, UA_Session *session,
                            UA_Node *node, void *data) {
    UA_MonitoredItem *mon = (UA_MonitoredItem*)data;
    UA_assert(mon != (UA_MonitoredItem*)~0);
    mon->sampling.nodeListNext = node->head.monitoredItems;
    node->head.monitoredItems = mon;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
removeMonitoredItemBackPointer(UA_Server *server, UA_Session *session,
                               UA_Node *node, void *data) {
    if(!node->head.monitoredItems)
        return UA_STATUSCODE_GOOD;

    /* Edge case that it's the first element */
    UA_MonitoredItem *remove = (UA_MonitoredItem*)data;
    if(node->head.monitoredItems == remove) {
        node->head.monitoredItems = remove->sampling.nodeListNext;
        return UA_STATUSCODE_GOOD;
    }

    UA_MonitoredItem *prev = node->head.monitoredItems;
    UA_MonitoredItem *entry = prev->sampling.nodeListNext;
    for(; entry != NULL; prev = entry, entry = entry->sampling.nodeListNext) {
        if(entry == remove) {
            prev->sampling.nodeListNext = entry->sampling.nodeListNext;
            break;
        }
    }

    return UA_STATUSCODE_GOOD;
}

void
UA_Server_registerMonitoredItem(UA_Server *server, UA_MonitoredItem *mon) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    if(mon->registered)
        return;
    mon->registered = true;

    /* Register in Subscription and Server */
    UA_Subscription *sub = mon->subscription;
    mon->monitoredItemId = ++sub->lastMonitoredItemId;
    mon->subscription = sub;
    LIST_INSERT_HEAD(&sub->monitoredItems, mon, listEntry);
    sub->monitoredItemsSize++;
    server->monitoredItemsSize++;

    /* Register the MonitoredItem in userland */
    if(server->config.monitoredItemRegisterCallback) {
        UA_Session *session = sub->session;
        void *targetContext = NULL;
        getNodeContext(server, mon->itemToMonitor.nodeId, &targetContext);
        UA_UNLOCK(&server->serviceMutex);
        server->config.monitoredItemRegisterCallback(server,
                                                     session ? &session->sessionId : NULL,
                                                     session ? session->context : NULL,
                                                     &mon->itemToMonitor.nodeId,
                                                     targetContext,
                                                     mon->itemToMonitor.attributeId, false);
        UA_LOCK(&server->serviceMutex);
    }
}

static void
UA_Server_unregisterMonitoredItem(UA_Server *server, UA_MonitoredItem *mon) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    if(!mon->registered)
        return;
    mon->registered = false;

    UA_Subscription *sub = mon->subscription;
    UA_LOG_INFO_SUBSCRIPTION(server->config.logging, sub,
                             "MonitoredItem %" PRIi32 " | Deleting the MonitoredItem",
                             mon->monitoredItemId);

    /* Deregister MonitoredItem in userland */
    if(server->config.monitoredItemRegisterCallback) {
        UA_Session *session = sub->session;
        void *targetContext = NULL;
        getNodeContext(server, mon->itemToMonitor.nodeId, &targetContext);
        UA_UNLOCK(&server->serviceMutex);
        server->config.monitoredItemRegisterCallback(server,
                                                     session ? &session->sessionId : NULL,
                                                     session ? session->context : NULL,
                                                     &mon->itemToMonitor.nodeId,
                                                     targetContext,
                                                     mon->itemToMonitor.attributeId, true);
        UA_LOCK(&server->serviceMutex);
    }

    /* Deregister in Subscription and server */
    sub->monitoredItemsSize--;
    LIST_REMOVE(mon, listEntry);
    server->monitoredItemsSize--;
}

UA_StatusCode
UA_MonitoredItem_setMonitoringMode(UA_Server *server, UA_MonitoredItem *mon,
                                   UA_MonitoringMode monitoringMode) {
    /* Check if the MonitoringMode is valid or not */
    if(monitoringMode > UA_MONITORINGMODE_REPORTING)
        return UA_STATUSCODE_BADMONITORINGMODEINVALID;

    /* Set the MonitoringMode, store the old mode */
    UA_MonitoringMode oldMode = mon->monitoringMode;
    mon->monitoringMode = monitoringMode;

    UA_Notification *notification;
    /* Reporting is disabled. This causes all Notifications to be dequeued and
     * deleted. Also remove the last samples so that we immediately generate a
     * Notification when re-activated. */
    if(mon->monitoringMode == UA_MONITORINGMODE_DISABLED) {
        UA_Notification *notification_tmp;
        UA_MonitoredItem_unregisterSampling(server, mon);
        TAILQ_FOREACH_SAFE(notification, &mon->queue, localEntry, notification_tmp) {
            UA_Notification_delete(notification);
        }
        UA_DataValue_clear(&mon->lastValue);
        return UA_STATUSCODE_GOOD;
    }

    /* When reporting is enabled, put all notifications that were already
     * sampled into the global queue of the subscription. When sampling is
     * enabled, remove all notifications from the global queue. !!! This needs
     * to be the same operation as in UA_Notification_enqueue !!! */
    if(mon->monitoringMode == UA_MONITORINGMODE_REPORTING) {
        /* Make all notifications reporting. Re-enqueue to ensure they have the
         * right order if some notifications are already reported by a trigger
         * link. */
        TAILQ_FOREACH(notification, &mon->queue, localEntry) {
            UA_Notification_dequeueSub(notification);
            UA_Notification_enqueueSub(notification);
        }
    } else /* mon->monitoringMode == UA_MONITORINGMODE_SAMPLING */ {
        /* Make all notifications non-reporting */
        TAILQ_FOREACH(notification, &mon->queue, localEntry)
            UA_Notification_dequeueSub(notification);
    }

    /* Register the sampling callback with an interval. If registering the
     * sampling callback failed, set to disabled. But don't delete the current
     * notifications. */
    UA_StatusCode res = UA_MonitoredItem_registerSampling(server, mon);
    if(res != UA_STATUSCODE_GOOD) {
        mon->monitoringMode = UA_MONITORINGMODE_DISABLED;
        return res;
    }

    /* Manually create the first sample if the MonitoredItem was disabled, the
     * MonitoredItem is now sampling (or reporting) and it is not an
     * Event-MonitoredItem */
    if(oldMode == UA_MONITORINGMODE_DISABLED &&
       mon->monitoringMode > UA_MONITORINGMODE_DISABLED &&
       mon->itemToMonitor.attributeId != UA_ATTRIBUTEID_EVENTNOTIFIER)
        monitoredItem_sampleCallback(server, mon);

    return UA_STATUSCODE_GOOD;
}

static void
delayedFreeMonitoredItem(void *app, void *context) {
    UA_free(context);
}

void
UA_MonitoredItem_delete(UA_Server *server, UA_MonitoredItem *mon) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Remove the sampling callback */
    UA_MonitoredItem_unregisterSampling(server, mon);

    /* Deregister in Server and Subscription */
    if(mon->registered)
        UA_Server_unregisterMonitoredItem(server, mon);

    /* Remove the TriggeringLinks */
    if(mon->triggeringLinksSize > 0) {
        UA_free(mon->triggeringLinks);
        mon->triggeringLinks = NULL;
        mon->triggeringLinksSize = 0;
    }

    /* Remove the queued notifications attached to the subscription */
    UA_Notification *notification, *notification_tmp;
    TAILQ_FOREACH_SAFE(notification, &mon->queue, localEntry, notification_tmp) {
        UA_Notification_delete(notification);
    }

    /* Remove the settings */
    UA_ReadValueId_clear(&mon->itemToMonitor);
    UA_MonitoringParameters_clear(&mon->parameters);

    /* Remove the last samples */
    UA_DataValue_clear(&mon->lastValue);

    /* If this is a local MonitoredItem, clean up additional values */
    if(mon->subscription == server->adminSubscription) {
        UA_LocalMonitoredItem *lm = (UA_LocalMonitoredItem*)mon;
        for(size_t i = 0; i < lm->eventFields.mapSize; i++)
            UA_Variant_init(&lm->eventFields.map[i].value);
        UA_KeyValueMap_clear(&lm->eventFields);
    }

    /* Add a delayed callback to remove the MonitoredItem when the current jobs
     * have completed. This is needed to allow that a local MonitoredItem can
     * remove itself in the callback. */
    mon->delayedFreePointers.callback = delayedFreeMonitoredItem;
    mon->delayedFreePointers.application = NULL;
    mon->delayedFreePointers.context = mon;
    UA_EventLoop *el = server->config.eventLoop;
    el->addDelayedCallback(el, &mon->delayedFreePointers);
}

void
UA_MonitoredItem_ensureQueueSpace(UA_Server *server, UA_MonitoredItem *mon) {
    /* There can be only one EventOverflow more than normal entries. Because
     * EventOverflows are never adjacent. */
    UA_assert(mon->queueSize >= mon->eventOverflows);
    UA_assert(mon->eventOverflows <= mon->queueSize - mon->eventOverflows + 1);

    /* Always attached to a Subscription (no local MonitoredItem) */
    UA_Subscription *sub = mon->subscription;
    UA_assert(sub);

    /* Nothing to do */
    if(mon->queueSize - mon->eventOverflows <= mon->parameters.queueSize)
        return;

    /* Remove notifications until the required queue size is reached */
    UA_Boolean reporting = false;
    size_t remove = mon->queueSize - mon->eventOverflows - mon->parameters.queueSize;
    while(remove > 0) {
        /* The minimum queue size (without EventOverflows) is 1. At least two
         * notifications that are not EventOverflows are in the queue. */
        UA_assert(mon->queueSize - mon->eventOverflows >= 2);

        /* Select the next notification to delete. Skip over overflow events. */
        UA_Notification *del = NULL;
        if(mon->parameters.discardOldest) {
            /* Remove the oldest */
            del = TAILQ_FIRST(&mon->queue);
#if defined(UA_ENABLE_SUBSCRIPTIONS_EVENTS) && !defined(__clang_analyzer__)
            while(del->isOverflowEvent)
                del = TAILQ_NEXT(del, localEntry); /* skip overflow events */
#endif
        } else {
            /* Remove the second newest (to keep the up-to-date notification).
             * The last entry is not an OverflowEvent -- we just added it. */
            del = TAILQ_LAST(&mon->queue, NotificationQueue);
            del = TAILQ_PREV(del, NotificationQueue, localEntry);
#if defined(UA_ENABLE_SUBSCRIPTIONS_EVENTS) && !defined(__clang_analyzer__)
            while(del->isOverflowEvent)
                del = TAILQ_PREV(del, NotificationQueue, localEntry); /* skip overflow events */
#endif
        }

        UA_assert(del); /* There must have been one entry that can be deleted */

        /* Only create OverflowEvents (and set InfoBits) if the notification
         * that is removed is reported */
        if(TAILQ_NEXT(del, globalEntry) != UA_SUBSCRIPTION_QUEUE_SENTINEL)
            reporting = true;

        /* Move the entry after del in the per-MonitoredItem queue right after
         * del in the per-Subscription queue. So we don't starve MonitoredItems
         * with a high sampling interval in the Subscription queue by always
         * removing their first appearance in the per-Subscription queue.
         *
         * With MonitoringMode == SAMPLING, the Notifications are not (all) in
         * the per-Subscription queue. Don't reinsert in that case.
         *
         * For the reinsertion to work, first insert into the per-Subscription
         * queue. */
        if(TAILQ_NEXT(del, globalEntry) != UA_SUBSCRIPTION_QUEUE_SENTINEL) {
            UA_Notification *after_del = TAILQ_NEXT(del, localEntry);
            UA_assert(after_del); /* There must be one remaining element after del */
            if(TAILQ_NEXT(after_del, globalEntry) != UA_SUBSCRIPTION_QUEUE_SENTINEL) {
                TAILQ_REMOVE(&sub->notificationQueue, after_del, globalEntry);
                TAILQ_INSERT_AFTER(&sub->notificationQueue, del, after_del, globalEntry);
            }
        }

        remove--;

        /* Delete the notification and remove it from the queues */
        UA_Notification_delete(del);

        /* Update the subscription diagnostics statistics */
#ifdef UA_ENABLE_DIAGNOSTICS
        sub->monitoringQueueOverflowCount++;
#endif

        /* Assertions to help Clang's scan-analyzer */
        UA_assert(del != TAILQ_FIRST(&mon->queue));
        UA_assert(del != TAILQ_LAST(&mon->queue, NotificationQueue));
        UA_assert(del != TAILQ_PREV(TAILQ_LAST(&mon->queue, NotificationQueue),
                                    NotificationQueue, localEntry));
    }

        /* Leave an entry to indicate that notifications were removed */
    if(reporting) {
#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
        if(mon->itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER)
            createEventOverflowNotification(server, sub, mon);
        else
#endif
            setOverflowInfoBits(mon);
    }
}

UA_StatusCode
UA_MonitoredItem_registerSampling(UA_Server *server, UA_MonitoredItem *mon) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Sampling is already registered */
    if(mon->samplingType != UA_MONITOREDITEMSAMPLINGTYPE_NONE)
        return UA_STATUSCODE_GOOD;

    /* The subscription is attached to a session at this point */
    UA_Subscription *sub = mon->subscription;
    if(!sub->session)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(mon->itemToMonitor.attributeId == UA_ATTRIBUTEID_EVENTNOTIFIER ||
       mon->parameters.samplingInterval == 0.0) {
        /* Add to the linked list in the node */
        res = UA_Server_editNode(server, sub->session, &mon->itemToMonitor.nodeId,
                                 addMonitoredItemBackpointer, mon);
        if(res == UA_STATUSCODE_GOOD)
            mon->samplingType = UA_MONITOREDITEMSAMPLINGTYPE_EVENT;
    } else if(mon->parameters.samplingInterval == sub->publishingInterval) {
        /* Add to the subscription for sampling before every publish */
        LIST_INSERT_HEAD(&sub->samplingMonitoredItems, mon,
                         sampling.subscriptionSampling);
        mon->samplingType = UA_MONITOREDITEMSAMPLINGTYPE_PUBLISH;
    } else {
        /* DataChange MonitoredItems with a positive sampling interval have a
         * repeated callback. Other MonitoredItems are attached to the Node in a
         * linked list of backpointers. */
        res = addRepeatedCallback(server,
                                  (UA_ServerCallback)UA_MonitoredItem_sampleCallback,
                                  mon, mon->parameters.samplingInterval,
                                  &mon->sampling.callbackId);
        if(res == UA_STATUSCODE_GOOD)
            mon->samplingType = UA_MONITOREDITEMSAMPLINGTYPE_CYCLIC;
    }

    return res;
}

void
UA_MonitoredItem_unregisterSampling(UA_Server *server, UA_MonitoredItem *mon) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    switch(mon->samplingType) {
    case UA_MONITOREDITEMSAMPLINGTYPE_CYCLIC:
        /* Remove repeated callback */
        removeCallback(server, mon->sampling.callbackId);
        break;

    case UA_MONITOREDITEMSAMPLINGTYPE_EVENT: {
        /* Removing is always done with the AdminSession. So it also works when
         * the Subscription has been detached from its Session. */
        UA_Server_editNode(server, &server->adminSession, &mon->itemToMonitor.nodeId,
                           removeMonitoredItemBackPointer, mon);
        break;
    }

    case UA_MONITOREDITEMSAMPLINGTYPE_PUBLISH:
        /* Added to the subscription */
        LIST_REMOVE(mon, sampling.subscriptionSampling);
        break;

    case UA_MONITOREDITEMSAMPLINGTYPE_NONE:
    default:
        /* Sampling is not registered */
        break;
    }

    mon->samplingType = UA_MONITOREDITEMSAMPLINGTYPE_NONE;
}

UA_StatusCode
UA_MonitoredItem_removeLink(UA_Subscription *sub, UA_MonitoredItem *mon, UA_UInt32 linkId) {
    /* Find the index */
    size_t i = 0;
    for(; i < mon->triggeringLinksSize; i++) {
        if(mon->triggeringLinks[i] == linkId)
            break;
    }

    /* Not existing / already removed */
    if(i == mon->triggeringLinksSize)
        return UA_STATUSCODE_BADMONITOREDITEMIDINVALID;

    /* Remove the link */
    mon->triggeringLinksSize--;
    if(mon->triggeringLinksSize == 0) {
        UA_free(mon->triggeringLinks);
        mon->triggeringLinks = NULL;
    } else {
        mon->triggeringLinks[i] = mon->triggeringLinks[mon->triggeringLinksSize];
        UA_UInt32 *tmpLinks = (UA_UInt32*)
            UA_realloc(mon->triggeringLinks, mon->triggeringLinksSize * sizeof(UA_UInt32));
        if(tmpLinks)
            mon->triggeringLinks = tmpLinks;
    }

    /* Does the target MonitoredItem exist? This is stupid, but the CTT wants us
     * to to this. We don't auto-remove links together with the target
     * MonitoredItem. Links to removed MonitoredItems are removed when the link
     * triggers and the target no longer exists. */
    UA_MonitoredItem *mon2 = UA_Subscription_getMonitoredItem(sub, linkId);
    if(!mon2)
        return UA_STATUSCODE_BADMONITOREDITEMIDINVALID;

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_MonitoredItem_addLink(UA_Subscription *sub, UA_MonitoredItem *mon, UA_UInt32 linkId) {
    /* Does the target MonitoredItem exist? */
    UA_MonitoredItem *mon2 = UA_Subscription_getMonitoredItem(sub, linkId);
    if(!mon2)
        return UA_STATUSCODE_BADMONITOREDITEMIDINVALID;

    /* Does the link already exist? */
    for(size_t i = 0 ; i < mon->triggeringLinksSize; i++) {
        if(mon->triggeringLinks[i] == linkId)
            return UA_STATUSCODE_GOOD;
    }

    /* Allocate the memory */
    UA_UInt32 *tmpLinkIds = (UA_UInt32*)
        UA_realloc(mon->triggeringLinks, (mon->triggeringLinksSize + 1) * sizeof(UA_UInt32));
    if(!tmpLinkIds)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    mon->triggeringLinks = tmpLinkIds;

    /* Add the link */
    mon->triggeringLinks[mon->triggeringLinksSize] = linkId;
    mon->triggeringLinksSize++;
    return UA_STATUSCODE_GOOD;
}

#endif /* UA_ENABLE_SUBSCRIPTIONS */

/**** amalgamated original file "/src/server/ua_subscription_datachange.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2017-2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2018 (c) Ari Breitkreuz, fortiss GmbH
 *    Copyright 2018 (c) Thomas Stalder, Blue Time Concept SA
 *    Copyright 2018 (c) Fabian Arndt, Root-Core
 */


#ifdef UA_ENABLE_SUBSCRIPTIONS /* conditional compilation */

/* Detect value changes outside the deadband */
#define UA_DETECT_DEADBAND(TYPE) do {                           \
    TYPE v1 = *(const TYPE*)data1;                              \
    TYPE v2 = *(const TYPE*)data2;                              \
    TYPE diff = (v1 > v2) ? (TYPE)(v1 - v2) : (TYPE)(v2 - v1);  \
    return ((UA_Double)diff > deadband);                        \
} while(false);

static UA_Boolean
detectScalarDeadBand(const void *data1, const void *data2,
                     const UA_DataType *type, const UA_Double deadband) {
    if(type->typeKind == UA_DATATYPEKIND_SBYTE) {
        UA_DETECT_DEADBAND(UA_SByte);
    } else if(type->typeKind == UA_DATATYPEKIND_BYTE) {
        UA_DETECT_DEADBAND(UA_Byte);
    } else if(type->typeKind == UA_DATATYPEKIND_INT16) {
        UA_DETECT_DEADBAND(UA_Int16);
    } else if(type->typeKind == UA_DATATYPEKIND_UINT16) {
        UA_DETECT_DEADBAND(UA_UInt16);
    } else if(type->typeKind == UA_DATATYPEKIND_INT32) {
        UA_DETECT_DEADBAND(UA_Int32);
    } else if(type->typeKind == UA_DATATYPEKIND_UINT32) {
        UA_DETECT_DEADBAND(UA_UInt32);
    } else if(type->typeKind == UA_DATATYPEKIND_INT64) {
        UA_DETECT_DEADBAND(UA_Int64);
    } else if(type->typeKind == UA_DATATYPEKIND_UINT64) {
        UA_DETECT_DEADBAND(UA_UInt64);
    } else if(type->typeKind == UA_DATATYPEKIND_FLOAT) {
        UA_DETECT_DEADBAND(UA_Float);
    } else if(type->typeKind == UA_DATATYPEKIND_DOUBLE) {
        UA_DETECT_DEADBAND(UA_Double);
    } else {
        return false; /* Not a known numerical type */
    }
}

static UA_Boolean
detectVariantDeadband(const UA_Variant *value, const UA_Variant *oldValue,
                      const UA_Double deadbandValue) {
    if(value->arrayLength != oldValue->arrayLength)
        return true;
    if(value->type != oldValue->type)
        return true;
    size_t length = 1;
    if(!UA_Variant_isScalar(value))
        length = value->arrayLength;
    uintptr_t data = (uintptr_t)value->data;
    uintptr_t oldData = (uintptr_t)oldValue->data;
    UA_UInt32 memSize = value->type->memSize;
    for(size_t i = 0; i < length; ++i) {
        if(detectScalarDeadBand((const void*)data, (const void*)oldData,
                                value->type, deadbandValue))
            return true;
        data += memSize;
        oldData += memSize;
    }
    return false;
}

static UA_Boolean
detectValueChange(UA_Server *server, UA_MonitoredItem *mon, const UA_DataValue *dv) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Status changes are always reported */
    if(dv->hasStatus != mon->lastValue.hasStatus ||
       dv->status != mon->lastValue.status) {
        return true;
    }

    /* Default trigger is Status + Value */
    UA_DataChangeTrigger trigger = UA_DATACHANGETRIGGER_STATUSVALUE;

    /* Use the configured trigger */
    const UA_DataChangeFilter *dcf = NULL;
    const UA_ExtensionObject *filter = &mon->parameters.filter;
    if(filter->content.decoded.type == &UA_TYPES[UA_TYPES_DATACHANGEFILTER]) {
        dcf = (UA_DataChangeFilter*)filter->content.decoded.data;
        trigger = dcf->trigger;
    }

    /* The status was already tested above */
    if(trigger == UA_DATACHANGETRIGGER_STATUS)
        return false;

    UA_assert(trigger == UA_DATACHANGETRIGGER_STATUSVALUE ||
              trigger == UA_DATACHANGETRIGGER_STATUSVALUETIMESTAMP);

    /* Test absolute deadband */
    if(dcf && dcf->deadbandType == UA_DEADBANDTYPE_ABSOLUTE &&
       dv->value.type != NULL && UA_DataType_isNumeric(dv->value.type))
        return detectVariantDeadband(&dv->value, &mon->lastValue.value,
                                     dcf->deadbandValue);

    /* Compare the source timestamp if the trigger requires that */
    if(trigger == UA_DATACHANGETRIGGER_STATUSVALUETIMESTAMP) {
        if(dv->hasSourceTimestamp != mon->lastValue.hasSourceTimestamp)
            return true;
        if(dv->hasSourceTimestamp &&
           dv->sourceTimestamp != mon->lastValue.sourceTimestamp)
            return true;
    }

    /* Has the value changed? */
    if(dv->hasValue != mon->lastValue.hasValue)
        return true;
    return !UA_equal(&dv->value, &mon->lastValue.value,
                     &UA_TYPES[UA_TYPES_VARIANT]);
}

UA_StatusCode
UA_MonitoredItem_createDataChangeNotification(UA_Server *server, UA_MonitoredItem *mon,
                                              const UA_DataValue *dv) {
    /* Allocate a new notification */
    UA_Notification *newNot = UA_Notification_new();
    if(!newNot)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Prepare the notification */
    newNot->mon = mon;
    newNot->data.dataChange.clientHandle = mon->parameters.clientHandle;
    UA_StatusCode retval = UA_DataValue_copy(dv, &newNot->data.dataChange.value);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free(newNot);
        return retval;
    }

    /* Enqueue the notification */
    UA_Notification_enqueueAndTrigger(server, newNot);
    return UA_STATUSCODE_GOOD;
}

void
UA_MonitoredItem_processSampledValue(UA_Server *server, UA_MonitoredItem *mon,
                                     UA_DataValue *value) {
    UA_assert(mon->itemToMonitor.attributeId != UA_ATTRIBUTEID_EVENTNOTIFIER);
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Has the value changed (with the filters applied)? */
    UA_Boolean changed = detectValueChange(server, mon, value);
    if(!changed) {
        UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, mon->subscription,
                                  "MonitoredItem %" PRIi32 " | "
                                  "The value has not changed", mon->monitoredItemId);
        UA_DataValue_clear(value);
        return;
    }

    /* Prepare a notification and enqueue it */
    UA_StatusCode res =
        UA_MonitoredItem_createDataChangeNotification(server, mon, value);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING_SUBSCRIPTION(server->config.logging, mon->subscription,
                                    "MonitoredItem %" PRIi32 " | "
                                    "Processing the sample returned the statuscode %s",
                                    mon->monitoredItemId, UA_StatusCode_name(res));
        UA_DataValue_clear(value);
        return;
    }

    /* Move/store the value for filter comparison and TransferSubscription */
    UA_DataValue_clear(&mon->lastValue);
    mon->lastValue = *value;
}

void
UA_MonitoredItem_sampleCallback(UA_Server *server, UA_MonitoredItem *mon) {
    UA_LOCK(&server->serviceMutex);
    monitoredItem_sampleCallback(server, mon);
    UA_UNLOCK(&server->serviceMutex);
}

void
monitoredItem_sampleCallback(UA_Server *server, UA_MonitoredItem *mon) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);
    UA_assert(mon->itemToMonitor.attributeId != UA_ATTRIBUTEID_EVENTNOTIFIER);

    UA_Subscription *sub = mon->subscription;
    UA_LOG_DEBUG_SUBSCRIPTION(server->config.logging, sub, "MonitoredItem %" PRIi32
                              " | Sample callback called", mon->monitoredItemId);

    /* Sample the current value */
    UA_Session *session = (sub) ? sub->session : &server->adminSession;
    UA_DataValue dv = readWithSession(server, session, &mon->itemToMonitor,
                                      mon->timestampsToReturn);

    /* Process the sample. This always clears the value. */
    UA_MonitoredItem_processSampledValue(server, mon, &dv);
}

#endif /* UA_ENABLE_SUBSCRIPTIONS */

/**** amalgamated original file "/src/server/ua_subscription_events.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2018 (c) Ari Breitkreuz, fortiss GmbH
 *    Copyright 2020 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati)
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Andreas Ebner)
 */


#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS

/* We use a 16-Byte ByteString as an identifier */
UA_StatusCode
generateEventId(UA_ByteString *generatedId) {
    /* EventId is a ByteString, which is basically just a string
     * We will use a 16-Byte ByteString as an identifier */
    UA_StatusCode res = UA_ByteString_allocBuffer(generatedId, 16 * sizeof(UA_Byte));
    if(res != UA_STATUSCODE_GOOD)
        return res;
    UA_UInt32 *ids = (UA_UInt32*)generatedId->data;
    ids[0] = UA_UInt32_random();
    ids[1] = UA_UInt32_random();
    ids[2] = UA_UInt32_random();
    ids[3] = UA_UInt32_random();
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
createEvent(UA_Server *server, const UA_NodeId eventType, UA_NodeId *outNodeId) {
    if(!outNodeId) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_USERLAND,
                     "outNodeId must not be NULL. The event's NodeId must be returned "
                     "so it can be triggered.");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    /* Make sure the eventType is a subtype of BaseEventType */
    UA_NodeId baseEventTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE);
    if(!isNodeInTree_singleRef(server, &eventType, &baseEventTypeId,
                               UA_REFERENCETYPEINDEX_HASSUBTYPE)) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_USERLAND,
                     "Event type must be a subtype of BaseEventType!");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    /* Create an ObjectNode which represents the event */
    UA_QualifiedName name;
    /*  set a dummy name. This is not used. */
    name = UA_QUALIFIEDNAME(0,"E");
    UA_NodeId newNodeId = UA_NODEID_NULL;
    UA_ObjectAttributes oAttr = UA_ObjectAttributes_default;
    UA_StatusCode retval = addNode(server, UA_NODECLASS_OBJECT,
                                   UA_NODEID_NULL, /* Set a random unused NodeId */
                                   UA_NODEID_NULL, /* No parent */
                                   UA_NODEID_NULL, /* No parent reference */
                                   name,           /* an event does not have a name */
                                   eventType,      /* the type of the event */
                                   &oAttr,         /* default attributes are fine */
                                   &UA_TYPES[UA_TYPES_OBJECTATTRIBUTES],
                                   NULL,           /* no node context */
                                   &newNodeId);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_USERLAND,
                     "Adding event failed. StatusCode %s", UA_StatusCode_name(retval));
        return retval;
    }

    /* Find the eventType variable */
    name = UA_QUALIFIEDNAME(0, "EventType");
    UA_BrowsePathResult bpr = browseSimplifiedBrowsePath(server, newNodeId, 1, &name);
    if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
        retval = bpr.statusCode;
        UA_BrowsePathResult_clear(&bpr);
        deleteNode(server, newNodeId, true);
        UA_NodeId_clear(&newNodeId);
        return retval;
    }

    /* Set the EventType */
    UA_Variant value;
    UA_Variant_init(&value);
    UA_Variant_setScalar(&value, (void*)(uintptr_t)&eventType, &UA_TYPES[UA_TYPES_NODEID]);
    retval = writeValueAttribute(server, bpr.targets[0].targetId.nodeId, &value);
    UA_BrowsePathResult_clear(&bpr);
    if(retval != UA_STATUSCODE_GOOD) {
        deleteNode(server, newNodeId, true);
        UA_NodeId_clear(&newNodeId);
        return retval;
    }

    *outNodeId = newNodeId;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Server_createEvent(UA_Server *server, const UA_NodeId eventType,
                      UA_NodeId *outNodeId) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res = createEvent(server, eventType, outNodeId);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

static UA_StatusCode
eventSetStandardFields(UA_Server *server, const UA_NodeId *event,
                       const UA_NodeId *origin, UA_ByteString *outEventId) {
    /* Set the SourceNode */
    UA_StatusCode retval;
    UA_QualifiedName name = UA_QUALIFIEDNAME(0, "SourceNode");
    UA_BrowsePathResult bpr = browseSimplifiedBrowsePath(server, *event, 1, &name);
    if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
        retval = bpr.statusCode;
        UA_BrowsePathResult_clear(&bpr);
        return retval;
    }
    UA_Variant value;
    UA_Variant_init(&value);
    UA_Variant_setScalarCopy(&value, origin, &UA_TYPES[UA_TYPES_NODEID]);
    retval = writeValueAttribute(server, bpr.targets[0].targetId.nodeId, &value);
    UA_Variant_clear(&value);
    UA_BrowsePathResult_clear(&bpr);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Set the ReceiveTime */
    name = UA_QUALIFIEDNAME(0, "ReceiveTime");
    bpr = browseSimplifiedBrowsePath(server, *event, 1, &name);
    if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
        retval = bpr.statusCode;
        UA_BrowsePathResult_clear(&bpr);
        return retval;
    }

    UA_EventLoop *el = server->config.eventLoop;
    UA_DateTime rcvTime = el->dateTime_now(el);
    UA_Variant_setScalar(&value, &rcvTime, &UA_TYPES[UA_TYPES_DATETIME]);
    retval = writeValueAttribute(server, bpr.targets[0].targetId.nodeId, &value);
    UA_BrowsePathResult_clear(&bpr);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Set the EventId */
    UA_ByteString eventId = UA_BYTESTRING_NULL;
    retval = generateEventId(&eventId);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    name = UA_QUALIFIEDNAME(0, "EventId");
    bpr = browseSimplifiedBrowsePath(server, *event, 1, &name);
    if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
        retval = bpr.statusCode;
        UA_ByteString_clear(&eventId);
        UA_BrowsePathResult_clear(&bpr);
        return retval;
    }
    UA_Variant_init(&value);
    UA_Variant_setScalar(&value, &eventId, &UA_TYPES[UA_TYPES_BYTESTRING]);
    retval = writeValueAttribute(server, bpr.targets[0].targetId.nodeId, &value);
    UA_BrowsePathResult_clear(&bpr);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&eventId);
        return retval;
    }

    /* Return the EventId */
    if(outEventId)
        *outEventId = eventId;
    else
        UA_ByteString_clear(&eventId);

    return UA_STATUSCODE_GOOD;
}

/* Filters an event according to the filter specified by mon and then adds it to
 * mons notification queue */
UA_StatusCode
UA_MonitoredItem_addEvent(UA_Server *server, UA_MonitoredItem *mon,
                          const UA_NodeId *event) {
    /* Get the filter */
    if(mon->parameters.filter.content.decoded.type != &UA_TYPES[UA_TYPES_EVENTFILTER])
        return UA_STATUSCODE_BADFILTERNOTALLOWED;
    UA_EventFilter *eventFilter = (UA_EventFilter*)
        mon->parameters.filter.content.decoded.data;

    /* Allocate memory for the notification */
    UA_Notification *notification = UA_Notification_new();
    if(!notification)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* The MonitoredItem must be attached to a Subscription. This code path is
     * not taken for local MonitoredItems (once they are enabled for Events). */
    UA_assert(mon->subscription);
    UA_Subscription *sub = mon->subscription;
    UA_Session *session = sub->session;

    UA_EventFilterResult res; /* FilterResult contains only statuscodes. Ignored
                               * outside the initial setup/validation. */
    UA_EventFilterResult_init(&res);
    UA_StatusCode retval = filterEvent(server, session, event, eventFilter,
                                       &notification->data.event, &res);
    UA_EventFilterResult_clear(&res);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_Notification_delete(notification);
        if(retval == UA_STATUSCODE_BADNOMATCH)
            return UA_STATUSCODE_GOOD;
        return retval;
    }

    notification->data.event.clientHandle = mon->parameters.clientHandle;
    notification->mon = mon;

    UA_Notification_enqueueAndTrigger(server, notification);
    return UA_STATUSCODE_GOOD;
}

#ifdef UA_ENABLE_HISTORIZING
static void
setHistoricalEvent(UA_Server *server, const UA_NodeId *origin,
                   const UA_NodeId *emitNodeId, const UA_NodeId *eventNodeId) {
    UA_Variant historicalEventFilterValue;
    UA_Variant_init(&historicalEventFilterValue);

    /* A HistoricalEventNode that has event history available will provide this property */
    UA_StatusCode retval =
        readObjectProperty(server, *emitNodeId,
                           UA_QUALIFIEDNAME(0, "HistoricalEventFilter"),
                           &historicalEventFilterValue);
    if(retval != UA_STATUSCODE_GOOD) {
        /* Do not vex users with no match errors */
        if(retval != UA_STATUSCODE_BADNOMATCH)
            UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                           "Cannot read the HistoricalEventFilter property of a "
                           "listening node. StatusCode %s",
                           UA_StatusCode_name(retval));
        return;
    }

    /* If found then check if HistoricalEventFilter property has a valid value */
    if(UA_Variant_isEmpty(&historicalEventFilterValue) ||
       !UA_Variant_isScalar(&historicalEventFilterValue) ||
       historicalEventFilterValue.type != &UA_TYPES[UA_TYPES_EVENTFILTER]) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "HistoricalEventFilter property of a listening node "
                       "does not have a valid value");
        UA_Variant_clear(&historicalEventFilterValue);
        return;
    }

    /* Finally, if found and valid then filter */
    UA_EventFilter *filter = (UA_EventFilter*) historicalEventFilterValue.data;
    UA_EventFieldList efl;
    UA_EventFilterResult result;
    retval = filterEvent(server, &server->adminSession, eventNodeId, filter, &efl, &result);
    if(retval == UA_STATUSCODE_GOOD)
        server->config.historyDatabase.setEvent(server, server->config.historyDatabase.context,
                                                origin, emitNodeId, filter, &efl);
    UA_EventFilterResult_clear(&result);
    UA_Variant_clear(&historicalEventFilterValue);
    UA_EventFieldList_clear(&efl);
}
#endif

static const UA_NodeId objectsFolderId = {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_OBJECTSFOLDER}};
#define EMIT_REFS_ROOT_COUNT 4
static const UA_NodeId emitReferencesRoots[EMIT_REFS_ROOT_COUNT] =
    {{0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_ORGANIZES}},
     {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASCOMPONENT}},
     {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASEVENTSOURCE}},
     {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASNOTIFIER}}};

static const UA_NodeId isInFolderReferences[2] =
    {{0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_ORGANIZES}},
     {0, UA_NODEIDTYPE_NUMERIC, {UA_NS0ID_HASCOMPONENT}}};

UA_StatusCode
triggerEvent(UA_Server *server, const UA_NodeId eventNodeId,
             const UA_NodeId origin, UA_ByteString *outEventId,
             const UA_Boolean deleteEventNode) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    UA_LOG_NODEID_DEBUG(&origin,
        UA_LOG_DEBUG(server->config.logging, UA_LOGCATEGORY_SERVER,
            "Events: An event is triggered on node %.*s",
            (int)nodeIdStr.length, nodeIdStr.data));

#ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS
    UA_Boolean isCallerAC = false;
    if(isConditionOrBranch(server, &eventNodeId, &origin, &isCallerAC)) {
        if(!isCallerAC) {
          UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                                 "Condition Events: Please use A&C API to trigger Condition Events 0x%08X",
                                  UA_STATUSCODE_BADINVALIDARGUMENT);
          return UA_STATUSCODE_BADINVALIDARGUMENT;
        }
    }
#endif /* UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS */

    /* Check that the origin node exists */
    const UA_Node *originNode = UA_NODESTORE_GET(server, &origin);
    if(!originNode) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_USERLAND,
                     "Origin node for event does not exist.");
        return UA_STATUSCODE_BADNOTFOUND;
    }
    UA_NODESTORE_RELEASE(server, originNode);

    /* Make sure the origin is in the ObjectsFolder (TODO: or in the ViewsFolder) */
    /* Only use Organizes and HasComponent to check if we are below the ObjectsFolder */
    UA_StatusCode retval;
    UA_ReferenceTypeSet refTypes;
    UA_ReferenceTypeSet_init(&refTypes);
    for(int i = 0; i < 2; ++i) {
        UA_ReferenceTypeSet tmpRefTypes;
        retval = referenceTypeIndices(server, &isInFolderReferences[i], &tmpRefTypes, true);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                           "Events: Could not create the list of references and their subtypes "
                           "with StatusCode %s", UA_StatusCode_name(retval));
        }
        refTypes = UA_ReferenceTypeSet_union(refTypes, tmpRefTypes);
    }

    if(!isNodeInTree(server, &origin, &objectsFolderId, &refTypes)) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_USERLAND,
                     "Node for event must be in ObjectsFolder!");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    /* Update the standard fields of the event */
    retval = eventSetStandardFields(server, &eventNodeId, &origin, outEventId);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Events: Could not set the standard event fields with StatusCode %s",
                       UA_StatusCode_name(retval));
        return retval;
    }

    /* List of nodes that emit the node. Events propagate upwards (bubble up) in
     * the node hierarchy. */
    UA_ExpandedNodeId *emitNodes = NULL;
    size_t emitNodesSize = 0;

    /* Add the server node to the list of nodes from which the event is emitted.
     * The server node emits all events.
     *
     * Part 3, 7.17: In particular, the root notifier of a Server, the Server
     * Object defined in Part 5, is always capable of supplying all Events from
     * a Server and as such has implied HasEventSource References to every event
     * source in a Server. */
    UA_NodeId emitStartNodes[2];
    emitStartNodes[0] = origin;
    emitStartNodes[1] = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER);

    /* Get all ReferenceTypes over which the events propagate */
    UA_ReferenceTypeSet emitRefTypes;
    UA_ReferenceTypeSet_init(&emitRefTypes);
    for(size_t i = 0; i < EMIT_REFS_ROOT_COUNT; i++) {
        UA_ReferenceTypeSet tmpRefTypes;
        retval = referenceTypeIndices(server, &emitReferencesRoots[i], &tmpRefTypes, true);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                           "Events: Could not create the list of references for event "
                           "propagation with StatusCode %s", UA_StatusCode_name(retval));
            goto cleanup;
        }
        emitRefTypes = UA_ReferenceTypeSet_union(emitRefTypes, tmpRefTypes);
    }

    /* Get the list of nodes in the hierarchy that emits the event. */
    retval = browseRecursive(server, 2, emitStartNodes, UA_BROWSEDIRECTION_INVERSE,
                             &emitRefTypes, UA_NODECLASS_UNSPECIFIED, true,
                             &emitNodesSize, &emitNodes);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                       "Events: Could not create the list of nodes listening on the "
                       "event with StatusCode %s", UA_StatusCode_name(retval));
        goto cleanup;
    }

    /* Add the event to the listening MonitoredItems at each relevant node */
    for(size_t i = 0; i < emitNodesSize; i++) {
        /* Get the node */
        const UA_Node *node = UA_NODESTORE_GET(server, &emitNodes[i].nodeId);
        if(!node)
            continue;

        /* Only consider objects */
        if(node->head.nodeClass != UA_NODECLASS_OBJECT) {
            UA_NODESTORE_RELEASE(server, node);
            continue;
        }

        /* Add event to monitoreditems */
        UA_MonitoredItem *mon = node->head.monitoredItems;
        for(; mon != NULL; mon = mon->sampling.nodeListNext) {
            /* Is this an Event-MonitoredItem? */
            if(mon->itemToMonitor.attributeId != UA_ATTRIBUTEID_EVENTNOTIFIER)
                continue;
            retval = UA_MonitoredItem_addEvent(server, mon, &eventNodeId);
            if(retval != UA_STATUSCODE_GOOD) {
                UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                               "Events: Could not add the event to a listening "
                               "node with StatusCode %s", UA_StatusCode_name(retval));
                retval = UA_STATUSCODE_GOOD; /* Only log problems with individual emit nodes */
            }
        }

        UA_NODESTORE_RELEASE(server, node);

        /* Add event entry in the historical database */
#ifdef UA_ENABLE_HISTORIZING
        if(server->config.historyDatabase.setEvent)
            setHistoricalEvent(server, &origin, &emitNodes[i].nodeId, &eventNodeId);
#endif
    }

    /* Delete the node representation of the event */
    if(deleteEventNode) {
        retval = deleteNode(server, eventNodeId, true);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_LOG_WARNING(server->config.logging, UA_LOGCATEGORY_SERVER,
                           "Attempt to remove event using deleteNode failed. StatusCode %s",
                           UA_StatusCode_name(retval));
        }
    }

 cleanup:
    UA_Array_delete(emitNodes, emitNodesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);
    return retval;
}

UA_StatusCode
UA_Server_triggerEvent(UA_Server *server, const UA_NodeId eventNodeId,
                       const UA_NodeId origin, UA_ByteString *outEventId,
                       const UA_Boolean deleteEventNode) {
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res =
        triggerEvent(server, eventNodeId, origin, outEventId, deleteEventNode);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}
#endif /* UA_ENABLE_SUBSCRIPTIONS_EVENTS */

/**** amalgamated original file "/src/server/ua_subscription_events_filter.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2018 (c) Ari Breitkreuz, fortiss GmbH
 *    Copyright 2020 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati)
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Andreas Ebner)
 *    Copyright 2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 */


#ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS

/* Ternary Logic
 * -------------
 * Similar to SQL, OPC UA Queries use the K3 - Strong Kleene Logic that
 * considers ternary values true/false/null (unknown). Most operators resolve to
 * a ternary value. Some operators can resolve to a literal value (e.g. CAST). */

typedef enum {
    UA_TERNARY_FALSE = -1,
    UA_TERNARY_NULL = 0,
    UA_TERNARY_TRUE = 1
} UA_Ternary;

static UA_Ternary
UA_Ternary_and(UA_Ternary first, UA_Ternary second) {
    if(first == UA_TERNARY_FALSE || second == UA_TERNARY_FALSE)
        return UA_TERNARY_FALSE;
    if(first == UA_TERNARY_TRUE && second == UA_TERNARY_TRUE)
        return UA_TERNARY_TRUE;
    return UA_TERNARY_NULL;
}

static UA_Ternary
UA_Ternary_or(UA_Ternary first, UA_Ternary second) {
    if(first == UA_TERNARY_TRUE || second == UA_TERNARY_TRUE)
        return UA_TERNARY_TRUE;
    if(first == UA_TERNARY_NULL || second == UA_TERNARY_NULL)
        return UA_TERNARY_TRUE;
    return UA_TERNARY_FALSE;
}

/* Part 4: The NOT operator always evaluates to NULL if applied to a NULL
 * operand. We simply swap true/false. */
static UA_Ternary
UA_Ternary_not(UA_Ternary v) {
    return (UA_Ternary)((int)v * -1);
}

static UA_Ternary v2t(const UA_Variant *v) {
    if(UA_Variant_isEmpty(v) || !UA_Variant_hasScalarType(v, &UA_TYPES[UA_TYPES_BOOLEAN]))
        return UA_TERNARY_NULL;
    UA_Boolean b = *(UA_Boolean*)v->data;
    return (b) ? UA_TERNARY_TRUE : UA_TERNARY_FALSE;
}

static const UA_Boolean bFalse = false;
static const UA_Boolean bTrue  = true;

static UA_Variant t2v(UA_Ternary t) {
    UA_Variant v;
    UA_Variant_init(&v);
    switch(t) {
    case UA_TERNARY_FALSE:
        UA_Variant_setScalar(&v, (void*)(uintptr_t)&bFalse, &UA_TYPES[UA_TYPES_BOOLEAN]);
        break;
    case UA_TERNARY_TRUE:
        UA_Variant_setScalar(&v, (void*)(uintptr_t)&bTrue, &UA_TYPES[UA_TYPES_BOOLEAN]);
        break;
    default:
        return v;
    }
    v.storageType = UA_VARIANT_DATA_NODELETE;
    return v;
}

/* Type Casting Rules
 * ------------------
 * For comparison operations values from different datatypes can be implicitly
 * or explicitly cast. The standard defines rules to selected the target type
 * for casting and when implicit casts are possible. */

/* Defined in Part 4 Table 123 "Data Precedence Rules". Implicit casting is
 * always to the type of lower precedence value. */
static UA_Byte typePrecedence[UA_DATATYPEKINDS] = {
    12, 10, 11, 8, 9, 5, 6, 3, 4, 2, 1, 14, 255, 13, 255, 255, 16,
    15, 7, 18, 17, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
};

/* Type conversion table from the standard.
 * 0 -> Same Type, 1 -> Implicit Cast, 2 -> Only explicit Cast, -1 -> cast invalid */
static UA_SByte convertLookup[21][21] = {
    { 0, 1,-1,-1, 1,-1, 1,-1, 1, 1, 1,-1, 1,-1, 2,-1,-1, 1, 1, 1,-1},
    { 2, 0,-1,-1, 1,-1, 1,-1, 1, 1, 1,-1, 1,-1, 2,-1,-1, 1, 1, 1,-1},
    {-1,-1, 0,-1,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1},
    {-1,-1,-1, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1},
    { 2, 2,-1,-1, 0,-1, 2,-1, 2, 2, 2,-1, 2,-1, 2,-1,-1, 2, 2, 2,-1},
    {-1,-1,-1,-1,-1, 0,-1,-1,-1,-1,-1, 2,-1,-1, 1,-1,-1,-1,-1,-1,-1},
    { 2, 2,-1,-1, 1,-1, 0,-1, 2, 2, 2,-1, 2,-1, 2,-1,-1, 2, 2, 2,-1},
    {-1,-1, 2,-1,-1,-1,-1, 0,-1,-1,-1,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1},
    { 2, 2,-1,-1, 1,-1, 1,-1, 0, 1, 1,-1, 2,-1, 2,-1,-1, 2, 1, 1,-1},
    { 2, 2,-1,-1, 1,-1, 1,-1, 2, 0, 1,-1, 2, 2, 2,-1,-1, 2, 2, 1,-1},
    { 2, 2,-1,-1, 1,-1, 1,-1, 2, 2, 0,-1, 2, 2, 2,-1,-1, 2, 2, 2,-1},
    {-1,-1,-1,-1,-1, 1,-1,-1,-1,-1,-1, 0,-1,-1, 1,-1,-1,-1,-1,-1,-1},
    { 2, 2,-1,-1, 1,-1, 1,-1, 1, 1, 1,-1, 0,-1, 2,-1,-1, 1, 1, 1,-1},
    {-1,-1,-1,-1,-1,-1,-1,-1,-1, 1, 1,-1,-1, 0,-1,-1,-1, 2, 1, 1,-1},
    { 1, 1,-1, 2, 1, 2, 1, 1, 1, 1, 1, 2, 1,-1, 0, 2, 2, 1, 1, 1,-1},
    {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1, 0,-1,-1,-1,-1,-1},
    {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 1, 1, 0,-1,-1,-1,-1},
    { 2, 2,-1,-1, 1,-1, 1,-1, 1, 1, 1,-1, 2, 1, 2,-1,-1, 0, 1, 1,-1},
    { 2, 2,-1,-1, 1,-1, 1,-1, 2, 1, 1,-1, 2, 2, 2,-1,-1, 2, 0, 1,-1},
    { 2, 2,-1,-1, 1,-1, 1,-1, 2, 2, 1,-1, 2, 2, 2,-1,-1, 2, 2, 0,-1},
    {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, 0}
};

/* This array maps the index of the DataType-Kind to the index of the type
 * conversion matrix (255 -> not contained in the matrix) */
static UA_Byte convertLookupIndex[UA_DATATYPEKINDS] = {
    0,  12,  1,  8, 17,  9, 18, 10, 19,  6, 4,  14,  3,  7,  2,
    20, 11,  5, 13, 16, 15,255,255,255,255,255,255,255,255,255,255
};

/* Returns the target type for implicit cassting or NULL if no implicit casting
 * is possible */
static const UA_DataType *
implicitCastTargetType(const UA_DataType *t1, const UA_DataType *t2) {
    if(!t1 || t1 == t2)
        return t1;

    /* Get the type precedence. Return if no implicit casting is possible. */
    UA_Byte p1 = typePrecedence[t1->typeKind];
    UA_Byte p2 = typePrecedence[t2->typeKind];
    if(p1 == UA_BYTE_MAX || p2 == UA_BYTE_MAX)
        return NULL;

    /* Which is the target type based on the precedence rules? */
    const UA_DataType *targetType = (p1 < p2) ? t1 : t2;
    const UA_DataType *sourceType = (p1 < p2) ? t2 : t1;

    /* Lookup the casting rule */
    UA_Byte sourceIndex = convertLookupIndex[sourceType->typeKind];
    UA_Byte targetIndex = convertLookupIndex[targetType->typeKind];
    if(sourceIndex == UA_BYTE_MAX || targetIndex == UA_BYTE_MAX)
        return NULL;
    UA_SByte castingRule = convertLookup[sourceIndex][targetIndex];

    /* Is implicit casting allowed? */
    if(castingRule != 0 && castingRule != 1)
        return NULL;
    return targetType;
}

/* Cast Numerical
 * --------------
 * To reduce the number of cases we first "normalize" to either of
 * Int64/UInt64/Double. Then cast from there to the target type. This works for
 * all numericals (not only the implicit conversion).
 *
 * Numerical conversion rules from the standard:
 *
 * - If the conversion fails the result is a null value.
 * - Floating point values are rounded by adding 0.5 and truncating when they
 *   are converted to integer values.
 * - Converting a value that is outside the range of the target type causes a
 *   conversion error. */

#define UA_CAST_SIGNED(t, T)                                         \
    if(i < T##_MIN || (i > 0 && (t)i > T##_MAX))                     \
        return;                                                      \
    *(t*)data = (t)i;                                                \
    do { } while(0)

#define UA_CAST_UNSIGNED(t, T)                                       \
    if(u > T##_MAX)                                                  \
        return;                                                      \
    *(t*)data = (t)u;                                                \
    do { } while(0)

#define UA_CAST_FLOAT(t, T)                                          \
    if(f + 0.5 < (UA_Double)T##_MIN || f + 0.5 > (UA_Double)T##_MAX) \
        return;                                                      \
    *(t*)data = (t)(f + 0.5);                                        \
    do { } while(0)

/* We can cast between any numerical type. So this can be reused for explicit casting. */
static void
castNumerical(const UA_Variant *in, const UA_DataType *type, UA_Variant *out) {
    UA_assert(UA_Variant_isScalar(in));
    UA_Variant_init(out); /* Set to null value */

    UA_Int64  i = 0;
    UA_UInt64 u = 0;
    UA_Double f = 0.0;

    const UA_DataTypeKind ink = (UA_DataTypeKind)in->type->typeKind;
    switch(ink) {
    case UA_DATATYPEKIND_SBYTE:  i = *(UA_SByte*)in->data; break;
    case UA_DATATYPEKIND_INT16:  i = *(UA_Int16*)in->data; break;
    case UA_DATATYPEKIND_INT32:  i = *(UA_Int32*)in->data; break;
    case UA_DATATYPEKIND_INT64:  i = *(UA_Int64*)in->data; break;
    case UA_DATATYPEKIND_BYTE: /* or */
    case UA_DATATYPEKIND_BOOLEAN: u = *(UA_Byte*)in->data; break;
    case UA_DATATYPEKIND_UINT16:  u = *(UA_UInt16*)in->data; break;
    case UA_DATATYPEKIND_UINT32: /* or */
    case UA_DATATYPEKIND_STATUSCODE: u = *(UA_UInt32*)in->data; break;
    case UA_DATATYPEKIND_UINT64: u = *(UA_UInt64*)in->data; break;
    case UA_DATATYPEKIND_FLOAT:  f = *(UA_Float*)in->data; break;
    case UA_DATATYPEKIND_DOUBLE: f = *(UA_Double*)in->data; break;
    default: return;
    }

    void *data = UA_new(type);
    if(!data)
        return;

    if(ink == UA_DATATYPEKIND_SBYTE || ink == UA_DATATYPEKIND_INT16 ||
       ink == UA_DATATYPEKIND_INT32 || ink == UA_DATATYPEKIND_INT64) {
        /* Cast from signed */
        switch(type->typeKind) {
        case UA_DATATYPEKIND_SBYTE:  UA_CAST_SIGNED(UA_SByte, UA_SBYTE); break;
        case UA_DATATYPEKIND_INT16:  UA_CAST_SIGNED(UA_Int16, UA_INT16); break;
        case UA_DATATYPEKIND_INT32:  UA_CAST_SIGNED(UA_Int32, UA_INT32); break;
        case UA_DATATYPEKIND_INT64:  *(UA_Int64*)data = i; break;
        case UA_DATATYPEKIND_BYTE:   UA_CAST_SIGNED(UA_Byte, UA_BYTE); break;
        case UA_DATATYPEKIND_UINT16: UA_CAST_SIGNED(UA_UInt16, UA_UINT16); break;
        case UA_DATATYPEKIND_UINT32: UA_CAST_SIGNED(UA_UInt32, UA_UINT32); break;
        case UA_DATATYPEKIND_UINT64: UA_CAST_SIGNED(UA_UInt64, UA_UINT64); break;
        case UA_DATATYPEKIND_FLOAT:  *(UA_Float*)data = (UA_Float)i; break;
        case UA_DATATYPEKIND_DOUBLE: *(UA_Double*)data = (UA_Double)i; break;
        default:
            UA_free(data);
            return;
        }
    } else if(ink == UA_DATATYPEKIND_BYTE   || ink == UA_DATATYPEKIND_UINT16 ||
              ink == UA_DATATYPEKIND_UINT32 || ink == UA_DATATYPEKIND_UINT64) {
        /* Cast from unsigned */
        switch(type->typeKind) {
        case UA_DATATYPEKIND_SBYTE:  UA_CAST_UNSIGNED(UA_SByte, UA_SBYTE); break;
        case UA_DATATYPEKIND_INT16:  UA_CAST_UNSIGNED(UA_Int16, UA_INT16); break;
        case UA_DATATYPEKIND_INT32:  UA_CAST_UNSIGNED(UA_Int32, UA_INT32); break;
        case UA_DATATYPEKIND_INT64:  UA_CAST_UNSIGNED(UA_Int64, UA_INT64); break;
        case UA_DATATYPEKIND_BYTE:   UA_CAST_UNSIGNED(UA_Byte, UA_BYTE); break;
        case UA_DATATYPEKIND_UINT16: UA_CAST_UNSIGNED(UA_UInt16, UA_UINT16); break;
        case UA_DATATYPEKIND_UINT32: UA_CAST_UNSIGNED(UA_UInt32, UA_UINT32); break;
        case UA_DATATYPEKIND_UINT64: *(UA_UInt64*)data = u; break;
        case UA_DATATYPEKIND_FLOAT:  *(UA_Float*)data = (UA_Float)u; break;
        case UA_DATATYPEKIND_DOUBLE: *(UA_Double*)data = (UA_Double)u; break;
        default:
            UA_free(data);
            return;
        }
    } else {
        /* Cast from float */
        if(f != f) {
            /* NaN cannot be cast */
            UA_free(data);
            return;
        }
        switch(type->typeKind) {
        case UA_DATATYPEKIND_SBYTE:  UA_CAST_FLOAT(UA_SByte, UA_SBYTE); break;
        case UA_DATATYPEKIND_INT16:  UA_CAST_FLOAT(UA_Int16, UA_INT16); break;
        case UA_DATATYPEKIND_INT32:  UA_CAST_FLOAT(UA_Int32, UA_INT32); break;
        case UA_DATATYPEKIND_INT64:  UA_CAST_FLOAT(UA_Int64, UA_INT64); break;
        case UA_DATATYPEKIND_BYTE:   UA_CAST_FLOAT(UA_Byte, UA_BYTE); break;
        case UA_DATATYPEKIND_UINT16: UA_CAST_FLOAT(UA_UInt16, UA_UINT16); break;
        case UA_DATATYPEKIND_UINT32: UA_CAST_FLOAT(UA_UInt32, UA_UINT32); break;
        case UA_DATATYPEKIND_UINT64: UA_CAST_FLOAT(UA_UInt64, UA_UINT64); break;
        case UA_DATATYPEKIND_FLOAT:  *(UA_Float*)data = (UA_Float)f; break;
        case UA_DATATYPEKIND_DOUBLE: *(UA_Double*)data = (UA_Double)f; break;
        default:
            UA_free(data);
            return;
        }
    }

    UA_Variant_setScalar(out, data, type);
}

/* Implicit Casting
 * ---------------- */

static UA_INLINE UA_Byte uppercase(UA_Byte in) { return in | 32; }

static UA_StatusCode
castImplicitFromString(const UA_Variant *in, const UA_DataType *outType, UA_Variant *out) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(outType == &UA_TYPES[UA_TYPES_BOOLEAN]) {
        /* String -> Boolean
         *
         * Part 4 says: String values containing "true", "false", "1" or "0"
         * can be converted to Boolean values. Other string values cause a
         * conversion error. In this case Strings are case-insensitive. */
        UA_Boolean b;
        const UA_String *inStr = (const UA_String*)in->data;
        if(inStr->length == 1 && inStr->data[0] == '0') {
            b = false;
        } else if(inStr->length == 1 && inStr->data[0] == '1') {
            b = true;
        } else if(inStr->length == 4 &&
                  uppercase(inStr->data[0])== 'T' && uppercase(inStr->data[1])== 'R' &&
                  uppercase(inStr->data[2])== 'U' && uppercase(inStr->data[3])== 'E') {
            b = true;
        } else if(inStr->length == 5              && uppercase(inStr->data[0])== 'F' &&
                  uppercase(inStr->data[1])== 'A' && uppercase(inStr->data[2])== 'L' &&
                  uppercase(inStr->data[3])== 'S' && uppercase(inStr->data[4])== 'E') {
            b = false;
        } else {
            return UA_STATUSCODE_BADTYPEMISMATCH;
        }
        return UA_Variant_setScalarCopy(out, &b, outType);
    }

#ifdef UA_ENABLE_PARSING
    else if(outType == &UA_TYPES[UA_TYPES_GUID]) {
        /* String -> Guid */
        UA_Guid guid;
        res = UA_Guid_parse(&guid, *(UA_String*)in->data);
        if(res != UA_STATUSCODE_GOOD)
            return res;
        return UA_Variant_setScalarCopy(out, &guid, outType);
    }
#endif

#ifdef UA_ENABLE_JSON_ENCODING
    /* String -> Numerical, uses the JSON decoding */
    else if(UA_DataType_isNumeric(outType)) {
        void *outData = UA_new(outType);
        if(!outData)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        res = UA_decodeJson((const UA_ByteString*)in->data, outData, outType, NULL);
        if(res != UA_STATUSCODE_GOOD) {
            UA_free(outData);
            return res;
        }
        UA_Variant_setScalar(out, outData, outType);
        return UA_STATUSCODE_GOOD;
    }
#endif

    /* No implicit casting possible */
    return UA_STATUSCODE_BADTYPEMISMATCH;
}

static UA_StatusCode
castImplicit(const UA_Variant *in, const UA_DataType *outType, UA_Variant *out) {
    /* Of the input is empty, casting results in a NULL value */
    if(UA_Variant_isEmpty(in)) {
        UA_Variant_init(out);
        return UA_STATUSCODE_GOOD;
    }

    /* TODO: We only support scalar values for now */
    if(!UA_Variant_isScalar(in))
        return UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED;

    /* No casting necessary */
    if(in->type == outType) {
        *out = *in;
        out->storageType = UA_VARIANT_DATA_NODELETE;
        return UA_STATUSCODE_GOOD;
    }

    UA_StatusCode res = UA_STATUSCODE_GOOD;
    switch(in->type->typeKind) {
    case UA_DATATYPEKIND_EXPANDEDNODEID: {
        /* ExpandedNodeId -> String */
        if(outType != &UA_TYPES[UA_TYPES_STRING])
            break;
        UA_String *outStr = UA_String_new();
        if(!outStr)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        res = UA_ExpandedNodeId_print((const UA_ExpandedNodeId*)in->data, outStr);
        if(res != UA_STATUSCODE_GOOD) {
            UA_free(outStr);
            break;
        }
        UA_Variant_setScalar(out, outStr, outType);
        break;
    }

    case UA_DATATYPEKIND_NODEID: {
        if(outType == &UA_TYPES[UA_TYPES_STRING]) {
            /* NodeId -> String */
            UA_String *outStr = UA_String_new();
            if(!outStr)
                return UA_STATUSCODE_BADOUTOFMEMORY;
            res = UA_NodeId_print((const UA_NodeId*)in->data, outStr);
            if(res != UA_STATUSCODE_GOOD) {
                UA_free(outStr);
                break;
            }
            UA_Variant_setScalar(out, outStr, outType);
        } else if(outType == &UA_TYPES[UA_TYPES_EXPANDEDNODEID]) {
            /* NodeId -> ExpandedNodeId */
            UA_ExpandedNodeId *eid = UA_ExpandedNodeId_new();
            if(!eid)
                return UA_STATUSCODE_BADOUTOFMEMORY;
            res = UA_NodeId_copy((const UA_NodeId*)in->data, &eid->nodeId);
            if(res != UA_STATUSCODE_GOOD) {
                UA_free(eid);
                break;
            }
            UA_Variant_setScalar(out, eid, outType);
        }
        break;
    }

    case UA_DATATYPEKIND_STRING:
        res = castImplicitFromString(in, outType, out);
        break;

    case UA_DATATYPEKIND_LOCALIZEDTEXT: {
        if(outType != &UA_TYPES[UA_TYPES_STRING])
            break;
        /* LocalizedText -> String */
        UA_LocalizedText *inLT = (UA_LocalizedText*)in->data;
        res = UA_Variant_setScalarCopy(out, &inLT->text, outType);
        break;
    }

    case UA_DATATYPEKIND_QUALIFIEDNAME: {
        UA_QualifiedName *inQN = (UA_QualifiedName*)in->data;
        if(outType == &UA_TYPES[UA_TYPES_STRING]) {
            /* QualifiedName -> String */
            res = UA_Variant_setScalarCopy(out, &inQN->name, outType);
        } else if(outType == &UA_TYPES[UA_TYPES_LOCALIZEDTEXT]) {
            /* QualifiedName -> LocalizedText */
            UA_LocalizedText lt;
            lt.text = inQN->name;
            lt.locale = UA_STRING_NULL;
            res = UA_Variant_setScalarCopy(out, &lt, outType);
        }
        break;
    }

    default:
        /* Try casting between numericals (also works for Boolean and StatusCode
         * input). The conversion can fail if the limits of the output type are
         * exceeded and then results in a NULL value. */
        castNumerical(in, outType, out);
    }

    return res;
}

/* Filter Evaluation
 * ----------------- */

typedef struct {
    UA_Server *server;
    UA_Session *session;
    const UA_NodeId *eventNode;
    const UA_ContentFilter *filter;
    UA_ContentFilterResult *filterResult;
    UA_Variant results[UA_EVENTFILTER_MAXELEMENTS];

    /* The stack contains temporary variants. Cleaned up after the evaluation of
     * each operator. */
    size_t top;
    UA_Variant stack[UA_EVENTFILTER_MAXOPERANDS];
} UA_FilterEvalContext;

/* Operand Resolving
 * ~~~~~~~~~~~~~~~~~
 * Methods that all resolve an operator operand to a Variant. */

/* Part 4, 7.4.4.5 SimpleAttributeOperand: The clause can point to any attribute
 * of nodes. Either a child of the event node and also the event type. */
static UA_StatusCode
resolveSimpleAttributeOperand(UA_Server *server, UA_Session *session,
                              const UA_NodeId *origin,
                              const UA_SimpleAttributeOperand *sao,
                              UA_Variant *value) {
    /* Prepare the ReadValueId */
    UA_ReadValueId rvi;
    UA_ReadValueId_init(&rvi);
    rvi.indexRange = sao->indexRange;
    rvi.attributeId = sao->attributeId;

    /* Read the value */
    UA_DataValue v;
    if(sao->browsePathSize == 0) {
        /* If this list (browsePath) is empty, the Node is the instance of the
         * TypeDefinition. (Part 4, 7.4.4.5) */
        rvi.nodeId = *origin;

        /* A Condition is an indirection. Look up the target node. */
        /* TODO: check for Branches! One Condition could have multiple Branches */
        UA_NodeId conditionTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_CONDITIONTYPE);
        if(UA_NodeId_equal(&sao->typeDefinitionId, &conditionTypeId)) {
#ifdef UA_ENABLE_SUBSCRIPTIONS_ALARMS_CONDITIONS
            UA_StatusCode res = UA_getConditionId(server, origin, &rvi.nodeId);
            UA_CHECK_STATUS(res, return res);
#else
            return UA_STATUSCODE_BADNOTSUPPORTED;
#endif
        }

        v = readWithSession(server, session, &rvi, UA_TIMESTAMPSTORETURN_NEITHER);
    } else {
        /* Resolve the browse path, starting from the event-source (and not the
         * typeDefinitionId). */
        UA_BrowsePathResult bpr =
            browseSimplifiedBrowsePath(server, *origin,
                                       sao->browsePathSize, sao->browsePath);
        if(bpr.targetsSize == 0 && bpr.statusCode == UA_STATUSCODE_GOOD)
            bpr.statusCode = UA_STATUSCODE_BADNOTFOUND;
        if(bpr.statusCode != UA_STATUSCODE_GOOD) {
            UA_StatusCode res = bpr.statusCode;
            UA_BrowsePathResult_clear(&bpr);
            return res;
        }

        /* Use the first match */
        rvi.nodeId = bpr.targets[0].targetId.nodeId;
        v = readWithSession(server, session, &rvi, UA_TIMESTAMPSTORETURN_NEITHER);
        UA_BrowsePathResult_clear(&bpr);
    }

    /* Validate the result */
    if(v.status != UA_STATUSCODE_GOOD) {
        UA_Variant_clear(&v.value);
        return v.status;
    }
    if(!v.hasValue)
        return UA_STATUSCODE_BADNODATAAVAILABLE;

    /* Move the result to the output */
    *value = v.value;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
resolveOperand(UA_FilterEvalContext *ctx, UA_ExtensionObject *op, UA_Variant *out) {
    if(op->encoding != UA_EXTENSIONOBJECT_DECODED &&
       op->encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE)
        return UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED;

    /* Result of an operator that was evaluated prior */
    if(op->content.decoded.type == &UA_TYPES[UA_TYPES_ELEMENTOPERAND]) {
        UA_ElementOperand *eo = (UA_ElementOperand*)op->content.decoded.data;
        *out = ctx->results[eo->index];
        out->storageType = UA_VARIANT_DATA_NODELETE;
        return UA_STATUSCODE_GOOD;
    }

    /* Literal value */
    if(op->content.decoded.type == &UA_TYPES[UA_TYPES_LITERALOPERAND]) {
        UA_LiteralOperand *lo = (UA_LiteralOperand*)op->content.decoded.data;
        *out = lo->value;
        out->storageType = UA_VARIANT_DATA_NODELETE;
        return UA_STATUSCODE_GOOD;
    }

    /* SimpleAttributeOperand with a BrowsePath */
    if(op->content.decoded.type == &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND]) {
        UA_SimpleAttributeOperand *sao =
            (UA_SimpleAttributeOperand*)op->content.decoded.data;
        return resolveSimpleAttributeOperand(ctx->server, ctx->session,
                                             ctx->eventNode, sao, out);
    }

    return UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED;
}

/* The operandIndex is within the operator arguments, not the operand index for
 * the overall stack */
static UA_StatusCode
setOperandError(UA_FilterEvalContext *ctx, size_t elementIndex,
                size_t operandIndex, UA_StatusCode statusCode) {
    UA_ContentFilterElementResult *res = &ctx->filterResult->elementResults[elementIndex];
    res->operandStatusCodes[operandIndex] = statusCode;
    /* The operator status is set globally in a single location upwards the call chain
     * res->statusCode = statusCode; */
    return statusCode;
}

/* Filter Operators
 * ~~~~~~~~~~~~~~~~ */

static UA_StatusCode
ofTypeOperator(UA_FilterEvalContext *ctx, size_t index) {
    const UA_ContentFilterElement *elm = &ctx->filter->elements[index];
    UA_assert(elm->filterOperandsSize == 1);

    /* Get the operand. Must be a literal NodeId */
    UA_Variant *op0 = &ctx->stack[ctx->top++];
    UA_StatusCode res = resolveOperand(ctx, &elm->filterOperands[0], op0);
    if(res != UA_STATUSCODE_GOOD || !UA_Variant_hasScalarType(op0, &UA_TYPES[UA_TYPES_NODEID]))
        return setOperandError(ctx, index, 0, UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED);

    /* Read the event type */
    UA_Variant eventTypeVar;
    UA_Variant_init(&eventTypeVar);
    const UA_NodeId *operandTypeId = (const UA_NodeId *)op0->data;
    res = readObjectProperty(ctx->server, *ctx->eventNode,
                             UA_QUALIFIEDNAME(0, "EventType"), &eventTypeVar);
    UA_CHECK_STATUS(res, return res);

    if(!UA_Variant_hasScalarType(&eventTypeVar, &UA_TYPES[UA_TYPES_NODEID])) {
        UA_LOG_WARNING(ctx->server->config.logging, UA_LOGCATEGORY_SERVER,
                       "EventType has an invalid type.");
        UA_Variant_clear(&eventTypeVar);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Check if the eventtype is equal to the operand or a subtype of it */
    const UA_NodeId *eventTypeId = (UA_NodeId*)eventTypeVar.data;
    UA_Boolean ofType = isNodeInTree_singleRef(ctx->server, eventTypeId, operandTypeId,
                                               UA_REFERENCETYPEINDEX_HASSUBTYPE);
    ctx->results[index] = t2v(ofType ? UA_TERNARY_TRUE : UA_TERNARY_FALSE);
    UA_Variant_clear(&eventTypeVar);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
andOperator(UA_FilterEvalContext *ctx, size_t index) {
    const UA_ContentFilterElement *elm = &ctx->filter->elements[index];
    UA_assert(elm->filterOperandsSize == 2);
    UA_Variant *op0 = &ctx->stack[ctx->top++];
    UA_StatusCode res = resolveOperand(ctx, &elm->filterOperands[0], op0);
    UA_CHECK_STATUS(res, return res);
    UA_Variant *op1 = &ctx->stack[ctx->top++];
    res = resolveOperand(ctx, &elm->filterOperands[1], op1);
    UA_CHECK_STATUS(res, return res);
    ctx->results[index] = t2v(UA_Ternary_and(v2t(op0), v2t(op1)));
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
orOperator(UA_FilterEvalContext *ctx, size_t index) {
    const UA_ContentFilterElement *elm = &ctx->filter->elements[index];
    UA_assert(elm->filterOperandsSize == 2);
    UA_Variant *op0 = &ctx->stack[ctx->top++];
    UA_StatusCode res = resolveOperand(ctx, &elm->filterOperands[0], op0);
    UA_CHECK_STATUS(res, return res);
    UA_Variant *op1 = &ctx->stack[ctx->top++];
    res = resolveOperand(ctx, &elm->filterOperands[1], op1);
    UA_CHECK_STATUS(res, return res);
    ctx->results[index] = t2v(UA_Ternary_or(v2t(op0), v2t(op1)));
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
notOperator(UA_FilterEvalContext *ctx, size_t index) {
    const UA_ContentFilterElement *elm = &ctx->filter->elements[index];
    UA_assert(elm->filterOperandsSize == 1);
    UA_Variant *op0 = &ctx->stack[ctx->top++];
    UA_StatusCode res = resolveOperand(ctx, &elm->filterOperands[0], op0);
    UA_CHECK_STATUS(res, return res);
    ctx->results[index] = t2v(UA_Ternary_not(v2t(op0)));
    return UA_STATUSCODE_GOOD;
}

/* Resolves the operands and casts them implicitly to the same type.
 * The result is set at &ctx->stack[ctx->top] (for the initial value of top). */
static UA_StatusCode
castResolveOperands(UA_FilterEvalContext *ctx, size_t index, UA_Boolean setError) {
    /* Enough space on the stack left? */
    const UA_ContentFilterElement *elm = &ctx->filter->elements[index];
    if(ctx->top + elm->filterOperandsSize > UA_EVENTFILTER_MAXOPERANDS)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Resolve all operands */
    UA_assert(ctx->top == 0); /* Assume the stack is empty */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    for(size_t i = 0; i < elm->filterOperandsSize; i++) {
        res = resolveOperand(ctx, &elm->filterOperands[i], &ctx->stack[ctx->top++]);
        UA_CHECK_STATUS(res, return res);
    }
    UA_assert(ctx->top > 0); /* Assume the stack is no longer empty */

    /* Get the datatype for casting */
    const UA_DataType *targetType = ctx->stack[0].type;
    for(size_t pos = 1; pos < ctx->top; pos++) {
        if(targetType)
            targetType = implicitCastTargetType(targetType, ctx->stack[pos].type);
        if(!targetType)
            return (setError) ? setOperandError(ctx, index, pos, res) : res;
    }

    /* Cast the operands. Put the result in the same location on the stack. */
    for(size_t pos = 0; pos < ctx->top; pos++) {
        UA_Variant orig = ctx->stack[pos];
        res = castImplicit(&orig, targetType, &ctx->stack[pos]);
        if(res != UA_STATUSCODE_GOOD)
            return (setError) ? setOperandError(ctx, index, pos, res) : res;
        if(ctx->stack[pos].data == orig.data) {
            /* Reuse the storage type of the original data if the variant is
             * identical or only the type has changed */
            ctx->stack[pos].storageType = orig.storageType;
        } else {
            UA_Variant_clear(&orig); /* Fresh allocation of the cast variant. Clean up. */
        }
    }

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
compareOperator(UA_FilterEvalContext *ctx, size_t index, UA_FilterOperator op) {
    UA_assert(ctx->filter->elements[index].filterOperandsSize == 2);

    /* Resolve and cast the operands. A failed casting results in FALSE. Note
     * that operands could cast to NULL. */
    UA_assert(ctx->top == 0); /* Assume the stack is empty */
    UA_StatusCode res = castResolveOperands(ctx, index, false);
    if(res != UA_STATUSCODE_GOOD || !ctx->stack[0].type ||
       ctx->stack[0].type != ctx->stack[1].type) {
        ctx->results[index] = t2v(UA_TERNARY_FALSE);
        return UA_STATUSCODE_GOOD;
    }
    UA_assert(ctx->top == 2); /* Assume the stack is no longer empty */

    /* The equals operator is always possible. For the other comparisons it has
     * to be an ordered type: Numerical, Boolean, StatusCode or DateTime. */
    const UA_DataType *type = ctx->stack[0].type;
    if(op != UA_FILTEROPERATOR_EQUALS && !UA_DataType_isNumeric(type) &&
       type->typeKind != UA_DATATYPEKIND_BOOLEAN &&
       type->typeKind != UA_DATATYPEKIND_STATUSCODE &&
       type->typeKind != UA_DATATYPEKIND_DATETIME)
        return setOperandError(ctx, index, 0, UA_STATUSCODE_BADFILTEROPERANDINVALID);

    /* Compute the order */
    UA_Order eq = UA_order(ctx->stack[0].data, ctx->stack[1].data, type);
    UA_Ternary operatorResult = UA_TERNARY_FALSE;
    switch(op) {
    case UA_FILTEROPERATOR_EQUALS:
    default:
        if(eq == UA_ORDER_EQ)
            operatorResult = UA_TERNARY_TRUE;
        break;
    case UA_FILTEROPERATOR_GREATERTHAN:
        if(eq == UA_ORDER_MORE)
            operatorResult = UA_TERNARY_TRUE;
        break;
    case UA_FILTEROPERATOR_LESSTHAN:
        if(eq == UA_ORDER_LESS)
            operatorResult = UA_TERNARY_TRUE;
        break;
    case UA_FILTEROPERATOR_GREATERTHANOREQUAL:
        if(eq == UA_ORDER_MORE || eq == UA_ORDER_EQ)
            operatorResult = UA_TERNARY_TRUE;
        break;
    case UA_FILTEROPERATOR_LESSTHANOREQUAL:
        if(eq == UA_ORDER_LESS || eq == UA_ORDER_EQ)
            operatorResult = UA_TERNARY_TRUE;
        break;
    }

    /* Set result as a literal value */
    ctx->results[index] = t2v(operatorResult);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
equalsOperator(UA_FilterEvalContext *ctx, size_t index) {
    return compareOperator(ctx, index, UA_FILTEROPERATOR_EQUALS);
}

static UA_StatusCode
gtOperator(UA_FilterEvalContext *ctx, size_t index) {
    return compareOperator(ctx, index, UA_FILTEROPERATOR_GREATERTHAN);
}

static UA_StatusCode
ltOperator(UA_FilterEvalContext *ctx, size_t index) {
    return compareOperator(ctx, index, UA_FILTEROPERATOR_LESSTHAN);
}

static UA_StatusCode
gteOperator(UA_FilterEvalContext *ctx, size_t index) {
    return compareOperator(ctx, index, UA_FILTEROPERATOR_GREATERTHANOREQUAL);
}

static UA_StatusCode
lteOperator(UA_FilterEvalContext *ctx, size_t index) {
    return compareOperator(ctx, index, UA_FILTEROPERATOR_LESSTHANOREQUAL);
}

static UA_StatusCode
bitwiseOperator(UA_FilterEvalContext *ctx, size_t index, UA_FilterOperator op) {
    UA_assert(ctx->filter->elements[index].filterOperandsSize == 2);

    /* Resolve and cast the operands. Note that operands could cast to NULL. */
    UA_assert(ctx->top == 0); /* Assume the stack is empty */
    UA_StatusCode res = castResolveOperands(ctx, index, true);
    UA_CHECK_STATUS(res, return res);
    UA_assert(ctx->top == 2); /* Assume we have two elements */

    /* Operands can cast to NULL */
    const UA_DataType *type = ctx->stack[0].type;
    if(!type || !UA_DataType_isNumeric(type) ||
       ctx->stack[0].type != ctx->stack[1].type)
        return UA_STATUSCODE_BADTYPEMISMATCH;

    /* Copy the casted literal to the result */
    res = UA_Variant_copy(&ctx->stack[0], &ctx->results[index]);
    UA_CHECK_STATUS(res, return res);

    /* Do the bitwise operation on the result data */
    UA_Byte *bytesOut = (UA_Byte*)ctx->results[index].data;
    const UA_Byte *bytes2 = (const UA_Byte*)ctx->stack[1].data;
    for(size_t i = 0; i < type->memSize; i++) {
        if(op == UA_FILTEROPERATOR_BITWISEAND)
            bytesOut[i] = bytesOut[i] & bytes2[i];
        else
            bytesOut[i] = bytesOut[i] | bytes2[i];
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
bitwiseAndOperator(UA_FilterEvalContext *ctx, size_t index) {
    return bitwiseOperator(ctx, index, UA_FILTEROPERATOR_BITWISEAND);
}

static UA_StatusCode
bitwiseOrOperator(UA_FilterEvalContext *ctx, size_t index) {
    return bitwiseOperator(ctx, index, UA_FILTEROPERATOR_BITWISEOR);
}

static UA_StatusCode
betweenOperator(UA_FilterEvalContext *ctx, size_t index) {
    UA_assert(ctx->filter->elements[index].filterOperandsSize == 3);

    /* If no implicit conversion is available and the operands are of different
     * types, the particular result is FALSE. */
    UA_assert(ctx->top == 0); /* Assume the stack is empty */
    UA_StatusCode res = castResolveOperands(ctx, index, false);
    if(res != UA_STATUSCODE_GOOD) {
        ctx->results[index] = t2v(UA_TERNARY_FALSE);
        return UA_STATUSCODE_GOOD;
    }
    UA_assert(ctx->top == 3); /* Assume we have three elements */

    /* The casting can result in NULL values or a non-numerical type */
    const UA_DataType *type = ctx->stack[0].type;
    if(!type || !UA_DataType_isNumeric(type) ||
       type != ctx->stack[1].type || type != ctx->stack[2].type)
        return UA_STATUSCODE_BADTYPEMISMATCH;

    UA_Order o1 = UA_order(ctx->stack[0].data, ctx->stack[1].data, type);
    UA_Order o2 = UA_order(ctx->stack[0].data, ctx->stack[2].data, type);
    UA_Ternary comp = ((o1 == UA_ORDER_MORE || o1 == UA_ORDER_EQ) &&
                       (o2 == UA_ORDER_LESS || o2 == UA_ORDER_EQ)) ?
        UA_TERNARY_TRUE : UA_TERNARY_FALSE;

    ctx->results[index] = t2v(comp);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
inListOperator(UA_FilterEvalContext *ctx, size_t index) {
    const UA_ContentFilterElement *elm = &ctx->filter->elements[index];
    UA_assert(elm->filterOperandsSize >= 2);
    UA_Boolean found = false;
    UA_Variant *op0 = &ctx->stack[ctx->top++];
    UA_Variant *op1 = &ctx->stack[ctx->top++];
    UA_StatusCode res = resolveOperand(ctx, &elm->filterOperands[0], op0);
    UA_CHECK_STATUS(res, return res);
    for(size_t i = 1; i < elm->filterOperandsSize && !found; i++) {
        res = resolveOperand(ctx, &elm->filterOperands[i], op1);
        if(res != UA_STATUSCODE_GOOD)
            continue;
        if(op0->type == op1->type && UA_equal(op0->data, op1->data, op0->type))
            found = true;
        UA_Variant_clear(op1);
    }
    ctx->results[index] = t2v((found) ? UA_TERNARY_TRUE: UA_TERNARY_FALSE);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
isNullOperator(UA_FilterEvalContext *ctx, size_t index) {
    const UA_ContentFilterElement *elm = &ctx->filter->elements[index];
    UA_assert(elm->filterOperandsSize == 1);
    UA_Variant *op0 = &ctx->stack[ctx->top++];
    UA_StatusCode res = resolveOperand(ctx, &elm->filterOperands[0], op0);
    UA_CHECK_STATUS(res, return res);
    ctx->results[index] = t2v(UA_Variant_isEmpty(op0) ? UA_TERNARY_TRUE : UA_TERNARY_FALSE);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
notImplementedOperator(UA_FilterEvalContext *ctx, size_t index) {
    return UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED;
}

/* Filter Evaluation
 * ~~~~~~~~~~~~~~~~~ */

typedef struct {
    UA_StatusCode (*operatorMethod)(UA_FilterEvalContext *ctx, size_t index);
    UA_Byte minOperatorCount;
    UA_Byte maxOperatorCount;
} UA_FilterOperatorJumptableElement;

static const UA_FilterOperatorJumptableElement operatorJumptable[18] = {
    {equalsOperator, 2, 2},
    {isNullOperator, 1, 1},
    {gtOperator, 2, 2},
    {ltOperator, 2, 2},
    {gteOperator, 2, 2},
    {lteOperator, 2, 2},
    {notImplementedOperator, 0, UA_EVENTFILTER_MAXOPERANDS}, /* like */
    {notOperator, 1, 1},
    {betweenOperator, 3, 3},
    {inListOperator, 2, UA_EVENTFILTER_MAXOPERANDS},
    {andOperator, 2, 2},
    {orOperator, 2, 2},
    {notImplementedOperator, 0, UA_EVENTFILTER_MAXOPERANDS}, /* cast */
    {notImplementedOperator, 0, UA_EVENTFILTER_MAXOPERANDS}, /* in view */
    {ofTypeOperator, 1, 1},
    {notImplementedOperator, 0, UA_EVENTFILTER_MAXOPERANDS}, /* related to */
    {bitwiseAndOperator, 2, 2},
    {bitwiseOrOperator, 2, 2}
};

UA_StatusCode
evaluateWhereClause(UA_Server *server, UA_Session *session, const UA_NodeId *eventNode,
                    const UA_ContentFilter *contentFilter,
                    UA_ContentFilterResult *contentFilterResult) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* An empty filter always succeeds */
    if(contentFilter->elementsSize == 0)
        return UA_STATUSCODE_GOOD;

    /* Prepare the context */
    UA_FilterEvalContext ctx;
    ctx.filterResult = contentFilterResult;
    ctx.filter = contentFilter;
    ctx.server = server;
    ctx.session = session;
    ctx.eventNode = eventNode;
    ctx.top = 0;

    /* Pacify some compilers by initializing the first result */
    UA_Variant_init(&ctx.results[0]);

    /* Evaluate the filter. Iterate backwards over the filter elements and
     * resolve each. This ensures that all element-index operands point to an
     * evaluated element. */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    int i = (int)contentFilter->elementsSize - 1;
    for(; i >= 0; i--) {
        UA_ContentFilterElement *cfe = &contentFilter->elements[i];
        res = operatorJumptable[cfe->filterOperator].operatorMethod(&ctx, (size_t)i);
        for(size_t j = 0; j < ctx.top; j++)
            UA_Variant_clear(&ctx.stack[j]); /* clean up the stack */
        ctx.top = 0;
        if(res != UA_STATUSCODE_GOOD)
            break;
    }

    /* The filter matches if the operator at the first position evaluates to TRUE */
    if(res == UA_STATUSCODE_GOOD && v2t(&ctx.results[0]) != UA_TERNARY_TRUE)
        res = UA_STATUSCODE_BADNOMATCH;

    /* Clean up the element result variants */
    for(int j = (int)contentFilter->elementsSize - 1; j > i; j--)
        UA_Variant_clear(&ctx.results[j]);
    return res;
}

static UA_Boolean
isValidEvent(UA_Server *server, const UA_NodeId *validEventParent,
             const UA_NodeId *eventId) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    /* Find the eventType variableNode */
    UA_QualifiedName findName = UA_QUALIFIEDNAME(0, "EventType");
    UA_BrowsePathResult bpr = browseSimplifiedBrowsePath(server, *eventId, 1, &findName);
    if(bpr.statusCode != UA_STATUSCODE_GOOD || bpr.targetsSize < 1) {
        UA_BrowsePathResult_clear(&bpr);
        return false;
    }

    /* Get the EventType Property Node */
    UA_Variant tOutVariant;
    UA_Variant_init(&tOutVariant);
    /* Read the Value of EventType Property Node (the Value should be a NodeId) */
    UA_StatusCode retval = readWithReadValue(server, &bpr.targets[0].targetId.nodeId,
                                             UA_ATTRIBUTEID_VALUE, &tOutVariant);
    if(retval != UA_STATUSCODE_GOOD ||
       !UA_Variant_hasScalarType(&tOutVariant, &UA_TYPES[UA_TYPES_NODEID])) {
        UA_BrowsePathResult_clear(&bpr);
        return false;
    }

    const UA_NodeId *tEventType = (UA_NodeId*)tOutVariant.data;

    /* Check whether the EventType is a Subtype of CondtionType (Part 9 first
     * implementation) */
    UA_NodeId conditionTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_CONDITIONTYPE);
    if(UA_NodeId_equal(validEventParent, &conditionTypeId) &&
       isNodeInTree_singleRef(server, tEventType, &conditionTypeId,
                              UA_REFERENCETYPEINDEX_HASSUBTYPE)) {
        UA_BrowsePathResult_clear(&bpr);
        UA_Variant_clear(&tOutVariant);
        return true;
    }

    /* EventType is not a Subtype of CondtionType (ConditionId Clause won't be
     * present in Events, which are not Conditions) */
    /* Check whether Valid Event other than Conditions */
    UA_NodeId baseEventTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE);
    UA_Boolean isSubtypeOfBaseEvent =
        isNodeInTree_singleRef(server, tEventType, &baseEventTypeId,
                               UA_REFERENCETYPEINDEX_HASSUBTYPE);

    UA_BrowsePathResult_clear(&bpr);
    UA_Variant_clear(&tOutVariant);
    return isSubtypeOfBaseEvent;
}

UA_StatusCode
filterEvent(UA_Server *server, UA_Session *session,
            const UA_NodeId *eventNode, UA_EventFilter *filter,
            UA_EventFieldList *efl, UA_EventFilterResult *result) {
    UA_LOCK_ASSERT(&server->serviceMutex, 1);

    if(filter->selectClausesSize == 0)
        return UA_STATUSCODE_BADEVENTFILTERINVALID;

    UA_EventFieldList_init(efl);
    efl->eventFields = (UA_Variant *)
        UA_Array_new(filter->selectClausesSize, &UA_TYPES[UA_TYPES_VARIANT]);
    if(!efl->eventFields)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    efl->eventFieldsSize = filter->selectClausesSize;

    /* Empty event filter result */
    UA_EventFilterResult_init(result);
    result->selectClauseResultsSize = filter->selectClausesSize;
    result->selectClauseResults = (UA_StatusCode *)
        UA_Array_new(filter->selectClausesSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
    if(!result->selectClauseResults) {
        UA_EventFieldList_clear(efl);
        UA_EventFilterResult_clear(result);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    /* Prepare content filter result structure */
    if(filter->whereClause.elementsSize > 0) {
        result->whereClauseResult.elementResultsSize = filter->whereClause.elementsSize;
        result->whereClauseResult.elementResults = (UA_ContentFilterElementResult *)
            UA_Array_new(filter->whereClause.elementsSize,
                         &UA_TYPES[UA_TYPES_CONTENTFILTERELEMENTRESULT]);
        if(!result->whereClauseResult.elementResults) {
            UA_EventFieldList_clear(efl);
            UA_EventFilterResult_clear(result);
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }

        for(size_t i = 0; i < filter->whereClause.elementsSize; ++i) {
            UA_ContentFilterElementResult *er =
                &result->whereClauseResult.elementResults[i];
            UA_ContentFilterElement *cf = &filter->whereClause.elements[i];
            er->operandStatusCodesSize = cf->filterOperandsSize;
            er->operandStatusCodes = (UA_StatusCode *)
                UA_Array_new(er->operandStatusCodesSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
            if(!er->operandStatusCodes) {
                UA_EventFieldList_clear(efl);
                UA_EventFilterResult_clear(result);
                return UA_STATUSCODE_BADOUTOFMEMORY;
            }
        }
    }

    /* Evaluate the where filter. Do we event need to consider the event? */
    UA_StatusCode res = evaluateWhereClause(server, session, eventNode,
                                            &filter->whereClause,
                                            &result->whereClauseResult);
    if(res != UA_STATUSCODE_GOOD){
        UA_EventFieldList_clear(efl);
        UA_EventFilterResult_clear(result);
        return res;
    }

    /* Apply the select filter */
    UA_NodeId baseEventTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE);
    for(size_t i = 0; i < filter->selectClausesSize; i++) {
        UA_SimpleAttributeOperand *sc = &filter->selectClauses[i];
        /* Check if the browsePath is BaseEventType, in which case nothing more
         * needs to be checked */
        if(!UA_NodeId_equal(&sc->typeDefinitionId, &baseEventTypeId) &&
           !isValidEvent(server, &sc->typeDefinitionId, eventNode)) {
            UA_Variant_init(&efl->eventFields[i]);
            /* EventFilterResult currently isn't being used
               notification->result.selectClauseResults[i] =
                   UA_STATUSCODE_BADTYPEDEFINITIONINVALID; */
            continue;
        }

        /* Lookup the field. The overall filter can succeed even if a single
         * select-field cannot be resolved. */
        result->selectClauseResults[i] =
            resolveSimpleAttributeOperand(server, session, eventNode,
                                          sc, &efl->eventFields[i]);
    }

    return UA_STATUSCODE_GOOD;
}

/*****************************************/
/* Validation of Filters during Creation */
/*****************************************/

/* Initial select clause validation. The following checks are currently performed:
 * - Check if typedefenitionid or browsepath of any clause is NULL
 * - Check if the eventType is a subtype of BaseEventType
 * - Check if attributeId is valid
 * - Check if browsePath contains null
 * - Check if indexRange is defined and if it is parsable
 * - Check if attributeId is value */
UA_StatusCode
UA_SimpleAttributeOperandValidation(UA_Server *server,
                                    const UA_SimpleAttributeOperand *sao) {
    /* TypeDefinition is not NULL? */
    if(UA_NodeId_isNull(&sao->typeDefinitionId))
        return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;

    /* EventType is a subtype of BaseEventType? */
    UA_NodeId baseEventTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE);
    if(!isNodeInTree_singleRef(server, &sao->typeDefinitionId,
                               &baseEventTypeId, UA_REFERENCETYPEINDEX_HASSUBTYPE))
        return UA_STATUSCODE_BADTYPEDEFINITIONINVALID;

    /* AttributeId is valid ? */
    if(sao->attributeId == 0 || sao->attributeId >= 28)
        return UA_STATUSCODE_BADATTRIBUTEIDINVALID;

    /* If the BrowsePath is empty, the Node is the instance of the
     * TypeDefinition. (Part 4, 7.4.4.5) */
    if(sao->browsePathSize == 0)
        return UA_STATUSCODE_GOOD;

    /* BrowsePath contains empty BrowseNames? */
    for(size_t j = 0; j < sao->browsePathSize; ++j) {
        if(UA_QualifiedName_isNull(&sao->browsePath[j]))
            return UA_STATUSCODE_BADBROWSENAMEINVALID;
    }

    /* Get the list of subtypes from event type (including the event type itself) */
    UA_ReferenceTypeSet reftypes_interface =
        UA_REFTYPESET(UA_REFERENCETYPEINDEX_HASSUBTYPE);
    UA_ExpandedNodeId *childTypeNodes = NULL;
    size_t childTypeNodesSize = 0;
    UA_StatusCode res = browseRecursive(server, 1, &sao->typeDefinitionId,
                                        UA_BROWSEDIRECTION_FORWARD, &reftypes_interface,
                                        UA_NODECLASS_OBJECTTYPE, true, &childTypeNodesSize,
                                        &childTypeNodes);
    if(res != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADATTRIBUTEIDINVALID;

    /* Is the browse path valid for one of them? */
    UA_Boolean subTypeContainField = false;
    for(size_t j = 0; j < childTypeNodesSize && !subTypeContainField; j++) {
        UA_BrowsePathResult bpr =
            browseSimplifiedBrowsePath(server, childTypeNodes[j].nodeId,
                                       sao->browsePathSize, sao->browsePath);

        if(bpr.statusCode == UA_STATUSCODE_GOOD && bpr.targetsSize > 0)
            subTypeContainField = true;
        UA_BrowsePathResult_clear(&bpr);
    }

    UA_Array_delete(childTypeNodes, childTypeNodesSize, &UA_TYPES[UA_TYPES_EXPANDEDNODEID]);

    if(!subTypeContainField)
        return UA_STATUSCODE_BADNODEIDUNKNOWN;

    /* IndexRange is defined ? */
    if(!UA_String_isEmpty(&sao->indexRange)) {
        UA_NumericRange numericRange = UA_NUMERICRANGE("");
        if(UA_NumericRange_parse(&numericRange, sao->indexRange) != UA_STATUSCODE_GOOD)
            return UA_STATUSCODE_BADINDEXRANGEINVALID;
        UA_free(numericRange.dimensions);

        /* AttributeId has to be a value if an IndexRange is defined */
        if(sao->attributeId != UA_ATTRIBUTEID_VALUE)
            return UA_STATUSCODE_BADTYPEMISMATCH;
    }

    return UA_STATUSCODE_GOOD;
}

/* Initial content filter (where clause) check. Current checks:
 * - Number of operands for each (supported) operator
 * - ElementOperands point forward only */
UA_ContentFilterElementResult
UA_ContentFilterElementValidation(UA_Server *server, size_t operatorIndex,
                                  size_t operatorsCount,
                                  const UA_ContentFilterElement *ef) {
    /* Initialize the result structure */
    UA_ContentFilterElementResult er;
    UA_ContentFilterElementResult_init(&er);
    er.operandStatusCodes = (UA_StatusCode *)
        UA_Array_new(ef->filterOperandsSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
    if(!er.operandStatusCodes) {
        er.statusCode = UA_STATUSCODE_BADOUTOFMEMORY;
        return er;
    }
    er.operandStatusCodesSize = ef->filterOperandsSize;

    /* Is the operator in the defined range? Test this before the following
     * jumptable lookup. */
    if(ef->filterOperator < 0 || ef->filterOperator > UA_FILTEROPERATOR_BITWISEOR) {
        er.statusCode = UA_STATUSCODE_BADEVENTFILTERINVALID;
        return er;
    }

    /* Number of operands supported for the operator? */
    if(ef->filterOperandsSize < operatorJumptable[ef->filterOperator].minOperatorCount ||
       ef->filterOperandsSize > operatorJumptable[ef->filterOperator].maxOperatorCount) {
        er.statusCode = UA_STATUSCODE_BADFILTEROPERANDCOUNTMISMATCH;
        return er;
    }

    /* Generic validation of the operands */
    for(size_t i = 0; i < ef->filterOperandsSize; i++) {
        /* Must be a decoded ExtensionObject */
        UA_ExtensionObject *op = &ef->filterOperands[i];
        if(op->encoding != UA_EXTENSIONOBJECT_DECODED &&
           op->encoding != UA_EXTENSIONOBJECT_DECODED_NODELETE) {
            er.operandStatusCodes[i] = UA_STATUSCODE_BADFILTEROPERANDINVALID;
            er.statusCode = UA_STATUSCODE_BADFILTEROPERANDINVALID;
            return er;
        }

        /* Supported type and conforming to the rules? */
        if(op->content.decoded.type == &UA_TYPES[UA_TYPES_ELEMENTOPERAND]) {
            /* Part 4, 7.4.4.2 defines conditions for Element Operands: An index
             * is considered valid if its value is greater than the element
             * index it is part of and it does not Reference a non-existent
             * element. Clients shall construct filters in this way to avoid
             * circular and invalid References. */
            UA_ElementOperand *eo = (UA_ElementOperand *)op->content.decoded.data;
            if(eo->index <= operatorIndex || eo->index >= operatorsCount) {
                er.operandStatusCodes[i] = UA_STATUSCODE_BADINDEXRANGEINVALID;
                er.statusCode = UA_STATUSCODE_BADINDEXRANGEINVALID;
                return er;
            }
        } else if(op->content.decoded.type == &UA_TYPES[UA_TYPES_ATTRIBUTEOPERAND]) {
            er.operandStatusCodes[i] = UA_STATUSCODE_BADNOTSUPPORTED;
            er.statusCode = UA_STATUSCODE_BADFILTERNOTALLOWED;
            return er;
        } else if(op->content.decoded.type != &UA_TYPES[UA_TYPES_SIMPLEATTRIBUTEOPERAND] &&
                  op->content.decoded.type != &UA_TYPES[UA_TYPES_LITERALOPERAND]) {
            er.operandStatusCodes[i] = UA_STATUSCODE_BADFILTEROPERANDINVALID;
            er.statusCode = UA_STATUSCODE_BADFILTEROPERANDINVALID;
            return er;
        }
    }

    /* Specific validations for different operators */
    switch(ef->filterOperator) {
        case UA_FILTEROPERATOR_INVIEW:
        case UA_FILTEROPERATOR_RELATEDTO:
            /* Not allowed for event WhereClause according to 7.17.3 in Part 4 */
            er.statusCode = UA_STATUSCODE_BADEVENTFILTERINVALID;
            break;

        case UA_FILTEROPERATOR_EQUALS:
        case UA_FILTEROPERATOR_GREATERTHAN:
        case UA_FILTEROPERATOR_LESSTHAN:
        case UA_FILTEROPERATOR_GREATERTHANOREQUAL:
        case UA_FILTEROPERATOR_LESSTHANOREQUAL:
        case UA_FILTEROPERATOR_BITWISEAND:
        case UA_FILTEROPERATOR_BITWISEOR:
        case UA_FILTEROPERATOR_BETWEEN:
        case UA_FILTEROPERATOR_INLIST:
        case UA_FILTEROPERATOR_AND:
        case UA_FILTEROPERATOR_OR:
        case UA_FILTEROPERATOR_ISNULL:
        case UA_FILTEROPERATOR_NOT:
            break;

        case UA_FILTEROPERATOR_OFTYPE: {
            /* Make sure the operand is a NodeId literal */
            UA_ExtensionObject *o = &ef->filterOperands[0];
            UA_LiteralOperand *lo = (UA_LiteralOperand *)o->content.decoded.data;
            if(o->content.decoded.type != &UA_TYPES[UA_TYPES_LITERALOPERAND] ||
               !UA_Variant_hasScalarType(&lo->value, &UA_TYPES[UA_TYPES_NODEID])) {
                er.operandStatusCodes[0] = UA_STATUSCODE_BADFILTEROPERANDINVALID;
                er.statusCode = UA_STATUSCODE_BADFILTEROPERANDINVALID;
                break;
            }

            /* Make sure the operand is a subtype of BaseEventType */
            UA_NodeId baseEventTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEEVENTTYPE);
            if(!isNodeInTree_singleRef(server, (UA_NodeId *)lo->value.data, &baseEventTypeId,
                                       UA_REFERENCETYPEINDEX_HASSUBTYPE)) {
                er.operandStatusCodes[0] = UA_STATUSCODE_BADFILTEROPERANDINVALID;
                er.statusCode = UA_STATUSCODE_BADFILTEROPERANDINVALID;
                break;
            }
            break;
        }

        case UA_FILTEROPERATOR_LIKE:
        case UA_FILTEROPERATOR_CAST:
            er.statusCode = UA_STATUSCODE_BADFILTEROPERATORUNSUPPORTED;
            break;

        default:
            er.statusCode = UA_STATUSCODE_BADFILTEROPERATORINVALID;
            break;
    }
    return er;
}

#endif /* UA_ENABLE_SUBSCRIPTIONS_EVENTS */

/**** amalgamated original file "/src/server/ua_discovery.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2014-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2014, 2017 (c) Florian Palm
 *    Copyright 2015-2016, 2019 (c) Sten Grüner
 *    Copyright 2015 (c) Chris Iatrou
 *    Copyright 2015-2016 (c) Oleksiy Vasylyev
 *    Copyright 2016-2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Julian Grothoff
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) HMS Industrial Networks AB (Author: Jonas Green)
 */


#ifdef UA_ENABLE_DISCOVERY

void
UA_DiscoveryManager_setState(UA_Server *server,
                             UA_DiscoveryManager *dm,
                             UA_LifecycleState state) {
    /* Check if open connections remain */
    if(state == UA_LIFECYCLESTATE_STOPPING ||
       state == UA_LIFECYCLESTATE_STOPPED) {
        state = UA_LIFECYCLESTATE_STOPPED;
#ifdef UA_ENABLE_DISCOVERY_MULTICAST
        if(dm->mdnsRecvConnectionsSize != 0 || dm->mdnsSendConnection != 0)
            state = UA_LIFECYCLESTATE_STOPPING;
#endif

        for(size_t i = 0; i < UA_MAXREGISTERREQUESTS; i++) {
            if(dm->registerRequests[i].client != NULL)
                state = UA_LIFECYCLESTATE_STOPPING;
        }
    }

    /* No change */
    if(state == dm->sc.state)
        return;

    /* Set the new state and notify */
    dm->sc.state = state;
    if(dm->sc.notifyState)
        dm->sc.notifyState(server, &dm->sc, state);
}

static UA_StatusCode
UA_DiscoveryManager_free(UA_Server *server,
                         struct UA_ServerComponent *sc) {
    UA_DiscoveryManager *dm = (UA_DiscoveryManager*)sc;

    if(sc->state != UA_LIFECYCLESTATE_STOPPED) {
        UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                     "Cannot delete the DiscoveryManager because "
                     "it is not stopped");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    registeredServer *rs, *rs_tmp;
    LIST_FOREACH_SAFE(rs, &dm->registeredServers, pointers, rs_tmp) {
        LIST_REMOVE(rs, pointers);
        UA_RegisteredServer_clear(&rs->registeredServer);
        UA_free(rs);
    }

# ifdef UA_ENABLE_DISCOVERY_MULTICAST
    serverOnNetwork *son, *son_tmp;
    LIST_FOREACH_SAFE(son, &dm->serverOnNetwork, pointers, son_tmp) {
        LIST_REMOVE(son, pointers);
        UA_ServerOnNetwork_clear(&son->serverOnNetwork);
        if(son->pathTmp)
            UA_free(son->pathTmp);
        UA_free(son);
    }

    UA_String_clear(&dm->selfFqdnMdnsRecord);

    for(size_t i = 0; i < SERVER_ON_NETWORK_HASH_SIZE; i++) {
        serverOnNetwork_hash_entry* currHash = dm->serverOnNetworkHash[i];
        while(currHash) {
            serverOnNetwork_hash_entry* nextHash = currHash->next;
            UA_free(currHash);
            currHash = nextHash;
        }
    }
# endif /* UA_ENABLE_DISCOVERY_MULTICAST */

    UA_free(dm);
    return UA_STATUSCODE_GOOD;
}

/* Cleanup server registration: If the semaphore file path is set, then it just
 * checks the existence of the file. When it is deleted, the registration is
 * removed. If there is no semaphore file, then the registration will be removed
 * if it is older than 60 minutes. */
static void
UA_DiscoveryManager_cleanupTimedOut(UA_Server *server, void *data) {
    UA_EventLoop *el = server->config.eventLoop;
    UA_DiscoveryManager *dm = (UA_DiscoveryManager*)data;

    /* TimedOut gives the last DateTime at which we must have seen the
     * registered server. Otherwise it is timed out. */
    UA_DateTime timedOut = el->dateTime_nowMonotonic(el);
    if(server->config.discoveryCleanupTimeout)
        timedOut -= server->config.discoveryCleanupTimeout * UA_DATETIME_SEC;

    registeredServer *current, *temp;
    LIST_FOREACH_SAFE(current, &dm->registeredServers, pointers, temp) {
        UA_Boolean semaphoreDeleted = false;

#ifdef UA_ENABLE_DISCOVERY_SEMAPHORE
        if(current->registeredServer.semaphoreFilePath.length) {
            size_t fpSize = current->registeredServer.semaphoreFilePath.length+1;
            char* filePath = (char *)UA_malloc(fpSize);
            if(filePath) {
                memcpy(filePath, current->registeredServer.semaphoreFilePath.data,
                       current->registeredServer.semaphoreFilePath.length );
                filePath[current->registeredServer.semaphoreFilePath.length] = '\0';
                semaphoreDeleted = UA_fileExists(filePath) == false;
                UA_free(filePath);
            } else {
                UA_LOG_ERROR(server->config.logging, UA_LOGCATEGORY_SERVER,
                             "Cannot check registration semaphore. Out of memory");
            }
        }
#endif

        if(semaphoreDeleted ||
           (server->config.discoveryCleanupTimeout &&
            current->lastSeen < timedOut)) {
            if(semaphoreDeleted) {
                UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_SERVER,
                            "Registration of server with URI %.*s is removed because "
                            "the semaphore file '%.*s' was deleted",
                            (int)current->registeredServer.serverUri.length,
                            current->registeredServer.serverUri.data,
                            (int)current->registeredServer.semaphoreFilePath.length,
                            current->registeredServer.semaphoreFilePath.data);
            } else {
                // cppcheck-suppress unreadVariable
                UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_SERVER,
                            "Registration of server with URI %.*s has timed out "
                            "and is removed",
                            (int)current->registeredServer.serverUri.length,
                            current->registeredServer.serverUri.data);
            }
            LIST_REMOVE(current, pointers);
            UA_RegisteredServer_clear(&current->registeredServer);
            UA_free(current);
            dm->registeredServersSize--;
        }
    }

#ifdef UA_ENABLE_DISCOVERY_MULTICAST
    /* Send out multicast */
    UA_DiscoveryManager_sendMulticastMessages(dm);
#endif
}

static UA_StatusCode
UA_DiscoveryManager_start(UA_Server *server,
                          struct UA_ServerComponent *sc) {
    if(sc->state != UA_LIFECYCLESTATE_STOPPED)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_DiscoveryManager *dm = (UA_DiscoveryManager*)sc;
    dm->server = server; /* Set the backpointer */

    UA_StatusCode res =
        addRepeatedCallback(server, UA_DiscoveryManager_cleanupTimedOut,
                            dm, 1000.0, &dm->discoveryCallbackId);
    if(res != UA_STATUSCODE_GOOD)
        return res;

#ifdef UA_ENABLE_DISCOVERY_MULTICAST
    if(server->config.mdnsEnabled)
        UA_DiscoveryManager_startMulticast(dm);
#endif

    UA_DiscoveryManager_setState(server, dm, UA_LIFECYCLESTATE_STARTED);
    return UA_STATUSCODE_GOOD;
}

static void
UA_DiscoveryManager_stop(UA_Server *server,
                         struct UA_ServerComponent *sc) {
    if(sc->state != UA_LIFECYCLESTATE_STARTED)
        return;

    UA_DiscoveryManager *dm = (UA_DiscoveryManager*)sc;
    removeCallback(server, dm->discoveryCallbackId);

    /* Cancel all outstanding register requests */
    for(size_t i = 0; i < UA_MAXREGISTERREQUESTS; i++) {
        if(dm->registerRequests[i].client == NULL)
            continue;
        UA_Client_disconnectSecureChannelAsync(dm->registerRequests[i].client);
    }

#ifdef UA_ENABLE_DISCOVERY_MULTICAST
    if(server->config.mdnsEnabled)
        UA_DiscoveryManager_stopMulticast(dm);
#endif

    UA_DiscoveryManager_setState(server, dm, UA_LIFECYCLESTATE_STOPPED);
}

UA_ServerComponent *
UA_DiscoveryManager_new(UA_Server *server) {
    UA_DiscoveryManager *dm = (UA_DiscoveryManager*)
        UA_calloc(1, sizeof(UA_DiscoveryManager));
    if(!dm)
        return NULL;

#ifdef UA_ENABLE_DISCOVERY_MULTICAST
    UA_EventLoop *el = server->config.eventLoop;
    dm->serverOnNetworkRecordIdLastReset = el->dateTime_now(el);
#endif /* UA_ENABLE_DISCOVERY_MULTICAST */

    dm->sc.name = UA_STRING("discovery");
    dm->sc.start = UA_DiscoveryManager_start;
    dm->sc.stop = UA_DiscoveryManager_stop;
    dm->sc.free = UA_DiscoveryManager_free;
    return &dm->sc;
}

/********************************/
/* Register at Discovery Server */
/********************************/

static void
asyncRegisterRequest_clear(void *app, void *context) {
    UA_Server *server = (UA_Server*)app;
    asyncRegisterRequest *ar = (asyncRegisterRequest*)context;
    UA_DiscoveryManager *dm = ar->dm;

    UA_String_clear(&ar->semaphoreFilePath);
    if(ar->client)
        UA_Client_delete(ar->client);
    memset(ar, 0, sizeof(asyncRegisterRequest));

    /* The Discovery manager is fully stopped? */
    UA_DiscoveryManager_setState(server, dm, dm->sc.state);
}

static void
asyncRegisterRequest_clearAsync(asyncRegisterRequest *ar) {
    UA_Server *server = ar->server;
    UA_ServerConfig *sc = &server->config;
    UA_EventLoop *el = sc->eventLoop;

    ar->cleanupCallback.callback = asyncRegisterRequest_clear;
    ar->cleanupCallback.application = server;
    ar->cleanupCallback.context = ar;
    el->addDelayedCallback(el, &ar->cleanupCallback);
}

static void
setupRegisterRequest(asyncRegisterRequest *ar, UA_RequestHeader *rh,
                     UA_RegisteredServer *rs) {
    UA_ServerConfig *sc = &ar->dm->server->config;

    rh->timeoutHint = 10000;

    rs->isOnline = !ar->unregister;
    rs->serverUri = sc->applicationDescription.applicationUri;
    rs->productUri = sc->applicationDescription.productUri;
    rs->serverType = sc->applicationDescription.applicationType;
    rs->gatewayServerUri = sc->applicationDescription.gatewayServerUri;
    rs->semaphoreFilePath = ar->semaphoreFilePath;

    rs->serverNames = &sc->applicationDescription.applicationName;
    rs->serverNamesSize = 1;

    /* Mirror the discovery URLs from the server config (includes hostnames from
     * the network layers) */
    rs->discoveryUrls = sc->applicationDescription.discoveryUrls;
    rs->discoveryUrlsSize = sc->applicationDescription.discoveryUrlsSize;
}

static void
registerAsyncResponse(UA_Client *client, void *userdata,
                      UA_UInt32 requestId, void *resp) {
    asyncRegisterRequest *ar = (asyncRegisterRequest*)userdata;
    const UA_ServerConfig *sc = &ar->dm->server->config;
    UA_Response *response = (UA_Response*)resp;
    const char *regtype = (ar->register2) ? "RegisterServer2" : "RegisterServer";

    /* Success registering? */
    if(response->responseHeader.serviceResult == UA_STATUSCODE_GOOD) {
        UA_LOG_INFO(sc->logging, UA_LOGCATEGORY_SERVER, "%s succeeded", regtype);
        goto done;
    }

    UA_LOG_WARNING(sc->logging, UA_LOGCATEGORY_SERVER,
                   "%s failed with statuscode %s", regtype,
                   UA_StatusCode_name(response->responseHeader.serviceResult));

    /* Try RegisterServer next */
    ar->register2 = false;

    /* Try RegisterServer immediately if we can.
     * Otherwise wait for the next state callback. */
    UA_SecureChannelState ss;
    UA_Client_getState(client, &ss, NULL, NULL);
    if(!ar->shutdown && ss == UA_SECURECHANNELSTATE_OPEN) {
        UA_RegisterServerRequest request;
        UA_RegisterServerRequest_init(&request);
        setupRegisterRequest(ar, &request.requestHeader, &request.server);
        UA_StatusCode res =
            __UA_Client_AsyncService(client, &request,
                                     &UA_TYPES[UA_TYPES_REGISTERSERVERREQUEST],
                                     registerAsyncResponse,
                                     &UA_TYPES[UA_TYPES_REGISTERSERVERRESPONSE], ar, NULL);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR((const UA_Logger *)&sc->logging, UA_LOGCATEGORY_CLIENT,
                         "RegisterServer failed with statuscode %s",
                         UA_StatusCode_name(res));
            goto done;
        }
    }

    return;

 done:
    /* Close the client connection, will be cleaned up in the client state
     * callback when closing is complete */
    ar->shutdown = true;
    UA_Client_disconnectSecureChannelAsync(ar->client);
}

static void
discoveryClientStateCallback(UA_Client *client,
                             UA_SecureChannelState channelState,
                             UA_SessionState sessionState,
                             UA_StatusCode connectStatus) {
    asyncRegisterRequest *ar = (asyncRegisterRequest*)
        UA_Client_getContext(client);
    UA_ServerConfig *sc = &ar->dm->server->config;

    /* Connection failed */
    if(connectStatus != UA_STATUSCODE_GOOD) {
        if(connectStatus != UA_STATUSCODE_BADCONNECTIONCLOSED) {
            UA_LOG_ERROR(sc->logging, UA_LOGCATEGORY_SERVER,
                         "Could not connect to the Discovery server with error %s",
                         UA_StatusCode_name(connectStatus));
        }

        /* Connection fully closed */
        if(channelState == UA_SECURECHANNELSTATE_CLOSED) {
            if(!ar->connectSuccess || ar->shutdown) {
                asyncRegisterRequest_clearAsync(ar); /* Clean up */
            } else {
                ar->connectSuccess = false;
                __UA_Client_connect(client, true);   /* Reconnect */
            }
        }
        return;
    }

    /* Wait until the SecureChannel is open */
    if(channelState != UA_SECURECHANNELSTATE_OPEN)
        return;

    /* We have at least succeeded to connect */
    ar->connectSuccess = true;

    /* Is this the encrypted SecureChannel already? (We might have to wait for
     * the second connection after the FindServers handshake */
    UA_MessageSecurityMode msm = UA_MESSAGESECURITYMODE_INVALID;
    UA_Client_getConnectionAttribute_scalar(client, UA_QUALIFIEDNAME(0, "securityMode"),
                                            &UA_TYPES[UA_TYPES_MESSAGESECURITYMODE],
                                            &msm);
    if(msm != UA_MESSAGESECURITYMODE_SIGNANDENCRYPT)
        return;

    const UA_DataType *reqType;
    const UA_DataType *respType;
    UA_RegisterServerRequest reg1;
    UA_RegisterServer2Request reg2;
#ifdef UA_ENABLE_DISCOVERY_MULTICAST
    UA_ExtensionObject mdnsConfig;
#endif
    void *request;

    /* Prepare the request. This does not allocate memory */
    if(ar->register2) {
        UA_RegisterServer2Request_init(&reg2);
        setupRegisterRequest(ar, &reg2.requestHeader, &reg2.server);
        reqType = &UA_TYPES[UA_TYPES_REGISTERSERVER2REQUEST];
        respType = &UA_TYPES[UA_TYPES_REGISTERSERVER2RESPONSE];
        request = &reg2;

#ifdef UA_ENABLE_DISCOVERY_MULTICAST
        /* Set the configuration that is only available for
         * UA_RegisterServer2Request */
        UA_ExtensionObject_setValueNoDelete(&mdnsConfig, &sc->mdnsConfig,
                                            &UA_TYPES[UA_TYPES_MDNSDISCOVERYCONFIGURATION]);
        reg2.discoveryConfigurationSize = 1;
        reg2.discoveryConfiguration = &mdnsConfig;
#endif
    } else {
        UA_RegisterServerRequest_init(&reg1);
        setupRegisterRequest(ar, &reg1.requestHeader, &reg1.server);
        reqType = &UA_TYPES[UA_TYPES_REGISTERSERVERREQUEST];
        respType = &UA_TYPES[UA_TYPES_REGISTERSERVERRESPONSE];
        request = &reg1;
    }

    /* Try to call RegisterServer2 */
    UA_StatusCode res =
        __UA_Client_AsyncService(client, request, reqType, registerAsyncResponse,
                                 respType, ar, NULL);
    if(res != UA_STATUSCODE_GOOD) {
        /* Close the client connection, will be cleaned up in the client state
         * callback when closing is complete */
        UA_Client_disconnectSecureChannelAsync(ar->client);
        UA_LOG_ERROR(sc->logging, UA_LOGCATEGORY_CLIENT,
                     "RegisterServer2 failed with statuscode %s",
                     UA_StatusCode_name(res));
    }
}

static UA_StatusCode
UA_Server_register(UA_Server *server, UA_ClientConfig *cc, UA_Boolean unregister,
                   const UA_String discoveryServerUrl,
                   const UA_String semaphoreFilePath) {
    /* Get the discovery manager */
    UA_DiscoveryManager *dm = (UA_DiscoveryManager*)
        getServerComponentByName(server, UA_STRING("discovery"));
    if(!dm) {
        UA_ClientConfig_clear(cc);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Check that the discovery manager is running */
    UA_ServerConfig *sc = &server->config;
    if(dm->sc.state != UA_LIFECYCLESTATE_STARTED) {
        UA_LOG_ERROR(sc->logging, UA_LOGCATEGORY_SERVER,
                     "The server must be started for registering");
        UA_ClientConfig_clear(cc);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Find a free slot for storing the async request information */
    asyncRegisterRequest *ar = NULL;
    for(size_t i = 0; i < UA_MAXREGISTERREQUESTS; i++) {
        if(dm->registerRequests[i].client == NULL) {
            ar = &dm->registerRequests[i];
            break;
        }
    }
    if(!ar) {
        UA_LOG_ERROR(sc->logging, UA_LOGCATEGORY_SERVER,
                     "Too many outstanding register requests. Cannot proceed.");
        UA_ClientConfig_clear(cc);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Use the EventLoop from the server for the client */
    if(cc->eventLoop && !cc->externalEventLoop)
        cc->eventLoop->free(cc->eventLoop);
    cc->eventLoop = sc->eventLoop;
    cc->externalEventLoop = true;

    /* Set the state callback method and context */
    cc->stateCallback = discoveryClientStateCallback;
    cc->clientContext = ar;

    /* Use encryption by default */
#ifdef UA_ENABLE_ENCRYPTION
    cc->securityMode = UA_MESSAGESECURITYMODE_SIGNANDENCRYPT;
#endif

    /* Open only a SecureChannel */
    cc->noSession = true;

    /* Move the endpoint url */
    UA_String_clear(&cc->endpointUrl);
    UA_String_copy(&discoveryServerUrl, &cc->endpointUrl);

    /* Instantiate the client */
    ar->client = UA_Client_newWithConfig(cc);
    if(!ar->client) {
        UA_ClientConfig_clear(cc);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    /* Zero out the supplied config */
    memset(cc, 0, sizeof(UA_ClientConfig));

    /* Finish setting up the context */
    ar->server = server;
    ar->dm = dm;
    ar->unregister = unregister;
    ar->register2 = true; /* Try register2 first */
    UA_String_copy(&semaphoreFilePath, &ar->semaphoreFilePath);

    /* Connect asynchronously. The register service is called once the
     * connection is open. */
    ar->connectSuccess = false;
    return __UA_Client_connect(ar->client, true);
}

UA_StatusCode
UA_Server_registerDiscovery(UA_Server *server, UA_ClientConfig *cc,
                            const UA_String discoveryServerUrl,
                            const UA_String semaphoreFilePath) {
    UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_SERVER,
                "Registering at the DiscoveryServer: %.*s",
                (int)discoveryServerUrl.length, discoveryServerUrl.data);
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res =
        UA_Server_register(server, cc, false, discoveryServerUrl, semaphoreFilePath);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

UA_StatusCode
UA_Server_deregisterDiscovery(UA_Server *server, UA_ClientConfig *cc,
                              const UA_String discoveryServerUrl) {
    UA_LOG_INFO(server->config.logging, UA_LOGCATEGORY_SERVER,
                "Deregistering at the DiscoveryServer: %.*s",
                (int)discoveryServerUrl.length, discoveryServerUrl.data);
    UA_LOCK(&server->serviceMutex);
    UA_StatusCode res =
        UA_Server_register(server, cc, true, discoveryServerUrl, UA_STRING_NULL);
    UA_UNLOCK(&server->serviceMutex);
    return res;
}

#endif /* UA_ENABLE_DISCOVERY */

/**** amalgamated original file "/plugins/crypto/mbedtls/securitypolicy_mbedtls_common.h" ****/

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
 *
 *    Copyright 2019 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 */



#if defined(UA_ENABLE_ENCRYPTION_MBEDTLS) || defined(UA_ENABLE_PUBSUB_ENCRYPTION)

#include <mbedtls/md.h>
#include <mbedtls/x509_crt.h>
#include <mbedtls/ctr_drbg.h>

// MBEDTLS_ENTROPY_HARDWARE_ALT should be defined if your hardware does not supportd platform entropy

#define UA_SHA1_LENGTH 20

_UA_BEGIN_DECLS

void
swapBuffers(UA_ByteString *const bufA, UA_ByteString *const bufB);

UA_StatusCode
mbedtls_hmac(mbedtls_md_context_t *context, const UA_ByteString *key,
             const UA_ByteString *in, unsigned char *out);

UA_StatusCode
mbedtls_generateKey(mbedtls_md_context_t *context,
                    const UA_ByteString *secret, const UA_ByteString *seed,
                    UA_ByteString *out);

UA_StatusCode
mbedtls_verifySig_sha1(mbedtls_x509_crt *certificate, const UA_ByteString *message,
                       const UA_ByteString *signature);

UA_StatusCode
mbedtls_sign_sha1(mbedtls_pk_context *localPrivateKey,
                  mbedtls_ctr_drbg_context *drbgContext,
                  const UA_ByteString *message,
                  UA_ByteString *signature);

UA_StatusCode
mbedtls_thumbprint_sha1(const UA_ByteString *certificate,
                        UA_ByteString *thumbprint);

/* Set the hashing scheme before calling
 * E.g. mbedtls_rsa_set_padding(context, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1); */
UA_StatusCode
mbedtls_encrypt_rsaOaep(mbedtls_rsa_context *context,
                        mbedtls_ctr_drbg_context *drbgContext,
                        UA_ByteString *data, const size_t plainTextBlockSize);

UA_StatusCode
mbedtls_decrypt_rsaOaep(mbedtls_pk_context *localPrivateKey,
                        mbedtls_ctr_drbg_context *drbgContext,
                        UA_ByteString *data, int hash_id);

int UA_mbedTLS_LoadPrivateKey(const UA_ByteString *key, mbedtls_pk_context *target, void *p_rng);

UA_StatusCode UA_mbedTLS_LoadLocalCertificate(const UA_ByteString *certData, UA_ByteString *target);

UA_ByteString UA_mbedTLS_CopyDataFormatAware(const UA_ByteString *data);

_UA_END_DECLS

#endif


/**** amalgamated original file "/plugins/crypto/mbedtls/securitypolicy_mbedtls_common.c" ****/


#if defined(UA_ENABLE_ENCRYPTION_MBEDTLS) || defined(UA_ENABLE_PUBSUB_ENCRYPTION)


#include <mbedtls/aes.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
#include <mbedtls/error.h>
#include <mbedtls/md.h>
#include <mbedtls/sha1.h>
#include <mbedtls/version.h>
#include <mbedtls/x509_crt.h>

void
swapBuffers(UA_ByteString *const bufA, UA_ByteString *const bufB) {
    UA_ByteString tmp = *bufA;
    *bufA = *bufB;
    *bufB = tmp;
}

UA_StatusCode
mbedtls_hmac(mbedtls_md_context_t *context, const UA_ByteString *key,
             const UA_ByteString *in, unsigned char *out) {

    if(mbedtls_md_hmac_starts(context, key->data, key->length) != 0)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    if(mbedtls_md_hmac_update(context, in->data, in->length) != 0)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    if(mbedtls_md_hmac_finish(context, out) != 0)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
mbedtls_generateKey(mbedtls_md_context_t *context,
                    const UA_ByteString *secret, const UA_ByteString *seed,
                    UA_ByteString *out) {
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    size_t hashLen = (size_t)mbedtls_md_get_size(context->md_info);
#else
    size_t hashLen = (size_t)mbedtls_md_get_size(context->private_md_info);
#endif

    UA_ByteString A_and_seed;
    UA_ByteString_allocBuffer(&A_and_seed, hashLen + seed->length);
    memcpy(A_and_seed.data + hashLen, seed->data, seed->length);

    UA_ByteString ANext_and_seed;
    UA_ByteString_allocBuffer(&ANext_and_seed, hashLen + seed->length);
    memcpy(ANext_and_seed.data + hashLen, seed->data, seed->length);

    UA_ByteString A = {
        hashLen,
        A_and_seed.data
    };

    UA_ByteString ANext = {
        hashLen,
        ANext_and_seed.data
    };

    UA_StatusCode retval = mbedtls_hmac(context, secret, seed, A.data);

    if(retval != UA_STATUSCODE_GOOD){
        UA_ByteString_clear(&A_and_seed);
        UA_ByteString_clear(&ANext_and_seed);
        return retval;
    }

    for(size_t offset = 0; offset < out->length; offset += hashLen) {
        UA_ByteString outSegment = {
            hashLen,
            out->data + offset
        };
        UA_Boolean bufferAllocated = UA_FALSE;
        // Not enough room in out buffer to write the hash.
        if(offset + hashLen > out->length) {
            outSegment.data = NULL;
            outSegment.length = 0;
            retval = UA_ByteString_allocBuffer(&outSegment, hashLen);
            if(retval != UA_STATUSCODE_GOOD) {
                UA_ByteString_clear(&A_and_seed);
                UA_ByteString_clear(&ANext_and_seed);
                return retval;
            }
            bufferAllocated = UA_TRUE;
        }

        retval = mbedtls_hmac(context, secret, &A_and_seed, outSegment.data);
        if(retval != UA_STATUSCODE_GOOD){
            UA_ByteString_clear(&A_and_seed);
            UA_ByteString_clear(&ANext_and_seed);
            return retval;
        }
        retval = mbedtls_hmac(context, secret, &A, ANext.data);
        if(retval != UA_STATUSCODE_GOOD){
            UA_ByteString_clear(&A_and_seed);
            UA_ByteString_clear(&ANext_and_seed);
            return retval;
        }

        if(bufferAllocated) {
            memcpy(out->data + offset, outSegment.data, out->length - offset);
            UA_ByteString_clear(&outSegment);
        }

        swapBuffers(&ANext_and_seed, &A_and_seed);
        swapBuffers(&ANext, &A);
    }

    UA_ByteString_clear(&A_and_seed);
    UA_ByteString_clear(&ANext_and_seed);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
mbedtls_verifySig_sha1(mbedtls_x509_crt *certificate, const UA_ByteString *message,
                       const UA_ByteString *signature) {
    /* Compute the sha1 hash */
    unsigned char hash[UA_SHA1_LENGTH];
#if MBEDTLS_VERSION_NUMBER >= 0x02070000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_sha1_ret(message->data, message->length, hash);
#else
    mbedtls_sha1(message->data, message->length, hash);
#endif

    /* Set the RSA settings */
    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(certificate->pk);
    if(!rsaContext)
        return UA_STATUSCODE_BADINTERNALERROR;
    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_NONE);

    /* Verify */
    int mbedErr = mbedtls_pk_verify(&certificate->pk,
                                    MBEDTLS_MD_SHA1, hash, UA_SHA1_LENGTH,
                                    signature->data, signature->length);
    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
mbedtls_sign_sha1(mbedtls_pk_context *localPrivateKey,
                  mbedtls_ctr_drbg_context *drbgContext,
                  const UA_ByteString *message,
                  UA_ByteString *signature) {
    unsigned char hash[UA_SHA1_LENGTH];
#if MBEDTLS_VERSION_NUMBER >= 0x02070000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_sha1_ret(message->data, message->length, hash);
#else
    mbedtls_sha1(message->data, message->length, hash);
#endif

    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(*localPrivateKey);
    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_NONE);

    size_t sigLen = 0;
    int mbedErr = mbedtls_pk_sign(localPrivateKey, MBEDTLS_MD_SHA1, hash,
                                  UA_SHA1_LENGTH, signature->data,
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
                                  signature->length,
#endif
                                  &sigLen,
                                  mbedtls_ctr_drbg_random, drbgContext);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
mbedtls_thumbprint_sha1(const UA_ByteString *certificate,
                        UA_ByteString *thumbprint) {
    if(UA_ByteString_equal(certificate, &UA_BYTESTRING_NULL))
        return UA_STATUSCODE_BADINTERNALERROR;

    if(thumbprint->length != UA_SHA1_LENGTH)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* The certificate thumbprint is always a 20 bit sha1 hash, see Part 4 of the Specification. */
#if MBEDTLS_VERSION_NUMBER >= 0x02070000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_sha1_ret(certificate->data, certificate->length, thumbprint->data);
#else
    mbedtls_sha1(certificate->data, certificate->length, thumbprint->data);
#endif
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
mbedtls_encrypt_rsaOaep(mbedtls_rsa_context *context,
                        mbedtls_ctr_drbg_context *drbgContext,
                        UA_ByteString *data, const size_t plainTextBlockSize) {
    if(data->length % plainTextBlockSize != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t max_blocks = data->length / plainTextBlockSize;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    size_t keylen = context->len;
#else
    size_t keylen = mbedtls_rsa_get_len(context);
#endif

    UA_ByteString encrypted;
    UA_StatusCode retval = UA_ByteString_allocBuffer(&encrypted, max_blocks * keylen);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    size_t lenDataToEncrypt = data->length;
    size_t inOffset = 0;
    size_t offset = 0;
    const unsigned char *label = NULL;
    while(lenDataToEncrypt >= plainTextBlockSize) {
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
        int mbedErr = mbedtls_rsa_rsaes_oaep_encrypt(context, mbedtls_ctr_drbg_random,
                                                     drbgContext, MBEDTLS_RSA_PUBLIC,
                                                     label, 0, plainTextBlockSize,
                                                     data->data + inOffset, encrypted.data + offset);
#else
        int mbedErr = mbedtls_rsa_rsaes_oaep_encrypt(context, mbedtls_ctr_drbg_random,
                                                     drbgContext, label, 0, plainTextBlockSize,
                                                     data->data + inOffset, encrypted.data + offset);
#endif

        if(mbedErr) {
            UA_ByteString_clear(&encrypted);
            return UA_STATUSCODE_BADINTERNALERROR;
        }

        inOffset += plainTextBlockSize;
        offset += keylen;
        lenDataToEncrypt -= plainTextBlockSize;
    }

    memcpy(data->data, encrypted.data, offset);
    UA_ByteString_clear(&encrypted);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
mbedtls_decrypt_rsaOaep(mbedtls_pk_context *localPrivateKey,
                        mbedtls_ctr_drbg_context *drbgContext,
                        UA_ByteString *data, int hash_id) {
    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(*localPrivateKey);
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V21, hash_id);
    size_t keylen = rsaContext->len;
#else
    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V21, (mbedtls_md_type_t)hash_id);
    size_t keylen = mbedtls_rsa_get_len(rsaContext);
#endif
    if(data->length % keylen != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t inOffset = 0;
    size_t outOffset = 0;
    size_t outLength = 0;
    unsigned char buf[512];

    while(inOffset < data->length) {
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
        int mbedErr = mbedtls_rsa_rsaes_oaep_decrypt(rsaContext, mbedtls_ctr_drbg_random,
                                                     drbgContext, MBEDTLS_RSA_PRIVATE,
                                                     NULL, 0, &outLength,
                                                     data->data + inOffset,
                                                     buf, 512);
#else
        int mbedErr = mbedtls_rsa_rsaes_oaep_decrypt(rsaContext, mbedtls_ctr_drbg_random,
                                                     drbgContext,
                                                     NULL, 0, &outLength,
                                                     data->data + inOffset,
                                                     buf, 512);
#endif

        if(mbedErr)
            return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

        memcpy(data->data + outOffset, buf, outLength);
        inOffset += keylen;
        outOffset += outLength;
    }

    data->length = outOffset;
    return UA_STATUSCODE_GOOD;
}

int
UA_mbedTLS_LoadPrivateKey(const UA_ByteString *key, mbedtls_pk_context *target, void *p_rng) {
    UA_ByteString data = UA_mbedTLS_CopyDataFormatAware(key);
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    int mbedErr = mbedtls_pk_parse_key(target, data.data, data.length, NULL, 0);
#else
    int mbedErr = mbedtls_pk_parse_key(target, data.data, data.length, NULL, 0, mbedtls_entropy_func, p_rng);
#endif
    UA_ByteString_clear(&data);
    return mbedErr;
}

UA_StatusCode
UA_mbedTLS_LoadLocalCertificate(const UA_ByteString *certData,
                                UA_ByteString *target) {
    UA_ByteString data = UA_mbedTLS_CopyDataFormatAware(certData);

    mbedtls_x509_crt cert;
    mbedtls_x509_crt_init(&cert);

    int mbedErr = mbedtls_x509_crt_parse(&cert, data.data, data.length);

    UA_StatusCode result = UA_STATUSCODE_BADINVALIDARGUMENT;

    if (!mbedErr) {
        UA_ByteString tmp;
        tmp.data = cert.raw.p;
        tmp.length = cert.raw.len;

        result = UA_ByteString_copy(&tmp, target);
    } else {
        UA_ByteString_init(target);
    }

    UA_ByteString_clear(&data);
    mbedtls_x509_crt_free(&cert);
    return result;
}

// mbedTLS expects PEM data to be null terminated
// The data length parameter must include the null terminator
UA_ByteString
UA_mbedTLS_CopyDataFormatAware(const UA_ByteString *data) {
    UA_ByteString result;
    UA_ByteString_init(&result);

    if (!data->length)
        return result;

    if (data->length && data->data[0] == '-') {
        UA_ByteString_allocBuffer(&result, data->length + 1);
        memcpy(result.data, data->data, data->length);
        result.data[data->length] = '\0';
    } else {
        UA_ByteString_copy(data, &result);
    }

    return result;
}

#endif

/**** amalgamated original file "/plugins/ua_log_stdout.c" ****/

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
 *
 *    Copyright 2016-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2017 (c) Thomas Stalder, Blue Time Concept SA
 */


#include <stdio.h>

/* ANSI escape sequences for color output taken from here:
 * https://stackoverflow.com/questions/3219393/stdlib-and-colored-output-in-c*/

#ifdef UA_ARCHITECTURE_POSIX
# define ANSI_COLOR_RED     "\x1b[31m"
# define ANSI_COLOR_GREEN   "\x1b[32m"
# define ANSI_COLOR_YELLOW  "\x1b[33m"
# define ANSI_COLOR_BLUE    "\x1b[34m"
# define ANSI_COLOR_MAGENTA "\x1b[35m"
# define ANSI_COLOR_CYAN    "\x1b[36m"
# define ANSI_COLOR_RESET   "\x1b[0m"
#else
# define ANSI_COLOR_RED     ""
# define ANSI_COLOR_GREEN   ""
# define ANSI_COLOR_YELLOW  ""
# define ANSI_COLOR_BLUE    ""
# define ANSI_COLOR_MAGENTA ""
# define ANSI_COLOR_CYAN    ""
# define ANSI_COLOR_RESET   ""
#endif

static
const char *logLevelNames[6] = {"trace", "debug",
                                ANSI_COLOR_GREEN "info",
                                ANSI_COLOR_YELLOW "warn",
                                ANSI_COLOR_RED "error",
                                ANSI_COLOR_MAGENTA "fatal"};
static const char *
logCategoryNames[UA_LOGCATEGORIES] =
    {"network", "channel", "session", "server", "client",
     "userland", "securitypolicy", "eventloop", "pubsub", "discovery"};

/* Protect crosstalk during logging via global lock.
 * Use a spinlock on non-POSIX as we cannot statically initialize a global lock. */
#if UA_MULTITHREADING >= 100
# ifdef UA_ARCHITECTURE_POSIX
UA_Lock logLock = UA_LOCK_STATIC_INIT;
# else
void * volatile logSpinLock = NULL;
static UA_INLINE void spinLock(void) {
    while(UA_atomic_cmpxchg(&logSpinLock, NULL, (void*)0x1) != NULL) {}
}
static UA_INLINE void spinUnLock(void) {
    UA_atomic_xchg(&logSpinLock, NULL);
}
# endif
#endif

#ifdef __clang__
__attribute__((__format__(__printf__, 4 , 0)))
#endif
static void
UA_Log_Stdout_log(void *context, UA_LogLevel level, UA_LogCategory category,
                  const char *msg, va_list args) {
    /* MinLevel encoded in the context pointer */
    UA_LogLevel minLevel = (UA_LogLevel)(uintptr_t)context;
    if(minLevel > level)
        return;

    UA_Int64 tOffset = UA_DateTime_localTimeUtcOffset();
    UA_DateTimeStruct dts = UA_DateTime_toStruct(UA_DateTime_now() + tOffset);

    int logLevelSlot = ((int)level / 100) - 1;
    if(logLevelSlot < 0 || logLevelSlot > 5)
        logLevelSlot = 5; /* Set to fatal if the level is outside the range */

    /* Lock */
#if UA_MULTITHREADING >= 100
# ifdef UA_ARCHITECTURE_POSIX
    UA_LOCK(&logLock);
# else
    spinLock();
# endif
#endif

    /* Log */
    printf("[%04u-%02u-%02u %02u:%02u:%02u.%03u (UTC%+05d)] %s/%s" ANSI_COLOR_RESET "\t",
           dts.year, dts.month, dts.day, dts.hour, dts.min, dts.sec, dts.milliSec,
           (int)(tOffset / UA_DATETIME_SEC / 36), logLevelNames[logLevelSlot],
           logCategoryNames[category]);
    vprintf(msg, args);
    printf("\n");
    fflush(stdout);

    /* Unlock */
#if UA_MULTITHREADING >= 100
# ifdef UA_ARCHITECTURE_POSIX
    UA_UNLOCK(&logLock);
# else
    spinUnLock();
# endif
#endif
}

static void
UA_Log_Stdout_clear(UA_Logger *logger) {
    UA_free(logger);
}

const UA_Logger UA_Log_Stdout_ = {UA_Log_Stdout_log, NULL, NULL};
const UA_Logger *UA_Log_Stdout = &UA_Log_Stdout_;

UA_Logger
UA_Log_Stdout_withLevel(UA_LogLevel minlevel) {
    UA_Logger logger =
        {UA_Log_Stdout_log, (void*)(uintptr_t)minlevel, NULL};
    return logger;
}

UA_Logger *
UA_Log_Stdout_new(UA_LogLevel minlevel) {
    UA_Logger *logger = (UA_Logger*)UA_malloc(sizeof(UA_Logger));
    if(!logger)
        return NULL;
    *logger = UA_Log_Stdout_withLevel(minlevel);
    logger->clear = UA_Log_Stdout_clear;
    return logger;
}

/**** amalgamated original file "/plugins/ua_accesscontrol_default.c" ****/

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
 *
 *    Copyright 2016-2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2019 (c) HMS Industrial Networks AB (Author: Jonas Green)
 */


/* Example access control management. Anonymous and username / password login.
 * The access rights are maximally permissive.
 *
 * FOR PRODUCTION USE, THIS EXAMPLE PLUGIN SHOULD BE REPLACED WITH LESS
 * PERMISSIVE ACCESS CONTROL.
 *
 * For TransferSubscriptions, we check whether the transfer happens between
 * Sessions for the same user. */

typedef struct {
    UA_Boolean allowAnonymous;
    size_t usernamePasswordLoginSize;
    UA_UsernamePasswordLogin *usernamePasswordLogin;
    UA_UsernamePasswordLoginCallback loginCallback;
    void *loginContext;
    UA_CertificateGroup verifyX509;
} AccessControlContext;

#define ANONYMOUS_POLICY "open62541-anonymous-policy"
#define CERTIFICATE_POLICY "open62541-certificate-policy"
#define USERNAME_POLICY "open62541-username-policy"
const UA_String anonymous_policy = UA_STRING_STATIC(ANONYMOUS_POLICY);
const UA_String certificate_policy = UA_STRING_STATIC(CERTIFICATE_POLICY);
const UA_String username_policy = UA_STRING_STATIC(USERNAME_POLICY);

/************************/
/* Access Control Logic */
/************************/

static UA_StatusCode
activateSession_default(UA_Server *server, UA_AccessControl *ac,
                        const UA_EndpointDescription *endpointDescription,
                        const UA_ByteString *secureChannelRemoteCertificate,
                        const UA_NodeId *sessionId,
                        const UA_ExtensionObject *userIdentityToken,
                        void **sessionContext) {
    AccessControlContext *context = (AccessControlContext*)ac->context;
    UA_ServerConfig *config = UA_Server_getConfig(server);

    /* The empty token is interpreted as anonymous */
    UA_AnonymousIdentityToken anonToken;
    UA_ExtensionObject tmpIdentity;
    if(userIdentityToken->encoding == UA_EXTENSIONOBJECT_ENCODED_NOBODY) {
        UA_AnonymousIdentityToken_init(&anonToken);
        UA_ExtensionObject_init(&tmpIdentity);
        UA_ExtensionObject_setValueNoDelete(&tmpIdentity,
                                            &anonToken,
                                            &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN]);
        userIdentityToken = &tmpIdentity;
    }

    /* Could the token be decoded? */
    if(userIdentityToken->encoding < UA_EXTENSIONOBJECT_DECODED)
        return UA_STATUSCODE_BADIDENTITYTOKENINVALID;

    const UA_DataType *tokenType = userIdentityToken->content.decoded.type;
    if(tokenType == &UA_TYPES[UA_TYPES_ANONYMOUSIDENTITYTOKEN]) {
        /* Anonymous login */
        if(!context->allowAnonymous)
            return UA_STATUSCODE_BADIDENTITYTOKENINVALID;

        const UA_AnonymousIdentityToken *token = (UA_AnonymousIdentityToken*)
            userIdentityToken->content.decoded.data;

        /* Match the beginnig of the PolicyId.
         * Compatibility notice: Siemens OPC Scout v10 provides an empty
         * policyId. This is not compliant. For compatibility, assume that empty
         * policyId == ANONYMOUS_POLICY */
        if(token->policyId.data &&
           (token->policyId.length < anonymous_policy.length ||
            strncmp((const char*)token->policyId.data,
                    (const char*)anonymous_policy.data,
                    anonymous_policy.length) != 0)) {
            return UA_STATUSCODE_BADIDENTITYTOKENINVALID;
        }
    } else if(tokenType == &UA_TYPES[UA_TYPES_USERNAMEIDENTITYTOKEN]) {
        /* Username and password */
        const UA_UserNameIdentityToken *userToken = (UA_UserNameIdentityToken*)
            userIdentityToken->content.decoded.data;

        /* Match the beginnig of the PolicyId */
        if(userToken->policyId.length < username_policy.length ||
           strncmp((const char*)userToken->policyId.data,
                   (const char*)username_policy.data,
                   username_policy.length) != 0) {
            return UA_STATUSCODE_BADIDENTITYTOKENINVALID;
        }

        /* The userToken has been decrypted by the server before forwarding
         * it to the plugin. This information can be used here. */
        /* if(userToken->encryptionAlgorithm.length > 0) {} */

        /* Empty username and password */
        if(userToken->userName.length == 0 && userToken->password.length == 0)
            return UA_STATUSCODE_BADIDENTITYTOKENINVALID;

        /* Try to match username/pw */
        UA_Boolean match = false;
        if(context->loginCallback) {
            if(context->loginCallback(&userToken->userName, &userToken->password,
               context->usernamePasswordLoginSize, context->usernamePasswordLogin,
               sessionContext, context->loginContext) == UA_STATUSCODE_GOOD)
                match = true;
        } else {
            for(size_t i = 0; i < context->usernamePasswordLoginSize; i++) {
                if(UA_String_equal(&userToken->userName, &context->usernamePasswordLogin[i].username) &&
                   UA_String_equal(&userToken->password, &context->usernamePasswordLogin[i].password)) {
                    match = true;
                    break;
                }
            }
        }
        if(!match)
            return UA_STATUSCODE_BADUSERACCESSDENIED;
    } else if(tokenType == &UA_TYPES[UA_TYPES_X509IDENTITYTOKEN]) {
        /* x509 certificate */
        const UA_X509IdentityToken *userToken = (UA_X509IdentityToken*)
            userIdentityToken->content.decoded.data;

        /* Match the beginnig of the PolicyId */
        if(userToken->policyId.length < certificate_policy.length ||
           strncmp((const char*)userToken->policyId.data,
                   (const char*)certificate_policy.data,
                   certificate_policy.length) != 0) {
            return UA_STATUSCODE_BADIDENTITYTOKENINVALID;
        }

        if(!config->sessionPKI.verifyCertificate)
            return UA_STATUSCODE_BADIDENTITYTOKENINVALID;

       UA_StatusCode res = config->sessionPKI.
            verifyCertificate(&config->sessionPKI, &userToken->certificateData);
        if(res != UA_STATUSCODE_GOOD)
            return UA_STATUSCODE_BADIDENTITYTOKENREJECTED;
    } else {
        /* Unsupported token type */
        return UA_STATUSCODE_BADIDENTITYTOKENINVALID;
    }

    return UA_STATUSCODE_GOOD;
}

static void
closeSession_default(UA_Server *server, UA_AccessControl *ac,
                     const UA_NodeId *sessionId, void *sessionContext) {
}

static UA_UInt32
getUserRightsMask_default(UA_Server *server, UA_AccessControl *ac,
                          const UA_NodeId *sessionId, void *sessionContext,
                          const UA_NodeId *nodeId, void *nodeContext) {
    return 0xFFFFFFFF;
}

static UA_Byte
getUserAccessLevel_default(UA_Server *server, UA_AccessControl *ac,
                           const UA_NodeId *sessionId, void *sessionContext,
                           const UA_NodeId *nodeId, void *nodeContext) {
    return 0xFF;
}

static UA_Boolean
getUserExecutable_default(UA_Server *server, UA_AccessControl *ac,
                          const UA_NodeId *sessionId, void *sessionContext,
                          const UA_NodeId *methodId, void *methodContext) {
    return true;
}

static UA_Boolean
getUserExecutableOnObject_default(UA_Server *server, UA_AccessControl *ac,
                                  const UA_NodeId *sessionId, void *sessionContext,
                                  const UA_NodeId *methodId, void *methodContext,
                                  const UA_NodeId *objectId, void *objectContext) {
    return true;
}

static UA_Boolean
allowAddNode_default(UA_Server *server, UA_AccessControl *ac,
                     const UA_NodeId *sessionId, void *sessionContext,
                     const UA_AddNodesItem *item) {
    return true;
}

static UA_Boolean
allowAddReference_default(UA_Server *server, UA_AccessControl *ac,
                          const UA_NodeId *sessionId, void *sessionContext,
                          const UA_AddReferencesItem *item) {
    return true;
}

static UA_Boolean
allowDeleteNode_default(UA_Server *server, UA_AccessControl *ac,
                        const UA_NodeId *sessionId, void *sessionContext,
                        const UA_DeleteNodesItem *item) {
    return true;
}

static UA_Boolean
allowDeleteReference_default(UA_Server *server, UA_AccessControl *ac,
                             const UA_NodeId *sessionId, void *sessionContext,
                             const UA_DeleteReferencesItem *item) {
    return true;
}

static UA_Boolean
allowBrowseNode_default(UA_Server *server, UA_AccessControl *ac,
                        const UA_NodeId *sessionId, void *sessionContext,
                        const UA_NodeId *nodeId, void *nodeContext) {
    return true;
}

#ifdef UA_ENABLE_SUBSCRIPTIONS
static UA_Boolean
allowTransferSubscription_default(UA_Server *server, UA_AccessControl *ac,
                                  const UA_NodeId *oldSessionId, void *oldSessionContext,
                                  const UA_NodeId *newSessionId, void *newSessionContext) {
    if(!oldSessionId)
        return true;
    /* Allow the transfer if the same user-id was used to activate both sessions */
    UA_Variant session1UserId;
    UA_Variant_init(&session1UserId);
    UA_Server_getSessionAttribute(server, oldSessionId,
                                  UA_QUALIFIEDNAME(0, "clientUserId"),
                                  &session1UserId);
    UA_Variant session2UserId;
    UA_Variant_init(&session2UserId);
    UA_Server_getSessionAttribute(server, newSessionId,
                                  UA_QUALIFIEDNAME(0, "clientUserId"),
                                  &session2UserId);

    return (UA_order(&session1UserId, &session2UserId,
                     &UA_TYPES[UA_TYPES_VARIANT]) == UA_ORDER_EQ);
}
#endif

#ifdef UA_ENABLE_HISTORIZING
static UA_Boolean
allowHistoryUpdateUpdateData_default(UA_Server *server, UA_AccessControl *ac,
                                     const UA_NodeId *sessionId, void *sessionContext,
                                     const UA_NodeId *nodeId,
                                     UA_PerformUpdateType performInsertReplace,
                                     const UA_DataValue *value) {
    return true;
}

static UA_Boolean
allowHistoryUpdateDeleteRawModified_default(UA_Server *server, UA_AccessControl *ac,
                                            const UA_NodeId *sessionId, void *sessionContext,
                                            const UA_NodeId *nodeId,
                                            UA_DateTime startTimestamp,
                                            UA_DateTime endTimestamp,
                                            bool isDeleteModified) {
    return true;
}
#endif

/***************************************/
/* Create Delete Access Control Plugin */
/***************************************/

static void clear_default(UA_AccessControl *ac) {
    UA_Array_delete((void*)(uintptr_t)ac->userTokenPolicies,
                    ac->userTokenPoliciesSize,
                    &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
    ac->userTokenPolicies = NULL;
    ac->userTokenPoliciesSize = 0;

    AccessControlContext *context = (AccessControlContext*)ac->context;

    if (context) {
        for(size_t i = 0; i < context->usernamePasswordLoginSize; i++) {
            UA_String_clear(&context->usernamePasswordLogin[i].username);
            UA_String_clear(&context->usernamePasswordLogin[i].password);
        }
        if(context->usernamePasswordLoginSize > 0)
            UA_free(context->usernamePasswordLogin);

        UA_free(ac->context);
        ac->context = NULL;
    }
}

UA_StatusCode
UA_AccessControl_default(UA_ServerConfig *config,
                         UA_Boolean allowAnonymous,
                         const UA_ByteString *userTokenPolicyUri,
                         size_t usernamePasswordLoginSize,
                         const UA_UsernamePasswordLogin *usernamePasswordLogin) {
    UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SERVER,
                   "AccessControl: Unconfigured AccessControl. Users have all permissions.");
    UA_AccessControl *ac = &config->accessControl;

    if(ac->clear)
        clear_default(ac);

    ac->clear = clear_default;
    ac->activateSession = activateSession_default;
    ac->closeSession = closeSession_default;
    ac->getUserRightsMask = getUserRightsMask_default;
    ac->getUserAccessLevel = getUserAccessLevel_default;
    ac->getUserExecutable = getUserExecutable_default;
    ac->getUserExecutableOnObject = getUserExecutableOnObject_default;
    ac->allowAddNode = allowAddNode_default;
    ac->allowAddReference = allowAddReference_default;
    ac->allowBrowseNode = allowBrowseNode_default;

#ifdef UA_ENABLE_SUBSCRIPTIONS
    ac->allowTransferSubscription = allowTransferSubscription_default;
#endif

#ifdef UA_ENABLE_HISTORIZING
    ac->allowHistoryUpdateUpdateData = allowHistoryUpdateUpdateData_default;
    ac->allowHistoryUpdateDeleteRawModified = allowHistoryUpdateDeleteRawModified_default;
#endif

    ac->allowDeleteNode = allowDeleteNode_default;
    ac->allowDeleteReference = allowDeleteReference_default;

    AccessControlContext *context = (AccessControlContext*)
            UA_malloc(sizeof(AccessControlContext));
    if(!context)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    memset(context, 0, sizeof(AccessControlContext));
    ac->context = context;

    /* Allow anonymous? */
    context->allowAnonymous = allowAnonymous;
    if(allowAnonymous) {
        UA_LOG_INFO(config->logging, UA_LOGCATEGORY_SERVER,
                    "AccessControl: Anonymous login is enabled");
    }

    /* Copy username/password to the access control plugin */
    if(usernamePasswordLoginSize > 0) {
        context->usernamePasswordLogin = (UA_UsernamePasswordLogin*)
            UA_malloc(usernamePasswordLoginSize * sizeof(UA_UsernamePasswordLogin));
        if(!context->usernamePasswordLogin)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        context->usernamePasswordLoginSize = usernamePasswordLoginSize;
        for(size_t i = 0; i < usernamePasswordLoginSize; i++) {
            UA_String_copy(&usernamePasswordLogin[i].username,
                           &context->usernamePasswordLogin[i].username);
            UA_String_copy(&usernamePasswordLogin[i].password,
                           &context->usernamePasswordLogin[i].password);
        }
    }

    size_t numOfPolcies = 1;
    if(!userTokenPolicyUri) {
        if(config->securityPoliciesSize > 0)
            numOfPolcies = config->securityPoliciesSize;
        else {
            UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SERVER,
                           "No security policies defined for the secure channel.");
            return UA_STATUSCODE_BADINTERNALERROR;
        }
    }

    /* Set the allowed policies */
    size_t policies = 0;
    if(allowAnonymous)
        policies++;
    if(usernamePasswordLoginSize > 0)
        policies++;
    if(config->sessionPKI.verifyCertificate)
        policies++;
    ac->userTokenPoliciesSize = 0;
    ac->userTokenPolicies = (UA_UserTokenPolicy *)
        UA_Array_new(policies * numOfPolcies, &UA_TYPES[UA_TYPES_USERTOKENPOLICY]);
    if(!ac->userTokenPolicies)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    ac->userTokenPoliciesSize = policies * numOfPolcies;

    if(policies == 0) {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SERVER,
                       "No allowed policies set.");
        return UA_STATUSCODE_GOOD;
    }

    const UA_ByteString *utpUri = NULL;
    policies = 0;
    for(size_t i = 0; i < numOfPolcies; i++) {
        if(userTokenPolicyUri) {
            utpUri = userTokenPolicyUri;
        } else {
            utpUri = &config->securityPolicies[i].policyUri;
        }
        if(allowAnonymous) {
            ac->userTokenPolicies[policies].tokenType = UA_USERTOKENTYPE_ANONYMOUS;
            ac->userTokenPolicies[policies].policyId = UA_STRING_ALLOC(ANONYMOUS_POLICY);
            UA_ByteString_copy(utpUri,
                               &ac->userTokenPolicies[policies].securityPolicyUri);
            policies++;
        }

        if(config->sessionPKI.verifyCertificate) {
            ac->userTokenPolicies[policies].tokenType = UA_USERTOKENTYPE_CERTIFICATE;
            ac->userTokenPolicies[policies].policyId = UA_STRING_ALLOC(CERTIFICATE_POLICY);
#if UA_LOGLEVEL <= 400
            if(UA_ByteString_equal(utpUri, &UA_SECURITY_POLICY_NONE_URI)) {
                UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SERVER,
                               "x509 Certificate Authentication configured, "
                               "but no encrypting SecurityPolicy. "
                               "This can leak credentials on the network.");
            }
#endif
            UA_ByteString_copy(utpUri,
                               &ac->userTokenPolicies[policies].securityPolicyUri);
            policies++;
        }

        if(usernamePasswordLoginSize > 0) {
            ac->userTokenPolicies[policies].tokenType = UA_USERTOKENTYPE_USERNAME;
            ac->userTokenPolicies[policies].policyId = UA_STRING_ALLOC(USERNAME_POLICY);
#if UA_LOGLEVEL <= 400
            if(UA_ByteString_equal(utpUri, &UA_SECURITY_POLICY_NONE_URI)) {
                UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_SERVER,
                               "Username/Password Authentication configured, "
                               "but no encrypting SecurityPolicy. "
                               "This can leak credentials on the network.");
            }
#endif
            UA_ByteString_copy(utpUri,
                               &ac->userTokenPolicies[policies].securityPolicyUri);
            policies++;
        }
    }
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_AccessControl_defaultWithLoginCallback(UA_ServerConfig *config,
                                          UA_Boolean allowAnonymous,
                                          const UA_ByteString *userTokenPolicyUri,
                                          size_t usernamePasswordLoginSize,
                                          const UA_UsernamePasswordLogin *usernamePasswordLogin,
                                          UA_UsernamePasswordLoginCallback loginCallback,
                                          void *loginContext) {
    AccessControlContext *context;
    UA_StatusCode sc =
        UA_AccessControl_default(config, allowAnonymous, userTokenPolicyUri,
                                 usernamePasswordLoginSize, usernamePasswordLogin);
    if(sc != UA_STATUSCODE_GOOD)
        return sc;

    context = (AccessControlContext *)config->accessControl.context;
    context->loginCallback = loginCallback;
    context->loginContext = loginContext;

    return UA_STATUSCODE_GOOD;
}


/**** amalgamated original file "/plugins/ua_nodestore_ziptree.c" ****/

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
 *
 *    Copyright 2014-2018 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2017 (c) Julian Grothoff
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 */


#ifndef container_of
#define container_of(ptr, type, member) \
    (type *)((uintptr_t)ptr - offsetof(type,member))
#endif

struct NodeEntry;
typedef struct NodeEntry NodeEntry;

struct NodeEntry {
    ZIP_ENTRY(NodeEntry) zipfields;
    UA_UInt32 nodeIdHash;
    UA_UInt16 refCount; /* How many consumers have a reference to the node? */
    UA_Boolean deleted; /* Node was marked as deleted and can be deleted when refCount == 0 */
    NodeEntry *orig;    /* If a copy is made to replace a node, track that we
                         * replace only the node from which the copy was made.
                         * Important for concurrent operations. */
    UA_NodeId nodeId; /* This is actually a UA_Node that also starts with a NodeId */
};

/* Absolute ordering for NodeIds */
static enum ZIP_CMP
cmpNodeId(const void *a, const void *b) {
    const NodeEntry *aa = (const NodeEntry*)a;
    const NodeEntry *bb = (const NodeEntry*)b;

    /* Compare hash */
    if(aa->nodeIdHash < bb->nodeIdHash)
        return ZIP_CMP_LESS;
    if(aa->nodeIdHash > bb->nodeIdHash)
        return ZIP_CMP_MORE;

    /* Compore nodes in detail */
    return (enum ZIP_CMP)UA_NodeId_order(&aa->nodeId, &bb->nodeId);
}

ZIP_HEAD(NodeTree, NodeEntry);
typedef struct NodeTree NodeTree;

typedef struct {
    NodeTree root;

    /* Maps ReferenceTypeIndex to the NodeId of the ReferenceType */
    UA_NodeId referenceTypeIds[UA_REFERENCETYPESET_MAX];
    UA_Byte referenceTypeCounter;
} ZipContext;

ZIP_FUNCTIONS(NodeTree, NodeEntry, zipfields, NodeEntry, zipfields, cmpNodeId)

static NodeEntry *
newEntry(UA_NodeClass nodeClass) {
    size_t size = sizeof(NodeEntry) - sizeof(UA_NodeId);
    switch(nodeClass) {
    case UA_NODECLASS_OBJECT:
        size += sizeof(UA_ObjectNode);
        break;
    case UA_NODECLASS_VARIABLE:
        size += sizeof(UA_VariableNode);
        break;
    case UA_NODECLASS_METHOD:
        size += sizeof(UA_MethodNode);
        break;
    case UA_NODECLASS_OBJECTTYPE:
        size += sizeof(UA_ObjectTypeNode);
        break;
    case UA_NODECLASS_VARIABLETYPE:
        size += sizeof(UA_VariableTypeNode);
        break;
    case UA_NODECLASS_REFERENCETYPE:
        size += sizeof(UA_ReferenceTypeNode);
        break;
    case UA_NODECLASS_DATATYPE:
        size += sizeof(UA_DataTypeNode);
        break;
    case UA_NODECLASS_VIEW:
        size += sizeof(UA_ViewNode);
        break;
    default:
        return NULL;
    }
    NodeEntry *entry = (NodeEntry*)UA_calloc(1, size);
    if(!entry)
        return NULL;
    UA_Node *node = (UA_Node*)&entry->nodeId;
    node->head.nodeClass = nodeClass;
    return entry;
}

static void
deleteEntry(NodeEntry *entry) {
    UA_Node_clear((UA_Node*)&entry->nodeId);
    UA_free(entry);
}

static void
cleanupEntry(NodeEntry *entry) {
    if(entry->refCount > 0)
        return;
    if(entry->deleted) {
        deleteEntry(entry);
        return;
    }
    UA_NodeHead *head = (UA_NodeHead*)&entry->nodeId;
    for(size_t i = 0; i < head->referencesSize; i++) {
        UA_NodeReferenceKind *rk = &head->references[i];
        if(rk->targetsSize > 16 && !rk->hasRefTree)
            UA_NodeReferenceKind_switch(rk);
    }
}

/***********************/
/* Interface functions */
/***********************/

/* Not yet inserted into the ZipContext */
static UA_Node *
zipNsNewNode(void *nsCtx, UA_NodeClass nodeClass) {
    NodeEntry *entry = newEntry(nodeClass);
    if(!entry)
        return NULL;
    return (UA_Node*)&entry->nodeId;
}

/* Not yet inserted into the ZipContext */
static void
zipNsDeleteNode(void *nsCtx, UA_Node *node) {
    deleteEntry(container_of(node, NodeEntry, nodeId));
}

static const UA_Node *
zipNsGetNode(void *nsCtx, const UA_NodeId *nodeId,
             UA_UInt32 attributeMask,
             UA_ReferenceTypeSet references,
             UA_BrowseDirection referenceDirections) {
    ZipContext *ns = (ZipContext*)nsCtx;
    NodeEntry dummy;
    dummy.nodeIdHash = UA_NodeId_hash(nodeId);
    dummy.nodeId = *nodeId;
    NodeEntry *entry = ZIP_FIND(NodeTree, &ns->root, &dummy);
    if(!entry)
        return NULL;
    ++entry->refCount;
    return (const UA_Node*)&entry->nodeId;
}

static const UA_Node *
zipNsGetNodeFromPtr(void *nsCtx, UA_NodePointer ptr,
                    UA_UInt32 attributeMask,
                    UA_ReferenceTypeSet references,
                    UA_BrowseDirection referenceDirections) {
    if(!UA_NodePointer_isLocal(ptr))
        return NULL;
    UA_NodeId id = UA_NodePointer_toNodeId(ptr);
    return zipNsGetNode(nsCtx, &id, attributeMask,
                        references, referenceDirections);
}

static void
zipNsReleaseNode(void *nsCtx, const UA_Node *node) {
    if(!node)
        return;
    NodeEntry *entry = container_of(node, NodeEntry, nodeId);
    UA_assert(entry->refCount > 0);
    --entry->refCount;
    cleanupEntry(entry);
}

static UA_StatusCode
zipNsGetNodeCopy(void *nsCtx, const UA_NodeId *nodeId,
                 UA_Node **outNode) {
    /* Get the node (with all attributes and references, the mask and refs are
       currently noy evaluated within the plugin.) */
    const UA_Node *node =
        zipNsGetNode(nsCtx, nodeId, UA_NODEATTRIBUTESMASK_ALL,
                     UA_REFERENCETYPESET_ALL, UA_BROWSEDIRECTION_BOTH);
    if(!node)
        return UA_STATUSCODE_BADNODEIDUNKNOWN;

    /* Create the new entry */
    NodeEntry *ne = newEntry(node->head.nodeClass);
    if(!ne) {
        zipNsReleaseNode(nsCtx, node);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    /* Copy the node content */
    UA_Node *nnode = (UA_Node*)&ne->nodeId;
    UA_StatusCode retval = UA_Node_copy(node, nnode);
    zipNsReleaseNode(nsCtx, node);
    if(retval != UA_STATUSCODE_GOOD) {
        deleteEntry(ne);
        return retval;
    }

    ne->orig = container_of(node, NodeEntry, nodeId);
    *outNode = nnode;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
zipNsInsertNode(void *nsCtx, UA_Node *node, UA_NodeId *addedNodeId) {
    NodeEntry *entry = container_of(node, NodeEntry, nodeId);
    ZipContext *ns = (ZipContext*)nsCtx;

    /* Ensure that the NodeId is unique */
    NodeEntry dummy;
    memset(&dummy, 0, sizeof(NodeEntry));
    dummy.nodeId = node->head.nodeId;
    if(node->head.nodeId.identifierType == UA_NODEIDTYPE_NUMERIC &&
       node->head.nodeId.identifier.numeric == 0) {
        do { /* Create a random nodeid until we find an unoccupied id */
            UA_UInt32 numId = UA_UInt32_random();
#if SIZE_MAX <= UA_UINT32_MAX
            /* The compressed "immediate" representation of nodes does not
             * support the full range on 32bit systems. Generate smaller
             * identifiers as they can be stored more compactly. */
            if(numId >= (0x01 << 24))
                numId = numId % (0x01 << 24);
#endif
            node->head.nodeId.identifier.numeric = numId;
            dummy.nodeId.identifier.numeric = numId;
            dummy.nodeIdHash = UA_NodeId_hash(&node->head.nodeId);
        } while(ZIP_FIND(NodeTree, &ns->root, &dummy));
    } else {
        dummy.nodeIdHash = UA_NodeId_hash(&node->head.nodeId);
        if(ZIP_FIND(NodeTree, &ns->root, &dummy)) { /* The nodeid exists */
            deleteEntry(entry);
            return UA_STATUSCODE_BADNODEIDEXISTS;
        }
    }

    /* Copy the NodeId */
    if(addedNodeId) {
        UA_StatusCode retval = UA_NodeId_copy(&node->head.nodeId, addedNodeId);
        if(retval != UA_STATUSCODE_GOOD) {
            deleteEntry(entry);
            return retval;
        }
    }

    /* For new ReferencetypeNodes add to the index map */
    if(node->head.nodeClass == UA_NODECLASS_REFERENCETYPE) {
        UA_ReferenceTypeNode *refNode = &node->referenceTypeNode;
        if(ns->referenceTypeCounter >= UA_REFERENCETYPESET_MAX) {
            deleteEntry(entry);
            return UA_STATUSCODE_BADINTERNALERROR;
        }

        UA_StatusCode retval =
            UA_NodeId_copy(&node->head.nodeId, &ns->referenceTypeIds[ns->referenceTypeCounter]);
        if(retval != UA_STATUSCODE_GOOD) {
            deleteEntry(entry);
            return UA_STATUSCODE_BADINTERNALERROR;
        }

        /* Assign the ReferenceTypeIndex to the new ReferenceTypeNode */
        refNode->referenceTypeIndex = ns->referenceTypeCounter;
        refNode->subTypes = UA_REFTYPESET(ns->referenceTypeCounter);

        ns->referenceTypeCounter++;
    }

    /* Insert the node */
    entry->nodeIdHash = dummy.nodeIdHash;
    ZIP_INSERT(NodeTree, &ns->root, entry);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
zipNsReplaceNode(void *nsCtx, UA_Node *node) {
    /* Find the node (the mask and refs are not evaluated yet by the plugin)*/
    const UA_Node *oldNode =
        zipNsGetNode(nsCtx, &node->head.nodeId, UA_NODEATTRIBUTESMASK_ALL,
                     UA_REFERENCETYPESET_ALL, UA_BROWSEDIRECTION_BOTH);
    if(!oldNode) {
        deleteEntry(container_of(node, NodeEntry, nodeId));
        return UA_STATUSCODE_BADNODEIDUNKNOWN;
    }

    /* Test if the copy is current */
    NodeEntry *entry = container_of(node, NodeEntry, nodeId);
    NodeEntry *oldEntry = container_of(oldNode, NodeEntry, nodeId);
    if(oldEntry != entry->orig) {
        /* The node was already updated since the copy was made */
        deleteEntry(entry);
        zipNsReleaseNode(nsCtx, oldNode);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Replace */
    ZipContext *ns = (ZipContext*)nsCtx;
    ZIP_REMOVE(NodeTree, &ns->root, oldEntry);
    entry->nodeIdHash = oldEntry->nodeIdHash;
    ZIP_INSERT(NodeTree, &ns->root, entry);
    oldEntry->deleted = true;

    zipNsReleaseNode(nsCtx, oldNode);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
zipNsRemoveNode(void *nsCtx, const UA_NodeId *nodeId) {
    ZipContext *ns = (ZipContext*)nsCtx;
    NodeEntry dummy;
    dummy.nodeIdHash = UA_NodeId_hash(nodeId);
    dummy.nodeId = *nodeId;
    NodeEntry *entry = ZIP_FIND(NodeTree, &ns->root, &dummy);
    if(!entry)
        return UA_STATUSCODE_BADNODEIDUNKNOWN;
    ZIP_REMOVE(NodeTree, &ns->root, entry);
    entry->deleted = true;
    cleanupEntry(entry);
    return UA_STATUSCODE_GOOD;
}

static const UA_NodeId *
zipNsGetReferenceTypeId(void *nsCtx, UA_Byte refTypeIndex) {
    ZipContext *ns = (ZipContext*)nsCtx;
    if(refTypeIndex >= ns->referenceTypeCounter)
        return NULL;
    return &ns->referenceTypeIds[refTypeIndex];
}

struct VisitorData {
    UA_NodestoreVisitor visitor;
    void *visitorContext;
};

static void *
nodeVisitor(void *data, NodeEntry *entry) {
    struct VisitorData *d = (struct VisitorData*)data;
    d->visitor(d->visitorContext, (UA_Node*)&entry->nodeId);
    return NULL;
}

static void
zipNsIterate(void *nsCtx, UA_NodestoreVisitor visitor,
             void *visitorCtx) {
    struct VisitorData d;
    d.visitor = visitor;
    d.visitorContext = visitorCtx;
    ZipContext *ns = (ZipContext*)nsCtx;
    ZIP_ITER(NodeTree, &ns->root, nodeVisitor, &d);
}

static void *
deleteNodeVisitor(void *data, NodeEntry *entry) {
    deleteEntry(entry);
    return NULL;
}

/***********************/
/* Nodestore Lifecycle */
/***********************/

static void
zipNsClear(void *nsCtx) {
    if (!nsCtx)
        return;
    ZipContext *ns = (ZipContext*)nsCtx;
    ZIP_ITER(NodeTree, &ns->root, deleteNodeVisitor, NULL);

    /* Clean up the ReferenceTypes index array */
    for(size_t i = 0; i < ns->referenceTypeCounter; i++)
        UA_NodeId_clear(&ns->referenceTypeIds[i]);

    UA_free(ns);
}

UA_StatusCode
UA_Nodestore_ZipTree(UA_Nodestore *ns) {
    /* Allocate and initialize the context */
    ZipContext *ctx = (ZipContext*)UA_malloc(sizeof(ZipContext));
    if(!ctx)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    ZIP_INIT(&ctx->root);
    ctx->referenceTypeCounter = 0;

    /* Populate the nodestore */
    ns->context = (void*)ctx;
    ns->clear = zipNsClear;
    ns->newNode = zipNsNewNode;
    ns->deleteNode = zipNsDeleteNode;
    ns->getNode = zipNsGetNode;
    ns->getNodeFromPtr = zipNsGetNodeFromPtr;
    ns->releaseNode = zipNsReleaseNode;
    ns->getNodeCopy = zipNsGetNodeCopy;
    ns->insertNode = zipNsInsertNode;
    ns->replaceNode = zipNsReplaceNode;
    ns->removeNode = zipNsRemoveNode;
    ns->getReferenceTypeId = zipNsGetReferenceTypeId;
    ns->iterate = zipNsIterate;

    return UA_STATUSCODE_GOOD;
}

/**** amalgamated original file "/plugins/ua_nodestore_hashmap.c" ****/

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
 *
 *    Copyright 2014-2019 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2017 (c) Julian Grothoff
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 */


#ifndef container_of
#define container_of(ptr, type, member) \
    (type *)((uintptr_t)ptr - offsetof(type,member))
#endif

/* The default Nodestore is simply a hash-map from NodeIds to Nodes. To find an
 * entry, iterate over candidate positions according to the NodeId hash.
 *
 * - Tombstone or non-matching NodeId: continue searching
 * - Matching NodeId: Return the entry
 * - NULL: Abort the search */

typedef struct UA_NodeMapEntry {
    struct UA_NodeMapEntry *orig; /* the version this is a copy from (or NULL) */
    UA_UInt16 refCount; /* How many consumers have a reference to the node? */
    UA_Boolean deleted; /* Node was marked as deleted and can be deleted when refCount == 0 */
    UA_Node node;
} UA_NodeMapEntry;

#define UA_NODEMAP_MINSIZE 64
#define UA_NODEMAP_TOMBSTONE ((UA_NodeMapEntry*)0x01)

typedef struct {
    UA_NodeMapEntry *entry;
    UA_UInt32 nodeIdHash;
} UA_NodeMapSlot;

typedef struct {
    UA_NodeMapSlot *slots;
    UA_UInt32 size;
    UA_UInt32 count;
    UA_UInt32 sizePrimeIndex;

    /* Maps ReferenceTypeIndex to the NodeId of the ReferenceType */
    UA_NodeId referenceTypeIds[UA_REFERENCETYPESET_MAX];
    UA_Byte referenceTypeCounter;
} UA_NodeMap;

/*********************/
/* HashMap Utilities */
/*********************/

/* The size of the hash-map is always a prime number. They are chosen to be
 * close to the next power of 2. So the size ca. doubles with each prime. */
static UA_UInt32 const primes[] = {
    7,         13,         31,         61,         127,         251,
    509,       1021,       2039,       4093,       8191,        16381,
    32749,     65521,      131071,     262139,     524287,      1048573,
    2097143,   4194301,    8388593,    16777213,   33554393,    67108859,
    134217689, 268435399,  536870909,  1073741789, 2147483647,  4294967291
};

static UA_UInt32 mod(UA_UInt32 h, UA_UInt32 size) { return h % size; }
static UA_UInt32 mod2(UA_UInt32 h, UA_UInt32 size) { return 1 + (h % (size - 2)); }

static UA_UInt16
higher_prime_index(UA_UInt32 n) {
    UA_UInt16 low  = 0;
    UA_UInt16 high = (UA_UInt16)(sizeof(primes) / sizeof(UA_UInt32));
    while(low != high) {
        UA_UInt16 mid = (UA_UInt16)(low + ((high - low) / 2));
        if(n > primes[mid])
            low = (UA_UInt16)(mid + 1);
        else
            high = mid;
    }
    return low;
}

/* Returns an empty slot or null if the nodeid exists or if no empty slot is found. */
static UA_NodeMapSlot *
findFreeSlot(const UA_NodeMap *ns, const UA_NodeId *nodeid) {
    UA_UInt32 h = UA_NodeId_hash(nodeid);
    UA_UInt32 size = ns->size;
    UA_UInt64 idx = mod(h, size); /* Use 64bit container to avoid overflow  */
    UA_UInt32 startIdx = (UA_UInt32)idx;
    UA_UInt32 hash2 = mod2(h, size);

    UA_NodeMapSlot *candidate = NULL;
    do {
        UA_NodeMapSlot *slot = &ns->slots[(UA_UInt32)idx];

        if(slot->entry > UA_NODEMAP_TOMBSTONE) {
            /* A Node with the NodeId does already exist */
            if(slot->nodeIdHash == h &&
               UA_NodeId_equal(&slot->entry->node.head.nodeId, nodeid))
                return NULL;
        } else {
            /* Found a candidate node */
            if(!candidate)
                candidate = slot;
            /* No matching node can come afterwards */
            if(slot->entry == NULL)
                return candidate;
        }

        idx += hash2;
        if(idx >= size)
            idx -= size;
    } while((UA_UInt32)idx != startIdx);

    return candidate;
}

/* The occupancy of the table after the call will be about 50% */
static UA_StatusCode
expand(UA_NodeMap *ns) {
    UA_UInt32 osize = ns->size;
    UA_UInt32 count = ns->count;
    /* Resize only when table after removal of unused elements is either too
       full or too empty */
    if(count * 2 < osize && (count * 8 > osize || osize <= UA_NODEMAP_MINSIZE))
        return UA_STATUSCODE_GOOD;

    UA_NodeMapSlot *oslots = ns->slots;
    UA_UInt32 nindex = higher_prime_index(count * 2);
    UA_UInt32 nsize = primes[nindex];
    UA_NodeMapSlot *nslots= (UA_NodeMapSlot*)UA_calloc(nsize, sizeof(UA_NodeMapSlot));
    if(!nslots)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    ns->slots = nslots;
    ns->size = nsize;
    ns->sizePrimeIndex = nindex;

    /* recompute the position of every entry and insert the pointer */
    for(size_t i = 0, j = 0; i < osize && j < count; ++i) {
        if(oslots[i].entry <= UA_NODEMAP_TOMBSTONE)
            continue;
        UA_NodeMapSlot *s = findFreeSlot(ns, &oslots[i].entry->node.head.nodeId);
        UA_assert(s);
        *s = oslots[i];
        ++j;
    }

    UA_free(oslots);
    return UA_STATUSCODE_GOOD;
}

static UA_NodeMapEntry *
createEntry(UA_NodeClass nodeClass) {
    size_t size = sizeof(UA_NodeMapEntry) - sizeof(UA_Node);
    switch(nodeClass) {
    case UA_NODECLASS_OBJECT:
        size += sizeof(UA_ObjectNode);
        break;
    case UA_NODECLASS_VARIABLE:
        size += sizeof(UA_VariableNode);
        break;
    case UA_NODECLASS_METHOD:
        size += sizeof(UA_MethodNode);
        break;
    case UA_NODECLASS_OBJECTTYPE:
        size += sizeof(UA_ObjectTypeNode);
        break;
    case UA_NODECLASS_VARIABLETYPE:
        size += sizeof(UA_VariableTypeNode);
        break;
    case UA_NODECLASS_REFERENCETYPE:
        size += sizeof(UA_ReferenceTypeNode);
        break;
    case UA_NODECLASS_DATATYPE:
        size += sizeof(UA_DataTypeNode);
        break;
    case UA_NODECLASS_VIEW:
        size += sizeof(UA_ViewNode);
        break;
    default:
        return NULL;
    }
    UA_NodeMapEntry *entry = (UA_NodeMapEntry*)UA_calloc(1, size);
    if(!entry)
        return NULL;
    entry->node.head.nodeClass = nodeClass;
    return entry;
}

static void
deleteNodeMapEntry(UA_NodeMapEntry *entry) {
    UA_Node_clear(&entry->node);
    UA_free(entry);
}

static void
cleanupNodeMapEntry(UA_NodeMapEntry *entry) {
    if(entry->refCount > 0)
        return;
    if(entry->deleted) {
        deleteNodeMapEntry(entry);
        return;
    }
    for(size_t i = 0; i < entry->node.head.referencesSize; i++) {
        UA_NodeReferenceKind *rk = &entry->node.head.references[i];
        if(rk->targetsSize > 16 && !rk->hasRefTree)
            UA_NodeReferenceKind_switch(rk);
    }
}

static UA_NodeMapSlot *
findOccupiedSlot(const UA_NodeMap *ns, const UA_NodeId *nodeid) {
    UA_UInt32 h = UA_NodeId_hash(nodeid);
    UA_UInt32 size = ns->size;
    UA_UInt64 idx = mod(h, size); /* Use 64bit container to avoid overflow */
    UA_UInt32 hash2 = mod2(h, size);
    UA_UInt32 startIdx = (UA_UInt32)idx;

    do {
        UA_NodeMapSlot *slot= &ns->slots[(UA_UInt32)idx];
        if(slot->entry > UA_NODEMAP_TOMBSTONE) {
            if(slot->nodeIdHash == h &&
               UA_NodeId_equal(&slot->entry->node.head.nodeId, nodeid))
                return slot;
        } else {
            if(slot->entry == NULL)
                return NULL; /* No further entry possible */
        }

        idx += hash2;
        if(idx >= size)
            idx -= size;
    } while((UA_UInt32)idx != startIdx);

    return NULL;
}

/***********************/
/* Interface functions */
/***********************/

static UA_Node *
UA_NodeMap_newNode(void *context, UA_NodeClass nodeClass) {
    UA_NodeMapEntry *entry = createEntry(nodeClass);
    if(!entry)
        return NULL;
    return &entry->node;
}

static void
UA_NodeMap_deleteNode(void *context, UA_Node *node) {
    UA_NodeMapEntry *entry = container_of(node, UA_NodeMapEntry, node);
    UA_assert(&entry->node == node);
    deleteNodeMapEntry(entry);
}

static const UA_Node *
UA_NodeMap_getNode(void *context, const UA_NodeId *nodeid,
                   UA_UInt32 attributeMask,
                   UA_ReferenceTypeSet references,
                   UA_BrowseDirection referenceDirections) {
    UA_NodeMap *ns = (UA_NodeMap*)context;
    UA_NodeMapSlot *slot = findOccupiedSlot(ns, nodeid);
    if(!slot)
        return NULL;
    ++slot->entry->refCount;
    return &slot->entry->node;
}

static const UA_Node *
UA_NodeMap_getNodeFromPtr(void *context, UA_NodePointer ptr,
                          UA_UInt32 attributeMask,
                          UA_ReferenceTypeSet references,
                          UA_BrowseDirection referenceDirections) {
    if(!UA_NodePointer_isLocal(ptr))
        return NULL;
    UA_NodeId id = UA_NodePointer_toNodeId(ptr);
    return UA_NodeMap_getNode(context, &id, attributeMask, references, referenceDirections);
}

static void
UA_NodeMap_releaseNode(void *context, const UA_Node *node) {
    if (!node)
        return;
    UA_NodeMapEntry *entry = container_of(node, UA_NodeMapEntry, node);
    UA_assert(&entry->node == node);
    UA_assert(entry->refCount > 0);
    --entry->refCount;
    cleanupNodeMapEntry(entry);
}

static UA_StatusCode
UA_NodeMap_getNodeCopy(void *context, const UA_NodeId *nodeid,
                       UA_Node **outNode) {
    UA_NodeMap *ns = (UA_NodeMap*)context;
    UA_NodeMapSlot *slot = findOccupiedSlot(ns, nodeid);
    if(!slot)
        return UA_STATUSCODE_BADNODEIDUNKNOWN;
    UA_NodeMapEntry *entry = slot->entry;
    UA_NodeMapEntry *newItem = createEntry(entry->node.head.nodeClass);
    if(!newItem)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    UA_StatusCode retval = UA_Node_copy(&entry->node, &newItem->node);
    if(retval == UA_STATUSCODE_GOOD) {
        newItem->orig = entry; /* Store the pointer to the original */
        *outNode = &newItem->node;
    } else {
        deleteNodeMapEntry(newItem);
    }
    return retval;
}

static UA_StatusCode
UA_NodeMap_removeNode(void *context, const UA_NodeId *nodeid) {
    UA_NodeMap *ns = (UA_NodeMap*)context;
    UA_NodeMapSlot *slot = findOccupiedSlot(ns, nodeid);
    if(!slot)
        return UA_STATUSCODE_BADNODEIDUNKNOWN;

    UA_NodeMapEntry *entry = slot->entry;
    slot->entry = UA_NODEMAP_TOMBSTONE;
    entry->deleted = true;
    cleanupNodeMapEntry(entry);
    --ns->count;
    /* Downsize the hashmap if it is very empty */
    if(ns->count * 8 < ns->size && ns->size > UA_NODEMAP_MINSIZE)
        expand(ns); /* Can fail. Just continue with the bigger hashmap. */
    return UA_STATUSCODE_GOOD;
}

/*
 * If this function fails in any way, the node parameter is deleted here,
 * so the caller function does not need to take care of it anymore
 */
static UA_StatusCode
UA_NodeMap_insertNode(void *context, UA_Node *node,
                      UA_NodeId *addedNodeId) {
    UA_NodeMap *ns = (UA_NodeMap*)context;
    if(ns->size * 3 <= ns->count * 4) {
        if(expand(ns) != UA_STATUSCODE_GOOD){
            deleteNodeMapEntry(container_of(node, UA_NodeMapEntry, node));
            return UA_STATUSCODE_BADINTERNALERROR;
        }
    }

    UA_NodeMapSlot *slot;
    if(node->head.nodeId.identifierType == UA_NODEIDTYPE_NUMERIC &&
       node->head.nodeId.identifier.numeric == 0) {
        /* Create a random nodeid: Start at least with 50,000 to make sure we
         * don not conflict with nodes from the spec. If we find a conflict, we
         * just try another identifier until we have tried all possible
         * identifiers. Since the size is prime and we don't change the increase
         * val, we will reach the starting id again. E.g. adding a nodeset will
         * create children while there are still other nodes which need to be
         * created. Thus the node ids may collide. */
        UA_UInt32 size = ns->size;
        UA_UInt64 identifier = mod(50000 + size+1, UA_UINT32_MAX); /* Use 64bit to
                                                                    * avoid overflow */
        UA_UInt32 increase = mod2(ns->count+1, size);
        UA_UInt32 startId = (UA_UInt32)identifier; /* mod ensures us that the id
                                                    * is a valid 32 bit integer */

        do {
            node->head.nodeId.identifier.numeric = (UA_UInt32)identifier;
            slot = findFreeSlot(ns, &node->head.nodeId);
            if(slot)
                break;
            identifier += increase;
            if(identifier >= size)
                identifier -= size;
#if SIZE_MAX <= UA_UINT32_MAX
            /* The compressed "immediate" representation of nodes does not
             * support the full range on 32bit systems. Generate smaller
             * identifiers as they can be stored more compactly. */
            if(identifier >= (0x01 << 24))
                identifier = identifier % (0x01 << 24);
#endif
        } while((UA_UInt32)identifier != startId);
    } else {
        slot = findFreeSlot(ns, &node->head.nodeId);
    }

    if(!slot) {
        deleteNodeMapEntry(container_of(node, UA_NodeMapEntry, node));
        return UA_STATUSCODE_BADNODEIDEXISTS;
    }

    /* Copy the NodeId */
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(addedNodeId) {
        retval = UA_NodeId_copy(&node->head.nodeId, addedNodeId);
        if(retval != UA_STATUSCODE_GOOD) {
            deleteNodeMapEntry(container_of(node, UA_NodeMapEntry, node));
            return retval;
        }
    }

    /* For new ReferencetypeNodes add to the index map */
    if(node->head.nodeClass == UA_NODECLASS_REFERENCETYPE) {
        UA_ReferenceTypeNode *refNode = &node->referenceTypeNode;
        if(ns->referenceTypeCounter >= UA_REFERENCETYPESET_MAX) {
            deleteNodeMapEntry(container_of(node, UA_NodeMapEntry, node));
            return UA_STATUSCODE_BADINTERNALERROR;
        }

        retval = UA_NodeId_copy(&node->head.nodeId, &ns->referenceTypeIds[ns->referenceTypeCounter]);
        if(retval != UA_STATUSCODE_GOOD) {
            deleteNodeMapEntry(container_of(node, UA_NodeMapEntry, node));
            return UA_STATUSCODE_BADINTERNALERROR;
        }

        /* Assign the ReferenceTypeIndex to the new ReferenceTypeNode */
        refNode->referenceTypeIndex = ns->referenceTypeCounter;
        refNode->subTypes = UA_REFTYPESET(ns->referenceTypeCounter);

        ns->referenceTypeCounter++;
    }

    /* Insert the node */
    UA_NodeMapEntry *newEntry = container_of(node, UA_NodeMapEntry, node);
    slot->nodeIdHash = UA_NodeId_hash(&node->head.nodeId);
    slot->entry = newEntry;
    ++ns->count;
    return retval;
}

static UA_StatusCode
UA_NodeMap_replaceNode(void *context, UA_Node *node) {
    UA_NodeMap *ns = (UA_NodeMap*)context;
    UA_NodeMapEntry *newEntry = container_of(node, UA_NodeMapEntry, node);

    /* Find the node */
    UA_NodeMapSlot *slot = findOccupiedSlot(ns, &node->head.nodeId);
    if(!slot) {
        deleteNodeMapEntry(newEntry);
        return UA_STATUSCODE_BADNODEIDUNKNOWN;
    }

    /* The node was already updated since the copy was made? */
    UA_NodeMapEntry *oldEntry = slot->entry;
    if(oldEntry != newEntry->orig) {
        deleteNodeMapEntry(newEntry);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Replace the entry */
    slot->entry = newEntry;
    oldEntry->deleted = true;
    cleanupNodeMapEntry(oldEntry);
    return UA_STATUSCODE_GOOD;
}

static const UA_NodeId *
UA_NodeMap_getReferenceTypeId(void *nsCtx, UA_Byte refTypeIndex) {
    UA_NodeMap *ns = (UA_NodeMap*)nsCtx;
    if(refTypeIndex >= ns->referenceTypeCounter)
        return NULL;
    return &ns->referenceTypeIds[refTypeIndex];
}

static void
UA_NodeMap_iterate(void *context, UA_NodestoreVisitor visitor,
                   void *visitorContext) {
    UA_NodeMap *ns = (UA_NodeMap*)context;
    for(UA_UInt32 i = 0; i < ns->size; ++i) {
        UA_NodeMapSlot *slot = &ns->slots[i];
        if(slot->entry > UA_NODEMAP_TOMBSTONE) {
            /* The visitor can delete the node. So refcount here. */
            slot->entry->refCount++;
            visitor(visitorContext, &slot->entry->node);
            slot->entry->refCount--;
            cleanupNodeMapEntry(slot->entry);
        }
    }
}

static void
UA_NodeMap_delete(void *context) {
    /* Already cleaned up? */
    if(!context)
        return;

    UA_NodeMap *ns = (UA_NodeMap*)context;
    UA_UInt32 size = ns->size;
    UA_NodeMapSlot *slots = ns->slots;
    for(UA_UInt32 i = 0; i < size; ++i) {
        if(slots[i].entry > UA_NODEMAP_TOMBSTONE) {
            /* On debugging builds, check that all nodes were release */
            UA_assert(slots[i].entry->refCount == 0);
            /* Delete the node */
            deleteNodeMapEntry(slots[i].entry);
        }
    }
    UA_free(ns->slots);

    /* Clean up the ReferenceTypes index array */
    for(size_t i = 0; i < ns->referenceTypeCounter; i++)
        UA_NodeId_clear(&ns->referenceTypeIds[i]);

    UA_free(ns);
}

UA_StatusCode
UA_Nodestore_HashMap(UA_Nodestore *ns) {
    /* Allocate and initialize the nodemap */
    UA_NodeMap *nodemap = (UA_NodeMap*)UA_malloc(sizeof(UA_NodeMap));
    if(!nodemap)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    nodemap->sizePrimeIndex = higher_prime_index(UA_NODEMAP_MINSIZE);
    nodemap->size = primes[nodemap->sizePrimeIndex];
    nodemap->count = 0;
    nodemap->slots = (UA_NodeMapSlot*)
        UA_calloc(nodemap->size, sizeof(UA_NodeMapSlot));
    if(!nodemap->slots) {
        UA_free(nodemap);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    nodemap->referenceTypeCounter = 0;

    /* Populate the nodestore */
    ns->context = nodemap;
    ns->clear = UA_NodeMap_delete;
    ns->newNode = UA_NodeMap_newNode;
    ns->deleteNode = UA_NodeMap_deleteNode;
    ns->getNode = UA_NodeMap_getNode;
    ns->getNodeFromPtr = UA_NodeMap_getNodeFromPtr;
    ns->releaseNode = UA_NodeMap_releaseNode;
    ns->getNodeCopy = UA_NodeMap_getNodeCopy;
    ns->insertNode = UA_NodeMap_insertNode;
    ns->replaceNode = UA_NodeMap_replaceNode;
    ns->removeNode = UA_NodeMap_removeNode;
    ns->getReferenceTypeId = UA_NodeMap_getReferenceTypeId;
    ns->iterate = UA_NodeMap_iterate;
    return UA_STATUSCODE_GOOD;
}

/**** amalgamated original file "/plugins/ua_config_default.c" ****/

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
 *
 *    Copyright 2017 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2017 (c) Julian Grothoff
 *    Copyright 2017-2018 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2017 (c) Thomas Stalder, Blue Time Concept SA
 *    Copyright 2018 (c) Daniel Feist, Precitec GmbH & Co. KG
 *    Copyright 2018 (c) Fabian Arndt, Root-Core
 *    Copyright 2019 (c) Kalycito Infotech Private Limited
 *    Copyright 2017-2020 (c) HMS Industrial Networks AB (Author: Jonas Green)
 *    Copyright 2020 (c) Wind River Systems, Inc.
 */



#include <stdio.h>
#ifdef _WIN32
# include <winsock2.h>
#else
# include <unistd.h>
#endif

/* Struct initialization works across ANSI C/C99/C++ if it is done when the
 * variable is first declared. Assigning values to existing structs is
 * heterogeneous across the three. */
static UA_INLINE UA_UInt32Range
UA_UINT32RANGE(UA_UInt32 min, UA_UInt32 max) {
    UA_UInt32Range range = {min, max};
    return range;
}

static UA_INLINE UA_DurationRange
UA_DURATIONRANGE(UA_Duration min, UA_Duration max) {
    UA_DurationRange range = {min, max};
    return range;
}

/* Request the private key password from stdin if no callback is defined */
#ifdef UA_ENABLE_ENCRYPTION
static UA_StatusCode
readPrivateKeyPassword(UA_ByteString *password) {
    /* Read from stdin */
    char buf[256];
    fputs("Private key requires a password. Enter and press return: ", stdout);
    char *s = fgets(buf, 256, stdin);
    if(!s)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Get rid of any trailing \n */
    size_t len = strlen(buf);
    if(len == 0)
        return UA_STATUSCODE_BADINTERNALERROR;
    if(buf[len-1] == '\n')
        buf[len-1] = 0;

    *password = UA_BYTESTRING_ALLOC(buf);
    return UA_STATUSCODE_GOOD;
}
#endif

UA_Server *
UA_Server_new(void) {
    UA_ServerConfig config;
    memset(&config, 0, sizeof(UA_ServerConfig));
    UA_StatusCode res = UA_ServerConfig_setDefault(&config);
    if(res != UA_STATUSCODE_GOOD)
        return NULL;
    return UA_Server_newWithConfig(&config);
}

#if defined(UA_ARCHITECTURE_POSIX) || defined(UA_ARCHITECTURE_WIN32)

/* Required for the definition of SIGINT */
#include <signal.h>

struct InterruptContext {
    UA_Server *server;
    UA_Boolean running;
};

static void
shutdownServer(UA_Server *server, void *context) {
    struct InterruptContext *ic = (struct InterruptContext*)context;
    UA_ServerConfig *config = UA_Server_getConfig(ic->server);
    UA_LOG_INFO(config->logging, UA_LOGCATEGORY_USERLAND,
                "Stopping the server");
    ic->running = false;
}

static void
interruptServer(UA_InterruptManager *im, uintptr_t interruptHandle,
                void *context, const UA_KeyValueMap *parameters) {
    struct InterruptContext *ic = (struct InterruptContext*)context;
    UA_ServerConfig *config = UA_Server_getConfig(ic->server);

    if(config->shutdownDelay <= 0.0) {
        UA_LOG_INFO(config->logging, UA_LOGCATEGORY_USERLAND,
                    "Received SIGINT interrupt. Stopping the server.");
        ic->running = false;
        return;
    }

    UA_LOG_INFO(config->logging, UA_LOGCATEGORY_USERLAND,
                "Received SIGINT interrupt. Stopping the server in %.2fs.",
                config->shutdownDelay / 1000.0);

    UA_UInt32 secondsTillShutdown = (UA_UInt32)(config->shutdownDelay / 1000.0);
    UA_Variant val;
    UA_Variant_setScalar(&val, &secondsTillShutdown, &UA_TYPES[UA_TYPES_UINT32]);
    UA_Server_writeValue(ic->server,
              UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_SECONDSTILLSHUTDOWN), val);
    UA_Server_addTimedCallback(ic->server, shutdownServer, ic, UA_DateTime_nowMonotonic() +
                               (UA_DateTime)(config->shutdownDelay * UA_DATETIME_MSEC),
                               NULL);

    /* Notify the application that the server is stopping */
    if(config->notifyLifecycleState)
        config->notifyLifecycleState(ic->server, UA_LIFECYCLESTATE_STOPPING);
}

UA_StatusCode
UA_Server_runUntilInterrupt(UA_Server *server) {
    if(!server)
        return UA_STATUSCODE_BADINTERNALERROR;
    UA_ServerConfig *config = UA_Server_getConfig(server);
    UA_EventLoop *el = config->eventLoop;
    if(!el)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Get the interrupt manager */
    UA_EventSource *es = el->eventSources;
    while(es) {
        if(es->eventSourceType == UA_EVENTSOURCETYPE_INTERRUPTMANAGER)
            break;
        es = es->next;
    }
    if(!es) {
        UA_LOG_ERROR(config->logging, UA_LOGCATEGORY_USERLAND,
                       "No Interrupt EventSource configured");
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    UA_InterruptManager *im = (UA_InterruptManager*)es;

    /* Register the interrupt */
    struct InterruptContext ic;
    ic.server = server;
    ic.running = true;
    UA_StatusCode retval =
        im->registerInterrupt(im, SIGINT, &UA_KEYVALUEMAP_NULL,
                              interruptServer, &ic);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(config->logging, UA_LOGCATEGORY_USERLAND,
                     "Could not register the interrupt with status code %s",
                     UA_StatusCode_name(retval));
        return retval;
    }

    /* Run the server */
    retval = UA_Server_run_startup(server);
    if(retval != UA_STATUSCODE_GOOD)
        goto deregister_interrupt;
    while(ic.running) {
        UA_Server_run_iterate(server, true);
    }

    /* Shut down the server */
    retval = UA_Server_run_shutdown(server);

    /* Deregister the interrupt */
 deregister_interrupt:
    im->deregisterInterrupt(im, SIGINT);
    return retval;
}

#endif /* defined(UA_ARCHITECTURE_POSIX) || defined(UA_ARCHITECTURE_WIN32) */

/*******************************/
/* Default Connection Settings */
/*******************************/

const UA_ConnectionConfig UA_ConnectionConfig_default = {
    0,       /* .protocolVersion */
    2 << 16, /* .sendBufferSize, 64k per chunk */
    2 << 16, /* .recvBufferSize, 64k per chunk */
    2 << 29, /* .localMaxMessageSize, 512 MB */
    2 << 29, /* .remoteMaxMessageSize, 512 MB */
    2 << 14, /* .localMaxChunkCount, 16k */
    2 << 14  /* .remoteMaxChunkCount, 16k */
};

/***************************/
/* Default Server Settings */
/***************************/

#define MANUFACTURER_NAME "open62541"
#define PRODUCT_NAME "open62541 OPC UA Server"
#define PRODUCT_URI "http://open62541.org"
#define APPLICATION_NAME "open62541-based OPC UA Application"
#define APPLICATION_URI "urn:unconfigured:application"
#define APPLICATION_URI_SERVER "urn:open62541.server.application"

#define SECURITY_POLICY_SIZE 6

#define STRINGIFY(arg) #arg
#define VERSION(MAJOR, MINOR, PATCH, LABEL) \
    STRINGIFY(MAJOR) "." STRINGIFY(MINOR) "." STRINGIFY(PATCH) LABEL

static UA_StatusCode
addEndpoint(UA_ServerConfig *conf,
            const UA_SecurityPolicy *securityPolicy,
            UA_MessageSecurityMode securityMode) {
    /* Test if the endpoint already exists */
    for(size_t i = 0; i < conf->endpointsSize; i++) {
        UA_EndpointDescription *ep = &conf->endpoints[i];
        if(!UA_String_equal(&securityPolicy->policyUri, &ep->securityPolicyUri))
            continue;
        if(ep->securityMode != securityMode)
            continue;
        return UA_STATUSCODE_GOOD;
    }

    /* Reallocate the array size */
    UA_EndpointDescription *tmp = (UA_EndpointDescription *)
        UA_realloc(conf->endpoints,
                   sizeof(UA_EndpointDescription) * (1 + conf->endpointsSize));
    if(!tmp)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    conf->endpoints = tmp;

    /* The following fields are overwritten internally with up-to-date
     * information from the server config:
     *
     * UserTokenPolicies
     * ApplicationDescription (server)
     * ServerCertificate
     * EndpointURL */
    UA_EndpointDescription *endpoint = &conf->endpoints[conf->endpointsSize];
    UA_EndpointDescription_init(endpoint);
    endpoint->transportProfileUri =
        UA_STRING_ALLOC("http://opcfoundation.org/UA-Profile/Transport/uatcp-uasc-uabinary");
    endpoint->securityMode = securityMode;
    endpoint->securityLevel = securityPolicy->securityLevel;

    UA_StatusCode retval = UA_String_copy(&securityPolicy->policyUri,
                                          &endpoint->securityPolicyUri);

    if(retval == UA_STATUSCODE_GOOD) {
        conf->endpointsSize++;
    } else {
        UA_EndpointDescription_clear(endpoint);
        if(conf->endpointsSize == 0) {
            UA_free(conf->endpoints);
            conf->endpoints = NULL;
        }
    }

    return retval;
}

static UA_StatusCode
setDefaultConfig(UA_ServerConfig *conf, UA_UInt16 portNumber) {
    if(!conf)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    /* NodeStore */
    if(conf->nodestore.context == NULL)
        UA_Nodestore_HashMap(&conf->nodestore);

    /* Logging */
    if(conf->logging == NULL)
        conf->logging = UA_Log_Stdout_new(UA_LOGLEVEL_INFO);

    /* EventLoop */
    if(conf->eventLoop == NULL) {
        conf->eventLoop = UA_EventLoop_new_POSIX(conf->logging);
        if(conf->eventLoop == NULL)
            return UA_STATUSCODE_BADOUTOFMEMORY;

        conf->externalEventLoop = false;

        /* Add the TCP connection manager */
        UA_ConnectionManager *tcpCM =
            UA_ConnectionManager_new_POSIX_TCP(UA_STRING("tcp connection manager"));
        if(tcpCM)
            conf->eventLoop->registerEventSource(conf->eventLoop, (UA_EventSource *)tcpCM);

        /* Add the UDP connection manager */
        UA_ConnectionManager *udpCM =
            UA_ConnectionManager_new_POSIX_UDP(UA_STRING("udp connection manager"));
        if(udpCM)
            conf->eventLoop->registerEventSource(conf->eventLoop, (UA_EventSource *)udpCM);

        /* Add the Ethernet connection manager */
#ifdef __linux__
        UA_ConnectionManager *ethCM =
            UA_ConnectionManager_new_POSIX_Ethernet(UA_STRING("eth connection manager"));
        if(ethCM)
            conf->eventLoop->registerEventSource(conf->eventLoop, (UA_EventSource *)ethCM);
#endif

        /* Add the interrupt manager */
        UA_InterruptManager *im = UA_InterruptManager_new_POSIX(UA_STRING("interrupt manager"));
        if(im) {
            conf->eventLoop->registerEventSource(conf->eventLoop, &im->eventSource);
        } else {
            UA_LOG_WARNING(conf->logging, UA_LOGCATEGORY_USERLAND,
                           "Cannot create the Interrupt Manager (only relevant if used)");
        }
#ifdef UA_ENABLE_MQTT
        /* Add the MQTT connection manager */
        UA_ConnectionManager *mqttCM =
            UA_ConnectionManager_new_MQTT(UA_STRING("mqtt connection manager"));
        if(mqttCM)
            conf->eventLoop->registerEventSource(conf->eventLoop, (UA_EventSource *)mqttCM);
#endif
    }
    if(conf->eventLoop != NULL) {
        if(conf->eventLoop->state != UA_EVENTLOOPSTATE_STARTED) {
            UA_StatusCode statusCode = conf->eventLoop->start(conf->eventLoop);
            if(statusCode != UA_STATUSCODE_GOOD) {
                return statusCode;
            }
        }
    }

    /* --> Start setting the default static config <-- */

    conf->shutdownDelay = 0.0;

    /* Server Description */
    UA_BuildInfo_clear(&conf->buildInfo);
    conf->buildInfo.productUri = UA_STRING_ALLOC(PRODUCT_URI);
    conf->buildInfo.manufacturerName = UA_STRING_ALLOC(MANUFACTURER_NAME);
    conf->buildInfo.productName = UA_STRING_ALLOC(PRODUCT_NAME);
    conf->buildInfo.softwareVersion =
        UA_STRING_ALLOC(VERSION(UA_OPEN62541_VER_MAJOR, UA_OPEN62541_VER_MINOR,
                                UA_OPEN62541_VER_PATCH, UA_OPEN62541_VER_LABEL));
#ifdef UA_PACK_DEBIAN
    conf->buildInfo.buildNumber = UA_STRING_ALLOC("deb");
#else
    conf->buildInfo.buildNumber = UA_STRING_ALLOC(__DATE__ " " __TIME__);
#endif
    conf->buildInfo.buildDate = UA_DateTime_now();

    UA_ApplicationDescription_clear(&conf->applicationDescription);
    conf->applicationDescription.applicationUri = UA_STRING_ALLOC(APPLICATION_URI_SERVER);
    conf->applicationDescription.productUri = UA_STRING_ALLOC(PRODUCT_URI);
    conf->applicationDescription.applicationName =
        UA_LOCALIZEDTEXT_ALLOC("en", APPLICATION_NAME);
    conf->applicationDescription.applicationType = UA_APPLICATIONTYPE_SERVER;
    /* conf->applicationDescription.gatewayServerUri = UA_STRING_NULL; */
    /* conf->applicationDescription.discoveryProfileUri = UA_STRING_NULL; */
    /* conf->applicationDescription.discoveryUrlsSize = 0; */
    /* conf->applicationDescription.discoveryUrls = NULL; */

#ifdef UA_ENABLE_DISCOVERY_MULTICAST
    UA_MdnsDiscoveryConfiguration_clear(&conf->mdnsConfig);
    conf->mdnsInterfaceIP = UA_STRING_NULL;
# if !defined(UA_HAS_GETIFADDR)
    conf->mdnsIpAddressList = NULL;
    conf->mdnsIpAddressListSize = 0;
# endif
#endif

    /* Custom DataTypes */
    /* conf->customDataTypesSize = 0; */
    /* conf->customDataTypes = NULL; */

    /* Networking */
    /* Set up the local ServerUrls. They are used during startup to initialize
     * the server sockets. */
    UA_String serverUrls[2];
    size_t serverUrlsSize = 0;
    char hostnamestr[256];
    char serverUrlBuffer[2][512];

    if(portNumber == 0) {
        UA_LOG_WARNING(conf->logging, UA_LOGCATEGORY_USERLAND,
                       "Cannot set the ServerUrl with a zero port");
    } else {
        if(conf->serverUrlsSize > 0) {
            UA_LOG_WARNING(conf->logging, UA_LOGCATEGORY_USERLAND,
                           "ServerUrls already set. Overriding.");
            UA_Array_delete(conf->serverUrls, conf->serverUrlsSize,
                            &UA_TYPES[UA_TYPES_STRING]);
            conf->serverUrls = NULL;
            conf->serverUrlsSize = 0;
        }

        /* 1) Listen on all interfaces (also external). This must be the first
         * entry if this is desired. Otherwise some interfaces may be blocked
         * (already in use) with a hostname that is only locally reachable.*/
        mp_snprintf(serverUrlBuffer[0], sizeof(serverUrlBuffer[0]),
                    "opc.tcp://:%u", portNumber);
        serverUrls[serverUrlsSize] = UA_STRING(serverUrlBuffer[0]);
        serverUrlsSize++;

        /* 2) Use gethostname to get the local hostname. For that temporarily
         * initialize the Winsock API on Win32. */
#ifdef _WIN32
        WSADATA wsaData;
        WSAStartup(MAKEWORD(2, 2), &wsaData);
#endif
        int err = gethostname(hostnamestr, sizeof(hostnamestr));
#ifdef _WIN32
        WSACleanup();
#endif

        if(err == 0) {
            mp_snprintf(serverUrlBuffer[1], sizeof(serverUrlBuffer[1]),
                        "opc.tcp://%s:%u", hostnamestr, portNumber);
            serverUrls[serverUrlsSize] = UA_STRING(serverUrlBuffer[1]);
            serverUrlsSize++;
        }

        /* 3) Add to the config */
        UA_StatusCode retval =
            UA_Array_copy(serverUrls, serverUrlsSize,
                          (void**)&conf->serverUrls, &UA_TYPES[UA_TYPES_STRING]);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
        conf->serverUrlsSize = serverUrlsSize;
    }

    /* Endpoints */
    /* conf->endpoints = {0, NULL}; */

    /* Set Logger for Certificate Verification */
    if(!conf->secureChannelPKI.logging)
        conf->secureChannelPKI.logging = conf->logging;
    if(!conf->sessionPKI.logging)
        conf->sessionPKI.logging = conf->logging;

    /* Certificate Verification that accepts every certificate. Can be
     * overwritten when the policy is specialized. */
    UA_CertificateVerification_AcceptAll(&conf->secureChannelPKI);
    UA_CertificateVerification_AcceptAll(&conf->sessionPKI);

    /* * Global Node Lifecycle * */
    /* conf->nodeLifecycle.constructor = NULL; */
    /* conf->nodeLifecycle.destructor = NULL; */
    /* conf->nodeLifecycle.createOptionalChild = NULL; */
    /* conf->nodeLifecycle.generateChildNodeId = NULL; */
    conf->modellingRulesOnInstances = true;

    /* Limits for SecureChannels */
    conf->maxSecureChannels = 40;
    conf->maxSecurityTokenLifetime = 10 * 60 * 1000; /* 10 minutes */

    /* Limits for Sessions */
    conf->maxSessions = 100;
    conf->maxSessionTimeout = 60.0 * 60.0 * 1000.0; /* 1h */

#ifdef UA_ENABLE_SUBSCRIPTIONS
    /* Limits for Subscriptions */
    conf->publishingIntervalLimits = UA_DURATIONRANGE(100.0, 3600.0 * 1000.0);
    conf->lifeTimeCountLimits = UA_UINT32RANGE(3, 15000);
    conf->keepAliveCountLimits = UA_UINT32RANGE(1, 100);
    conf->maxNotificationsPerPublish = 1000;
    conf->enableRetransmissionQueue = true;
    conf->maxRetransmissionQueueSize = 0; /* unlimited */
# ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
    conf->maxEventsPerNode = 0; /* unlimited */
# endif

    /* Limits for MonitoredItems */
    conf->samplingIntervalLimits = UA_DURATIONRANGE(50.0, 24.0 * 3600.0 * 1000.0);
    conf->queueSizeLimits = UA_UINT32RANGE(1, 100);
#endif

#ifdef UA_ENABLE_DISCOVERY
    conf->discoveryCleanupTimeout = 60 * 60;
#endif

#ifdef UA_ENABLE_HISTORIZING
    /* conf->accessHistoryDataCapability = false; */
    /* conf->maxReturnDataValues = 0; */

    /* conf->accessHistoryEventsCapability = false; */
    /* conf->maxReturnEventValues = 0; */

    /* conf->insertDataCapability = false; */
    /* conf->insertEventCapability = false; */
    /* conf->insertAnnotationsCapability = false; */

    /* conf->replaceDataCapability = false; */
    /* conf->replaceEventCapability = false; */

    /* conf->updateDataCapability = false; */
    /* conf->updateEventCapability = false; */

    /* conf->deleteRawCapability = false; */
    /* conf->deleteEventCapability = false; */
    /* conf->deleteAtTimeDataCapability = false; */
#endif

#if UA_MULTITHREADING >= 100
    conf->maxAsyncOperationQueueSize = 0;
    conf->asyncOperationTimeout = 120000; /* Async Operation Timeout in ms (2 minutes) */
#endif

#ifdef UA_ENABLE_PUBSUB
    conf->pubSubConfig.enableDeltaFrames = true;
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
    conf->pubSubConfig.enableInformationModelMethods = true;
#endif
#endif

    /* --> Finish setting the default static config <-- */

    return UA_STATUSCODE_GOOD;
}

UA_EXPORT UA_StatusCode
UA_ServerConfig_setBasics(UA_ServerConfig* conf) {
    return UA_ServerConfig_setBasics_withPort(conf, 4840);
}

UA_EXPORT UA_StatusCode
UA_ServerConfig_setBasics_withPort(UA_ServerConfig* conf, UA_UInt16 portNumber) {
    return setDefaultConfig(conf, portNumber);
}

UA_EXPORT UA_StatusCode
UA_ServerConfig_addSecurityPolicyNone(UA_ServerConfig *config,
                                      const UA_ByteString *certificate) {
    /* Allocate the SecurityPolicies */
    UA_SecurityPolicy *tmp = (UA_SecurityPolicy *)
        UA_realloc(config->securityPolicies,
                   sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize));
    if(!tmp)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    config->securityPolicies = tmp;

    /* Populate the SecurityPolicies */
    UA_ByteString localCertificate = UA_BYTESTRING_NULL;
    if(certificate)
        localCertificate = *certificate;
    UA_StatusCode retval =
        UA_SecurityPolicy_None(&config->securityPolicies[config->securityPoliciesSize],
                               localCertificate, config->logging);
    if(retval != UA_STATUSCODE_GOOD) {
        if(config->securityPoliciesSize == 0) {
            UA_free(config->securityPolicies);
            config->securityPolicies = NULL;
        }
        return retval;
    }

    config->securityPoliciesSize++;
    return UA_STATUSCODE_GOOD;
}

UA_EXPORT UA_StatusCode
UA_ServerConfig_addEndpoint(UA_ServerConfig *config, const UA_String securityPolicyUri,
                            UA_MessageSecurityMode securityMode) {
    /* Lookup the security policy */
    const UA_SecurityPolicy *policy = NULL;
    for (size_t i = 0; i < config->securityPoliciesSize; ++i) {
        if (UA_String_equal(&securityPolicyUri, &config->securityPolicies[i].policyUri)) {
            policy = &config->securityPolicies[i];
            break;
        }
    }
    if(!policy)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    /* Populate the endpoint */
    return addEndpoint(config, policy, securityMode);
}

UA_EXPORT UA_StatusCode
UA_ServerConfig_addAllEndpoints(UA_ServerConfig *config) {
    /* Populate the endpoints */
    for(size_t i = 0; i < config->securityPoliciesSize; ++i) {
        if(UA_String_equal(&UA_SECURITY_POLICY_NONE_URI, &config->securityPolicies[i].policyUri)) {
            UA_StatusCode retval =
                addEndpoint(config, &config->securityPolicies[i], UA_MESSAGESECURITYMODE_NONE);
            if(retval != UA_STATUSCODE_GOOD)
                return retval;
        } else {
            UA_StatusCode retval =
                addEndpoint(config, &config->securityPolicies[i], UA_MESSAGESECURITYMODE_SIGN);
            if(retval != UA_STATUSCODE_GOOD)
                return retval;
            retval = addEndpoint(config, &config->securityPolicies[i],
                                 UA_MESSAGESECURITYMODE_SIGNANDENCRYPT);
            if(retval != UA_STATUSCODE_GOOD)
                return retval;
        }
    }

    return UA_STATUSCODE_GOOD;
}

UA_EXPORT UA_StatusCode
UA_ServerConfig_addAllSecureEndpoints(UA_ServerConfig *config) {

    /* Delete all predefined endpoints. */
    if(config->endpointsSize > 0) {
        for(size_t i = 0; i < config->endpointsSize; ++i)
            UA_EndpointDescription_clear(&config->endpoints[i]);

        UA_free(config->endpoints);
        config->endpoints = NULL;
        config->endpointsSize = 0;
    }

    /* Populate the endpoints */
    for(size_t i = 0; i < config->securityPoliciesSize; ++i) {
        /* Skip the None and all deprecated policies */
        if(config->securityPolicies[i].securityLevel == 0)
            continue;
        UA_StatusCode retval =
            addEndpoint(config, &config->securityPolicies[i], UA_MESSAGESECURITYMODE_SIGN);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
        retval = addEndpoint(config, &config->securityPolicies[i],
                             UA_MESSAGESECURITYMODE_SIGNANDENCRYPT);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
    }

    return UA_STATUSCODE_GOOD;
}

UA_EXPORT UA_StatusCode
UA_ServerConfig_setMinimalCustomBuffer(UA_ServerConfig *config, UA_UInt16 portNumber,
                                       const UA_ByteString *certificate,
                                       UA_UInt32 sendBufferSize,
                                       UA_UInt32 recvBufferSize) {
    if(!config)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_StatusCode retval = setDefaultConfig(config, portNumber);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ServerConfig_clean(config);
        return retval;
    }

    /* Set the TCP settings */
    config->tcpBufSize = recvBufferSize;

    /* Allocate the SecurityPolicies */
    retval = UA_ServerConfig_addSecurityPolicyNone(config, certificate);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ServerConfig_clean(config);
        return retval;
    }

    /* Initialize the Access Control plugin */
    retval = UA_AccessControl_default(config, true, NULL, 0, NULL);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ServerConfig_clean(config);
        return retval;
    }

    /* Allocate the endpoint */
    retval = UA_ServerConfig_addEndpoint(config, UA_SECURITY_POLICY_NONE_URI,
                                         UA_MESSAGESECURITYMODE_NONE);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ServerConfig_clean(config);
        return retval;
    }

    return UA_STATUSCODE_GOOD;
}

#ifdef UA_ENABLE_ENCRYPTION

UA_EXPORT UA_StatusCode
UA_ServerConfig_addSecurityPolicyBasic128Rsa15(UA_ServerConfig *config,
                                               const UA_ByteString *certificate,
                                               const UA_ByteString *privateKey) {
    /* Allocate the SecurityPolicies */
    UA_SecurityPolicy *tmp = (UA_SecurityPolicy *)
        UA_realloc(config->securityPolicies,
                   sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize));
    if(!tmp)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    config->securityPolicies = tmp;

    /* Populate the SecurityPolicies */
    UA_ByteString localCertificate = UA_BYTESTRING_NULL;
    UA_ByteString localPrivateKey  = UA_BYTESTRING_NULL;
    if(certificate)
        localCertificate = *certificate;
    if(privateKey)
       localPrivateKey = *privateKey;
    UA_StatusCode retval =
        UA_SecurityPolicy_Basic128Rsa15(&config->securityPolicies[config->securityPoliciesSize],
                                        localCertificate, localPrivateKey, config->logging);
    if(retval != UA_STATUSCODE_GOOD) {
        if(config->securityPoliciesSize == 0) {
            UA_free(config->securityPolicies);
            config->securityPolicies = NULL;
        }
        return retval;
    }

    config->securityPoliciesSize++;
    return UA_STATUSCODE_GOOD;
}

UA_EXPORT UA_StatusCode
UA_ServerConfig_addSecurityPolicyBasic256(UA_ServerConfig *config,
                                          const UA_ByteString *certificate,
                                          const UA_ByteString *privateKey) {
    /* Allocate the SecurityPolicies */
    UA_SecurityPolicy *tmp = (UA_SecurityPolicy *)
        UA_realloc(config->securityPolicies,
                   sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize));
    if(!tmp)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    config->securityPolicies = tmp;

    /* Populate the SecurityPolicies */
    UA_ByteString localCertificate = UA_BYTESTRING_NULL;
    UA_ByteString localPrivateKey  = UA_BYTESTRING_NULL;
    if(certificate)
        localCertificate = *certificate;
    if(privateKey)
       localPrivateKey = *privateKey;
    UA_StatusCode retval =
        UA_SecurityPolicy_Basic256(&config->securityPolicies[config->securityPoliciesSize],
                                   localCertificate, localPrivateKey, config->logging);
    if(retval != UA_STATUSCODE_GOOD) {
        if(config->securityPoliciesSize == 0) {
            UA_free(config->securityPolicies);
            config->securityPolicies = NULL;
        }
        return retval;
    }

    config->securityPoliciesSize++;
    return UA_STATUSCODE_GOOD;
}

UA_EXPORT UA_StatusCode
UA_ServerConfig_addSecurityPolicyBasic256Sha256(UA_ServerConfig *config,
                                                const UA_ByteString *certificate,
                                                const UA_ByteString *privateKey) {
    /* Allocate the SecurityPolicies */
    UA_SecurityPolicy *tmp = (UA_SecurityPolicy *)
        UA_realloc(config->securityPolicies,
                   sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize));
    if(!tmp)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    config->securityPolicies = tmp;

    /* Populate the SecurityPolicies */
    UA_ByteString localCertificate = UA_BYTESTRING_NULL;
    UA_ByteString localPrivateKey  = UA_BYTESTRING_NULL;
    if(certificate)
        localCertificate = *certificate;
    if(privateKey)
       localPrivateKey = *privateKey;
    UA_StatusCode retval =
        UA_SecurityPolicy_Basic256Sha256(&config->securityPolicies[config->securityPoliciesSize],
                                         localCertificate, localPrivateKey, config->logging);
    if(retval != UA_STATUSCODE_GOOD) {
        if(config->securityPoliciesSize == 0) {
            UA_free(config->securityPolicies);
            config->securityPolicies = NULL;
        }
        return retval;
    }

    config->securityPoliciesSize++;
    return UA_STATUSCODE_GOOD;
}

UA_EXPORT UA_StatusCode
UA_ServerConfig_addSecurityPolicyAes128Sha256RsaOaep(UA_ServerConfig *config,
                                                const UA_ByteString *certificate,
                                                const UA_ByteString *privateKey) {
    /* Allocate the SecurityPolicies */
    UA_SecurityPolicy *tmp = (UA_SecurityPolicy *)
        UA_realloc(config->securityPolicies,
                   sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize));
    if(!tmp)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    config->securityPolicies = tmp;

    /* Populate the SecurityPolicies */
    UA_ByteString localCertificate = UA_BYTESTRING_NULL;
    UA_ByteString localPrivateKey  = UA_BYTESTRING_NULL;
    if(certificate)
        localCertificate = *certificate;
    if(privateKey)
       localPrivateKey = *privateKey;
    UA_StatusCode retval =
        UA_SecurityPolicy_Aes128Sha256RsaOaep(&config->securityPolicies[config->securityPoliciesSize],
                                              localCertificate, localPrivateKey, config->logging);
    if(retval != UA_STATUSCODE_GOOD) {
        if(config->securityPoliciesSize == 0) {
            UA_free(config->securityPolicies);
            config->securityPolicies = NULL;
        }
        return retval;
    }

    config->securityPoliciesSize++;
    return UA_STATUSCODE_GOOD;
}

UA_EXPORT UA_StatusCode
UA_ServerConfig_addSecurityPolicyAes256Sha256RsaPss(UA_ServerConfig *config,
                                                     const UA_ByteString *certificate,
                                                     const UA_ByteString *privateKey) {
    /* Allocate the SecurityPolicies */
    UA_SecurityPolicy *tmp = (UA_SecurityPolicy *)
        UA_realloc(config->securityPolicies,
                   sizeof(UA_SecurityPolicy) * (1 + config->securityPoliciesSize));
    if(!tmp)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    config->securityPolicies = tmp;

    /* Populate the SecurityPolicies */
    UA_ByteString localCertificate = UA_BYTESTRING_NULL;
    UA_ByteString localPrivateKey  = UA_BYTESTRING_NULL;
    if(certificate)
        localCertificate = *certificate;
    if(privateKey)
        localPrivateKey = *privateKey;
    UA_StatusCode retval =
        UA_SecurityPolicy_Aes256Sha256RsaPss(&config->securityPolicies[config->securityPoliciesSize],
                                              localCertificate, localPrivateKey, config->logging);
    if(retval != UA_STATUSCODE_GOOD) {
        if(config->securityPoliciesSize == 0) {
            UA_free(config->securityPolicies);
            config->securityPolicies = NULL;
        }
        return retval;
    }

    config->securityPoliciesSize++;
    return UA_STATUSCODE_GOOD;
}

/* Always returns UA_STATUSCODE_GOOD. Logs a warning if policies could not be added. */
static UA_StatusCode
addAllSecurityPolicies(UA_ServerConfig *config, const UA_ByteString *certificate,
                       const UA_ByteString *privateKey, UA_Boolean onlySecure) {
    /* Populate the SecurityPolicies */
    UA_ByteString localCertificate = UA_BYTESTRING_NULL;
    UA_ByteString localPrivateKey  = UA_BYTESTRING_NULL;
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(certificate)
        localCertificate = *certificate;
    if(privateKey)
       localPrivateKey = *privateKey;

    /* Load the private key and convert to the DER format. Use an empty password
     * on the first try -- maybe the key does not require a password. */
    UA_ByteString decryptedPrivateKey = UA_BYTESTRING_NULL;
    UA_ByteString keyPassword = UA_BYTESTRING_NULL;
    UA_StatusCode keySuccess = UA_STATUSCODE_GOOD;

    if (privateKey && privateKey->length > 0)
        keySuccess = UA_CertificateUtils_decryptPrivateKey(localPrivateKey, keyPassword,
                                              &decryptedPrivateKey);

    /* Get the password and decrypt. An application might want to loop / retry
     * here to allow users to correct their entry. */
    if(keySuccess != UA_STATUSCODE_GOOD) {
        if(config->privateKeyPasswordCallback)
            keySuccess = config->privateKeyPasswordCallback(config, &keyPassword);
        else
            keySuccess = readPrivateKeyPassword(&keyPassword);
        if(keySuccess != UA_STATUSCODE_GOOD)
            return keySuccess;
        keySuccess = UA_CertificateUtils_decryptPrivateKey(localPrivateKey, keyPassword,
                                              &decryptedPrivateKey);
        UA_ByteString_memZero(&keyPassword);
        UA_ByteString_clear(&keyPassword);
    }
    if(keySuccess != UA_STATUSCODE_GOOD)
        return keySuccess;

    /* Basic256Sha256 */
    retval = UA_ServerConfig_addSecurityPolicyBasic256Sha256(config, &localCertificate,
                                                             &decryptedPrivateKey);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
                       "Could not add SecurityPolicy#Basic256Sha256 with error code %s",
                       UA_StatusCode_name(retval));
    }

    /* Aes256Sha256RsaPss */
    retval = UA_ServerConfig_addSecurityPolicyAes256Sha256RsaPss(config, &localCertificate,
                                                                 &decryptedPrivateKey);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
                       "Could not add SecurityPolicy#Aes256Sha256RsaPss with error code %s",
                       UA_StatusCode_name(retval));
    }

    /* Aes128Sha256RsaOaep */
    retval = UA_ServerConfig_addSecurityPolicyAes128Sha256RsaOaep(config, &localCertificate,
                                                                  &decryptedPrivateKey);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
                       "Could not add SecurityPolicy#Aes128Sha256RsaOaep with error code %s",
                       UA_StatusCode_name(retval));
    }

    if(onlySecure) {
        UA_ByteString_memZero(&decryptedPrivateKey);
        UA_ByteString_clear(&decryptedPrivateKey);
        return UA_STATUSCODE_GOOD;
    }

    /* None */
    retval = UA_ServerConfig_addSecurityPolicyNone(config, &localCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
                       "Could not add SecurityPolicy#None with error code %s",
                       UA_StatusCode_name(retval));
    }

    /* Basic128Rsa15 */
    retval = UA_ServerConfig_addSecurityPolicyBasic128Rsa15(config, &localCertificate,
                                                            &decryptedPrivateKey);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
                       "Could not add SecurityPolicy#Basic128Rsa15 with error code %s",
                       UA_StatusCode_name(retval));
    }

    /* Basic256 */
    retval = UA_ServerConfig_addSecurityPolicyBasic256(config, &localCertificate,
                                                       &decryptedPrivateKey);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
                       "Could not add SecurityPolicy#Basic256 with error code %s",
                       UA_StatusCode_name(retval));
    }

    UA_ByteString_memZero(&decryptedPrivateKey);
    UA_ByteString_clear(&decryptedPrivateKey);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_ServerConfig_addAllSecurityPolicies(UA_ServerConfig *config,
                                       const UA_ByteString *certificate,
                                       const UA_ByteString *privateKey) {
    return addAllSecurityPolicies(config, certificate, privateKey, false);
}

/* Always returns UA_STATUSCODE_GOOD. Logs a warning if policies could not be added. */
UA_StatusCode
UA_ServerConfig_addAllSecureSecurityPolicies(UA_ServerConfig *config,
                                             const UA_ByteString *certificate,
                                             const UA_ByteString *privateKey) {
    return addAllSecurityPolicies(config, certificate, privateKey, true);

}

UA_EXPORT UA_StatusCode
UA_ServerConfig_setDefaultWithSecurityPolicies(UA_ServerConfig *conf,
                                               UA_UInt16 portNumber,
                                               const UA_ByteString *certificate,
                                               const UA_ByteString *privateKey,
                                               const UA_ByteString *trustList,
                                               size_t trustListSize,
                                               const UA_ByteString *issuerList,
                                               size_t issuerListSize,
                                               const UA_ByteString *revocationList,
                                               size_t revocationListSize) {
    UA_StatusCode retval = setDefaultConfig(conf, portNumber);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ServerConfig_clean(conf);
        return retval;
    }

    retval = UA_CertificateVerification_Trustlist(&conf->sessionPKI,
                                                  trustList, trustListSize,
                                                  issuerList, issuerListSize,
                                                  revocationList, revocationListSize);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    retval = UA_CertificateVerification_Trustlist(&conf->secureChannelPKI,
                                                  trustList, trustListSize,
                                                  issuerList, issuerListSize,
                                                  revocationList, revocationListSize);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    retval = UA_ServerConfig_addAllSecurityPolicies(conf, certificate, privateKey);

    if(retval == UA_STATUSCODE_GOOD) {
        retval = UA_AccessControl_default(conf, true, NULL, 0, NULL);
    }
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ServerConfig_clean(conf);
        return retval;
    }

    retval = UA_ServerConfig_addAllEndpoints(conf);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ServerConfig_clean(conf);
        return retval;
    }

    return UA_STATUSCODE_GOOD;
}

UA_EXPORT UA_StatusCode
UA_ServerConfig_setDefaultWithSecureSecurityPolicies(UA_ServerConfig *conf,
                                               UA_UInt16 portNumber,
                                               const UA_ByteString *certificate,
                                               const UA_ByteString *privateKey,
                                               const UA_ByteString *trustList,
                                               size_t trustListSize,
                                               const UA_ByteString *issuerList,
                                               size_t issuerListSize,
                                               const UA_ByteString *revocationList,
                                               size_t revocationListSize) {
    UA_StatusCode retval = setDefaultConfig(conf, portNumber);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ServerConfig_clean(conf);
        return retval;
    }

    retval = UA_CertificateVerification_Trustlist(&conf->sessionPKI,
                                                  trustList, trustListSize,
                                                  issuerList, issuerListSize,
                                                  revocationList, revocationListSize);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    retval = UA_CertificateVerification_Trustlist(&conf->secureChannelPKI,
                                                  trustList, trustListSize,
                                                  issuerList, issuerListSize,
                                                  revocationList, revocationListSize);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    retval = UA_ServerConfig_addAllSecureSecurityPolicies(conf, certificate, privateKey);

    if(retval == UA_STATUSCODE_GOOD) {
        retval = UA_AccessControl_default(conf, false, NULL, 0, NULL);
    }
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ServerConfig_clean(conf);
        return retval;
    }

    retval = UA_ServerConfig_addAllSecureEndpoints(conf);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ServerConfig_clean(conf);
        return retval;
    }
    conf->securityPolicyNoneDiscoveryOnly = true;

    return UA_STATUSCODE_GOOD;
}

#endif

/***************************/
/* Default Client Settings */
/***************************/

UA_Client * UA_Client_new(void) {
    UA_ClientConfig config;
    memset(&config, 0, sizeof(UA_ClientConfig));
    /* Set up basic usable config including logger and event loop */
    UA_StatusCode res = UA_ClientConfig_setDefault(&config);
    if(res != UA_STATUSCODE_GOOD)
        return NULL;
    return UA_Client_newWithConfig(&config);
}

UA_StatusCode
UA_ClientConfig_setDefault(UA_ClientConfig *config) {
    /* The following fields are untouched and OK to leave as NULL or 0:
     *  clientContext
     *  userIdentityToken
     *  securityMode
     *  securityPolicyUri
     *  endpoint
     *  userTokenPolicy
     *  customDataTypes
     *  connectivityCheckInterval
     *  stateCallback
     *  inactivityCallback
     *  outStandingPublishRequests
     *  subscriptionInactivityCallback
     *  sessionLocaleIds
     *  sessionLocaleIdsSize */

    if(config->timeout == 0)
        config->timeout = 5 * 1000; /* 5 seconds */
    if(config->secureChannelLifeTime == 0)
        config->secureChannelLifeTime = 10 * 60 * 1000; /* 10 minutes */

    if(config->logging == NULL)
        config->logging = UA_Log_Stdout_new(UA_LOGLEVEL_INFO);

    /* EventLoop */
    if(config->eventLoop == NULL) {
        config->eventLoop = UA_EventLoop_new_POSIX(config->logging);
        config->externalEventLoop = false;

        /* Add the TCP connection manager */
        UA_ConnectionManager *tcpCM =
            UA_ConnectionManager_new_POSIX_TCP(UA_STRING("tcp connection manager"));
        config->eventLoop->registerEventSource(config->eventLoop, (UA_EventSource *)tcpCM);

        /* Add the UDP connection manager */
        UA_ConnectionManager *udpCM =
            UA_ConnectionManager_new_POSIX_UDP(UA_STRING("udp connection manager"));
        config->eventLoop->registerEventSource(config->eventLoop, (UA_EventSource *)udpCM);
    }

    if(config->localConnectionConfig.recvBufferSize == 0)
        config->localConnectionConfig = UA_ConnectionConfig_default;

    if(!config->certificateVerification.logging) {
        config->certificateVerification.logging = config->logging;
    }

    if(!config->certificateVerification.verifyCertificate) {
        /* Certificate Verification that accepts every certificate. Can be
         * overwritten when the policy is specialized. */
        UA_CertificateVerification_AcceptAll(&config->certificateVerification);
    }

    /* With encryption enabled, the applicationUri needs to match the URI from
     * the certificate */
    if(!config->clientDescription.applicationUri.data)
        config->clientDescription.applicationUri = UA_STRING_ALLOC(APPLICATION_URI);
    if(config->clientDescription.applicationType == 0)
        config->clientDescription.applicationType = UA_APPLICATIONTYPE_CLIENT;

    if(config->securityPoliciesSize == 0) {
        config->securityPolicies = (UA_SecurityPolicy*)UA_malloc(sizeof(UA_SecurityPolicy));
        if(!config->securityPolicies)
            return UA_STATUSCODE_BADOUTOFMEMORY;
        UA_StatusCode retval = UA_SecurityPolicy_None(config->securityPolicies,
                                                      UA_BYTESTRING_NULL, config->logging);
        if(retval != UA_STATUSCODE_GOOD) {
            UA_free(config->securityPolicies);
            config->securityPolicies = NULL;
            return retval;
        }
        config->securityPoliciesSize = 1;
    }

    if(config->requestedSessionTimeout == 0)
        config->requestedSessionTimeout = 1200000;

#ifdef UA_ENABLE_SUBSCRIPTIONS
    if(config->outStandingPublishRequests == 0)
        config->outStandingPublishRequests = 10;
#endif

    return UA_STATUSCODE_GOOD;
}

#ifdef UA_ENABLE_ENCRYPTION

UA_StatusCode
UA_ClientConfig_setDefaultEncryption(UA_ClientConfig *config,
                                     UA_ByteString localCertificate, UA_ByteString privateKey,
                                     const UA_ByteString *trustList, size_t trustListSize,
                                     const UA_ByteString *revocationList, size_t revocationListSize) {
    UA_StatusCode retval = UA_ClientConfig_setDefault(config);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    retval = UA_CertificateVerification_Trustlist(&config->certificateVerification,
                                                  trustList, trustListSize,
                                                  NULL, 0,
                                                  revocationList, revocationListSize);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Populate SecurityPolicies */
    UA_SecurityPolicy *sp = (UA_SecurityPolicy*)
        UA_realloc(config->securityPolicies, sizeof(UA_SecurityPolicy) * SECURITY_POLICY_SIZE);
    if(!sp)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    config->securityPolicies = sp;

    /* Load the private key and convert to the DER format. Use an empty password
     * on the first try -- maybe the key does not require a password. */
    UA_ByteString decryptedPrivateKey = UA_BYTESTRING_NULL;
    UA_ByteString keyPassword = UA_BYTESTRING_NULL;
    UA_StatusCode keySuccess = UA_STATUSCODE_GOOD;

    if (privateKey.length > 0)
        keySuccess = UA_CertificateUtils_decryptPrivateKey(privateKey, keyPassword,
                                              &decryptedPrivateKey);

    /* Get the password and decrypt. An application might want to loop / retry
     * here to allow users to correct their entry. */
    if(keySuccess != UA_STATUSCODE_GOOD) {
        if(config->privateKeyPasswordCallback)
            keySuccess = config->privateKeyPasswordCallback(config, &keyPassword);
        else
            keySuccess = readPrivateKeyPassword(&keyPassword);
        if(keySuccess != UA_STATUSCODE_GOOD)
            return keySuccess;
        keySuccess = UA_CertificateUtils_decryptPrivateKey(privateKey, keyPassword, &decryptedPrivateKey);
        UA_ByteString_memZero(&keyPassword);
        UA_ByteString_clear(&keyPassword);
    }
    if(keySuccess != UA_STATUSCODE_GOOD)
        return keySuccess;

    retval = UA_SecurityPolicy_Basic128Rsa15(&config->securityPolicies[config->securityPoliciesSize],
                                             localCertificate, decryptedPrivateKey, config->logging);
    if(retval == UA_STATUSCODE_GOOD) {
        ++config->securityPoliciesSize;
    } else {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
                       "Could not add SecurityPolicy#Basic128Rsa15 with error code %s",
                       UA_StatusCode_name(retval));
    }

    retval = UA_SecurityPolicy_Basic256(&config->securityPolicies[config->securityPoliciesSize],
                                        localCertificate, decryptedPrivateKey, config->logging);

    if(retval == UA_STATUSCODE_GOOD) {
        ++config->securityPoliciesSize;
    } else {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
                       "Could not add SecurityPolicy#Basic256 with error code %s",
                       UA_StatusCode_name(retval));
    }

    retval = UA_SecurityPolicy_Aes256Sha256RsaPss(&config->securityPolicies[config->securityPoliciesSize],
                                                  localCertificate, decryptedPrivateKey, config->logging);
    if(retval == UA_STATUSCODE_GOOD) {
        ++config->securityPoliciesSize;
    } else {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
                       "Could not add SecurityPolicy#Aes256Sha256RsaPss with error code %s",
                       UA_StatusCode_name(retval));
    }

    retval = UA_SecurityPolicy_Basic256Sha256(&config->securityPolicies[config->securityPoliciesSize],
                                              localCertificate, decryptedPrivateKey, config->logging);
    if(retval == UA_STATUSCODE_GOOD) {
        ++config->securityPoliciesSize;
    } else {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
                       "Could not add SecurityPolicy#Basic256Sha256 with error code %s",
                       UA_StatusCode_name(retval));
    }

    retval = UA_SecurityPolicy_Aes128Sha256RsaOaep(&config->securityPolicies[config->securityPoliciesSize],
                                                   localCertificate, decryptedPrivateKey, config->logging);
    if(retval == UA_STATUSCODE_GOOD) {
        ++config->securityPoliciesSize;
    } else {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
                       "Could not add SecurityPolicy#Aes128Sha256RsaOaep with error code %s",
                       UA_StatusCode_name(retval));
    }

    UA_ByteString_memZero(&decryptedPrivateKey);
    UA_ByteString_clear(&decryptedPrivateKey);

    if(config->securityPoliciesSize == 0) {
        UA_free(config->securityPolicies);
        config->securityPolicies = NULL;
    }

    return UA_STATUSCODE_GOOD;
}
#endif

#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_MBEDTLS)
UA_StatusCode
UA_ClientConfig_setAuthenticationCert(UA_ClientConfig *config,
                                      UA_ByteString certificateAuth,
                                      UA_ByteString privateKeyAuth) {
#ifdef UA_ENABLE_ENCRYPTION_LIBRESSL
    UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
                   "Certificate authentication with LibreSSL as crypto backend is not supported.");
    return UA_STATUSCODE_BADNOTIMPLEMENTED;
#endif
    /* Create UserIdentityToken */
    UA_X509IdentityToken* identityToken = UA_X509IdentityToken_new();
    if(!identityToken)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    /* Don't set identityToken->policyId. This is taken from the appropriate
     * endpoint at runtime. */
    UA_StatusCode retval = UA_ByteString_copy(&certificateAuth, &identityToken->certificateData);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_ExtensionObject_clear(&config->userIdentityToken);
    config->userIdentityToken.encoding = UA_EXTENSIONOBJECT_DECODED;
    config->userIdentityToken.content.decoded.type = &UA_TYPES[UA_TYPES_X509IDENTITYTOKEN];
    config->userIdentityToken.content.decoded.data = identityToken;

    /* Populate SecurityPolicies */
    UA_SecurityPolicy *sp = (UA_SecurityPolicy*)
        UA_realloc(config->authSecurityPolicies, sizeof(UA_SecurityPolicy) * 5);
    if(!sp)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    config->authSecurityPolicies = sp;

    retval = UA_SecurityPolicy_Basic128Rsa15(&config->authSecurityPolicies[config->authSecurityPoliciesSize],
                                                           certificateAuth, privateKeyAuth, config->logging);
    if(retval == UA_STATUSCODE_GOOD) {
        ++config->authSecurityPoliciesSize;
    } else {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
                       "Could not add SecurityPolicy#Basic128Rsa15 with error code %s",
                       UA_StatusCode_name(retval));
    }

    retval = UA_SecurityPolicy_Basic256(&config->authSecurityPolicies[config->authSecurityPoliciesSize],
                                        certificateAuth, privateKeyAuth, config->logging);
    if(retval == UA_STATUSCODE_GOOD) {
        ++config->authSecurityPoliciesSize;
    } else {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
                       "Could not add SecurityPolicy#Basic256 with error code %s",
                       UA_StatusCode_name(retval));
    }

    retval = UA_SecurityPolicy_Aes256Sha256RsaPss(&config->authSecurityPolicies[config->authSecurityPoliciesSize],
                                                   certificateAuth, privateKeyAuth, config->logging);
    if(retval == UA_STATUSCODE_GOOD) {
        ++config->authSecurityPoliciesSize;
    } else {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
                       "Could not add SecurityPolicy#Aes256Sha256RsaPss with error code %s",
                       UA_StatusCode_name(retval));
    }

    retval = UA_SecurityPolicy_Basic256Sha256(&config->authSecurityPolicies[config->authSecurityPoliciesSize],
                                              certificateAuth, privateKeyAuth, config->logging);
    if(retval == UA_STATUSCODE_GOOD) {
        ++config->authSecurityPoliciesSize;
    } else {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
                       "Could not add SecurityPolicy#Basic256Sha256 with error code %s",
                       UA_StatusCode_name(retval));
    }

    retval = UA_SecurityPolicy_Aes128Sha256RsaOaep(&config->authSecurityPolicies[config->authSecurityPoliciesSize],
                                                   certificateAuth, privateKeyAuth, config->logging);
    if(retval == UA_STATUSCODE_GOOD) {
        ++config->authSecurityPoliciesSize;
    } else {
        UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
                       "Could not add SecurityPolicy#Aes128Sha256RsaOaep with error code %s",
                       UA_StatusCode_name(retval));
    }

    if(config->authSecurityPoliciesSize == 0) {
        UA_free(config->authSecurityPolicies);
        config->authSecurityPolicies = NULL;
    }
    return UA_STATUSCODE_GOOD;
}
#endif

/**** amalgamated original file "/plugins/crypto/ua_certificategroup_none.c" ****/

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
 *
 *    Copyright 2020 (c) Julius Pfrommer, Fraunhofer IOSB
 *    Copyright 2024 (c) Fraunhofer IOSB (Author: Noel Graf)
 */


static UA_StatusCode
verifyCertificateAllowAll(UA_CertificateGroup *certGroup,
                          const UA_ByteString *certificate) {
    UA_LOG_WARNING(certGroup->logging, UA_LOGCATEGORY_USERLAND,
                   "No certificate store configured. Accepting the certificate.");
    return UA_STATUSCODE_GOOD;
}

static void
clearVerifyAllowAll(UA_CertificateGroup *certGroup) {

}

void UA_CertificateVerification_AcceptAll(UA_CertificateGroup *certGroup) {
    /* Clear the structure, as it may have already been initialized. */
    if(certGroup->clear)
        certGroup->clear(certGroup);
    certGroup->verifyCertificate = verifyCertificateAllowAll;
    certGroup->clear = clearVerifyAllowAll;
    certGroup->getTrustList = NULL;
    certGroup->setTrustList = NULL;
    certGroup->addToTrustList = NULL;
    certGroup->removeFromTrustList = NULL;
}

#ifndef UA_ENABLE_ENCRYPTION
UA_StatusCode
UA_CertificateUtils_verifyApplicationURI(UA_RuleHandling ruleHandling,
                                         const UA_ByteString *certificate,
                                         const UA_String *applicationURI){
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_CertificateUtils_getExpirationDate(UA_ByteString *certificate,
                                      UA_DateTime *expiryDateTime){
    return UA_STATUSCODE_BADNOTSUPPORTED;
}

UA_StatusCode
UA_CertificateUtils_getSubjectName(UA_ByteString *certificate,
                                   UA_String *subjectName){
    return UA_STATUSCODE_BADNOTSUPPORTED;
}

UA_StatusCode
UA_CertificateUtils_getThumbprint(UA_ByteString *certificate,
                                  UA_String *thumbprint){
    return UA_STATUSCODE_BADNOTSUPPORTED;
}
#endif

/**** amalgamated original file "/plugins/crypto/ua_securitypolicy_none.c" ****/

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
 *
 *    Copyright 2017-2018 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 */


#ifdef UA_ENABLE_ENCRYPTION_MBEDTLS
#endif

#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL)
#endif

static UA_StatusCode
verify_none(void *channelContext,
            const UA_ByteString *message,
            const UA_ByteString *signature) {
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
sign_none(void *channelContext, const UA_ByteString *message,
          UA_ByteString *signature) {
    return UA_STATUSCODE_GOOD;
}

static size_t
length_none(const void *channelContext) {
    return 0;
}

static UA_StatusCode
encrypt_none(void *channelContext, UA_ByteString *data) {
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
decrypt_none(void *channelContext, UA_ByteString *data) {
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
makeThumbprint_none(const UA_SecurityPolicy *securityPolicy,
                    const UA_ByteString *certificate,
                    UA_ByteString *thumbprint) {
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
compareThumbprint_none(const UA_SecurityPolicy *securityPolicy,
                       const UA_ByteString *certificateThumbprint) {
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
generateKey_none(void *policyContext, const UA_ByteString *secret,
                 const UA_ByteString *seed, UA_ByteString *out) {
    return UA_STATUSCODE_GOOD;
}

/* Use the non-cryptographic RNG to set the nonce */
static UA_StatusCode
generateNonce_none(void *policyContext, UA_ByteString *out) {
    if(out == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(out->length == 0)
        return UA_STATUSCODE_GOOD;

    /* Fill blocks of four byte */
    size_t i = 0;
    while(i + 3 < out->length) {
        UA_UInt32 randNumber = UA_UInt32_random();
        memcpy(&out->data[i], &randNumber, 4);
        i = i+4;
    }

    /* Fill the remaining byte */
    UA_UInt32 randNumber = UA_UInt32_random();
    memcpy(&out->data[i], &randNumber, out->length % 4);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
newContext_none(const UA_SecurityPolicy *securityPolicy,
                const UA_ByteString *remoteCertificate,
                void **channelContext) {
    return UA_STATUSCODE_GOOD;
}

static void
deleteContext_none(void *channelContext) {
}

static UA_StatusCode
setContextValue_none(void *channelContext,
                     const UA_ByteString *key) {
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
compareCertificate_none(const void *channelContext,
                        const UA_ByteString *certificate) {
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
updateCertificateAndPrivateKey_none(UA_SecurityPolicy *policy,
                                    const UA_ByteString newCertificate,
                                    const UA_ByteString newPrivateKey) {
    UA_ByteString_clear(&policy->localCertificate);
    UA_ByteString_copy(&newCertificate, &policy->localCertificate);
    return UA_STATUSCODE_GOOD;
}


static void
policy_clear_none(UA_SecurityPolicy *policy) {
    UA_ByteString_clear(&policy->localCertificate);
}

UA_StatusCode
UA_SecurityPolicy_None(UA_SecurityPolicy *policy, const UA_ByteString localCertificate,
                       const UA_Logger *logger) {
    policy->policyContext = (void *)(uintptr_t)logger;
    policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None");
    policy->securityLevel = 0;
    policy->logger = logger;

#ifdef UA_ENABLE_ENCRYPTION_MBEDTLS
    UA_mbedTLS_LoadLocalCertificate(&localCertificate, &policy->localCertificate);
#elif defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL)
    UA_OpenSSL_LoadLocalCertificate(&localCertificate, &policy->localCertificate);
#else
    UA_ByteString_copy(&localCertificate, &policy->localCertificate);
#endif

    policy->symmetricModule.generateKey = generateKey_none;
    policy->symmetricModule.generateNonce = generateNonce_none;

    UA_SecurityPolicySignatureAlgorithm *sym_signatureAlgorithm =
        &policy->symmetricModule.cryptoModule.signatureAlgorithm;
    sym_signatureAlgorithm->uri = UA_STRING_NULL;
    sym_signatureAlgorithm->verify = verify_none;
    sym_signatureAlgorithm->sign = sign_none;
    sym_signatureAlgorithm->getLocalSignatureSize = length_none;
    sym_signatureAlgorithm->getRemoteSignatureSize = length_none;
    sym_signatureAlgorithm->getLocalKeyLength = length_none;
    sym_signatureAlgorithm->getRemoteKeyLength = length_none;

    UA_SecurityPolicyEncryptionAlgorithm *sym_encryptionAlgorithm =
        &policy->symmetricModule.cryptoModule.encryptionAlgorithm;
    sym_encryptionAlgorithm->uri = UA_STRING_NULL;
    sym_encryptionAlgorithm->encrypt = encrypt_none;
    sym_encryptionAlgorithm->decrypt = decrypt_none;
    sym_encryptionAlgorithm->getLocalKeyLength = length_none;
    sym_encryptionAlgorithm->getRemoteKeyLength = length_none;
    sym_encryptionAlgorithm->getRemoteBlockSize = length_none;
    sym_encryptionAlgorithm->getRemotePlainTextBlockSize = length_none;
    policy->symmetricModule.secureChannelNonceLength = 0;

    policy->asymmetricModule.makeCertificateThumbprint = makeThumbprint_none;
    policy->asymmetricModule.compareCertificateThumbprint = compareThumbprint_none;

    // This only works for none since symmetric and asymmetric crypto modules do the same i.e. nothing
    policy->asymmetricModule.cryptoModule = policy->symmetricModule.cryptoModule;

    // Use the same signing algorithm as for asymmetric signing
    policy->certificateSigningAlgorithm = policy->asymmetricModule.cryptoModule.signatureAlgorithm;

    policy->channelModule.newContext = newContext_none;
    policy->channelModule.deleteContext = deleteContext_none;
    policy->channelModule.setLocalSymEncryptingKey = setContextValue_none;
    policy->channelModule.setLocalSymSigningKey = setContextValue_none;
    policy->channelModule.setLocalSymIv = setContextValue_none;
    policy->channelModule.setRemoteSymEncryptingKey = setContextValue_none;
    policy->channelModule.setRemoteSymSigningKey = setContextValue_none;
    policy->channelModule.setRemoteSymIv = setContextValue_none;
    policy->channelModule.compareCertificate = compareCertificate_none;
    policy->updateCertificateAndPrivateKey = updateCertificateAndPrivateKey_none;
    policy->clear = policy_clear_none;

    return UA_STATUSCODE_GOOD;
}

/**** amalgamated original file "/plugins/eventloop/eventloop_timer.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2017, 2018, 2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 */



_UA_BEGIN_DECLS

/* The timer is protected by its own mutex. The mutex is released before calling
 * into the callbacks. So the timer can be modified from the callbacks it is
 * executing. Also, the timer mutex can never lead to locking. Because the timer
 * mutex will be left without acquiring another mutex.
 *
 * Obviously, the timer must not be deleted from within one of its
 * callbacks. */

/* Callback where the application is either a client or a server */
typedef void (*UA_ApplicationCallback)(void *application, void *data);

typedef struct UA_TimerEntry {
    ZIP_ENTRY(UA_TimerEntry) treeEntry;
    UA_TimerPolicy timerPolicy;      /* Timer policy to handle cycle misses */
    UA_DateTime nextTime;            /* The next time when the callback is to be
                                      * executed */
    UA_UInt64 interval;              /* Interval in 100ns resolution. If the
                                      * interval is zero, the callback is not
                                      * repeated and removed after execution. */
    UA_ApplicationCallback callback; /* This is also a sentinel value. If the
                                      * callback is NULL, then the entry is
                                      * marked for deletion. */
    void *application;
    void *data;

    ZIP_ENTRY(UA_TimerEntry) idTreeEntry;
    UA_UInt64 id;                            /* Id of the entry */
} UA_TimerEntry;

typedef ZIP_HEAD(UA_TimerTree, UA_TimerEntry) UA_TimerTree;
typedef ZIP_HEAD(UA_TimerIdTree, UA_TimerEntry) UA_TimerIdTree;

typedef struct {
    UA_TimerTree tree;     /* The root of the time-sorted tree */
    UA_TimerIdTree idTree; /* The root of the id-sorted tree */
    UA_UInt64 idCounter;   /* Generate unique identifiers. Identifiers are
                            * always above zero. */
#if UA_MULTITHREADING >= 100
    UA_Lock timerMutex;
#endif

    UA_TimerTree processTree; /* When the timer is processed, all entries that
                               * need processing now are moved to processTree.
                               * Then we iterate over that tree. */
} UA_Timer;

void
UA_Timer_init(UA_Timer *t);

UA_DateTime
UA_Timer_nextRepeatedTime(UA_Timer *t);

UA_StatusCode
UA_Timer_addTimedCallback(UA_Timer *t, UA_ApplicationCallback callback,
                          void *application, void *data, UA_DateTime date,
                          UA_UInt64 *callbackId);

UA_StatusCode
UA_Timer_addRepeatedCallback(UA_Timer *t, UA_ApplicationCallback callback,
                             void *application, void *data, UA_Double interval_ms,
                             UA_DateTime now, UA_DateTime *baseTime,
                             UA_TimerPolicy timerPolicy, UA_UInt64 *callbackId);

UA_StatusCode
UA_Timer_changeRepeatedCallback(UA_Timer *t, UA_UInt64 callbackId,
                                UA_Double interval_ms, UA_DateTime now,
                                UA_DateTime *baseTime, UA_TimerPolicy timerPolicy);

void
UA_Timer_removeCallback(UA_Timer *t, UA_UInt64 callbackId);

UA_DateTime
UA_Timer_process(UA_Timer *t, UA_DateTime now);

void
UA_Timer_clear(UA_Timer *t);

_UA_END_DECLS


/**** amalgamated original file "/plugins/eventloop/eventloop_timer.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2017, 2018, 2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 */


static enum ZIP_CMP
cmpDateTime(const UA_DateTime *a, const UA_DateTime *b) {
    if(*a == *b)
        return ZIP_CMP_EQ;
    return (*a < *b) ? ZIP_CMP_LESS : ZIP_CMP_MORE;
}

static enum ZIP_CMP
cmpId(const UA_UInt64 *a, const UA_UInt64 *b) {
    if(*a == *b)
        return ZIP_CMP_EQ;
    return (*a < *b) ? ZIP_CMP_LESS : ZIP_CMP_MORE;
}

ZIP_FUNCTIONS(UA_TimerTree, UA_TimerEntry, treeEntry, UA_DateTime, nextTime, cmpDateTime)
ZIP_FUNCTIONS(UA_TimerIdTree, UA_TimerEntry, idTreeEntry, UA_UInt64, id, cmpId)

static UA_DateTime
calculateNextTime(UA_DateTime currentTime, UA_DateTime baseTime,
                  UA_DateTime interval) {
    /* Take the difference between current and base time */
    UA_DateTime diffCurrentTimeBaseTime = currentTime - baseTime;

    /* Take modulo of the diff time with the interval. This is the duration we
     * are already "into" the current interval. Subtract it from (current +
     * interval) to get the next execution time. */
    UA_DateTime cycleDelay = diffCurrentTimeBaseTime % interval;

    /* Handle the special case where the baseTime is in the future */
    if(UA_UNLIKELY(cycleDelay < 0))
        cycleDelay += interval;

    return currentTime + interval - cycleDelay;
}

void
UA_Timer_init(UA_Timer *t) {
    memset(t, 0, sizeof(UA_Timer));
    UA_LOCK_INIT(&t->timerMutex);
}

static UA_StatusCode
addCallback(UA_Timer *t, UA_ApplicationCallback callback, void *application,
            void *data, UA_DateTime nextTime, UA_UInt64 interval,
            UA_TimerPolicy timerPolicy, UA_UInt64 *callbackId) {
    /* A callback method needs to be present */
    if(!callback)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Allocate the repeated callback structure */
    UA_TimerEntry *te = (UA_TimerEntry*)UA_malloc(sizeof(UA_TimerEntry));
    if(!te)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Set the repeated callback */
    te->interval = (UA_UInt64)interval;
    te->id = ++t->idCounter;
    te->callback = callback;
    te->application = application;
    te->data = data;
    te->nextTime = nextTime;
    te->timerPolicy = timerPolicy;

    /* Set the output identifier */
    if(callbackId)
        *callbackId = te->id;

    ZIP_INSERT(UA_TimerTree, &t->tree, te);
    ZIP_INSERT(UA_TimerIdTree, &t->idTree, te);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Timer_addTimedCallback(UA_Timer *t, UA_ApplicationCallback callback,
                          void *application, void *data, UA_DateTime date,
                          UA_UInt64 *callbackId) {
    UA_LOCK(&t->timerMutex);
    UA_StatusCode res = addCallback(t, callback, application, data, date,
                                    0, UA_TIMER_HANDLE_CYCLEMISS_WITH_CURRENTTIME,
                                    callbackId);
    UA_UNLOCK(&t->timerMutex);
    return res;
}

/* Adding repeated callbacks: Add an entry with the "nextTime" timestamp in the
 * future. This will be picked up in the next iteration and inserted at the
 * correct place. So that the next execution takes place ät "nextTime". */
UA_StatusCode
UA_Timer_addRepeatedCallback(UA_Timer *t, UA_ApplicationCallback callback,
                             void *application, void *data, UA_Double interval_ms,
                             UA_DateTime now, UA_DateTime *baseTime,
                             UA_TimerPolicy timerPolicy, UA_UInt64 *callbackId) {
    /* The interval needs to be positive */
    if(interval_ms <= 0.0)
        return UA_STATUSCODE_BADINTERNALERROR;
    UA_UInt64 interval = (UA_UInt64)(interval_ms * UA_DATETIME_MSEC);
    if(interval == 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Compute the first time for execution */
    UA_DateTime nextTime;
    if(baseTime == NULL) {
        nextTime = now + (UA_DateTime)interval;
    } else {
        nextTime = calculateNextTime(now, *baseTime, (UA_DateTime)interval);
    }

    UA_LOCK(&t->timerMutex);
    UA_StatusCode res = addCallback(t, callback, application, data, nextTime,
                                    interval, timerPolicy, callbackId);
    UA_UNLOCK(&t->timerMutex);
    return res;
}

UA_StatusCode
UA_Timer_changeRepeatedCallback(UA_Timer *t, UA_UInt64 callbackId,
                                UA_Double interval_ms, UA_DateTime now,
                                UA_DateTime *baseTime, UA_TimerPolicy timerPolicy) {
    /* The interval needs to be positive */
    if(interval_ms <= 0.0)
        return UA_STATUSCODE_BADINTERNALERROR;
    UA_UInt64 interval = (UA_UInt64)(interval_ms * UA_DATETIME_MSEC);
    if(interval == 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_LOCK(&t->timerMutex);

    /* Find according to the id */
    UA_TimerEntry *te = ZIP_FIND(UA_TimerIdTree, &t->idTree, &callbackId);
    if(!te) {
        UA_UNLOCK(&t->timerMutex);
        return UA_STATUSCODE_BADNOTFOUND;
    }

    /* Try to remove from the time-sorted tree. If not found, then the entry is
     * in the processTree. If that is the case, leave it there and only adjust
     * the interval and nextTime (if the TimerPolicy uses a basetime). */
    UA_Boolean normalTree = (ZIP_REMOVE(UA_TimerTree, &t->tree, te) != NULL);

    /* Compute the next time for execution. The logic is identical to the
     * creation of a new repeated callback. */
    if(baseTime == NULL) {
        te->nextTime = now + (UA_DateTime)interval;
    } else {
        te->nextTime = calculateNextTime(now, *baseTime, (UA_DateTime)interval);
    }

    /* Update the remaining parameters and re-insert */
    te->interval = interval;
    te->timerPolicy = timerPolicy;

    if(normalTree)
        ZIP_INSERT(UA_TimerTree, &t->tree, te);

    UA_UNLOCK(&t->timerMutex);
    return UA_STATUSCODE_GOOD;
}

void
UA_Timer_removeCallback(UA_Timer *t, UA_UInt64 callbackId) {
    UA_LOCK(&t->timerMutex);
    UA_TimerEntry *te = ZIP_FIND(UA_TimerIdTree, &t->idTree, &callbackId);
    if(UA_LIKELY(te != NULL)) {
        if(t->processTree.root == NULL) {
            /* Remove/free the entry */
            ZIP_REMOVE(UA_TimerTree, &t->tree, te);
            ZIP_REMOVE(UA_TimerIdTree, &t->idTree, te);
            UA_free(te);
        } else {
            /* We are currently processing. Only mark the entry to be deleted.
             * Will be removed/freed the next time we reach it in the processing
             * callback. */
            te->callback = NULL;
        }
    }
    UA_UNLOCK(&t->timerMutex);
}

struct TimerProcessContext {
    UA_Timer *t;
    UA_DateTime now;
};

static void *
processEntryCallback(void *context, UA_TimerEntry *te) {
    struct TimerProcessContext *tpc = (struct TimerProcessContext*)context;
    UA_Timer *t = tpc->t;

    /* Execute the callback. The memory is not freed during the callback.
     * Instead, whenever t->processTree != NULL, the entries are only marked for
     * deletion by setting elm->callback to NULL. */
    if(te->callback) {
        UA_UNLOCK(&t->timerMutex);
        te->callback(te->application, te->data);
        UA_LOCK(&t->timerMutex);
    }

    /* Remove and free the entry if marked for deletion or a one-time timed
     * callback */
    if(!te->callback || te->interval == 0) {
        ZIP_REMOVE(UA_TimerIdTree, &t->idTree, te);
        UA_free(te);
        return NULL;
    }

    /* Set the time for the next regular execution */
    te->nextTime += (UA_DateTime)te->interval;

    /* Handle the case where the "window" was missed. E.g. due to congestion of
     * the application or if the clock was shifted.
     *
     * If the timer policy is "CurrentTime", then there is at least the
     * interval between executions. This is used for Monitoreditems, for
     * which the spec says: The sampling interval indicates the fastest rate
     * at which the Server should sample its underlying source for data
     * changes. (Part 4, 5.12.1.2) */
    if(te->nextTime < tpc->now) {
        if(te->timerPolicy == UA_TIMER_HANDLE_CYCLEMISS_WITH_BASETIME)
            te->nextTime = calculateNextTime(tpc->now, te->nextTime,
                                              (UA_DateTime)te->interval);
        else
            te->nextTime = tpc->now + (UA_DateTime)te->interval;
    }

    /* Insert back into the time-sorted tree */
    ZIP_INSERT(UA_TimerTree, &t->tree, te);
    return NULL;
}

UA_DateTime
UA_Timer_process(UA_Timer *t, UA_DateTime now) {
    UA_LOCK(&t->timerMutex);

    /* Not reentrant. Don't call _process from within _process. */
    if(!t->processTree.root) {
        /* Move all entries <= now to processTree */
        ZIP_UNZIP(UA_TimerTree, &t->tree, &now, &t->processTree, &t->tree);

        /* Consistency check. The smallest not-processed entry isn't ready. */
        UA_assert(!ZIP_MIN(UA_TimerTree, &t->tree) ||
                  ZIP_MIN(UA_TimerTree, &t->tree)->nextTime > now);
        
        /* Iterate over the entries that need processing in-order. This also
         * moves them back to the regular time-ordered tree. */
        struct TimerProcessContext ctx;
        ctx.t = t;
        ctx.now = now;
        ZIP_ITER(UA_TimerTree, &t->processTree, processEntryCallback, &ctx);
        
        /* Reset processTree. All entries are already moved to the normal tree. */
        t->processTree.root = NULL;
    }

    /* Compute the timestamp of the earliest next callback */
    UA_TimerEntry *first = ZIP_MIN(UA_TimerTree, &t->tree);
    UA_DateTime next = (first) ? first->nextTime : UA_INT64_MAX;
    UA_UNLOCK(&t->timerMutex);
    return next;
}

UA_DateTime
UA_Timer_nextRepeatedTime(UA_Timer *t) {
    UA_LOCK(&t->timerMutex);
    UA_TimerEntry *first = ZIP_MIN(UA_TimerTree, &t->tree);
    UA_DateTime next = (first) ? first->nextTime : UA_INT64_MAX;
    UA_UNLOCK(&t->timerMutex);
    return next;
}

static void *
freeEntryCallback(void *context, UA_TimerEntry *entry) {
    UA_free(entry);
    return NULL;
}

void
UA_Timer_clear(UA_Timer *t) {
    UA_LOCK(&t->timerMutex);

    ZIP_ITER(UA_TimerIdTree, &t->idTree, freeEntryCallback, NULL);
    t->tree.root = NULL;
    t->idTree.root = NULL;
    t->idCounter = 0;

    UA_UNLOCK(&t->timerMutex);

#if UA_MULTITHREADING >= 100
    UA_LOCK_DESTROY(&t->timerMutex);
#endif
}

/**** amalgamated original file "/plugins/eventloop/eventloop_common.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Jan Hermes)
 */



/* Utility definitions to be used in EventLoop implementations.
 * Not part of the public API. */

_UA_BEGIN_DECLS

/* Typing restrictions for key-value parameters */
typedef struct {
    UA_QualifiedName name;
    const UA_DataType *type;
    UA_Boolean required;
    UA_Boolean scalar;
    UA_Boolean array;
} UA_KeyValueRestriction;

UA_StatusCode
UA_KeyValueRestriction_validate(const UA_Logger *logger,
                                const char *logprefix,
                                const UA_KeyValueRestriction *restrictions,
                                size_t restrictionsSize,
                                const UA_KeyValueMap *map);

_UA_END_DECLS


/**** amalgamated original file "/plugins/eventloop/eventloop_common.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 */


UA_StatusCode
UA_KeyValueRestriction_validate(const UA_Logger *logger, const char *logprefix,
                                const UA_KeyValueRestriction *restrictions,
                                size_t restrictionsSize,
                                const UA_KeyValueMap *map) {
    for(size_t i = 0; i < restrictionsSize; i++) {
        const UA_KeyValueRestriction *r = &restrictions[i];
        const UA_Variant *val = UA_KeyValueMap_get(map, r->name);

        /* Value not present but required? */
        if(!val) {
            if(r->required) {
                UA_LOG_WARNING(logger, UA_LOGCATEGORY_USERLAND,
                               "%s\t| Parameter %.*s required but not defined",
                               logprefix, (int)r->name.name.length, (char*)r->name.name.data);
                return UA_STATUSCODE_BADINTERNALERROR;
            }
            continue;
        }

        /* Type matches */
        if(val->type != r->type) {
            UA_LOG_WARNING(logger, UA_LOGCATEGORY_USERLAND,
                           "%s\t| Parameter %.*s has the wrong type",
                           logprefix, (int)r->name.name.length, (char*)r->name.name.data);
            return UA_STATUSCODE_BADINTERNALERROR;
        }

        /* Scalar / array is allowed */
        UA_Boolean scalar = UA_Variant_isScalar(val);
        if(scalar && !r->scalar) {
            UA_LOG_WARNING(logger, UA_LOGCATEGORY_USERLAND,
                           "%s\t| Parameter %.*s must not be scalar",
                           logprefix, (int)r->name.name.length, (char*)r->name.name.data);
            return UA_STATUSCODE_BADINTERNALERROR;
        }
        if(!scalar && !r->array) {
            UA_LOG_WARNING(logger, UA_LOGCATEGORY_USERLAND,
                           "%s\t| Parameter %.*s must not be an array",
                           logprefix, (int)r->name.name.length, (char*)r->name.name.data);
            return UA_STATUSCODE_BADCONNECTIONREJECTED;
        }
    }

    return UA_STATUSCODE_GOOD;
}

/**** amalgamated original file "/plugins/eventloop/posix/eventloop_posix.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 *    Copyright 2021 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati)
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Jan Hermes)
 */




#if defined(UA_ARCHITECTURE_POSIX) || defined(UA_ARCHITECTURE_WIN32)

_UA_BEGIN_DECLS

#include <errno.h>

#if defined(UA_ARCHITECTURE_WIN32)

/*********************/
/* Win32 Definitions */
/*********************/

/* Disable some security warnings on MSVC */
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
# define _CRT_SECURE_NO_WARNINGS
#endif

#include <stdlib.h>
#include <stdio.h>
#include <winsock2.h>
#include <windows.h>
#include <ws2tcpip.h>
#include <basetsd.h>

#ifndef _SSIZE_T_DEFINED
typedef SSIZE_T ssize_t;
#endif

#define UA_IPV6 1
#define UA_SOCKET SOCKET
#define UA_INVALID_SOCKET INVALID_SOCKET
#define UA_ERRNO WSAGetLastError()
#define UA_INTERRUPTED WSAEINTR
#define UA_AGAIN EAGAIN /* the same as wouldblock on nearly every system */
#define UA_INPROGRESS WSAEINPROGRESS
#define UA_WOULDBLOCK WSAEWOULDBLOCK
#define UA_POLLIN POLLRDNORM
#define UA_POLLOUT POLLWRNORM
#define UA_SHUT_RDWR SD_BOTH

#define UA_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) \
    getnameinfo(sa, (socklen_t)salen, host, (DWORD)hostlen, serv, (DWORD)servlen, flags)
#define UA_poll(fds,nfds,timeout) WSAPoll((LPWSAPOLLFD)fds, nfds, timeout)
#define UA_send(sockfd, buf, len, flags) send(sockfd, buf, (int)(len), flags)
#define UA_recv(sockfd, buf, len, flags) recv(sockfd, buf, (int)(len), flags)
#define UA_sendto(sockfd, buf, len, flags, dest_addr, addrlen) \
    sendto(sockfd, (const char*)(buf), (int)(len), flags, dest_addr, (int) (addrlen))
#define UA_close closesocket
#define UA_select(nfds, readfds, writefds, exceptfds, timeout) \
    select((int)(nfds), readfds, writefds, exceptfds, timeout)
#define UA_connect(sockfd, addr, addrlen) connect(sockfd, addr, (int)(addrlen))
#define UA_getsockopt(sockfd, level, optname, optval, optlen) \
    getsockopt(sockfd, level, optname, (char*) (optval), optlen)
#define UA_setsockopt(sockfd, level, optname, optval, optlen) \
    setsockopt(sockfd, level, optname, (const char*) (optval), optlen)
#define UA_inet_pton InetPton

#if UA_IPV6
# define UA_if_nametoindex if_nametoindex

# include <iphlpapi.h>

#endif

#define UA_LOG_SOCKET_ERRNO_WRAP(LOG) { \
    char *errno_str = NULL; \
    FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, \
    NULL, WSAGetLastError(), \
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), \
    (LPSTR)&errno_str, 0, NULL); \
    LOG; \
    LocalFree(errno_str); \
}
#define UA_LOG_SOCKET_ERRNO_GAI_WRAP UA_LOG_SOCKET_ERRNO_WRAP

/* Fix redefinition of SLIST_ENTRY on mingw winnt.h */
#if !defined(_SYS_QUEUE_H_) && defined(SLIST_ENTRY)
# undef SLIST_ENTRY
#endif

#elif defined(UA_ARCHITECTURE_POSIX)

/*********************/
/* POSIX Definitions */
/*********************/

#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <net/if.h>
#include <poll.h>
#include <fcntl.h>
#include <unistd.h>

#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
# include <sys/param.h>
# if defined(BSD)
#  include <sys/socket.h>
# endif
#endif

#define UA_IPV6 1
#define UA_SOCKET int
#define UA_INVALID_SOCKET -1
#define UA_ERRNO errno
#define UA_INTERRUPTED EINTR
#define UA_AGAIN EAGAIN /* the same as wouldblock on nearly every system */
#define UA_INPROGRESS EINPROGRESS
#define UA_WOULDBLOCK EWOULDBLOCK
#define UA_POLLIN POLLIN
#define UA_POLLOUT POLLOUT
#define UA_SHUT_RDWR SHUT_RDWR

#define UA_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags) \
    getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
#define UA_poll poll
#define UA_send send
#define UA_recv recv
#define UA_sendto sendto
#define UA_close close
#define UA_select select
#define UA_connect connect
#define UA_getsockopt getsockopt
#define UA_setsockopt setsockopt
#define UA_inet_pton inet_pton
#if UA_IPV6
# define UA_if_nametoindex if_nametoindex
#endif

#define UA_clean_errno(STR_FUN) \
    (errno == 0 ? (char*) "None" : (STR_FUN)(errno))
#define UA_LOG_SOCKET_ERRNO_WRAP(LOG) \
    { char *errno_str = UA_clean_errno(strerror); LOG; errno = 0; }
#define UA_LOG_SOCKET_ERRNO_GAI_WRAP(LOG) \
    { const char *errno_str = UA_clean_errno(gai_strerror); LOG; errno = 0; }

/* epoll_pwait returns bogus data with the tc compiler */
#if defined(__linux__) && !defined(__TINYC__)
# define UA_HAVE_EPOLL
# include <sys/epoll.h>
#endif

#endif

/***********************/
/* General Definitions */
/***********************/

#define UA_MAXBACKLOG 100
#define UA_MAXHOSTNAME_LENGTH 256
#define UA_MAXPORTSTR_LENGTH 6

#ifndef MSG_NOSIGNAL
#define MSG_NOSIGNAL 0
#endif

#ifndef MSG_DONTWAIT
#define MSG_DONTWAIT 0
#endif

/* POSIX events are based on sockets / file descriptors. The EventSources can
 * register their fd in the EventLoop so that they are considered by the
 * EventLoop dropping into "poll" to wait for events. */

/* TODO: Move the macro-forest from /arch/<arch>/ua_architecture.h */

#define UA_FD UA_SOCKET
#define UA_INVALID_FD UA_INVALID_SOCKET

struct UA_RegisteredFD;
typedef struct UA_RegisteredFD UA_RegisteredFD;

/* Bitmask to be used for the UA_FDCallback event argument */
#define UA_FDEVENT_IN 1
#define UA_FDEVENT_OUT 2
#define UA_FDEVENT_ERR 4

typedef void (*UA_FDCallback)(UA_EventSource *es, UA_RegisteredFD *rfd, short event);

struct UA_RegisteredFD {
    UA_DelayedCallback dc; /* Used for async closing. Must be the first member
                            * because the rfd is freed by the delayed callback
                            * mechanism. */

    ZIP_ENTRY(UA_RegisteredFD) zipPointers; /* Register FD in the EventSource */
    UA_FD fd;
    short listenEvents; /* UA_FDEVENT_IN | UA_FDEVENT_OUT*/

    UA_EventSource *es; /* Backpointer to the EventSource */
    UA_FDCallback eventSourceCB;
};

enum ZIP_CMP cmpFD(const UA_FD *a, const UA_FD *b);
typedef ZIP_HEAD(UA_FDTree, UA_RegisteredFD) UA_FDTree;
ZIP_FUNCTIONS(UA_FDTree, UA_RegisteredFD, zipPointers, UA_FD, fd, cmpFD)

/* All ConnectionManager in the POSIX EventLoop can be cast to
 * UA_ConnectionManagerPOSIX. They carry a sorted tree of their open
 * sockets/file-descriptors. */
typedef struct {
    UA_ConnectionManager cm;

    /* Statically allocated buffers */
    UA_ByteString rxBuffer;
    UA_ByteString txBuffer;

    /* Sorted tree of the FDs */
    size_t fdsSize;
    UA_FDTree fds;
} UA_POSIXConnectionManager;

typedef struct {
    UA_EventLoop eventLoop;

    /* Timer */
    UA_Timer timer;

    /* Linked List of Delayed Callbacks */
    UA_DelayedCallback *delayedCallbacks;

    /* Flag determining whether the eventloop is currently within the
     * "run" method */
    UA_Boolean executing;

#if defined(UA_ARCHITECTURE_POSIX) && !defined(__APPLE__) && !defined(__MACH__)
    /* Clocks for the eventloop's time domain */
    UA_Int32 clockSource;
    UA_Int32 clockSourceMonotonic;
#endif

#if defined(UA_HAVE_EPOLL)
    UA_FD epollfd;
#else
    UA_RegisteredFD **fds;
    size_t fdsSize;
#endif

#if UA_MULTITHREADING >= 100
    UA_Lock elMutex;
#endif
} UA_EventLoopPOSIX;

/* The following functions differ between epoll and normal select */

/* Register to start receiving events */
UA_StatusCode
UA_EventLoopPOSIX_registerFD(UA_EventLoopPOSIX *el, UA_RegisteredFD *rfd);

/* Modify the events that the fd listens on */
UA_StatusCode
UA_EventLoopPOSIX_modifyFD(UA_EventLoopPOSIX *el, UA_RegisteredFD *rfd);

/* Deregister but do not close the fd. No further events are received. */
void
UA_EventLoopPOSIX_deregisterFD(UA_EventLoopPOSIX *el, UA_RegisteredFD *rfd);

UA_StatusCode
UA_EventLoopPOSIX_pollFDs(UA_EventLoopPOSIX *el, UA_DateTime listenTimeout);

/* Helper functions across EventSources */

UA_StatusCode
UA_EventLoopPOSIX_allocateStaticBuffers(UA_POSIXConnectionManager *pcm);

UA_StatusCode
UA_EventLoopPOSIX_allocNetworkBuffer(UA_ConnectionManager *cm,
                                     uintptr_t connectionId,
                                     UA_ByteString *buf,
                                     size_t bufSize);

void
UA_EventLoopPOSIX_freeNetworkBuffer(UA_ConnectionManager *cm,
                                    uintptr_t connectionId,
                                    UA_ByteString *buf);

/* Set the socket non-blocking. If the listen-socket is nonblocking, incoming
 * connections inherit this state. */
UA_StatusCode
UA_EventLoopPOSIX_setNonBlocking(UA_FD sockfd);

/* Don't have the socket create interrupt signals */
UA_StatusCode
UA_EventLoopPOSIX_setNoSigPipe(UA_FD sockfd);

/* Enables sharing of the same listening address on different sockets */
UA_StatusCode
UA_EventLoopPOSIX_setReusable(UA_FD sockfd);

_UA_END_DECLS

#endif /* defined(UA_ARCHITECTURE_POSIX) || defined(UA_ARCHITECTURE_WIN32) */


/**** amalgamated original file "/plugins/eventloop/posix/eventloop_posix.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Jan Hermes)
 */


#if defined(UA_ARCHITECTURE_POSIX) && !defined(__APPLE__) && !defined(__MACH__)
#include <time.h>
#endif

/*********/
/* Timer */
/*********/

static UA_DateTime
UA_EventLoopPOSIX_nextCyclicTime(UA_EventLoop *public_el) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)public_el;
    return UA_Timer_nextRepeatedTime(&el->timer);
}

static UA_StatusCode
UA_EventLoopPOSIX_addTimedCallback(UA_EventLoop *public_el,
                                   UA_Callback callback,
                                   void *application, void *data,
                                   UA_DateTime date,
                                   UA_UInt64 *callbackId) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)public_el;
    return UA_Timer_addTimedCallback(&el->timer, callback, application,
                                     data, date, callbackId);
}

static UA_StatusCode
UA_EventLoopPOSIX_addCyclicCallback(UA_EventLoop *public_el,
                                    UA_Callback cb,
                                    void *application, void *data,
                                    UA_Double interval_ms,
                                    UA_DateTime *baseTime,
                                    UA_TimerPolicy timerPolicy,
                                    UA_UInt64 *callbackId) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)public_el;
    return UA_Timer_addRepeatedCallback(&el->timer, cb, application,
                                        data, interval_ms,
                                        public_el->dateTime_nowMonotonic(public_el),
                                        baseTime, timerPolicy, callbackId);
}

static UA_StatusCode
UA_EventLoopPOSIX_modifyCyclicCallback(UA_EventLoop *public_el,
                                       UA_UInt64 callbackId,
                                       UA_Double interval_ms,
                                       UA_DateTime *baseTime,
                                       UA_TimerPolicy timerPolicy) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)public_el;
    return UA_Timer_changeRepeatedCallback(&el->timer, callbackId, interval_ms,
                                           public_el->dateTime_nowMonotonic(public_el),
                                           baseTime, timerPolicy);
}

static void
UA_EventLoopPOSIX_removeCyclicCallback(UA_EventLoop *public_el,
                                       UA_UInt64 callbackId) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)public_el;
    UA_Timer_removeCallback(&el->timer, callbackId);
}

static void
UA_EventLoopPOSIX_addDelayedCallback(UA_EventLoop *public_el,
                                     UA_DelayedCallback *dc) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)public_el;
    UA_LOCK(&el->elMutex);
    dc->next = el->delayedCallbacks;
    el->delayedCallbacks = dc;
    UA_UNLOCK(&el->elMutex);
}

static void
UA_EventLoopPOSIX_removeDelayedCallback(UA_EventLoop *public_el,
                                     UA_DelayedCallback *dc) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)public_el;
    UA_LOCK(&el->elMutex);
    UA_DelayedCallback **prev = &el->delayedCallbacks;
    while(*prev) {
        if(*prev == dc) {
            *prev = (*prev)->next;
            UA_UNLOCK(&el->elMutex);
            return;
        }
        prev = &(*prev)->next;
    }
    UA_UNLOCK(&el->elMutex);
}

/* Process and then free registered delayed callbacks */
static void
processDelayed(UA_EventLoopPOSIX *el) {
    UA_LOG_TRACE(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                 "Process delayed callbacks");

    UA_LOCK_ASSERT(&el->elMutex, 1);

    /* First empty the linked list in the el. So a delayed callback can add
     * (itself) to the list. New entries are then processed during the next
     * iteration. */
    UA_DelayedCallback *dc = el->delayedCallbacks, *next = NULL;
    el->delayedCallbacks = NULL;

    for(; dc; dc = next) {
        next = dc->next;
        /* Delayed Callbacks might have no callback set. We don't return a
         * StatusCode during "add" and don't validate. So test here. */
        if(!dc->callback)
            continue;
        UA_UNLOCK(&el->elMutex);
        dc->callback(dc->application, dc->context);
        UA_LOCK(&el->elMutex);
    }
}

/***********************/
/* EventLoop Lifecycle */
/***********************/

static UA_StatusCode
UA_EventLoopPOSIX_start(UA_EventLoopPOSIX *el) {
    UA_LOCK(&el->elMutex);

    if(el->eventLoop.state != UA_EVENTLOOPSTATE_FRESH &&
       el->eventLoop.state != UA_EVENTLOOPSTATE_STOPPED) {
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                "Starting the EventLoop");

    /* Setting the clock source */
    const UA_Int32 *cs = (const UA_Int32*)
        UA_KeyValueMap_getScalar(&el->eventLoop.params,
                                 UA_QUALIFIEDNAME(0, "clock-source"),
                                 &UA_TYPES[UA_TYPES_INT32]);
    const UA_Int32 *csm = (const UA_Int32*)
        UA_KeyValueMap_getScalar(&el->eventLoop.params,
                                 UA_QUALIFIEDNAME(0, "clock-source-monotonic"),
                                 &UA_TYPES[UA_TYPES_INT32]);
#if defined(UA_ARCHITECTURE_POSIX) && !defined(__APPLE__) && !defined(__MACH__)
    el->clockSource = CLOCK_REALTIME;
    if(cs)
        el->clockSource = *cs;

# ifdef CLOCK_MONOTONIC_RAW
    el->clockSourceMonotonic = CLOCK_MONOTONIC_RAW;
# else
    el->clockSourceMonotonic = CLOCK_MONOTONIC;
# endif
    if(csm)
        el->clockSourceMonotonic = *csm;
#else
    if(cs || csm) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "Eventloop\t| Cannot set a custom clock source");
    }
#endif

#ifdef UA_HAVE_EPOLL
    el->epollfd = epoll_create1(0);
    if(el->epollfd == -1) {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "Eventloop\t| Could not create the epoll socket (%s)",
                          errno_str));
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }
#endif

    UA_StatusCode res = UA_STATUSCODE_GOOD;
    UA_EventSource *es = el->eventLoop.eventSources;
    while(es) {
        UA_UNLOCK(&el->elMutex);
        res |= es->start(es);
        UA_LOCK(&el->elMutex);
        es = es->next;
    }

    /* Dirty-write the state that is const "from the outside" */
    *(UA_EventLoopState*)(uintptr_t)&el->eventLoop.state =
        UA_EVENTLOOPSTATE_STARTED;

    UA_UNLOCK(&el->elMutex);
    return res;
}

static void
checkClosed(UA_EventLoopPOSIX *el) {
    UA_LOCK_ASSERT(&el->elMutex, 1);

    UA_EventSource *es = el->eventLoop.eventSources;
    while(es) {
        if(es->state != UA_EVENTSOURCESTATE_STOPPED)
            return;
        es = es->next;
    }

    /* Not closed until all delayed callbacks are processed */
    if(el->delayedCallbacks != NULL)
        return;

    /* Dirty-write the state that is const "from the outside" */
    *(UA_EventLoopState*)(uintptr_t)&el->eventLoop.state =
        UA_EVENTLOOPSTATE_STOPPED;

    /* Close the epoll/IOCP socket once all EventSources have shut down */
#ifdef UA_HAVE_EPOLL
    close(el->epollfd);
#endif

    UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                "The EventLoop has stopped");
}

static void
UA_EventLoopPOSIX_stop(UA_EventLoopPOSIX *el) {
    UA_LOCK(&el->elMutex);

    if(el->eventLoop.state != UA_EVENTLOOPSTATE_STARTED) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                       "The EventLoop is not running, cannot be stopped");
        UA_UNLOCK(&el->elMutex);
        return;
    }

    UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                "Stopping the EventLoop");

    /* Set to STOPPING to prevent "normal use" */
    *(UA_EventLoopState*)(uintptr_t)&el->eventLoop.state =
        UA_EVENTLOOPSTATE_STOPPING;

    /* Stop all event sources (asynchronous) */
    UA_EventSource *es = el->eventLoop.eventSources;
    for(; es; es = es->next) {
        if(es->state == UA_EVENTSOURCESTATE_STARTING ||
           es->state == UA_EVENTSOURCESTATE_STARTED) {
            UA_UNLOCK(&el->elMutex);
            es->stop(es);
            UA_LOCK(&el->elMutex);
        }
    }

    /* Set to STOPPED if all EventSources are STOPPED */
    checkClosed(el);

    UA_UNLOCK(&el->elMutex);
}

static UA_StatusCode
UA_EventLoopPOSIX_run(UA_EventLoopPOSIX *el, UA_UInt32 timeout) {
    UA_LOCK(&el->elMutex);

    if(el->executing) {
        UA_LOG_ERROR(el->eventLoop.logger,
                     UA_LOGCATEGORY_EVENTLOOP,
                     "Cannot run EventLoop from the run method itself");
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    el->executing = true;

    if(el->eventLoop.state == UA_EVENTLOOPSTATE_FRESH ||
       el->eventLoop.state == UA_EVENTLOOPSTATE_STOPPED) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                       "Cannot iterate a stopped EventLoop");
        el->executing = false;
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_LOG_TRACE(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                 "Iterate the EventLoop");

    /* Process cyclic callbacks */
    UA_DateTime dateBefore =
        el->eventLoop.dateTime_nowMonotonic(&el->eventLoop);

    UA_UNLOCK(&el->elMutex);
    UA_DateTime dateNext = UA_Timer_process(&el->timer, dateBefore);
    UA_LOCK(&el->elMutex);

    /* Process delayed callbacks here:
     * - Removes closed sockets already here instead of polling them again.
     * - The timeout for polling is selected to be ready in time for the next
     *   cyclic callback. So we want to do little work between the timeout
     *   running out and executing the due cyclic callbacks. */
    processDelayed(el);

    /* A delayed callback could create another delayed callback (or re-add
     * itself). In that case we don't want to wait (indefinitely) for an event
     * to happen. Process queued events but don't sleep. Then process the
     * delayed callbacks in the next iteration. */
    if(el->delayedCallbacks != NULL)
        timeout = 0;

    /* Compute the remaining time */
    UA_DateTime maxDate = dateBefore + (timeout * UA_DATETIME_MSEC);
    if(dateNext > maxDate)
        dateNext = maxDate;
    UA_DateTime listenTimeout =
        dateNext - el->eventLoop.dateTime_nowMonotonic(&el->eventLoop);
    if(listenTimeout < 0)
        listenTimeout = 0;

    /* Listen on the active file-descriptors (sockets) from the
     * ConnectionManagers */
    UA_StatusCode rv = UA_EventLoopPOSIX_pollFDs(el, listenTimeout);

    /* Check if the last EventSource was successfully stopped */
    if(el->eventLoop.state == UA_EVENTLOOPSTATE_STOPPING)
        checkClosed(el);

    el->executing = false;
    UA_UNLOCK(&el->elMutex);
    return rv;
}

/*****************************/
/* Registering Event Sources */
/*****************************/

static UA_StatusCode
UA_EventLoopPOSIX_registerEventSource(UA_EventLoopPOSIX *el,
                                      UA_EventSource *es) {
    UA_LOCK(&el->elMutex);

    /* Already registered? */
    if(es->state != UA_EVENTSOURCESTATE_FRESH) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "Cannot register the EventSource \"%.*s\": "
                     "already registered",
                     (int)es->name.length, (char*)es->name.data);
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Add to linked list */
    es->next = el->eventLoop.eventSources;
    el->eventLoop.eventSources = es;

    es->eventLoop = &el->eventLoop;
    es->state = UA_EVENTSOURCESTATE_STOPPED;

    /* Start if the entire EventLoop is started */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    if(el->eventLoop.state == UA_EVENTLOOPSTATE_STARTED)
        res = es->start(es);

    UA_UNLOCK(&el->elMutex);
    return res;
}

static UA_StatusCode
UA_EventLoopPOSIX_deregisterEventSource(UA_EventLoopPOSIX *el,
                                        UA_EventSource *es) {
    UA_LOCK(&el->elMutex);

    if(es->state != UA_EVENTSOURCESTATE_STOPPED) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                       "Cannot deregister the EventSource %.*s: "
                       "Has to be stopped first",
                       (int)es->name.length, es->name.data);
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Remove from the linked list */
    UA_EventSource **s = &el->eventLoop.eventSources;
    while(*s) {
        if(*s == es) {
            *s = es->next;
            break;
        }
        s = &(*s)->next;
    }

    /* Set the state to non-registered */
    es->state = UA_EVENTSOURCESTATE_FRESH;

    UA_UNLOCK(&el->elMutex);
    return UA_STATUSCODE_GOOD;
}

/***************/
/* Time Domain */
/***************/

static UA_DateTime
UA_EventLoopPOSIX_DateTime_now(UA_EventLoop *el) {
#if defined(UA_ARCHITECTURE_POSIX) && !defined(__APPLE__) && !defined(__MACH__)
    UA_EventLoopPOSIX *pel = (UA_EventLoopPOSIX*)el;
    struct timespec ts;
    int res = clock_gettime(pel->clockSource, &ts);
    if(UA_UNLIKELY(res != 0))
        return 0;
    return (ts.tv_sec * UA_DATETIME_SEC) + (ts.tv_nsec / 100) + UA_DATETIME_UNIX_EPOCH;
#else
    return UA_DateTime_now();
#endif
}

static UA_DateTime
UA_EventLoopPOSIX_DateTime_nowMonotonic(UA_EventLoop *el) {
#if defined(UA_ARCHITECTURE_POSIX) && !defined(__APPLE__) && !defined(__MACH__)
    UA_EventLoopPOSIX *pel = (UA_EventLoopPOSIX*)el;
    struct timespec ts;
    int res = clock_gettime(pel->clockSourceMonotonic, &ts);
    if(UA_UNLIKELY(res != 0))
        return 0;
    /* Also add the unix epoch for the monotonic clock. So we get a "normal"
     * output when a "normal" source is configured. */
    return (ts.tv_sec * UA_DATETIME_SEC) + (ts.tv_nsec / 100) + UA_DATETIME_UNIX_EPOCH;
#else
    return UA_DateTime_nowMonotonic();
#endif
}

static UA_Int64
UA_EventLoopPOSIX_DateTime_localTimeUtcOffset(UA_EventLoop *el) {
    /* TODO: Fix for custom clock sources */
    return UA_DateTime_localTimeUtcOffset();
}

/*************************/
/* Initialize and Delete */
/*************************/

static UA_StatusCode
UA_EventLoopPOSIX_free(UA_EventLoopPOSIX *el) {
    UA_LOCK(&el->elMutex);

    /* Check if the EventLoop can be deleted */
    if(el->eventLoop.state != UA_EVENTLOOPSTATE_STOPPED &&
       el->eventLoop.state != UA_EVENTLOOPSTATE_FRESH) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                       "Cannot delete a running EventLoop");
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Deregister and delete all the EventSources */
    while(el->eventLoop.eventSources) {
        UA_EventSource *es = el->eventLoop.eventSources;
        UA_UNLOCK(&el->elMutex);
        UA_EventLoopPOSIX_deregisterEventSource(el, es);
        UA_LOCK(&el->elMutex);
        es->free(es);
    }

    /* Remove the repeated timed callbacks */
    UA_Timer_clear(&el->timer);

    /* Process remaining delayed callbacks */
    processDelayed(el);

#ifdef _WIN32
    /* Stop the Windows networking subsystem */
    WSACleanup();
#endif

    UA_KeyValueMap_clear(&el->eventLoop.params);

    /* Clean up */
    UA_UNLOCK(&el->elMutex);
    UA_LOCK_DESTROY(&el->elMutex);
    UA_free(el);
    return UA_STATUSCODE_GOOD;
}

UA_EventLoop *
UA_EventLoop_new_POSIX(const UA_Logger *logger) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)
        UA_calloc(1, sizeof(UA_EventLoopPOSIX));
    if(!el)
        return NULL;

    UA_LOCK_INIT(&el->elMutex);
    UA_Timer_init(&el->timer);

#ifdef _WIN32
    /* Start the WSA networking subsystem on Windows */
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);
#endif

    /* Set the public EventLoop content */
    el->eventLoop.logger = logger;

    el->eventLoop.start = (UA_StatusCode (*)(UA_EventLoop*))UA_EventLoopPOSIX_start;
    el->eventLoop.stop = (void (*)(UA_EventLoop*))UA_EventLoopPOSIX_stop;
    el->eventLoop.run = (UA_StatusCode (*)(UA_EventLoop*, UA_UInt32))UA_EventLoopPOSIX_run;
    el->eventLoop.free = (UA_StatusCode (*)(UA_EventLoop*))UA_EventLoopPOSIX_free;

    el->eventLoop.dateTime_now = UA_EventLoopPOSIX_DateTime_now;
    el->eventLoop.dateTime_nowMonotonic =
        UA_EventLoopPOSIX_DateTime_nowMonotonic;
    el->eventLoop.dateTime_localTimeUtcOffset =
        UA_EventLoopPOSIX_DateTime_localTimeUtcOffset;

    el->eventLoop.nextCyclicTime = UA_EventLoopPOSIX_nextCyclicTime;
    el->eventLoop.addCyclicCallback = UA_EventLoopPOSIX_addCyclicCallback;
    el->eventLoop.modifyCyclicCallback = UA_EventLoopPOSIX_modifyCyclicCallback;
    el->eventLoop.removeCyclicCallback = UA_EventLoopPOSIX_removeCyclicCallback;
    el->eventLoop.addTimedCallback = UA_EventLoopPOSIX_addTimedCallback;
    el->eventLoop.addDelayedCallback = UA_EventLoopPOSIX_addDelayedCallback;
    el->eventLoop.removeDelayedCallback = UA_EventLoopPOSIX_removeDelayedCallback;

    el->eventLoop.registerEventSource =
        (UA_StatusCode (*)(UA_EventLoop*, UA_EventSource*))
        UA_EventLoopPOSIX_registerEventSource;
    el->eventLoop.deregisterEventSource =
        (UA_StatusCode (*)(UA_EventLoop*, UA_EventSource*))
        UA_EventLoopPOSIX_deregisterEventSource;

    return &el->eventLoop;
}

/* Reusable EventSource functionality */

UA_StatusCode
UA_EventLoopPOSIX_allocNetworkBuffer(UA_ConnectionManager *cm,
                                     uintptr_t connectionId,
                                     UA_ByteString *buf,
                                     size_t bufSize) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    if(pcm->txBuffer.length == 0)
        return UA_ByteString_allocBuffer(buf, bufSize);
    if(pcm->txBuffer.length < bufSize)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    *buf = pcm->txBuffer;
    buf->length = bufSize;
    return UA_STATUSCODE_GOOD;
}

void
UA_EventLoopPOSIX_freeNetworkBuffer(UA_ConnectionManager *cm,
                                    uintptr_t connectionId,
                                    UA_ByteString *buf) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    if(pcm->txBuffer.data == buf->data)
        UA_ByteString_init(buf);
    else
        UA_ByteString_clear(buf);
}

UA_StatusCode
UA_EventLoopPOSIX_allocateStaticBuffers(UA_POSIXConnectionManager *pcm) {
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    UA_UInt32 rxBufSize = 2u << 16; /* The default is 64kb */
    const UA_UInt32 *configRxBufSize = (const UA_UInt32 *)
        UA_KeyValueMap_getScalar(&pcm->cm.eventSource.params,
                                 UA_QUALIFIEDNAME(0, "recv-bufsize"),
                                 &UA_TYPES[UA_TYPES_UINT32]);
    if(configRxBufSize)
        rxBufSize = *configRxBufSize;
    if(pcm->rxBuffer.length != rxBufSize) {
        UA_ByteString_clear(&pcm->rxBuffer);
        res = UA_ByteString_allocBuffer(&pcm->rxBuffer, rxBufSize);
    }

    const UA_UInt32 *txBufSize = (const UA_UInt32 *)
        UA_KeyValueMap_getScalar(&pcm->cm.eventSource.params,
                                 UA_QUALIFIEDNAME(0, "send-bufsize"),
                                 &UA_TYPES[UA_TYPES_UINT32]);
    if(txBufSize && pcm->txBuffer.length != *txBufSize) {
        UA_ByteString_clear(&pcm->txBuffer);
        res |= UA_ByteString_allocBuffer(&pcm->txBuffer, *txBufSize);
    }
    return res;
}

/* Socket Handling */

enum ZIP_CMP
cmpFD(const UA_FD *a, const UA_FD *b) {
    if(*a == *b)
        return ZIP_CMP_EQ;
    return (*a < *b) ? ZIP_CMP_LESS : ZIP_CMP_MORE;
}

UA_StatusCode
UA_EventLoopPOSIX_setNonBlocking(UA_FD sockfd) {
#ifndef _WIN32
    int opts = fcntl(sockfd, F_GETFL);
    if(opts < 0 || fcntl(sockfd, F_SETFL, opts | O_NONBLOCK) < 0)
        return UA_STATUSCODE_BADINTERNALERROR;
#else
    u_long iMode = 1;
    if(ioctlsocket(sockfd, FIONBIO, &iMode) != NO_ERROR)
        return UA_STATUSCODE_BADINTERNALERROR;
#endif
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_EventLoopPOSIX_setNoSigPipe(UA_FD sockfd) {
#ifdef SO_NOSIGPIPE
    int val = 1;
    int res = UA_setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val));
    if(res < 0)
        return UA_STATUSCODE_BADINTERNALERROR;
#endif
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_EventLoopPOSIX_setReusable(UA_FD sockfd) {
    int enableReuseVal = 1;
    int res = UA_setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
                            (const char*)&enableReuseVal, sizeof(enableReuseVal));
    return (res == 0) ? UA_STATUSCODE_GOOD : UA_STATUSCODE_BADINTERNALERROR;
}

/**** amalgamated original file "/plugins/eventloop/posix/eventloop_posix_select.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 */


#if !defined(UA_HAVE_EPOLL)

UA_StatusCode
UA_EventLoopPOSIX_registerFD(UA_EventLoopPOSIX *el, UA_RegisteredFD *rfd) {
    UA_LOCK_ASSERT(&el->elMutex, 1);
    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                 "Registering fd: %u", (unsigned)rfd->fd);

    /* Realloc */
    UA_RegisteredFD **fds_tmp = (UA_RegisteredFD**)
        UA_realloc(el->fds, sizeof(UA_RegisteredFD*) * (el->fdsSize + 1));
    if(!fds_tmp) {
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    el->fds = fds_tmp;

    /* Add to the last entry */
    el->fds[el->fdsSize] = rfd;
    el->fdsSize++;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_EventLoopPOSIX_modifyFD(UA_EventLoopPOSIX *el, UA_RegisteredFD *rfd) {
    /* Do nothing, it is enough if the data was changed in the rfd */
    UA_LOCK_ASSERT(&el->elMutex, 1);
    return UA_STATUSCODE_GOOD;
}

void
UA_EventLoopPOSIX_deregisterFD(UA_EventLoopPOSIX *el, UA_RegisteredFD *rfd) {
    UA_LOCK_ASSERT(&el->elMutex, 1);
    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                 "Unregistering fd: %u", (unsigned)rfd->fd);

    /* Find the entry */
    size_t i = 0;
    for(; i < el->fdsSize; i++) {
        if(el->fds[i] == rfd)
            break;
    }

    /* Not found? */
    if(i == el->fdsSize)
        return;

    if(el->fdsSize > 1) {
        /* Move the last entry in the ith slot and realloc. */
        el->fdsSize--;
        el->fds[i] = el->fds[el->fdsSize];
        UA_RegisteredFD **fds_tmp = (UA_RegisteredFD**)
            UA_realloc(el->fds, sizeof(UA_RegisteredFD*) * el->fdsSize);
        /* if realloc fails the fds are still in a correct state with
         * possibly lost memory, so failing silently here is ok */
        if(fds_tmp)
            el->fds = fds_tmp;
    } else {
        /* Remove the last entry */
        UA_free(el->fds);
        el->fds = NULL;
        el->fdsSize = 0;
    }
}

static UA_FD
setFDSets(UA_EventLoopPOSIX *el, fd_set *readset, fd_set *writeset, fd_set *errset) {
    UA_LOCK_ASSERT(&el->elMutex, 1);

    FD_ZERO(readset);
    FD_ZERO(writeset);
    FD_ZERO(errset);
    UA_FD highestfd = UA_INVALID_FD;
    for(size_t i = 0; i < el->fdsSize; i++) {
        UA_FD currentFD = el->fds[i]->fd;

        /* Add to the fd_sets */
        if(el->fds[i]->listenEvents & UA_FDEVENT_IN)
            FD_SET(currentFD, readset);
        if(el->fds[i]->listenEvents & UA_FDEVENT_OUT)
            FD_SET(currentFD, writeset);

        /* Always return errors */
        FD_SET(currentFD, errset);

        /* Highest fd? */
        if(currentFD > highestfd || highestfd == UA_INVALID_FD)
            highestfd = currentFD;
    }
    return highestfd;
}

UA_StatusCode
UA_EventLoopPOSIX_pollFDs(UA_EventLoopPOSIX *el, UA_DateTime listenTimeout) {
    UA_assert(listenTimeout >= 0);
    UA_LOCK_ASSERT(&el->elMutex, 1);

    fd_set readset, writeset, errset;
    UA_FD highestfd = setFDSets(el, &readset, &writeset, &errset);

    /* Nothing to do? */
    if(highestfd == UA_INVALID_FD) {
        UA_LOG_TRACE(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                     "No valid FDs for processing");
        return UA_STATUSCODE_GOOD;
    }

    struct timeval tmptv = {
#ifndef _WIN32
        (time_t)(listenTimeout / UA_DATETIME_SEC),
        (suseconds_t)((listenTimeout % UA_DATETIME_SEC) / UA_DATETIME_USEC)
#else
        (long)(listenTimeout / UA_DATETIME_SEC),
        (long)((listenTimeout % UA_DATETIME_SEC) / UA_DATETIME_USEC)
#endif
    };

    UA_UNLOCK(&el->elMutex);
    int selectStatus = UA_select(highestfd+1, &readset, &writeset, &errset, &tmptv);
    UA_LOCK(&el->elMutex);
    if(selectStatus < 0) {
        /* We will retry, only log the error */
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                           "Error during select: %s", errno_str));
        return UA_STATUSCODE_GOOD;
    }

    /* Loop over all registered FD to see if an event arrived. Yes, this is why
     * select is slow for many open sockets. */
    for(size_t i = 0; i < el->fdsSize; i++) {
        UA_RegisteredFD *rfd = el->fds[i];

        /* The rfd is already registered for removal. Don't process incoming
         * events any longer. */
        if(rfd->dc.callback)
            continue;

        /* Event signaled for the fd? */
        short event = 0;
        if(FD_ISSET(rfd->fd, &readset)) {
            event = UA_FDEVENT_IN;
        } else if(FD_ISSET(rfd->fd, &writeset)) {
            event = UA_FDEVENT_OUT;
        } else if(FD_ISSET(rfd->fd, &errset)) {
            event = UA_FDEVENT_ERR;
        } else {
            continue;
        }

        UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                     "Processing event %u on fd %u", (unsigned)event,
                     (unsigned)rfd->fd);

        /* Call the EventSource callback */
        rfd->eventSourceCB(rfd->es, rfd, event);

        /* The fd has removed itself */
        if(i == el->fdsSize || rfd != el->fds[i])
            i--;
    }
    return UA_STATUSCODE_GOOD;
}

#endif /* !defined(UA_HAVE_EPOLL) */

/**** amalgamated original file "/plugins/eventloop/posix/eventloop_posix_epoll.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 */


#if defined(UA_HAVE_EPOLL)

UA_StatusCode
UA_EventLoopPOSIX_registerFD(UA_EventLoopPOSIX *el, UA_RegisteredFD *rfd) {
    struct epoll_event event;
    memset(&event, 0, sizeof(struct epoll_event));
    event.data.ptr = rfd;
    event.events = 0;
    if(rfd->listenEvents & UA_FDEVENT_IN)
        event.events |= EPOLLIN;
    if(rfd->listenEvents & UA_FDEVENT_OUT)
        event.events |= EPOLLOUT;

    int err = epoll_ctl(el->epollfd, EPOLL_CTL_ADD, rfd->fd, &event);
    if(err != 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "TCP %u\t| Could not register for epoll (%s)",
                          rfd->fd, errno_str));
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_EventLoopPOSIX_modifyFD(UA_EventLoopPOSIX *el, UA_RegisteredFD *rfd) {
    struct epoll_event event;
    memset(&event, 0, sizeof(struct epoll_event));
    event.data.ptr = rfd;
    event.events = 0;
    if(rfd->listenEvents & UA_FDEVENT_IN)
        event.events |= EPOLLIN;
    if(rfd->listenEvents & UA_FDEVENT_OUT)
        event.events |= EPOLLOUT;

    int err = epoll_ctl(el->epollfd, EPOLL_CTL_MOD, rfd->fd, &event);
    if(err != 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "TCP %u\t| Could not modify for epoll (%s)",
                          rfd->fd, errno_str));
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return UA_STATUSCODE_GOOD;
}

void
UA_EventLoopPOSIX_deregisterFD(UA_EventLoopPOSIX *el, UA_RegisteredFD *rfd) {
    int res = epoll_ctl(el->epollfd, EPOLL_CTL_DEL, rfd->fd, NULL);
    if(res != 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "TCP %u\t| Could not deregister from epoll (%s)",
                          rfd->fd, errno_str));
    }
}

UA_StatusCode
UA_EventLoopPOSIX_pollFDs(UA_EventLoopPOSIX *el, UA_DateTime listenTimeout) {
    UA_assert(listenTimeout >= 0);

    /* Poll the registered sockets */
    struct epoll_event epoll_events[64];
    int epollfd = el->epollfd;
    UA_UNLOCK(&el->elMutex);
    int events = epoll_wait(epollfd, epoll_events, 64,
                            (int)(listenTimeout / UA_DATETIME_MSEC));
    /* TODO: Replace with pwait2 for higher-precision timeouts once this is
     * available in the standard library.
     *
     * struct timespec precisionTimeout = {
     *  (long)(listenTimeout / UA_DATETIME_SEC),
     *   (long)((listenTimeout % UA_DATETIME_SEC) * 100)
     * };
     * int events = epoll_pwait2(epollfd, epoll_events, 64,
     *                        precisionTimeout, NULL); */
    UA_LOCK(&el->elMutex);

    /* Handle error conditions */
    if(events == -1) {
        if(errno == EINTR) {
            /* We will retry, only log the error */
            UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                           "Timeout during poll");
            return UA_STATUSCODE_GOOD;
        }
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "TCP\t| Error %s, closing the server socket",
                          errno_str));
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Process all received events */
    for(int i = 0; i < events; i++) {
        UA_RegisteredFD *rfd = (UA_RegisteredFD*)epoll_events[i].data.ptr;

        /* The rfd is already registered for removal. Don't process incoming
         * events any longer. */
        if(rfd->dc.callback)
            continue;

        /* Get the event */
        short revent = 0;
        if((epoll_events[i].events & EPOLLIN) == EPOLLIN) {
            revent = UA_FDEVENT_IN;
        } else if((epoll_events[i].events & EPOLLOUT) == EPOLLOUT) {
            revent = UA_FDEVENT_OUT;
        } else {
            revent = UA_FDEVENT_ERR;
        }

        /* Call the EventSource callback */
        rfd->eventSourceCB(rfd->es, rfd, revent);
    }
    return UA_STATUSCODE_GOOD;
}

#endif /* defined(UA_HAVE_EPOLL) */

/**** amalgamated original file "/plugins/eventloop/posix/eventloop_posix_tcp.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2021-2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Jan Hermes)
 */


/* Configuration parameters */

#define TCP_MANAGERPARAMS 2

static UA_KeyValueRestriction tcpManagerParams[TCP_MANAGERPARAMS] = {
    {{0, UA_STRING_STATIC("recv-bufsize")}, &UA_TYPES[UA_TYPES_UINT32], false, true, false},
    {{0, UA_STRING_STATIC("send-bufsize")}, &UA_TYPES[UA_TYPES_UINT32], false, true, false}
};

#define TCP_PARAMETERSSIZE 4
#define TCP_PARAMINDEX_ADDR 0
#define TCP_PARAMINDEX_PORT 1
#define TCP_PARAMINDEX_LISTEN 2
#define TCP_PARAMINDEX_VALIDATE 3

static UA_KeyValueRestriction tcpConnectionParams[TCP_PARAMETERSSIZE] = {
    {{0, UA_STRING_STATIC("address")}, &UA_TYPES[UA_TYPES_STRING], false, true, true},
    {{0, UA_STRING_STATIC("port")}, &UA_TYPES[UA_TYPES_UINT16], true, true, false},
    {{0, UA_STRING_STATIC("listen")}, &UA_TYPES[UA_TYPES_BOOLEAN], false, true, false},
    {{0, UA_STRING_STATIC("validate")}, &UA_TYPES[UA_TYPES_BOOLEAN], false, true, false}
};

typedef struct {
    UA_RegisteredFD rfd;

    UA_ConnectionManager_connectionCallback applicationCB;
    void *application;
    void *context;
} TCP_FD;

static void
TCP_shutdown(UA_ConnectionManager *cm, TCP_FD *conn);

/* Do not merge packets on the socket (disable Nagle's algorithm) */
static UA_StatusCode
TCP_setNoNagle(UA_FD sockfd) {
    int val = 1;
    int res = UA_setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
    if(res < 0)
        return UA_STATUSCODE_BADINTERNALERROR;
    return UA_STATUSCODE_GOOD;
}

/* Test if the ConnectionManager can be stopped */
static void
TCP_checkStopped(UA_POSIXConnectionManager *pcm) {
    UA_LOCK_ASSERT(&((UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop)->elMutex, 1);

    if(pcm->fdsSize == 0 &&
       pcm->cm.eventSource.state == UA_EVENTSOURCESTATE_STOPPING) {
        UA_LOG_DEBUG(pcm->cm.eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
                     "TCP\t| All sockets closed, the EventLoop has stopped");
        pcm->cm.eventSource.state = UA_EVENTSOURCESTATE_STOPPED;
    }
}

static void
TCP_delayedClose(void *application, void *context) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)application;
    UA_ConnectionManager *cm = &pcm->cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
    TCP_FD *conn = (TCP_FD*)context;

    UA_LOCK(&el->elMutex);

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                 "TCP %u\t| Delayed closing of the connection",
                 (unsigned)conn->rfd.fd);

    /* Deregister from the EventLoop */
    UA_EventLoopPOSIX_deregisterFD(el, &conn->rfd);

    /* Deregister internally */
    ZIP_REMOVE(UA_FDTree, &pcm->fds, &conn->rfd);
    UA_assert(pcm->fdsSize > 0);
    pcm->fdsSize--;

    /* Signal closing to the application */
    UA_UNLOCK(&el->elMutex);
    conn->applicationCB(cm, (uintptr_t)conn->rfd.fd,
                        conn->application, &conn->context,
                        UA_CONNECTIONSTATE_CLOSING,
                        &UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);
    UA_LOCK(&el->elMutex);

    /* Close the socket */
    int ret = UA_close(conn->rfd.fd);
    if(ret == 0) {
        UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                    "TCP %u\t| Socket closed", (unsigned)conn->rfd.fd);
    } else {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "TCP %u\t| Could not close the socket (%s)",
                          (unsigned)conn->rfd.fd, errno_str));
    }

    UA_free(conn);

    /* Check if this was the last connection for a closing ConnectionManager */
    TCP_checkStopped(pcm);

    UA_UNLOCK(&el->elMutex);
}

static int
getSockError(TCP_FD *conn) {
    int error = 0;
#ifndef _WIN32
    socklen_t errlen = sizeof(int);
    int err = getsockopt(conn->rfd.fd, SOL_SOCKET, SO_ERROR, &error, &errlen);
#else
    int errlen = (int)sizeof(int);
    int err = getsockopt((SOCKET)conn->rfd.fd, SOL_SOCKET, SO_ERROR,
                         (char*)&error, &errlen);
#endif
    return (err == 0) ? error : err;
}

/* Gets called when a connection socket opens, receives data or closes */
static void
TCP_connectionSocketCallback(UA_ConnectionManager *cm, TCP_FD *conn,
                             short event) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex, 1);

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "TCP %u\t| Activity on the socket",
                 (unsigned)conn->rfd.fd);

    /* Error. The connection has closed. */
    if(event == UA_FDEVENT_ERR) {
        UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                    "TCP %u\t| The connection closes with error %i",
                    (unsigned)conn->rfd.fd, getSockError(conn));
        TCP_shutdown(cm, conn);
        return;
    }

    /* Write-Event, a new connection has opened. But some errors come as an
     * out-event. For example if the remote side could not be reached to
     * initiate the connection. So we check manually for error conditions on
     * the socket. */
    if(event == UA_FDEVENT_OUT) {
        int error = getSockError(conn);
        if(error != 0) {
            UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                        "TCP %u\t| The connection closes with error %i",
                        (unsigned)conn->rfd.fd, error);
            TCP_shutdown(cm, conn);
            return;
        }

        UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "TCP %u\t| Opening a new connection",
                     (unsigned)conn->rfd.fd);

        /* Now we are interested in read-events. */
        conn->rfd.listenEvents = UA_FDEVENT_IN;
        UA_EventLoopPOSIX_modifyFD(el, &conn->rfd);

        /* A new socket has opened. Signal it to the application. */
        UA_UNLOCK(&el->elMutex);
        conn->applicationCB(cm, (uintptr_t)conn->rfd.fd,
                            conn->application, &conn->context,
                            UA_CONNECTIONSTATE_ESTABLISHED,
                            &UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);
        UA_LOCK(&el->elMutex);
        return;
    }

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "TCP %u\t| Allocate receive buffer",
                 (unsigned)conn->rfd.fd);

    /* Use the already allocated receive-buffer */
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_ByteString response = pcm->rxBuffer;

    /* Receive */
#ifndef _WIN32
    ssize_t ret = UA_recv(conn->rfd.fd, (char*)response.data,
                          response.length, MSG_DONTWAIT);
#else
    int ret = UA_recv(conn->rfd.fd, (char*)response.data,
                      response.length, MSG_DONTWAIT);
#endif

    /* Receive has failed */
    if(ret <= 0) {
        if(UA_ERRNO == UA_INTERRUPTED ||
           UA_ERRNO == UA_WOULDBLOCK ||
           UA_ERRNO == UA_AGAIN)
            return; /* Temporary error on an non-blocking socket */

        /* Orderly shutdown of the socket */
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                        "TCP %u\t| recv signaled the socket was shutdown (%s)",
                        (unsigned)conn->rfd.fd, errno_str));
        TCP_shutdown(cm, conn);
        return;
    }

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "TCP %u\t| Received message of size %u",
                 (unsigned)conn->rfd.fd, (unsigned)ret);

    /* Callback to the application layer */
    response.length = (size_t)ret; /* Set the length of the received buffer */
    UA_UNLOCK(&el->elMutex);
    conn->applicationCB(cm, (uintptr_t)conn->rfd.fd,
                        conn->application, &conn->context,
                        UA_CONNECTIONSTATE_ESTABLISHED,
                        &UA_KEYVALUEMAP_NULL, response);
    UA_LOCK(&el->elMutex);
}

/* Gets called when a new connection opens or if the listenSocket is closed */
static void
TCP_listenSocketCallback(UA_ConnectionManager *cm, TCP_FD *conn, short event) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex, 1);

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "TCP %u\t| Callback on server socket",
                 (unsigned)conn->rfd.fd);

    /* Try to accept a new connection */
    struct sockaddr_storage remote;
    socklen_t remote_size = sizeof(remote);
    UA_FD newsockfd = accept(conn->rfd.fd, (struct sockaddr*)&remote, &remote_size);
    if(newsockfd == UA_INVALID_FD) {
        /* Temporary error -- retry */
        if(UA_ERRNO == UA_INTERRUPTED)
            return;

        /* Close the listen socket */
        if(cm->eventSource.state != UA_EVENTSOURCESTATE_STOPPING) {
            UA_LOG_SOCKET_ERRNO_WRAP(
                UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                               "TCP %u\t| Error %s, closing the server socket",
                               (unsigned)conn->rfd.fd, errno_str));
        }

        TCP_shutdown(cm, conn);
        return;
    }

    /* Log the name of the remote host */
    char hoststr[UA_MAXHOSTNAME_LENGTH];
    int get_res = UA_getnameinfo((struct sockaddr *)&remote, sizeof(remote),
                                 hoststr, sizeof(hoststr),
                                 NULL, 0, NI_NUMERICHOST);
    if(get_res != 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(cm->eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
                          "TCP %u\t| getnameinfo(...) could not resolve the "
                          "hostname (%s)", (unsigned)conn->rfd.fd, errno_str));
    }
    UA_LOG_INFO(cm->eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
                "TCP %u\t| Connection opened from \"%s\" via the server socket %u",
                (unsigned)newsockfd, hoststr, (unsigned)conn->rfd.fd);

    /* Configure the new socket */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    /* res |= UA_EventLoopPOSIX_setNonBlocking(newsockfd); Inherited from the listen-socket */
    res |= UA_EventLoopPOSIX_setNoSigPipe(newsockfd); /* Supress interrupts from the socket */
    res |= TCP_setNoNagle(newsockfd);     /* Disable Nagle's algorithm */
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_WARNING(cm->eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
                           "TCP %u\t| Error seeting the TCP options (%s)",
                           (unsigned)newsockfd, errno_str));
        /* Close the new socket */
        UA_close(newsockfd);
        return;
    }

    /* Allocate the UA_RegisteredFD */
    TCP_FD *newConn = (TCP_FD*)UA_calloc(1, sizeof(TCP_FD));
    if(!newConn) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "TCP %u\t| Error allocating memory for the socket",
                       (unsigned)newsockfd);
        UA_close(newsockfd);
        return;
    }

    newConn->rfd.fd = newsockfd;
    newConn->rfd.listenEvents = UA_FDEVENT_IN;
    newConn->rfd.es = &cm->eventSource;
    newConn->rfd.eventSourceCB = (UA_FDCallback)TCP_connectionSocketCallback;
    newConn->applicationCB = conn->applicationCB;
    newConn->application = conn->application;
    newConn->context = conn->context;

    /* Register in the EventLoop. Signal to the user if registering failed. */
    res = UA_EventLoopPOSIX_registerFD(el, &newConn->rfd);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "TCP %u\t| Error registering the socket",
                       (unsigned)newsockfd);
        UA_free(newConn);
        UA_close(newsockfd);
        return;
    }

    /* Register internally in the EventSource */
    ZIP_INSERT(UA_FDTree, &pcm->fds, &newConn->rfd);
    pcm->fdsSize++;

    /* Forward the remote hostname to the application */
    UA_KeyValuePair kvp;
    kvp.key = UA_QUALIFIEDNAME(0, "remote-address");
    UA_String hostName = UA_STRING(hoststr);
    UA_Variant_setScalar(&kvp.value, &hostName, &UA_TYPES[UA_TYPES_STRING]);

    UA_KeyValueMap kvm;
    kvm.mapSize = 1;
    kvm.map = &kvp;

    /* The socket has opened. Signal it to the application. */
    UA_UNLOCK(&el->elMutex);
    newConn->applicationCB(cm, (uintptr_t)newsockfd,
                           newConn->application, &newConn->context,
                           UA_CONNECTIONSTATE_ESTABLISHED,
                           &kvm, UA_BYTESTRING_NULL);
    UA_LOCK(&el->elMutex);
}

static UA_StatusCode
TCP_registerListenSocket(UA_POSIXConnectionManager *pcm, struct addrinfo *ai,
                         UA_UInt16 port, void *application, void *context,
                         UA_ConnectionManager_connectionCallback connectionCallback,
                         UA_Boolean validate) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex, 1);

    /* Get the hostname information */
    char hoststr[UA_MAXHOSTNAME_LENGTH];
    int get_res = UA_getnameinfo(ai->ai_addr, ai->ai_addrlen, hoststr,
                                 sizeof(hoststr), NULL, 0, NI_NUMERICHOST);
    if(get_res != 0) {
        hoststr[0] = 0;
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "TCP\t| getnameinfo(...) could not resolve the "
                          "hostname (%s)", errno_str));
    }

    /* Create the server socket */
    UA_FD listenSocket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
    if(listenSocket == UA_INVALID_FD) {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "TCP %u\t| Error opening the listen socket for "
                          "\"%s\" on port %u (%s)",
                          (unsigned)listenSocket, hoststr, port, errno_str));
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                "TCP %u\t| Creating server socket for \"%s\" on port %u",
                (unsigned)listenSocket, hoststr, port);

    /* Some Linux distributions have net.ipv6.bindv6only not activated. So
     * sockets can double-bind to IPv4 and IPv6. This leads to problems. Use
     * AF_INET6 sockets only for IPv6. */
    int optval = 1;
#if UA_IPV6
    if(ai->ai_family == AF_INET6 &&
       UA_setsockopt(listenSocket, IPPROTO_IPV6, IPV6_V6ONLY,
                     (const char*)&optval, sizeof(optval)) == -1) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "TCP %u\t| Could not set an IPv6 socket to IPv6 only",
                       (unsigned)listenSocket);
        UA_close(listenSocket);
        return UA_STATUSCODE_BADINTERNALERROR;
    }
#endif

    /* Allow rebinding to the IP/port combination. Eg. to restart the server. */
    if(UA_setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR,
                     (const char *)&optval, sizeof(optval)) == -1) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "TCP %u\t| Could not make the socket addr reusable",
                       (unsigned)listenSocket);
        UA_close(listenSocket);
        return UA_STATUSCODE_BADINTERNALERROR;
    }
#ifndef _WIN32
    /* Allow rebinding to the IP/port combination. Eg. to restart the server. */
    if(UA_setsockopt(listenSocket, SOL_SOCKET, SO_REUSEPORT,
                     (const char *)&optval, sizeof(optval)) == -1) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "TCP %u\t| Could not make the socket port reusable",
                       (unsigned)listenSocket);
        UA_close(listenSocket);
        return UA_STATUSCODE_BADINTERNALERROR;
    }
#endif
    /* Set the socket non-blocking */
    if(UA_EventLoopPOSIX_setNonBlocking(listenSocket) != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "TCP %u\t| Could not set the socket non-blocking",
                       (unsigned)listenSocket);
        UA_close(listenSocket);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Supress interrupts from the socket */
    if(UA_EventLoopPOSIX_setNoSigPipe(listenSocket) != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "TCP %u\t| Could not disable SIGPIPE",
                       (unsigned)listenSocket);
        UA_close(listenSocket);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Bind socket to address */
    int ret = bind(listenSocket, ai->ai_addr, (socklen_t)ai->ai_addrlen);
    if(ret < 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "TCP %u\t| Error binding the socket to the address %s (%s)",
                          (unsigned)listenSocket, hoststr, errno_str));
        UA_close(listenSocket);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Only validate, don't actually start listening */
    if(validate) {
        UA_close(listenSocket);
        return UA_STATUSCODE_GOOD;
    }

    /* Start listening */
    if(listen(listenSocket, UA_MAXBACKLOG) < 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "TCP %u\t| Error listening on the socket (%s)",
                          (unsigned)listenSocket, errno_str));
        UA_close(listenSocket);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Allocate the connection */
    TCP_FD *newConn = (TCP_FD*)UA_calloc(1, sizeof(TCP_FD));
    if(!newConn) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "TCP %u\t| Error allocating memory for the socket",
                       (unsigned)listenSocket);
        UA_close(listenSocket);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    newConn->rfd.fd = listenSocket;
    newConn->rfd.listenEvents = UA_FDEVENT_IN;
    newConn->rfd.es = &pcm->cm.eventSource;
    newConn->rfd.eventSourceCB = (UA_FDCallback)TCP_listenSocketCallback;
    newConn->applicationCB = connectionCallback;
    newConn->application = application;
    newConn->context = context;

    /* Register in the EventLoop */
    UA_StatusCode res = UA_EventLoopPOSIX_registerFD(el, &newConn->rfd);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "TCP %u\t| Error registering the socket",
                       (unsigned)listenSocket);
        UA_free(newConn);
        UA_close(listenSocket);
        return res;
    }

    /* Register internally */
    ZIP_INSERT(UA_FDTree, &pcm->fds, &newConn->rfd);
    pcm->fdsSize++;

    /* Set up the callback parameters */
    UA_KeyValuePair params[2];
    params[0].key = UA_QUALIFIEDNAME(0, "listen-address");
    params[1].key = UA_QUALIFIEDNAME(0, "listen-port");
    UA_KeyValueMap paramMap;
    paramMap.mapSize = 0;
    UA_String hostname;
    if(hoststr[0] != 0) {
        paramMap.mapSize = 2;
        hostname = UA_STRING(hoststr);
        UA_Variant_setScalar(&params[0].value, &hostname, &UA_TYPES[UA_TYPES_STRING]);
        UA_Variant_setScalar(&params[1].value, &port, &UA_TYPES[UA_TYPES_UINT16]);
        paramMap.map = params;
    }

    /* Announce the listen-socket in the application */
    UA_UNLOCK(&el->elMutex);
    connectionCallback(&pcm->cm, (uintptr_t)listenSocket,
                       application, &newConn->context,
                       UA_CONNECTIONSTATE_ESTABLISHED,
                       &paramMap, UA_BYTESTRING_NULL);
    UA_LOCK(&el->elMutex);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
TCP_registerListenSockets(UA_POSIXConnectionManager *pcm, const char *hostname,
                          UA_UInt16 port, void *application, void *context,
                          UA_ConnectionManager_connectionCallback connectionCallback,
                          UA_Boolean validate) {
    UA_LOCK_ASSERT(&((UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop)->elMutex, 1);

    /* Create a string for the port */
    char portstr[6];
    mp_snprintf(portstr, sizeof(portstr), "%d", port);

    /* Get all the interface and IPv4/6 combinations for the configured hostname */
    struct addrinfo hints, *res;
    memset(&hints, 0, sizeof hints);
#if UA_IPV6
    hints.ai_family = AF_UNSPEC; /* Allow IPv4 and IPv6 */
#else
    hints.ai_family = AF_INET;   /* IPv4 only */
#endif
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = AI_PASSIVE;

    int retcode = getaddrinfo(hostname, portstr, &hints, &res);
    if(retcode != 0) {
#ifdef _WIN32
        UA_LOG_SOCKET_ERRNO_WRAP(
        UA_LOG_WARNING(pcm->cm.eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
                       "TCP\t| Lookup for \"%s\" on port %u failed (%s)",
                       hostname, port, errno_str));
#else
        UA_LOG_WARNING(pcm->cm.eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
                       "TCP\t| Lookup for \"%s\" on port %u failed (%s)",
                       hostname, port, gai_strerror(retcode));
#endif
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Add listen sockets. Aggregate the results to see if at least one
     * listen-socket was established. */
    UA_StatusCode total_result = UA_INT32_MAX;
    struct addrinfo *ai = res;
    while(ai) {
        total_result &= TCP_registerListenSocket(pcm, ai, port, application, context,
                                                 connectionCallback, validate);
        ai = ai->ai_next;
    }
    freeaddrinfo(res);

    return total_result;
}

/* Close the connection via a delayed callback */
static void
TCP_shutdown(UA_ConnectionManager *cm, TCP_FD *conn) {
    /* Already closing - nothing to do */
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex, 1);

    if(conn->rfd.dc.callback) {
        UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "TCP %u\t| Cannot close - already closing",
                     (unsigned)conn->rfd.fd);
        return;
    }

    /* Shutdown the socket to cancel the current select/epoll */
    shutdown(conn->rfd.fd, UA_SHUT_RDWR);

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "TCP %u\t| Shutdown triggered",
                 (unsigned)conn->rfd.fd);

    /* Add to the delayed callback list. Will be cleaned up in the next
     * iteration. */
    UA_DelayedCallback *dc = &conn->rfd.dc;
    dc->callback = TCP_delayedClose;
    dc->application = cm;
    dc->context = conn;

    /* Don't use the "public" el->addDelayedCallback. It takes a lock. */
    dc->next = el->delayedCallbacks;
    el->delayedCallbacks = dc;
}

static UA_StatusCode
TCP_shutdownConnection(UA_ConnectionManager *cm, uintptr_t connectionId) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)cm->eventSource.eventLoop;
    UA_LOCK(&el->elMutex);

    UA_FD fd = (UA_FD)connectionId;
    TCP_FD *conn = (TCP_FD*)ZIP_FIND(UA_FDTree, &pcm->fds, &fd);
    if(!conn) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "TCP\t| Cannot close TCP connection %u - not found",
                       (unsigned)connectionId);
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADNOTFOUND;
    }

    TCP_shutdown(cm, conn);

    UA_UNLOCK(&el->elMutex);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
TCP_sendWithConnection(UA_ConnectionManager *cm, uintptr_t connectionId,
                       const UA_KeyValueMap *params, UA_ByteString *buf) {
    /* Don't have a lock and don't take a lock. As the connectionId is the fd,
     * no need to to a lookup and access internal data strucures. */
    UA_LOCK_ASSERT(&((UA_EventLoopPOSIX*)cm->eventSource.eventLoop)->elMutex, 0);

    /* Prevent OS signals when sending to a closed socket */
    int flags = MSG_NOSIGNAL;

    struct pollfd tmp_poll_fd;
    tmp_poll_fd.fd = (UA_FD)connectionId;
    tmp_poll_fd.events = UA_POLLOUT;

    /* Send the full buffer. This may require several calls to send */
    size_t nWritten = 0;
    do {
        ssize_t n = 0;
        do {
            UA_LOG_DEBUG(cm->eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
                         "TCP %u\t| Attempting to send", (unsigned)connectionId);
            size_t bytes_to_send = buf->length - nWritten;
            n = UA_send((UA_FD)connectionId,
                        (const char*)buf->data + nWritten,
                        bytes_to_send, flags);
            if(n < 0) {
                /* An error we cannot recover from? */
                if(UA_ERRNO != UA_INTERRUPTED && UA_ERRNO != UA_WOULDBLOCK &&
                   UA_ERRNO != UA_AGAIN)
                    goto shutdown;

                /* Poll for the socket resources to become available and retry
                 * (blocking) */
                int poll_ret;
                do {
                    poll_ret = UA_poll(&tmp_poll_fd, 1, 100);
                    if(poll_ret < 0 && UA_ERRNO != UA_INTERRUPTED)
                        goto shutdown;
                } while(poll_ret <= 0);
            }
        } while(n < 0);
        nWritten += (size_t)n;
    } while(nWritten < buf->length);

    /* Clean up and return */
    UA_EventLoopPOSIX_freeNetworkBuffer(cm, connectionId, buf);
    return UA_STATUSCODE_GOOD;

 shutdown:
    /* Error -> shutdown the connection  */
    UA_LOG_SOCKET_ERRNO_WRAP(
       UA_LOG_ERROR(cm->eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
                    "TCP %u\t| Send failed with error %s",
                    (unsigned)connectionId, errno_str));
    TCP_shutdownConnection(cm, connectionId);
    UA_EventLoopPOSIX_freeNetworkBuffer(cm, connectionId, buf);
    return UA_STATUSCODE_BADCONNECTIONCLOSED;
}

/* Create a listen-socket that waits for incoming connections */
static UA_StatusCode
TCP_openPassiveConnection(UA_POSIXConnectionManager *pcm, const UA_KeyValueMap *params,
                          void *application, void *context,
                          UA_ConnectionManager_connectionCallback connectionCallback,
                          UA_Boolean validate) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex, 1);

    /* Get the port parameter */
    const UA_UInt16 *port = (const UA_UInt16*)
        UA_KeyValueMap_getScalar(params, tcpConnectionParams[TCP_PARAMINDEX_PORT].name,
                                 &UA_TYPES[UA_TYPES_UINT16]);
    UA_assert(port); /* existence is checked before */

    /* Get the address parameter */
    const UA_Variant *addrs =
        UA_KeyValueMap_get(params, tcpConnectionParams[TCP_PARAMINDEX_ADDR].name);
    size_t addrsSize = 0;
    if(addrs) {
        UA_assert(addrs->type == &UA_TYPES[UA_TYPES_STRING]);
        if(UA_Variant_isScalar(addrs))
            addrsSize = 1;
        else
            addrsSize = addrs->arrayLength;
    }

    /* Undefined or empty addresses array -> listen on all interfaces */
    if(addrsSize == 0) {
        UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                    "TCP\t| Listening on all interfaces");
        return TCP_registerListenSockets(pcm, NULL, *port, application,
                                         context, connectionCallback, validate);
    }

    /* Iterate over the configured hostnames */
    UA_String *hostStrings = (UA_String*)addrs->data;
    for(size_t i = 0; i < addrsSize; i++) {
        char hostname[512];
        if(hostStrings[i].length >= sizeof(hostname))
            continue;
        memcpy(hostname, hostStrings[i].data, hostStrings->length);
        hostname[hostStrings->length] = '\0';
        TCP_registerListenSockets(pcm, hostname, *port, application,
                                  context, connectionCallback, validate);
    }

    return UA_STATUSCODE_GOOD;
}

/* Open a TCP connection to a remote host */
static UA_StatusCode
TCP_openActiveConnection(UA_POSIXConnectionManager *pcm, const UA_KeyValueMap *params,
                         void *application, void *context,
                         UA_ConnectionManager_connectionCallback connectionCallback,
                         UA_Boolean validate) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex, 1);

    /* Get the connection parameters */
    char hostname[UA_MAXHOSTNAME_LENGTH];
    char portStr[UA_MAXPORTSTR_LENGTH];

    /* Prepare the port parameter as a string */
    const UA_UInt16 *port = (const UA_UInt16*)
        UA_KeyValueMap_getScalar(params, tcpConnectionParams[TCP_PARAMINDEX_PORT].name,
                                 &UA_TYPES[UA_TYPES_UINT16]);
    UA_assert(port); /* existence is checked before */
    mp_snprintf(portStr, UA_MAXPORTSTR_LENGTH, "%d", *port);

    /* Prepare the hostname string */
    const UA_String *addr = (const UA_String*)
        UA_KeyValueMap_getScalar(params, tcpConnectionParams[TCP_PARAMINDEX_ADDR].name,
                                 &UA_TYPES[UA_TYPES_STRING]);
    if(!addr) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "TCP\t| Open TCP Connection: No hostname defined, aborting");
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    if(addr->length >= UA_MAXHOSTNAME_LENGTH) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                     "TCP\t| Open TCP Connection: Hostname too long, aborting");
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    strncpy(hostname, (const char*)addr->data, addr->length);
    hostname[addr->length] = 0;

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "TCP\t| Open a connection to \"%s\" on port %s", hostname, portStr);

    /* Create the socket description from the connectString
     * TODO: Make this non-blocking */
    struct addrinfo hints, *info;
    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    int error = getaddrinfo(hostname, portStr, &hints, &info);
    if(error != 0) {
#ifdef _WIN32
        UA_LOG_SOCKET_ERRNO_WRAP(
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "TCP\t| Lookup of %s failed (%s)",
                       hostname, errno_str));
#else
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "TCP\t| Lookup of %s failed (%s)",
                       hostname, gai_strerror(error));
#endif
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Create a socket */
    UA_FD newSock = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
    if(newSock == UA_INVALID_FD) {
        freeaddrinfo(info);
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                           "TCP\t| Could not create socket to connect to %s (%s)",
                           hostname, errno_str));
        return UA_STATUSCODE_BADDISCONNECT;
    }

    /* Set the socket options */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    res |= UA_EventLoopPOSIX_setNonBlocking(newSock);
    res |= UA_EventLoopPOSIX_setNoSigPipe(newSock);
    res |= TCP_setNoNagle(newSock);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                           "TCP\t| Could not set socket options: %s", errno_str));
        freeaddrinfo(info);
        UA_close(newSock);
        return res;
    }

    /* Only validate, don't actually open the connection */
    if(validate) {
        freeaddrinfo(info);
        UA_close(newSock);
        return UA_STATUSCODE_GOOD;
    }

    /* Non-blocking connect */
    error = UA_connect(newSock, info->ai_addr, info->ai_addrlen);
    freeaddrinfo(info);
    if(error != 0 &&
       UA_ERRNO != UA_INPROGRESS &&
       UA_ERRNO != UA_WOULDBLOCK) {
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                           "TCP\t| Connecting the socket to %s failed (%s)",
                           hostname, errno_str));
        UA_close(newSock);
        return UA_STATUSCODE_BADDISCONNECT;
    }

    /* Allocate the UA_RegisteredFD */
    TCP_FD *newConn = (TCP_FD*)UA_calloc(1, sizeof(TCP_FD));
    if(!newConn) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "TCP %u\t| Error allocating memory for the socket",
                       (unsigned)newSock);
        UA_close(newSock);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    newConn->rfd.fd = newSock;
    newConn->rfd.es = &pcm->cm.eventSource;
    newConn->rfd.eventSourceCB = (UA_FDCallback)TCP_connectionSocketCallback;
    newConn->rfd.listenEvents = UA_FDEVENT_OUT; /* Switched to _IN once the
                                                 * connection is open */
    newConn->applicationCB = connectionCallback;
    newConn->application = application;
    newConn->context = context;

    /* Register the fd to trigger when output is possible (the connection is open) */
    res = UA_EventLoopPOSIX_registerFD(el, &newConn->rfd);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "TCP\t| Registering the socket to connect to %s failed", hostname);
        UA_close(newSock);
        UA_free(newConn);
        return res;
    }

    /* Register internally in the EventSource */
    ZIP_INSERT(UA_FDTree, &pcm->fds, &newConn->rfd);
    pcm->fdsSize++;

    UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                "TCP %u\t| New connection to \"%s\" on port %s",
                (unsigned)newSock, hostname, portStr);

    /* Signal the new connection to the application as asynchonously opening */
    UA_UNLOCK(&el->elMutex);
    connectionCallback(&pcm->cm, (uintptr_t)newSock,
                       application, &newConn->context,
                       UA_CONNECTIONSTATE_OPENING, &UA_KEYVALUEMAP_NULL,
                       UA_BYTESTRING_NULL);
    UA_LOCK(&el->elMutex);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
TCP_openConnection(UA_ConnectionManager *cm, const UA_KeyValueMap *params,
                   void *application, void *context,
                   UA_ConnectionManager_connectionCallback connectionCallback) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
    UA_LOCK(&el->elMutex);

    if(cm->eventSource.state != UA_EVENTSOURCESTATE_STARTED) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "TCP\t| Cannot open a connection for a "
                     "ConnectionManager that is not started");
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Check the parameters */
    UA_StatusCode res =
        UA_KeyValueRestriction_validate(el->eventLoop.logger, "TCP",
                                        tcpConnectionParams,
                                        TCP_PARAMETERSSIZE, params);
    if(res != UA_STATUSCODE_GOOD) {
        UA_UNLOCK(&el->elMutex);
        return res;
    }

    /* Only validate the parameters? */
    UA_Boolean validate = false;
    const UA_Boolean *validateParam = (const UA_Boolean*)
        UA_KeyValueMap_getScalar(params,
                                 tcpConnectionParams[TCP_PARAMINDEX_VALIDATE].name,
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
    if(validateParam)
        validate = *validateParam;

    /* Listen or active connection? */
    UA_Boolean listen = false;
    const UA_Boolean *listenParam = (const UA_Boolean*)
        UA_KeyValueMap_getScalar(params,
                                 tcpConnectionParams[TCP_PARAMINDEX_LISTEN].name,
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
    if(listenParam)
        listen = *listenParam;

    if(listen) {
        res = TCP_openPassiveConnection(pcm, params, application, context,
                                        connectionCallback, validate);
    } else {
        res = TCP_openActiveConnection(pcm, params, application, context,
                                       connectionCallback, validate);
    }

    UA_UNLOCK(&el->elMutex);
    return res;
}

static UA_StatusCode
TCP_eventSourceStart(UA_ConnectionManager *cm) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
    if(!el)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_LOCK(&el->elMutex);

    /* Check the state */
    if(cm->eventSource.state != UA_EVENTSOURCESTATE_STOPPED) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "TCP\t| To start the ConnectionManager, it has to be "
                     "registered in an EventLoop and not started yet");
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Check the parameters */
    UA_StatusCode res =
        UA_KeyValueRestriction_validate(el->eventLoop.logger, "TCP",
                                        tcpManagerParams, TCP_MANAGERPARAMS,
                                        &cm->eventSource.params);
    if(res != UA_STATUSCODE_GOOD)
        goto finish;

    /* Allocate the rx buffer */
    res = UA_EventLoopPOSIX_allocateStaticBuffers(pcm);
    if(res != UA_STATUSCODE_GOOD)
        goto finish;

    /* Set the EventSource to the started state */
    cm->eventSource.state = UA_EVENTSOURCESTATE_STARTED;

 finish:
    UA_UNLOCK(&el->elMutex);
    return res;
}

static void *
TCP_shutdownCB(void *application, UA_RegisteredFD *rfd) {
    UA_ConnectionManager *cm = (UA_ConnectionManager*)application;
    TCP_shutdown(cm, (TCP_FD*)rfd);
    return NULL;
}

static void
TCP_eventSourceStop(UA_ConnectionManager *cm) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
    (void)el;

    UA_LOCK(&el->elMutex);

    UA_LOG_INFO(cm->eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
                "TCP\t| Shutting down the ConnectionManager");

    /* Prevent new connections to open */
    cm->eventSource.state = UA_EVENTSOURCESTATE_STOPPING;

    /* Shutdown all existing connection */
    ZIP_ITER(UA_FDTree, &pcm->fds, TCP_shutdownCB, cm);

    /* All sockets closed? Otherwise iterate some more. */
    TCP_checkStopped(pcm);

    UA_UNLOCK(&el->elMutex);
}

static UA_StatusCode
TCP_eventSourceDelete(UA_ConnectionManager *cm) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    if(cm->eventSource.state >= UA_EVENTSOURCESTATE_STARTING) {
        UA_LOG_ERROR(cm->eventSource.eventLoop->logger, UA_LOGCATEGORY_EVENTLOOP,
                     "TCP\t| The EventSource must be stopped before it can be deleted");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_ByteString_clear(&pcm->rxBuffer);
    UA_ByteString_clear(&pcm->txBuffer);
    UA_KeyValueMap_clear(&cm->eventSource.params);
    UA_String_clear(&cm->eventSource.name);
    UA_free(cm);

    return UA_STATUSCODE_GOOD;
}

static const char *tcpName = "tcp";

UA_ConnectionManager *
UA_ConnectionManager_new_POSIX_TCP(const UA_String eventSourceName) {
    UA_POSIXConnectionManager *cm = (UA_POSIXConnectionManager*)
        UA_calloc(1, sizeof(UA_POSIXConnectionManager));
    if(!cm)
        return NULL;

    cm->cm.eventSource.eventSourceType = UA_EVENTSOURCETYPE_CONNECTIONMANAGER;
    UA_String_copy(&eventSourceName, &cm->cm.eventSource.name);
    cm->cm.eventSource.start = (UA_StatusCode (*)(UA_EventSource *))TCP_eventSourceStart;
    cm->cm.eventSource.stop = (void (*)(UA_EventSource *))TCP_eventSourceStop;
    cm->cm.eventSource.free = (UA_StatusCode (*)(UA_EventSource *))TCP_eventSourceDelete;
    cm->cm.protocol = UA_STRING((char*)(uintptr_t)tcpName);
    cm->cm.openConnection = TCP_openConnection;
    cm->cm.allocNetworkBuffer = UA_EventLoopPOSIX_allocNetworkBuffer;
    cm->cm.freeNetworkBuffer = UA_EventLoopPOSIX_freeNetworkBuffer;
    cm->cm.sendWithConnection = TCP_sendWithConnection;
    cm->cm.closeConnection = TCP_shutdownConnection;
    return &cm->cm;
}

/**** amalgamated original file "/plugins/eventloop/posix/eventloop_posix_udp.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2021-2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Jan Hermes)
 */


#define IPV4_PREFIX_MASK 0xF0
#define IPV4_MULTICAST_PREFIX 0xE0
#if UA_IPV6
#   define IPV6_PREFIX_MASK 0xFF
#   define IPV6_MULTICAST_PREFIX 0xFF
#endif

/* Configuration parameters */

#define UDP_MANAGERPARAMS 2

static UA_KeyValueRestriction udpManagerParams[UDP_MANAGERPARAMS] = {
    {{0, UA_STRING_STATIC("recv-bufsize")}, &UA_TYPES[UA_TYPES_UINT32], false, true, false},
    {{0, UA_STRING_STATIC("send-bufsize")}, &UA_TYPES[UA_TYPES_UINT32], false, true, false}
};

#define UDP_PARAMETERSSIZE 9
#define UDP_PARAMINDEX_LISTEN 0
#define UDP_PARAMINDEX_ADDR 1
#define UDP_PARAMINDEX_PORT 2
#define UDP_PARAMINDEX_INTERFACE 3
#define UDP_PARAMINDEX_TTL 4
#define UDP_PARAMINDEX_LOOPBACK 5
#define UDP_PARAMINDEX_REUSE 6
#define UDP_PARAMINDEX_SOCKPRIO 7
#define UDP_PARAMINDEX_VALIDATE 8

static UA_KeyValueRestriction udpConnectionParams[UDP_PARAMETERSSIZE] = {
    {{0, UA_STRING_STATIC("listen")}, &UA_TYPES[UA_TYPES_BOOLEAN], false, true, false},
    {{0, UA_STRING_STATIC("address")}, &UA_TYPES[UA_TYPES_STRING], false, true, true},
    {{0, UA_STRING_STATIC("port")}, &UA_TYPES[UA_TYPES_UINT16], true, true, false},
    {{0, UA_STRING_STATIC("interface")}, &UA_TYPES[UA_TYPES_STRING], false, true, false},
    {{0, UA_STRING_STATIC("ttl")}, &UA_TYPES[UA_TYPES_UINT32], false, true, false},
    {{0, UA_STRING_STATIC("loopback")}, &UA_TYPES[UA_TYPES_BOOLEAN], false, true, false},
    {{0, UA_STRING_STATIC("reuse")}, &UA_TYPES[UA_TYPES_BOOLEAN], false, true, false},
    {{0, UA_STRING_STATIC("sockpriority")}, &UA_TYPES[UA_TYPES_UINT32], false, true, false},
    {{0, UA_STRING_STATIC("validate")}, &UA_TYPES[UA_TYPES_BOOLEAN], false, true, false}
};

/* A registered file descriptor with an additional method pointer */
typedef struct {
    UA_RegisteredFD rfd;

    UA_ConnectionManager_connectionCallback applicationCB;
    void *application;
    void *context;

    struct sockaddr_storage sendAddr;
#ifdef _WIN32
    size_t sendAddrLength;
#else
    socklen_t sendAddrLength;
#endif
} UDP_FD;

typedef enum {
    MULTICASTTYPE_NONE = 0,
    MULTICASTTYPE_IPV4,
    MULTICASTTYPE_IPV6
} MultiCastType;

static UA_Boolean
isMulticastAddress(const UA_Byte *address, UA_Byte mask, UA_Byte prefix) {
    return (address[0] & mask) == prefix;
}

static MultiCastType
multiCastType(struct addrinfo *info) {
    const UA_Byte *address;
    if(info->ai_family == AF_INET) {
        address = (UA_Byte *)&((struct sockaddr_in *)info->ai_addr)->sin_addr;
        if(isMulticastAddress(address, IPV4_PREFIX_MASK, IPV4_MULTICAST_PREFIX))
            return MULTICASTTYPE_IPV4;
#if UA_IPV6
    } else if(info->ai_family == AF_INET6) {
        address = (UA_Byte *)&((struct sockaddr_in6 *)info->ai_addr)->sin6_addr;
        if(isMulticastAddress(address, IPV6_PREFIX_MASK, IPV6_MULTICAST_PREFIX))
            return MULTICASTTYPE_IPV6;
#endif
    }
    return MULTICASTTYPE_NONE;
}

typedef union {
    struct ip_mreq ipv4;
#if UA_IPV6
    struct ipv6_mreq ipv6;
#endif
} IpMulticastRequest;

static UA_StatusCode
setupMulticastRequest(UA_FD socket, IpMulticastRequest *req, const UA_KeyValueMap *params,
                      struct addrinfo *info, const UA_Logger *logger) {
    /* Was an interface defined? */
    const UA_String *netif = (const UA_String*)
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_INTERFACE].name,
                                 &UA_TYPES[UA_TYPES_STRING]);
    if(!netif) {
        UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK,
                       "UDP %u\t| No network interface defined for multicast. "
                       "That means the first suitable network interface is used.",
                       (unsigned)socket);
    }

    if(info->ai_family == AF_INET) {
        struct sockaddr_in *sin = (struct sockaddr_in *)info->ai_addr;
        req->ipv4.imr_multiaddr = sin->sin_addr;
        req->ipv4.imr_interface.s_addr = htonl(INADDR_ANY); /* default ANY */
        if(!netif)
            return UA_STATUSCODE_GOOD;
        UA_STACKARRAY(char, interfaceAsChar, sizeof(char) * netif->length + 1);
        memcpy(interfaceAsChar, netif->data, netif->length);
        interfaceAsChar[netif->length] = 0;
        if(UA_inet_pton(AF_INET, interfaceAsChar, &req->ipv4.imr_interface) <= 0) {
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER,
                         "UDP\t| Interface configuration preparation failed.");
            return UA_STATUSCODE_BADINTERNALERROR;
        }
        return UA_STATUSCODE_GOOD;
#if UA_IPV6
    } else if(info->ai_family == AF_INET6) {
        struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)info->ai_addr;
        req->ipv6.ipv6mr_multiaddr = sin6->sin6_addr;
        req->ipv6.ipv6mr_interface = 0; /* default ANY interface */
        if(!netif)
            return UA_STATUSCODE_GOOD;
        UA_STACKARRAY(char, interfaceAsChar, sizeof(char) * netif->length + 1);
        memcpy(interfaceAsChar, netif->data, netif->length);
        interfaceAsChar[netif->length] = 0;
        req->ipv6.ipv6mr_interface = UA_if_nametoindex(interfaceAsChar);
        if(req->ipv6.ipv6mr_interface == 0) {
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SERVER,
                         "UDP\t| Interface configuration preparation failed.");
            return UA_STATUSCODE_BADINTERNALERROR;
        }
        return UA_STATUSCODE_GOOD;
#endif
    }
    return UA_STATUSCODE_BADINTERNALERROR;
}

/* Retrieves hostname and port from given key value parameters.
 *
 * @param[in] params the parameter map to retrieve from
 * @param[out] hostname the retrieved hostname when present, NULL otherwise
 * @param[out] portStr the retrieved port when present, NULL otherwise
 * @param[in] logger the logger to log information
 * @return -1 upon error, 0 if there was no host or port parameter, 1 if
 *         host and port are present */
static int
getHostAndPortFromParams(const UA_KeyValueMap *params,
                         char *hostname, char *portStr, const UA_Logger *logger) {
    /* Prepare the port parameter as a string */
    const UA_UInt16 *port = (const UA_UInt16*)
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_PORT].name,
                                 &UA_TYPES[UA_TYPES_UINT16]);
    UA_assert(port); /* checked before */
    mp_snprintf(portStr, UA_MAXPORTSTR_LENGTH, "%d", *port);

    /* Prepare the hostname string */
    const UA_String *host = (const UA_String*)
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_ADDR].name,
                                 &UA_TYPES[UA_TYPES_STRING]);
    if(!host) {
        UA_LOG_DEBUG(logger, UA_LOGCATEGORY_NETWORK,
                     "UDP\t| No address configured");
        return -1;
    }
    if(host->length >= UA_MAXHOSTNAME_LENGTH) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_EVENTLOOP,
                     "UDP\t| Open UDP Connection: Hostname too long, aborting");
        return -1;
    }
    strncpy(hostname, (const char*)host->data, host->length);
    hostname[host->length] = 0;
    return 1;
}

static int
getConnectionInfoFromParams(const UA_KeyValueMap *params,
                            char *hostname, char *portStr,
                            struct addrinfo **info, const UA_Logger *logger) {
    int foundParams = getHostAndPortFromParams(params, hostname, portStr, logger);
    if(foundParams < 0)
        return -1;

    /* Create the socket description from the connectString
     * TODO: Make this non-blocking */
    struct addrinfo hints;
    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_DGRAM;
    int error = getaddrinfo(hostname, portStr, &hints, info);
    if(error != 0) {
        UA_LOG_SOCKET_ERRNO_GAI_WRAP(
            UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK,
                           "UDP\t| Lookup of %s failed with error %d - %s",
                           hostname, error, errno_str));
        return -1;
    }
    return 1;
}

/* Set loop back data to your host */
static UA_StatusCode
setLoopBackData(UA_SOCKET sockfd, UA_Boolean enableLoopback,
                int ai_family, const UA_Logger *logger) {
    /* The Linux Kernel IPv6 socket code checks for optlen to be at least the
     * size of an integer. However, channelDataUDPMC->enableLoopback is a
     * boolean. In order for the code to work for IPv4 and IPv6 propagate it to
     * a temporary integer here. */
    UA_Int32 enable = enableLoopback;
#if UA_IPV6
    if(UA_setsockopt(sockfd,
                     ai_family == AF_INET6 ? IPPROTO_IPV6 : IPPROTO_IP,
                     ai_family == AF_INET6 ? IPV6_MULTICAST_LOOP : IP_MULTICAST_LOOP,
                     (const char *)&enable,
                     sizeof (enable)) < 0)
#else
        if(UA_setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_LOOP,
                     (const char *)&enable,
                     sizeof (enable)) < 0)
#endif
    {
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_NETWORK,
                         "UDP %u\t| Loopback setup failed: "
                         "Cannot set socket option IP_MULTICAST_LOOP. Error: %s",
                         (unsigned)sockfd, errno_str));
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
setTimeToLive(UA_SOCKET sockfd, UA_UInt32 messageTTL,
              int ai_family, const UA_Logger *logger) {
    /* Set Time to live (TTL). Value of 1 prevent forward beyond the local network. */
#if UA_IPV6
    if(UA_setsockopt(sockfd,
                     ai_family == PF_INET6 ? IPPROTO_IPV6 : IPPROTO_IP,
                     ai_family == PF_INET6 ? IPV6_MULTICAST_HOPS : IP_MULTICAST_TTL,
                     (const char *)&messageTTL,
                     sizeof(messageTTL)) < 0)
#else
    if(UA_setsockopt(sockfd, IPPROTO_IP, IP_MULTICAST_TTL,
                     (const char *)&messageTTL,
                     sizeof(messageTTL)) < 0)
#endif
    {
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK,
                           "UDP %u\t| Time to live setup failed: "
                           "Cannot set socket option IP_MULTICAST_TTL. Error: %s",
                           (unsigned)sockfd, errno_str));
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
setReuseAddress(UA_SOCKET sockfd, UA_Boolean enableReuse, const UA_Logger *logger) {
    /* Set reuse address -> enables sharing of the same listening address on
     * different sockets */
    int enableReuseVal = (enableReuse) ? 1 : 0;
    if(UA_setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
                     (const char*)&enableReuseVal, sizeof(enableReuseVal)) < 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK,
                           "UDP %u\t| Reuse address setup failed: "
                           "Cannot set socket option SO_REUSEADDR. Error: %s",
                           (unsigned)sockfd, errno_str));
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return UA_STATUSCODE_GOOD;
}

#ifdef __linux__
static UA_StatusCode
setSocketPriority(UA_SOCKET sockfd, UA_UInt32 socketPriority,
                  const UA_Logger *logger) {
    int prio = (int)socketPriority;
    if(UA_setsockopt(sockfd, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(int)) < 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_NETWORK,
                         "UDP %u\t| Socket priority setup failed: "
                         "Cannot set socket option SO_PRIORITY. Error: %s",
                         (unsigned)sockfd, errno_str));
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return UA_STATUSCODE_GOOD;
}
#endif

static UA_StatusCode
setConnectionConfig(UA_FD socket, const UA_KeyValueMap *params,
                    int ai_family, const UA_Logger *logger) {
    /* Set socket config that is always set */
    UA_StatusCode res = UA_STATUSCODE_GOOD;
    res |= UA_EventLoopPOSIX_setNonBlocking(socket);
    res |= UA_EventLoopPOSIX_setNoSigPipe(socket);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    /* Some Linux distributions have net.ipv6.bindv6only not activated. So
     * sockets can double-bind to IPv4 and IPv6. This leads to problems. Use
     * AF_INET6 sockets only for IPv6. */
    int optval = 1;
#if UA_IPV6
    if(ai_family == AF_INET6 &&
       UA_setsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY,
                     (const char*)&optval, sizeof(optval)) == -1) {
        UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK,
                       "UDP %u\t| Could not set an IPv6 socket to IPv6 only, closing",
                       (unsigned)socket);
        return UA_STATUSCODE_BADCONNECTIONREJECTED;
    }
#endif

    /* Set socket settings from the parameters */
    const UA_UInt32 *messageTTL = (const UA_UInt32*)
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_TTL].name,
                                 &UA_TYPES[UA_TYPES_UINT32]);
    if(messageTTL)
        res |= setTimeToLive(socket, *messageTTL, ai_family, logger);

    const UA_Boolean *enableLoopback = (const UA_Boolean*)
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_LOOPBACK].name,
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
    if(enableLoopback)
        res |= setLoopBackData(socket, *enableLoopback, ai_family, logger);

    const UA_Boolean *enableReuse = (const UA_Boolean*)
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_REUSE].name,
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
    if(enableReuse)
        res |= setReuseAddress(socket, *enableReuse, logger);

#ifdef __linux__
    const UA_UInt32 *socketPriority = (const UA_UInt32*)
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_SOCKPRIO].name,
                                 &UA_TYPES[UA_TYPES_UINT32]);
    if(socketPriority)
        res |= setSocketPriority(socket, *socketPriority, logger);
#endif

    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK,
                           "UDP\t| Could not set socket options: %s", errno_str));
    }
    return res;
}

static UA_StatusCode
setupListenMultiCast(UA_FD fd, struct addrinfo *info, const UA_KeyValueMap *params,
                     MultiCastType multiCastType, const UA_Logger *logger) {
    IpMulticastRequest req;
    UA_StatusCode res = setupMulticastRequest(fd, &req, params, info, logger);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    int result = -1;
    if(info->ai_family == AF_INET && multiCastType == MULTICASTTYPE_IPV4) {
        result = UA_setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
                               &req.ipv4, sizeof(req.ipv4));
#if UA_IPV6
    } else if(info->ai_family == AF_INET6 && multiCastType == MULTICASTTYPE_IPV6) {
        result = UA_setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP,
                               &req.ipv6, sizeof(req.ipv6));
#endif
    }

    if(result < 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_NETWORK,
                         "UDP %u\t| Cannot set socket for multicast receiving. Error: %s",
                         (unsigned)fd, errno_str));
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
setupSendMultiCast(UA_FD fd, struct addrinfo *info, const UA_KeyValueMap *params,
                   MultiCastType multiCastType, const UA_Logger *logger) {
    IpMulticastRequest req;
    UA_StatusCode res = setupMulticastRequest(fd, &req, params, info, logger);
    if(res != UA_STATUSCODE_GOOD)
        return res;

    int result = -1;
    if(info->ai_family == AF_INET && multiCastType == MULTICASTTYPE_IPV4) {
        result = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
#ifdef _WIN32
                            (const char *)&req.ipv4.imr_interface,
#else
                            &req.ipv4.imr_interface,
#endif
                            sizeof(struct in_addr));
#if UA_IPV6
    } else if(info->ai_family == AF_INET6 && multiCastType == MULTICASTTYPE_IPV6) {
        result = setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
#ifdef _WIN32
                            (const char *)&req.ipv6.ipv6mr_interface,
#else
                            &req.ipv6.ipv6mr_interface,
#endif
                            sizeof(req.ipv6.ipv6mr_interface));
#endif
    }

    if(result < 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_NETWORK,
                         "UDP %u\t| Cannot set socket for multicast sending. Error: %s",
                         (unsigned)fd, errno_str));
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return UA_STATUSCODE_GOOD;
}

/* Test if the ConnectionManager can be stopped */
static void
UDP_checkStopped(UA_POSIXConnectionManager *pcm) {
    UA_LOCK_ASSERT(&((UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop)->elMutex, 1);

    if(pcm->fdsSize == 0 &&
       pcm->cm.eventSource.state == UA_EVENTSOURCESTATE_STOPPING) {
        UA_LOG_DEBUG(pcm->cm.eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
                     "UDP\t| All sockets closed, the EventLoop has stopped");
        pcm->cm.eventSource.state = UA_EVENTSOURCESTATE_STOPPED;
    }
}

/* This method must not be called from the application directly, but from within
 * the EventLoop. Otherwise we cannot be sure whether the file descriptor is
 * still used after calling close. */
static void
UDP_close(UA_POSIXConnectionManager *pcm, UDP_FD *conn) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex, 1);

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "UDP %u\t| Closing connection",
                 (unsigned)conn->rfd.fd);

    /* Deregister from the EventLoop */
    UA_EventLoopPOSIX_deregisterFD(el, &conn->rfd);

    /* Deregister internally */
    ZIP_REMOVE(UA_FDTree, &pcm->fds, &conn->rfd);
    UA_assert(pcm->fdsSize > 0);
    pcm->fdsSize--;

    /* Signal closing to the application */
    UA_UNLOCK(&el->elMutex);
    conn->applicationCB(&pcm->cm, (uintptr_t)conn->rfd.fd,
                        conn->application, &conn->context,
                        UA_CONNECTIONSTATE_CLOSING,
                        &UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);
    UA_LOCK(&el->elMutex);

    /* Close the socket */
    int ret = UA_close(conn->rfd.fd);
    if(ret == 0) {
        UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                    "UDP %u\t| Socket closed", (unsigned)conn->rfd.fd);
    } else {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "UDP %u\t| Could not close the socket (%s)",
                          (unsigned)conn->rfd.fd, errno_str));
    }

    UA_free(conn);

    /* Stop if the ucm is stopping and this was the last open socket */
    UDP_checkStopped(pcm);
}

static void
UDP_delayedClose(void *application, void *context) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)application;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
    UDP_FD *conn = (UDP_FD*)context;
    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                 "UDP %u\t| Delayed closing of the connection",
                 (unsigned)conn->rfd.fd);
    UA_LOCK(&el->elMutex);
    UDP_close(pcm, conn);
    UA_UNLOCK(&el->elMutex);
}

/* Gets called when a socket receives data or closes */
static void
UDP_connectionSocketCallback(UA_POSIXConnectionManager *pcm, UDP_FD *conn,
                             short event) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex, 1);

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "UDP %u\t| Activity on the socket",
                 (unsigned)conn->rfd.fd);

    if(event == UA_FDEVENT_ERR) {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                        "UDP %u\t| recv signaled the socket was shutdown (%s)",
                        (unsigned)conn->rfd.fd, errno_str));
        UDP_close(pcm, conn);
        return;
    }

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "UDP %u\t| Allocate receive buffer", (unsigned)conn->rfd.fd);

    /* Use the already allocated receive-buffer */
    UA_ByteString response = pcm->rxBuffer;

    /* Receive */
    struct sockaddr_storage source;
#ifndef _WIN32
    socklen_t sourceSize = (socklen_t)sizeof(struct sockaddr_storage);
    ssize_t ret = recvfrom(conn->rfd.fd, (char*)response.data, response.length,
                           MSG_DONTWAIT, (struct sockaddr*)&source, &sourceSize);
#else
    int sourceSize = (int)sizeof(struct sockaddr_storage);
    int ret = recvfrom(conn->rfd.fd, (char*)response.data, (int)response.length,
                       MSG_DONTWAIT, (struct sockaddr*)&source, &sourceSize);
#endif

    /* Receive has failed */
    if(ret <= 0) {
        if(UA_ERRNO == UA_INTERRUPTED)
            return;

        /* Orderly shutdown of the socket. We can immediately close as no method
         * "below" in the call stack will use the socket in this iteration of
         * the EventLoop. */
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                        "UDP %u\t| recv signaled the socket was shutdown (%s)",
                        (unsigned)conn->rfd.fd, errno_str));
        UDP_close(pcm, conn);
        return;
    }

    response.length = (size_t)ret; /* Set the length of the received buffer */

    /* Extract message source and port */
    char sourceAddr[64];
    UA_UInt16 sourcePort;
    switch(source.ss_family) {
        case AF_INET:
            inet_ntop(AF_INET, &((struct sockaddr_in *)&source)->sin_addr,
                    sourceAddr, 64);
            sourcePort = htons(((struct sockaddr_in *)&source)->sin_port);
            break;
        case AF_INET6:
            inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)&source)->sin6_addr),
                    sourceAddr, 64);
            sourcePort = htons(((struct sockaddr_in6 *)&source)->sin6_port);
            break;
        default:
            sourceAddr[0] = 0;
            sourcePort = 0;
    }

    UA_String sourceAddrStr = UA_STRING(sourceAddr);
    UA_KeyValuePair kvp[2];
    kvp[0].key = UA_QUALIFIEDNAME(0, "remote-address");
    UA_Variant_setScalar(&kvp[0].value, &sourceAddrStr, &UA_TYPES[UA_TYPES_STRING]);
    kvp[1].key = UA_QUALIFIEDNAME(0, "remote-port");
    UA_Variant_setScalar(&kvp[1].value, &sourcePort, &UA_TYPES[UA_TYPES_UINT16]);
    UA_KeyValueMap kvm = {2, kvp};

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "UDP %u\t| Received message of size %u from %s on port %u",
                 (unsigned)conn->rfd.fd, (unsigned)ret,
                 sourceAddr, sourcePort);

    /* Callback to the application layer */
    UA_UNLOCK(&el->elMutex);
    conn->applicationCB(&pcm->cm, (uintptr_t)conn->rfd.fd,
                        conn->application, &conn->context,
                        UA_CONNECTIONSTATE_ESTABLISHED,
                        &kvm, response);
    UA_LOCK(&el->elMutex);
}

static UA_StatusCode
UDP_registerListenSocket(UA_POSIXConnectionManager *pcm, UA_UInt16 port,
                         struct addrinfo *info, const UA_KeyValueMap *params,
                         void *application, void *context,
                         UA_ConnectionManager_connectionCallback connectionCallback,
                         UA_Boolean validate) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex, 1);

    /* Get logging information */
    char hoststr[UA_MAXHOSTNAME_LENGTH];
    int get_res = UA_getnameinfo(info->ai_addr, info->ai_addrlen,
                                 hoststr, sizeof(hoststr),
                                 NULL, 0, NI_NUMERICHOST);
    if(get_res != 0) {
        hoststr[0] = 0;
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "UDP\t| getnameinfo(...) could not resolve the hostname (%s)",
                          errno_str));
        if(validate) {
            return UA_STATUSCODE_BADCONNECTIONREJECTED;
        }
    }

    /* Create the listen socket */
    UA_FD listenSocket = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
    if(listenSocket == UA_INVALID_FD) {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "UDP %u\t| Error opening the listen socket for "
                          "\"%s\" on port %u (%s)",
                          (unsigned)listenSocket, hoststr, port, errno_str));
        return UA_STATUSCODE_BADCONNECTIONREJECTED;
    }

    UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                "UDP %u\t| New listen socket for \"%s\" on port %u",
                (unsigned)listenSocket, hoststr, port);

    /* Set the socket configuration per the parameters */
    UA_StatusCode res =
        setConnectionConfig(listenSocket, params,
                            info->ai_family, el->eventLoop.logger);
    if(res != UA_STATUSCODE_GOOD) {
        UA_close(listenSocket);
        return UA_STATUSCODE_BADCONNECTIONREJECTED;
    }

    /* Are we going to prepare a socket for multicast? */
    MultiCastType mc = multiCastType(info);

    /* Bind socket to the address */
#ifdef _WIN32
    /* On windows we need to bind the socket to INADDR_ANY before registering
     * for the multicast group */
    int ret = -1;
    if(mc != MULTICASTTYPE_NONE) {
        if(info->ai_family == AF_INET) {
            struct sockaddr_in *orig = (struct sockaddr_in *)info->ai_addr;
            struct sockaddr_in sin;
            memset(&sin, 0, sizeof(sin));
            sin.sin_family = AF_INET;
            sin.sin_addr.s_addr = htonl(INADDR_ANY);
            sin.sin_port = orig->sin_port;
            ret = bind(listenSocket, (struct sockaddr*)&sin, sizeof(sin));
        } else if(info->ai_family == AF_INET6) {
            struct sockaddr_in6 *orig = (struct sockaddr_in6 *)info->ai_addr;
            struct sockaddr_in6 sin6;
            memset(&sin6, 0, sizeof(sin6));
            sin6.sin6_family = AF_INET6;
            sin6.sin6_addr = in6addr_any;
            sin6.sin6_port = orig->sin6_port;
            ret = bind(listenSocket, (struct sockaddr*)&sin6, sizeof(sin6));
        }
    } else {
        ret = bind(listenSocket, info->ai_addr, (socklen_t)info->ai_addrlen);
    }
#else
    int ret = bind(listenSocket, info->ai_addr, (socklen_t)info->ai_addrlen);
#endif
    if(ret < 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "UDP %u\t| Error binding the socket to the address (%s), closing",
                          (unsigned)listenSocket, errno_str));
        UA_close(listenSocket);
        return UA_STATUSCODE_BADCONNECTIONREJECTED;
    }

    /* Enable multicast if this is a multicast address */
    if(mc != MULTICASTTYPE_NONE) {
        res = setupListenMultiCast(listenSocket, info, params,
                                   mc, el->eventLoop.logger);
        if(res != UA_STATUSCODE_GOOD) {
            UA_close(listenSocket);
            return res;
        }
    }

    /* Validation is complete - close and return */
    if(validate) {
        UA_close(listenSocket);
        return UA_STATUSCODE_GOOD;
    }

    /* Allocate the UA_RegisteredFD */
    UDP_FD *newudpfd = (UDP_FD*)UA_calloc(1, sizeof(UDP_FD));
    if(!newudpfd) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "UDP %u\t| Error allocating memory for the socket, closing",
                       (unsigned)listenSocket);
        UA_close(listenSocket);
        return UA_STATUSCODE_BADCONNECTIONREJECTED;
    }

    newudpfd->rfd.fd = listenSocket;
    newudpfd->rfd.es = &pcm->cm.eventSource;
    newudpfd->rfd.listenEvents = UA_FDEVENT_IN;
    newudpfd->rfd.eventSourceCB = (UA_FDCallback)UDP_connectionSocketCallback;
    newudpfd->applicationCB = connectionCallback;
    newudpfd->application = application;
    newudpfd->context = context;

    /* Register in the EventLoop */
    res = UA_EventLoopPOSIX_registerFD(el, &newudpfd->rfd);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "UDP %u\t| Error registering the socket, closing",
                       (unsigned)listenSocket);
        UA_free(newudpfd);
        UA_close(listenSocket);
        return res;
    }

    /* Register internally in the EventSource */
    ZIP_INSERT(UA_FDTree, &pcm->fds, &newudpfd->rfd);
    pcm->fdsSize++;

    /* Register the listen socket in the application */
    UA_UNLOCK(&el->elMutex);
    connectionCallback(&pcm->cm, (uintptr_t)newudpfd->rfd.fd,
                       application, &newudpfd->context,
                       UA_CONNECTIONSTATE_ESTABLISHED,
                       &UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);
    UA_LOCK(&el->elMutex);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UDP_registerListenSockets(UA_POSIXConnectionManager *pcm, const char *hostname,
                          UA_UInt16 port, const UA_KeyValueMap *params,
                          void *application, void *context,
                          UA_ConnectionManager_connectionCallback connectionCallback,
                          UA_Boolean validate) {
    UA_LOCK_ASSERT(&((UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop)->elMutex, 1);

    /* Get all the interface and IPv4/6 combinations for the configured hostname */
    struct addrinfo hints, *res;
    memset(&hints, 0, sizeof hints);
#if UA_IPV6
    hints.ai_family = AF_UNSPEC; /* Allow IPv4 and IPv6 */
#else
    hints.ai_family = AF_INET;   /* IPv4 only */
#endif
    hints.ai_socktype = SOCK_DGRAM;
    hints.ai_protocol = IPPROTO_UDP;
    hints.ai_flags = AI_PASSIVE;

    /* Set up the port string */
    char portstr[6];
    mp_snprintf(portstr, 6, "%d", port);

    int retcode = getaddrinfo(hostname, portstr, &hints, &res);
    if(retcode != 0) {
        UA_LOG_SOCKET_ERRNO_GAI_WRAP(
           UA_LOG_WARNING(pcm->cm.eventSource.eventLoop->logger,
                          UA_LOGCATEGORY_NETWORK,
                          "UDP\t| getaddrinfo lookup for \"%s\" on port %u failed (%s)",
                          hostname, port, errno_str));
        return UA_STATUSCODE_BADCONNECTIONREJECTED;
    }

    /* Add listen sockets */
    struct addrinfo *ai = res;
    UA_StatusCode rv = UA_STATUSCODE_GOOD;
    while(ai) {
        rv = UDP_registerListenSocket(pcm, port, ai, params, application,
                                      context, connectionCallback, validate);
        if(rv != UA_STATUSCODE_GOOD)
            break;
        ai = ai->ai_next;
    }
    freeaddrinfo(res);
    return rv;
}

/* Close the connection via a delayed callback */
static void
UDP_shutdown(UA_ConnectionManager *cm, UA_RegisteredFD *rfd) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)cm->eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex, 1);

    if(rfd->dc.callback) {
        UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "UDP %u\t| Cannot close - already closing",
                     (unsigned)rfd->fd);
        return;
    }

    /* Shutdown the socket to cancel the current select/epoll */
    shutdown(rfd->fd, UA_SHUT_RDWR);

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "UDP %u\t| Shutdown called", (unsigned)rfd->fd);

    UA_DelayedCallback *dc = &rfd->dc;
    dc->callback = UDP_delayedClose;
    dc->application = cm;
    dc->context = rfd;

    /* Don't use the "public" el->addDelayedCallback. It takes a lock. */
    dc->next = el->delayedCallbacks;
    el->delayedCallbacks = dc;
}

static UA_StatusCode
UDP_shutdownConnection(UA_ConnectionManager *cm, uintptr_t connectionId) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)cm->eventSource.eventLoop;
    UA_FD fd = (UA_FD)connectionId;

    UA_LOCK(&el->elMutex);
    UA_RegisteredFD *rfd = ZIP_FIND(UA_FDTree, &pcm->fds, &fd);
    if(!rfd) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "UDP\t| Cannot close UDP connection %u - not found",
                       (unsigned)connectionId);
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADNOTFOUND;
    }
    UDP_shutdown(cm, rfd);
    UA_UNLOCK(&el->elMutex);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UDP_sendWithConnection(UA_ConnectionManager *cm, uintptr_t connectionId,
                       const UA_KeyValueMap *params,
                       UA_ByteString *buf) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;

    UA_LOCK(&el->elMutex);

    /* Look up the registered UDP socket */
    UA_FD fd = (UA_FD)connectionId;
    UDP_FD *conn = (UDP_FD*)ZIP_FIND(UA_FDTree, &pcm->fds, &fd);
    if(!conn) {
        UA_UNLOCK(&el->elMutex);
        UA_EventLoopPOSIX_freeNetworkBuffer(cm, connectionId, buf);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Send the full buffer. This may require several calls to send */
    size_t nWritten = 0;
    do {
        ssize_t n = 0;
        do {
            UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                         "UDP %u\t| Attempting to send", (unsigned)connectionId);

            /* Prevent OS signals when sending to a closed socket */
            int flags = MSG_NOSIGNAL;
            size_t bytes_to_send = buf->length - nWritten;
            n = UA_sendto((UA_FD)connectionId, (const char*)buf->data + nWritten,
                          bytes_to_send, flags, (struct sockaddr*)&conn->sendAddr,
                          conn->sendAddrLength);
            if(n < 0) {
                /* An error we cannot recover from? */
                if(UA_ERRNO != UA_INTERRUPTED &&
                   UA_ERRNO != UA_WOULDBLOCK &&
                   UA_ERRNO != UA_AGAIN) {
                    UA_LOG_SOCKET_ERRNO_WRAP(
                       UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                                    "UDP %u\t| Send failed with error %s",
                                    (unsigned)connectionId, errno_str));
                    UA_UNLOCK(&el->elMutex);
                    UDP_shutdownConnection(cm, connectionId);
                    UA_EventLoopPOSIX_freeNetworkBuffer(cm, connectionId, buf);
                    return UA_STATUSCODE_BADCONNECTIONCLOSED;
                }

                /* Poll for the socket resources to become available and retry
                 * (blocking) */
                int poll_ret;
                struct pollfd tmp_poll_fd;
                tmp_poll_fd.fd = (UA_FD)connectionId;
                tmp_poll_fd.events = UA_POLLOUT;
                do {
                    poll_ret = UA_poll(&tmp_poll_fd, 1, 100);
                    if(poll_ret < 0 && UA_ERRNO != UA_INTERRUPTED) {
                        UA_LOG_SOCKET_ERRNO_WRAP(
                           UA_LOG_ERROR(el->eventLoop.logger,
                                        UA_LOGCATEGORY_NETWORK,
                                        "UDP %u\t| Send failed with error %s",
                                        (unsigned)connectionId, errno_str));
                        UA_EventLoopPOSIX_freeNetworkBuffer(cm, connectionId, buf);
                        UDP_shutdown(cm, &conn->rfd);
                        UA_UNLOCK(&el->elMutex);
                        return UA_STATUSCODE_BADCONNECTIONCLOSED;
                    }
                } while(poll_ret <= 0);
            }
        } while(n < 0);
        nWritten += (size_t)n;
    } while(nWritten < buf->length);

    /* Free the buffer */
    UA_UNLOCK(&el->elMutex);
    UA_EventLoopPOSIX_freeNetworkBuffer(cm, connectionId, buf);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
registerSocketAndDestinationForSend(const UA_KeyValueMap *params,
                                    const char *hostname, struct addrinfo *info,
                                    int error, UDP_FD *ufd, UA_FD *sock,
                                    const UA_Logger *logger) {
    UA_FD newSock = socket(info->ai_family, info->ai_socktype, info->ai_protocol);
    *sock = newSock;
    if(newSock == UA_INVALID_FD) {
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_WARNING(logger, UA_LOGCATEGORY_NETWORK,
                           "UDP\t| Could not create socket to connect to %s (%s)",
                           hostname, errno_str));
        return UA_STATUSCODE_BADDISCONNECT;
    }
    UA_StatusCode res = setConnectionConfig(newSock, params, info->ai_family, logger);
    if(res != UA_STATUSCODE_GOOD) {
        UA_close(newSock);
        return res;
    }

    /* Prepare socket for multicast */
    MultiCastType mc = multiCastType(info);
    if(mc != MULTICASTTYPE_NONE) {
        res = setupSendMultiCast(newSock, info, params, mc, logger);
        if(res != UA_STATUSCODE_GOOD) {
            UA_close(newSock);
            return res;
        }
    }

    memcpy(&ufd->sendAddr, info->ai_addr, info->ai_addrlen);
    ufd->sendAddrLength = info->ai_addrlen;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UDP_openSendConnection(UA_POSIXConnectionManager *pcm, const UA_KeyValueMap *params,
                       void *application, void *context,
                       UA_ConnectionManager_connectionCallback connectionCallback,
                       UA_Boolean validate) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)pcm->cm.eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex, 1);

    /* Get the connection parameters */
    char hostname[UA_MAXHOSTNAME_LENGTH];
    char portStr[UA_MAXPORTSTR_LENGTH];
    struct addrinfo *info = NULL;

    int error = getConnectionInfoFromParams(params, hostname,
                                            portStr, &info, el->eventLoop.logger);
    if(error < 0 || info == NULL) {
        if(info != NULL) {
            freeaddrinfo(info);
        }
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "UDP\t| Opening a connection failed");
        return UA_STATUSCODE_BADCONNECTIONREJECTED;
    }
    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "UDP\t| Open a connection to \"%s\" on port %s", hostname, portStr);

    /* Allocate the UA_RegisteredFD */
    UDP_FD *conn = (UDP_FD*)UA_calloc(1, sizeof(UDP_FD));
    if(!conn) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "UDP\t| Error allocating memory for the socket, closing");
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    /* Create a socket and register the destination address from the provided parameters */
    UA_FD newSock = UA_INVALID_FD;
    UA_StatusCode res =
        registerSocketAndDestinationForSend(params, hostname, info,
                                            error, conn, &newSock,
                                            el->eventLoop.logger);
    freeaddrinfo(info);
    if(validate && res == UA_STATUSCODE_GOOD) {
        UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                    "UDP %u\t| Connection validated to \"%s\" on port %s",
                    (unsigned)newSock, hostname, portStr);
        UA_close(newSock);
        UA_free(conn);
        return UA_STATUSCODE_GOOD;
    }
    if(res != UA_STATUSCODE_GOOD) {
        UA_free(conn);
        return res;
    }

    conn->rfd.fd = newSock;
    conn->rfd.listenEvents = 0;
    conn->rfd.es = &pcm->cm.eventSource;
    conn->rfd.eventSourceCB = (UA_FDCallback)UDP_connectionSocketCallback;
    conn->applicationCB = connectionCallback;
    conn->application = application;
    conn->context = context;

    /* Register the fd to trigger when output is possible (the connection is open) */
    res = UA_EventLoopPOSIX_registerFD(el, &conn->rfd);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "UDP\t| Registering the socket for %s failed", hostname);
        UA_close(newSock);
        UA_free(conn);
        return res;
    }

    /* Register internally in the EventSource */
    ZIP_INSERT(UA_FDTree, &pcm->fds, &conn->rfd);
    pcm->fdsSize++;

    UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                "UDP %u\t| New connection to \"%s\" on port %s",
                (unsigned)newSock, hostname, portStr);

    /* Signal the connection as opening. The connection fully opens in the next
     * iteration of the EventLoop */
    UA_UNLOCK(&el->elMutex);
    connectionCallback(&pcm->cm, (uintptr_t)newSock, application,
                       &conn->context, UA_CONNECTIONSTATE_ESTABLISHED,
                       &UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);
    UA_LOCK(&el->elMutex);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UDP_openReceiveConnection(UA_POSIXConnectionManager *pcm, const UA_KeyValueMap *params,
                          void *application, void *context,
                          UA_ConnectionManager_connectionCallback connectionCallback,
                          UA_Boolean validate) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex, 1);

    /* Get the port */
    const UA_UInt16 *port = (const UA_UInt16*)
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_PORT].name,
                                 &UA_TYPES[UA_TYPES_UINT16]);
    UA_assert(port); /* checked before */

    /* Get the hostname configuration */
    const UA_Variant *addrs =
        UA_KeyValueMap_get(params, udpConnectionParams[UDP_PARAMINDEX_ADDR].name);
    size_t addrsSize = 0;
    if(addrs) {
        UA_assert(addrs->type == &UA_TYPES[UA_TYPES_STRING]);
        if(UA_Variant_isScalar(addrs))
            addrsSize = 1;
        else
            addrsSize = addrs->arrayLength;
    }

    /* No hostname configured -> listen on all interfaces */
    if(addrsSize == 0) {
        UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "UDP\t| Listening on all interfaces");
        return UDP_registerListenSockets(pcm, NULL, *port, params, application,
                                         context, connectionCallback, validate);
    }

    /* Iterate over the configured hostnames */
    UA_String *hostStrings = (UA_String*)addrs->data;
    for(size_t i = 0; i < addrsSize; i++) {
        char hn[UA_MAXHOSTNAME_LENGTH];
        if(hostStrings[i].length >= sizeof(hn))
            continue;
        memcpy(hn, hostStrings[i].data, hostStrings->length);
        hn[hostStrings->length] = '\0';
        UA_StatusCode rv =
            UDP_registerListenSockets(pcm, hn, *port, params, application,
                                      context, connectionCallback, validate);
        if(rv != UA_STATUSCODE_GOOD)
            return rv;
    }

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UDP_openConnection(UA_ConnectionManager *cm, const UA_KeyValueMap *params,
                   void *application, void *context,
                   UA_ConnectionManager_connectionCallback connectionCallback) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
    UA_LOCK(&el->elMutex);

    if(cm->eventSource.state != UA_EVENTSOURCESTATE_STARTED) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "UDP\t| Cannot open a connection for a "
                     "ConnectionManager that is not started");
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Check the parameters */
    UA_StatusCode res =
        UA_KeyValueRestriction_validate(el->eventLoop.logger, "UDP",
                                        udpConnectionParams,
                                        UDP_PARAMETERSSIZE, params);
    if(res != UA_STATUSCODE_GOOD) {
        UA_UNLOCK(&el->elMutex);
        return res;
    }

    UA_Boolean validate = false;
    const UA_Boolean *validationValue = (const UA_Boolean*)
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_VALIDATE].name,
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
    if(validationValue)
        validate = *validationValue;

    UA_Boolean listen = false;
    const UA_Boolean *listenValue = (const UA_Boolean*)
        UA_KeyValueMap_getScalar(params, udpConnectionParams[UDP_PARAMINDEX_LISTEN].name,
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
    if(listenValue)
        listen = *listenValue;

    if(listen) {
        res = UDP_openReceiveConnection(pcm, params, application, context,
                                        connectionCallback, validate);
    } else {
        res = UDP_openSendConnection(pcm, params, application, context,
                                     connectionCallback, validate);
    }
    UA_UNLOCK(&el->elMutex);
    return res;
}

static UA_StatusCode
UDP_eventSourceStart(UA_ConnectionManager *cm) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
    if(!el)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_LOCK(&el->elMutex);

    /* Check the state */
    if(cm->eventSource.state != UA_EVENTSOURCESTATE_STOPPED) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "UDP\t| To start the ConnectionManager, "
                     "it has to be registered in an EventLoop and not started");
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Check the parameters */
    UA_StatusCode res =
        UA_KeyValueRestriction_validate(el->eventLoop.logger, "UDP",
                                        udpManagerParams, UDP_MANAGERPARAMS,
                                        &cm->eventSource.params);
    if(res != UA_STATUSCODE_GOOD)
        goto finish;

    /* Allocate the rx buffer */
    res = UA_EventLoopPOSIX_allocateStaticBuffers(pcm);
    if(res != UA_STATUSCODE_GOOD)
        goto finish;

    /* Set the EventSource to the started state */
    cm->eventSource.state = UA_EVENTSOURCESTATE_STARTED;

 finish:
    UA_UNLOCK(&el->elMutex);
    return res;
}

static void *
UDP_shutdownCB(void *application, UA_RegisteredFD *rfd) {
    UA_ConnectionManager *cm = (UA_ConnectionManager*)application;
    UDP_shutdown(cm, rfd);
    return NULL;
}

static void
UDP_eventSourceStop(UA_ConnectionManager *cm) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
    (void)el;
    UA_LOCK(&el->elMutex);

    UA_LOG_INFO(cm->eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
                "UDP\t| Shutting down the ConnectionManager");

    /* Prevent new connections to open */
    cm->eventSource.state = UA_EVENTSOURCESTATE_STOPPING;

    /* Shutdown all existing connection */
    ZIP_ITER(UA_FDTree, &pcm->fds, UDP_shutdownCB, cm);

    /* Check if stopped once more (also checking inside UDP_close, but there we
     * don't check if there is no rfd at all) */
    UDP_checkStopped(pcm);

    UA_UNLOCK(&el->elMutex);
}

static UA_StatusCode
UDP_eventSourceDelete(UA_ConnectionManager *cm) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    if(cm->eventSource.state >= UA_EVENTSOURCESTATE_STARTING) {
        UA_LOG_ERROR(cm->eventSource.eventLoop->logger, UA_LOGCATEGORY_EVENTLOOP,
                     "UDP\t| The EventSource must be stopped before it can be deleted");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_ByteString_clear(&pcm->rxBuffer);
    UA_ByteString_clear(&pcm->txBuffer);
    UA_KeyValueMap_clear(&cm->eventSource.params);
    UA_String_clear(&cm->eventSource.name);
    UA_free(cm);

    return UA_STATUSCODE_GOOD;
}

static const char *udpName = "udp";

UA_ConnectionManager *
UA_ConnectionManager_new_POSIX_UDP(const UA_String eventSourceName) {
    UA_POSIXConnectionManager *cm = (UA_POSIXConnectionManager*)
        UA_calloc(1, sizeof(UA_POSIXConnectionManager));
    if(!cm)
        return NULL;

    cm->cm.eventSource.eventSourceType = UA_EVENTSOURCETYPE_CONNECTIONMANAGER;
    UA_String_copy(&eventSourceName, &cm->cm.eventSource.name);
    cm->cm.eventSource.start = (UA_StatusCode (*)(UA_EventSource *))UDP_eventSourceStart;
    cm->cm.eventSource.stop = (void (*)(UA_EventSource *))UDP_eventSourceStop;
    cm->cm.eventSource.free = (UA_StatusCode (*)(UA_EventSource *))UDP_eventSourceDelete;
    cm->cm.protocol = UA_STRING((char*)(uintptr_t)udpName);
    cm->cm.openConnection = UDP_openConnection;
    cm->cm.allocNetworkBuffer = UA_EventLoopPOSIX_allocNetworkBuffer;
    cm->cm.freeNetworkBuffer = UA_EventLoopPOSIX_freeNetworkBuffer;
    cm->cm.sendWithConnection = UDP_sendWithConnection;
    cm->cm.closeConnection = UDP_shutdownConnection;
    return &cm->cm;
}

/**** amalgamated original file "/plugins/eventloop/posix/eventloop_posix_eth.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *   Copyright 2018 (c) Kontron Europe GmbH (Author: Rudolf Hoyler)
 *   Copyright 2019-2020 (c) Kalycito Infotech Private Limited
 *   Copyright 2019-2020 (c) Wind River Systems, Inc.
 *   Copyright 2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 */


#if defined(UA_ARCHITECTURE_POSIX) && defined(__linux__)

#include <arpa/inet.h> /* htons */
#include <net/ethernet.h> /* ETH_P_*/
#include <linux/if_packet.h>
#include <linux/net_tstamp.h> /* txtime */

/* Configuration parameters */

#define ETH_MANAGERPARAMS 2

static UA_KeyValueRestriction ethManagerParams[ETH_MANAGERPARAMS] = {
    {{0, UA_STRING_STATIC("recv-bufsize")}, &UA_TYPES[UA_TYPES_UINT32], false, true, false},
    {{0, UA_STRING_STATIC("send-bufsize")}, &UA_TYPES[UA_TYPES_UINT32], false, true, false}
};

#define ETH_PARAMETERSSIZE 15
#define ETH_PARAMINDEX_ADDR 0
#define ETH_PARAMINDEX_LISTEN 1
#define ETH_PARAMINDEX_IFACE 2
#define ETH_PARAMINDEX_ETHERTYPE 3
#define ETH_PARAMINDEX_VID 4
#define ETH_PARAMINDEX_PCP 5
#define ETH_PARAMINDEX_DEI 6
#define ETH_PARAMINDEX_PROMISCUOUS 7
#define ETH_PARAMINDEX_PRIORITY 8
#define ETH_PARAMINDEX_TXTIME_ENABLE 9
#define ETH_PARAMINDEX_TXTIME_FLAGS 10
#define ETH_PARAMINDEX_TXTIME 11
#define ETH_PARAMINDEX_TXTIME_PICO 12
#define ETH_PARAMINDEX_TXTIME_DROP 13
#define ETH_PARAMINDEX_VALIDATE 14

static UA_KeyValueRestriction ethConnectionParams[ETH_PARAMETERSSIZE+1] = {
    {{0, UA_STRING_STATIC("address")}, &UA_TYPES[UA_TYPES_STRING], false, true, false},
    {{0, UA_STRING_STATIC("listen")}, &UA_TYPES[UA_TYPES_BOOLEAN], false, true, false},
    {{0, UA_STRING_STATIC("interface")}, &UA_TYPES[UA_TYPES_STRING], true, true, false},
    {{0, UA_STRING_STATIC("ethertype")}, &UA_TYPES[UA_TYPES_UINT16], false, true, false},
    {{0, UA_STRING_STATIC("vid")}, &UA_TYPES[UA_TYPES_UINT16], false, true, false},
    {{0, UA_STRING_STATIC("pcp")}, &UA_TYPES[UA_TYPES_BYTE], false, true, false},
    {{0, UA_STRING_STATIC("dei")}, &UA_TYPES[UA_TYPES_BOOLEAN], false, true, false},
    {{0, UA_STRING_STATIC("promiscuous")}, &UA_TYPES[UA_TYPES_BOOLEAN], false, true, false},
    {{0, UA_STRING_STATIC("priority")}, &UA_TYPES[UA_TYPES_UINT32], false, true, false},
    {{0, UA_STRING_STATIC("txtime-enable")}, &UA_TYPES[UA_TYPES_BOOLEAN], false, true, false},
    {{0, UA_STRING_STATIC("txtime-flags")}, &UA_TYPES[UA_TYPES_UINT32], false, true, false},
    {{0, UA_STRING_STATIC("txtime")}, &UA_TYPES[UA_TYPES_DATETIME], false, true, false},
    {{0, UA_STRING_STATIC("txtime-pico")}, &UA_TYPES[UA_TYPES_UINT16], false, true, false},
    {{0, UA_STRING_STATIC("txtime-drop-late")}, &UA_TYPES[UA_TYPES_BOOLEAN], false, true, false},
    {{0, UA_STRING_STATIC("validate")}, &UA_TYPES[UA_TYPES_BOOLEAN], false, true, false},
    /* Duplicated address parameter with a scalar value required. For the send-socket case. */
    {{0, UA_STRING_STATIC("address")}, &UA_TYPES[UA_TYPES_STRING], true, true, false},
};

#define UA_ETH_MAXHEADERLENGTH (2*ETHER_ADDR_LEN)+4+2+2

typedef struct {
    UA_RegisteredFD rfd;

    UA_ConnectionManager_connectionCallback applicationCB;
    void *application;
    void *context;

    struct sockaddr_ll sll;
    /* The Ethernet header to prepend for sending frames is precomputed and reused.
     * The length field (the last 2 byte) is adjusted.
     * - 2 * ETHER_ADDR_LEN: destination and source
     * - 4 byte: VLAN tagging (optional)
     * - 2 byte: EtherType (optional)
     * - 2 byte: length */
    unsigned char header[UA_ETH_MAXHEADERLENGTH];
    unsigned char headerSize;
    unsigned char lengthOffset; /* No length field if zero */

    UA_Boolean txtimeEnabled;
} ETH_FD;

/* The format of a Ethernet address is six groups of hexadecimal digits,
 * separated by hyphens (e.g. 01-23-45-67-89-ab). */
static UA_StatusCode
parseEthAddress(const UA_String *buf, UA_Byte *addr) {
    size_t curr = 0, idx = 0;
    for(; idx < ETHER_ADDR_LEN; idx++) {
        UA_UInt32 value;
        size_t progress = UA_readNumberWithBase(&buf->data[curr],
                                                buf->length - curr, &value, 16);
        if(progress == 0 || value > (long)0xff)
            return UA_STATUSCODE_BADINTERNALERROR;

        addr[idx] = (UA_Byte) value;

        curr += progress;
        if(curr == buf->length)
            break;

        if(buf->data[curr] != '-')
            return UA_STATUSCODE_BADINTERNALERROR;

        curr++; /* skip '-' */
    }

    if(idx != (ETH_ALEN-1))
        return UA_STATUSCODE_BADINTERNALERROR;

    return UA_STATUSCODE_GOOD;
}

static UA_Boolean
isMulticastEthAddress(const UA_Byte *address) {
    if((address[0] & 1) == 0)
        return false; /* Unicast address */
    for(size_t i = 0; i < ETHER_ADDR_LEN; i++) {
        if(address[i] != 0xff)
            return true; /* Not broadcast address ff-ff-ff-ff-ff-ff */
    }
    return false;
}

static void
setAddrString(unsigned char addrStr[18], unsigned char addr[ETHER_ADDR_LEN]) {
    mp_snprintf((char*)addrStr, 18, "%02x-%02x-%02x-%02x-%02x-%02x",
                addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
}

/* Return zero if parsing failed */
static size_t
parseETHHeader(const UA_ByteString *buf,
               unsigned char destAddr[ETHER_ADDR_LEN],
               unsigned char sourceAddr[ETHER_ADDR_LEN],
               UA_UInt16 *etherType, UA_UInt16 *vid,
               UA_Byte *pcp, UA_Boolean *dei) {
    if(buf->length < (2 * ETHER_ADDR_LEN)+2)
        return 0;

    /* Parse "normal" Ethernet header */
    memcpy(destAddr, buf->data, ETHER_ADDR_LEN);
    memcpy(sourceAddr, &buf->data[ETHER_ADDR_LEN], ETHER_ADDR_LEN);
    size_t pos = 2 * ETHER_ADDR_LEN;
    UA_UInt16 length = ntohs(*(UA_UInt16*)&buf->data[pos]);
    pos += 2;

    /* No EtherType and no VLAN */
    if(length <= 1500)
        return pos;

    /* Parse 802.1Q VLAN header */
    if(length == 0x8100) {
        if(buf->length < (2 * ETHER_ADDR_LEN)+2+4)
            return 0;
        pos += 2;
        UA_UInt16 vlan = ntohs(*(UA_UInt16*)&buf->data[pos]);
        *pcp = 0x07 & vlan;
        *dei = 0x01 & (vlan >> 3);
        *vid = vlan >> 4;
        pos += 2;
        length = ntohs(*(UA_UInt16*)&buf->data[pos]);
    }

    /* Set the EtherType if it is set */
    if(length > 1500)
        *etherType = length;

    return pos;
}

static unsigned char
setETHHeader(unsigned char *buf,
             unsigned char destAddr[ETHER_ADDR_LEN],
             unsigned char sourceAddr[ETHER_ADDR_LEN],
             UA_UInt16 etherType, UA_UInt16 vid,
             UA_Byte pcp, UA_Boolean dei, unsigned char *lengthOffset) {
    /* Set dest and source address */
    size_t pos = 0;
    memcpy(buf, destAddr, ETHER_ADDR_LEN);
    pos += ETHER_ADDR_LEN;
    memcpy(&buf[pos], destAddr, ETHER_ADDR_LEN);
    pos += ETHER_ADDR_LEN;

    /* Set the 802.1Q VLAN header */
    if(vid > 0 && vid != ETH_P_ALL) {
        *(UA_UInt16*)&buf[pos] = htons(0x8100);
        pos += 2;
        UA_UInt16 vlan = (UA_UInt16)((UA_UInt16)pcp + (((UA_UInt16)dei) << 3) + (vid << 4));
        *(UA_UInt16*)&buf[pos] = htons(vlan);
        pos += 2;
    }

    /* Set the Ethertype or store the offset for the length field */
    if(etherType == 0 || etherType == ETH_P_ALL) {
        *lengthOffset = (unsigned char)pos;
    } else {
        *(UA_UInt16*)&buf[pos] = htons(etherType);
    }
    pos += 2;
    return (unsigned char)pos;
}

static UA_StatusCode
ETH_allocNetworkBuffer(UA_ConnectionManager *cm, uintptr_t connectionId,
                       UA_ByteString *buf, size_t bufSize) {
    /* Get the ETH_FD */
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_FD fd = (UA_FD)connectionId;
    ETH_FD *erfd = (ETH_FD*)ZIP_FIND(UA_FDTree, &pcm->fds, &fd);
    if(!erfd)
        return UA_STATUSCODE_BADCONNECTIONREJECTED;

    /* Allocate the buffer with the hidden Ethernet header in front */
    UA_StatusCode res =
        UA_EventLoopPOSIX_allocNetworkBuffer(cm, connectionId, buf,
                                             bufSize + erfd->headerSize);
    if(UA_LIKELY(res == UA_STATUSCODE_GOOD)) {
        buf->data   += erfd->headerSize;
        buf->length -= erfd->headerSize;
    }
    return res;
}

static void
ETH_freeNetworkBuffer(UA_ConnectionManager *cm, uintptr_t connectionId,
                      UA_ByteString *buf) {
    /* Get the ETH_FD */
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_FD fd = (UA_FD)connectionId;
    ETH_FD *erfd = (ETH_FD*)ZIP_FIND(UA_FDTree, &pcm->fds, &fd);
    if(!erfd)
        return;

    /* Unhide the Ethernet header and free */
    buf->data   -= erfd->headerSize;
    buf->length += erfd->headerSize;
    UA_EventLoopPOSIX_freeNetworkBuffer(cm, connectionId, buf);
}

/* Test if the ConnectionManager can be stopped */
static void
ETH_checkStopped(UA_POSIXConnectionManager *pcm) {
    UA_LOCK_ASSERT(&((UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop)->elMutex, 1);

    if(pcm->fdsSize == 0 &&
       pcm->cm.eventSource.state == UA_EVENTSOURCESTATE_STOPPING) {
        UA_LOG_DEBUG(pcm->cm.eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
                     "ETH\t| All sockets closed, the EventLoop has stopped");
        pcm->cm.eventSource.state = UA_EVENTSOURCESTATE_STOPPED;
    }
}

/* This method must not be called from the application directly, but from within
 * the EventLoop. Otherwise we cannot be sure whether the file descriptor is
 * still used after calling close. */
static void
ETH_close(UA_POSIXConnectionManager *pcm, ETH_FD *conn) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex, 1);

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "ETH %u\t| Closing connection",
                 (unsigned)conn->rfd.fd);

    /* Deregister from the EventLoop */
    UA_EventLoopPOSIX_deregisterFD(el, &conn->rfd);

    /* Deregister internally */
    ZIP_REMOVE(UA_FDTree, &pcm->fds, &conn->rfd);
    UA_assert(pcm->fdsSize > 0);
    pcm->fdsSize--;

    /* Signal closing to the application */
    UA_UNLOCK(&el->elMutex);
    conn->applicationCB(&pcm->cm, (uintptr_t)conn->rfd.fd,
                        conn->application, &conn->context,
                        UA_CONNECTIONSTATE_CLOSING,
                        &UA_KEYVALUEMAP_NULL, UA_BYTESTRING_NULL);
    UA_LOCK(&el->elMutex);

    /* Close the socket */
    int ret = UA_close(conn->rfd.fd);
    if(ret == 0) {
        UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                    "ETH %u\t| Socket closed", (unsigned)conn->rfd.fd);
    } else {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "ETH %u\t| Could not close the socket (%s)",
                          (unsigned)conn->rfd.fd, errno_str));
    }

    /* Don't call free here. This might be done automatically via the delayed
     * callback that calls ETH_close. */
    /* UA_free(rfd); */

    /* Stop if the ucm is stopping and this was the last open socket */
    ETH_checkStopped(pcm);
}

static void
ETH_delayedClose(void *application, void *context) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)application;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
    ETH_FD *conn = (ETH_FD*)context;
    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                 "ETH %u\t| Delayed closing of the connection",
                 (unsigned)conn->rfd.fd);
    UA_LOCK(&el->elMutex);
    ETH_close(pcm, conn);
    UA_UNLOCK(&el->elMutex);
    UA_free(conn);
}

/* Gets called when a socket receives data or closes */
static void
ETH_connectionSocketCallback(UA_ConnectionManager *cm, UA_RegisteredFD *rfd,
                             short event) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex, 1);

    ETH_FD *conn = (ETH_FD*)rfd;
    if(event == UA_FDEVENT_ERR) {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                        "ETH %u\t| recv signaled the socket was shutdown (%s)",
                        (unsigned)rfd->fd, errno_str));
        ETH_close(pcm, conn);
        UA_free(rfd);
        return;
    }

    /* Use the already allocated receive-buffer */
    UA_ByteString response = pcm->rxBuffer;;

    /* Receive */
#ifndef _WIN32
    ssize_t ret = UA_recv(rfd->fd, (char*)response.data,
                          response.length, MSG_DONTWAIT);
#else
    int ret = UA_recv(rfd->fd, (char*)response.data,
                      response.length, MSG_DONTWAIT);
#endif

    /* Receive has failed */
    if(ret <= 0) {
        if(UA_ERRNO == UA_INTERRUPTED)
            return;

        /* Orderly shutdown of the socket. We can immediately close as no method
         * "below" in the call stack will use the socket in this iteration of
         * the EventLoop. */
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                        "ETH %u\t| recv signaled the socket was shutdown (%s)",
                        (unsigned)rfd->fd, errno_str));
        ETH_close(pcm, conn);
        UA_free(rfd);
        return;
    }

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "ETH %u\t| Received message of size %u",
                 (unsigned)rfd->fd, (unsigned)ret);

    response.length = (size_t)ret;

    /* Parse the Ethernet header */
    unsigned char destAddr[ETHER_ADDR_LEN];
    unsigned char sourceAddr[ETHER_ADDR_LEN];
    UA_UInt16 etherType = 0;
    UA_UInt16 vid = 0;
    UA_Byte pcp = 0;
    UA_Boolean dei = 0;
    size_t headerSize = parseETHHeader(&response, destAddr, sourceAddr,
                                       &etherType, &vid, &pcp, &dei);
    if(headerSize == 0)
        return;

    /* Set up the parameter arguments passed to the application */
    unsigned char destAddrBytes[18];
    unsigned char sourceAddrBytes[18];
    setAddrString(destAddrBytes, destAddr);
    setAddrString(sourceAddrBytes, sourceAddr);
    UA_String destAddrStr = {17, destAddrBytes};
    UA_String sourceAddrStr = {17, sourceAddrBytes};

    size_t paramsSize = 2;
    UA_KeyValuePair params[6];
    params[0].key = UA_QUALIFIEDNAME(0, "destination-address");
    UA_Variant_setScalar(&params[0].value, &destAddrStr, &UA_TYPES[UA_TYPES_STRING]);
    params[1].key = UA_QUALIFIEDNAME(0, "source-address");
    UA_Variant_setScalar(&params[1].value, &sourceAddrStr, &UA_TYPES[UA_TYPES_STRING]);

    if(etherType > 0) {
        params[2].key = UA_QUALIFIEDNAME(0, "ethertype");
        UA_Variant_setScalar(&params[1].value, &etherType, &UA_TYPES[UA_TYPES_UINT16]);
        paramsSize++;
    }

    if(vid > 0) {
        params[paramsSize].key = UA_QUALIFIEDNAME(0, "vid");
        UA_Variant_setScalar(&params[paramsSize].value, &vid, &UA_TYPES[UA_TYPES_UINT16]);
        params[paramsSize+1].key = UA_QUALIFIEDNAME(0, "pcp");
        UA_Variant_setScalar(&params[paramsSize+1].value, &pcp, &UA_TYPES[UA_TYPES_BYTE]);
        params[paramsSize+2].key = UA_QUALIFIEDNAME(0, "dei");
        UA_Variant_setScalar(&params[paramsSize+2].value, &dei, &UA_TYPES[UA_TYPES_BOOLEAN]);
        paramsSize += 3;
    }

    /* Callback to the application layer with the Ethernet header hidden */
    UA_KeyValueMap map = {paramsSize, params};
    response.data += headerSize;
    response.length -= headerSize;
    UA_UNLOCK(&el->elMutex);
    conn->applicationCB(cm, (uintptr_t)rfd->fd, conn->application, &conn->context,
                        UA_CONNECTIONSTATE_ESTABLISHED, &map, response);
    UA_LOCK(&el->elMutex);
    response.data -= headerSize;
    response.length += headerSize;
}

static UA_StatusCode
ETH_openListenConnection(UA_EventLoopPOSIX *el, ETH_FD *conn,
                         const UA_KeyValueMap *params,
                         int ifindex, UA_UInt16 etherType,
                         UA_Boolean validate) {
    UA_LOCK_ASSERT(&el->elMutex, 1);

    /* Bind the socket to interface and EtherType. Don't receive anything else. */
    struct sockaddr_ll sll;
    memset(&sll, 0, sizeof(struct sockaddr_ll));
    sll.sll_family = AF_PACKET;
    sll.sll_protocol = htons(etherType);
    sll.sll_ifindex = ifindex;
    if(!validate && bind(conn->rfd.fd, (struct sockaddr*)&sll, sizeof(sll)) < 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Immediately register for listen events. Don't have to wait for a
     * connection to open. */
    conn->rfd.listenEvents = UA_FDEVENT_IN;

    /* Set receiving to promiscuous (all target host addresses) */
    const UA_Boolean *promiscuous = (const UA_Boolean*)
        UA_KeyValueMap_getScalar(params, ethConnectionParams[ETH_PARAMINDEX_PROMISCUOUS].name,
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
    if(promiscuous && *promiscuous) {
        struct packet_mreq mreq;
        memset(&mreq, 0, sizeof(struct packet_mreq));
        mreq.mr_ifindex = ifindex;
        mreq.mr_type = PACKET_MR_PROMISC;
        int ret = setsockopt(conn->rfd.fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
                             &mreq, sizeof(mreq));
        if(ret < 0) {
            UA_LOG_SOCKET_ERRNO_WRAP(
               UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                            "ETH %u\t| Could not set raw socket to promiscuous mode %s",
                            (unsigned)conn->rfd.fd, errno_str));
            return UA_STATUSCODE_BADINTERNALERROR;
        } else {
            UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                        "ETH %u\t| The socket was set to promiscuous mode",
                        (unsigned)conn->rfd.fd);
        }
    }

    /* Register for multicast if an address is defined */
    const UA_String *address = (const UA_String*)
        UA_KeyValueMap_getScalar(params, ethConnectionParams[ETH_PARAMINDEX_ADDR].name,
                                 &UA_TYPES[UA_TYPES_STRING]);
    if(address) {
        UA_Byte addr[ETHER_ADDR_LEN];
        UA_StatusCode res = parseEthAddress(address, addr);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                         "ETH\t| Address for listening cannot be parsed");
            return res;
        }

        if(!isMulticastEthAddress(addr)) {
            UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                         "ETH\t| Address for listening is not a multicast address. Ignoring.");
            return UA_STATUSCODE_GOOD;
        }

        struct packet_mreq mreq;
        memset(&mreq, 0, sizeof(struct packet_mreq));
        mreq.mr_ifindex = ifindex;
        mreq.mr_type = PACKET_MR_MULTICAST;
        mreq.mr_alen = ETH_ALEN;
        memcpy(mreq.mr_address, addr, ETHER_ADDR_LEN);
        if(!validate && UA_setsockopt(conn->rfd.fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
                                      (char *)&mreq, sizeof(mreq)) < 0) {
            UA_LOG_SOCKET_ERRNO_WRAP(
               UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                            "ETH\t| Registering for multicast failed with error %s",
                            errno_str));
            return UA_STATUSCODE_BADINTERNALERROR;
        }
    }

    UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                "ETH %u\t| Opened an Ethernet listen socket",
                (unsigned)conn->rfd.fd);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
ETH_openSendConnection(UA_EventLoopPOSIX *el, ETH_FD *conn, const UA_KeyValueMap *params,
                       UA_Byte source[ETHER_ADDR_LEN], int ifindex, UA_UInt16 etherType) {
    UA_LOCK_ASSERT(&el->elMutex, 1);

    /* Parse the target address (has to exist) */
    const UA_String *address = (const UA_String*)
        UA_KeyValueMap_getScalar(params, ethConnectionParams[ETH_PARAMINDEX_ADDR].name,
                                 &UA_TYPES[UA_TYPES_STRING]);
    UA_Byte dest[ETHER_ADDR_LEN];
    UA_StatusCode res = parseEthAddress(address, dest);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "ETH\t| Could not parse the Ethernet address \"%.*s\"",
                     (int)address->length, (char*)address->data);
        return res;
    }

    /* Get the VLAN config */
    UA_UInt16 vid = 0;
    UA_Byte pcp = 0;
    UA_Boolean eid = false;

    const UA_UInt16 *vidp = (const UA_UInt16*)
        UA_KeyValueMap_getScalar(params, ethConnectionParams[ETH_PARAMINDEX_VID].name,
                                 &UA_TYPES[UA_TYPES_UINT16]);
    if(vidp)
        vid = *vidp;

    const UA_Byte *pcpp = (const UA_Byte*)
        UA_KeyValueMap_getScalar(params, ethConnectionParams[ETH_PARAMINDEX_PCP].name,
                                 &UA_TYPES[UA_TYPES_BYTE]);
    if(pcpp)
        pcp = *pcpp;

    const UA_Boolean *eidp = (const UA_Boolean*)
        UA_KeyValueMap_getScalar(params, ethConnectionParams[ETH_PARAMINDEX_DEI].name,
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
    if(eidp)
        eid = *eidp;

    /* Store the structure for sendto */
    conn->sll.sll_ifindex = ifindex;
	conn->sll.sll_halen = ETH_ALEN;
    memcpy(conn->sll.sll_addr, dest, ETHER_ADDR_LEN);

    /* Generate the Ethernet header */
    conn->headerSize = setETHHeader(conn->header, dest, source, etherType,
                                    vid, pcp, eid, &conn->lengthOffset);

    /* Set the send priority if defined */
    const UA_Int32 *soPriority = (const UA_Int32*)
        UA_KeyValueMap_getScalar(params, ethConnectionParams[ETH_PARAMINDEX_PRIORITY].name,
                                 &UA_TYPES[UA_TYPES_INT32]);
    if(soPriority) {
        int prioRes = setsockopt(conn->rfd.fd, SOL_SOCKET, SO_PRIORITY,
                                 soPriority, sizeof(int));
        if(prioRes != 0) {
            UA_LOG_SOCKET_ERRNO_WRAP(
               UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                            "setsockopt SO_PRIORITY failed with error %s", errno_str));
            return UA_STATUSCODE_BADINTERNALERROR;
        }
    }

    /* Enable txtime sending */
    const UA_Boolean *txtime_enable = (const UA_Boolean*)
        UA_KeyValueMap_getScalar(params,
                                 ethConnectionParams[ETH_PARAMINDEX_TXTIME_ENABLE].name,
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
    const UA_UInt32 *txtime_flags = (const UA_UInt32*)
        UA_KeyValueMap_getScalar(params,
                                 ethConnectionParams[ETH_PARAMINDEX_TXTIME_FLAGS].name,
                                 &UA_TYPES[UA_TYPES_UINT32]);
    if(txtime_enable && *txtime_enable) {
#ifndef SO_TXTIME
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "ETH %u\t| txtime feature not supported",
                       (unsigned)conn->rfd.fd);
#else
        struct sock_txtime so_txtime_val;
        memset(&so_txtime_val, 0, sizeof(struct sock_txtime));
        so_txtime_val.clockid = el->clockSourceMonotonic;
        so_txtime_val.flags = SOF_TXTIME_REPORT_ERRORS;
        if(txtime_flags)
            so_txtime_val.flags = *txtime_flags;
        if(setsockopt(conn->rfd.fd, SOL_SOCKET, SO_TXTIME,
                      &so_txtime_val, sizeof(so_txtime_val)) == 0) {
            conn->txtimeEnabled = true;
        } else {
            UA_LOG_SOCKET_ERRNO_WRAP(
               UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                              "ETH %u\t| Could not enable txtime (%s)",
                              (unsigned)conn->rfd.fd, errno_str));
        }
#endif
    }

    /* Done creating the socket */
    UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                "ETH %u\t| Opened an Ethernet send socket",
                (unsigned)conn->rfd.fd);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
ETH_openConnection(UA_ConnectionManager *cm, const UA_KeyValueMap *params,
                   void *application, void *context,
                   UA_ConnectionManager_connectionCallback connectionCallback) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)cm->eventSource.eventLoop;

    UA_LOCK(&el->elMutex);

    /* Listen or send connection? */
    const UA_Boolean *listen = (const UA_Boolean*)
        UA_KeyValueMap_getScalar(params,
                                 ethConnectionParams[ETH_PARAMINDEX_LISTEN].name,
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
    size_t ethParamRestrictions = ETH_PARAMETERSSIZE;
    if(!listen || !*listen)
        ethParamRestrictions++; /* Use the last restriction only for send connections */

    /* Validate the parameters */
    UA_StatusCode res =
        UA_KeyValueRestriction_validate(el->eventLoop.logger, "ETH", ethConnectionParams,
                                        ethParamRestrictions, params);
    if(res != UA_STATUSCODE_GOOD) {
        UA_UNLOCK(&el->elMutex);
        return res;
    }

    /* Only validate the parameters? */
    UA_Boolean validate = false;
    const UA_Boolean *validateParam = (const UA_Boolean*)
        UA_KeyValueMap_getScalar(params,
                                 ethConnectionParams[ETH_PARAMINDEX_VALIDATE].name,
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
    if(validateParam)
        validate = *validateParam;

    /* Get the EtherType parameter */
    UA_UInt16 etherType = ETH_P_ALL;
    const UA_UInt16 *etParam =  (const UA_UInt16*)
        UA_KeyValueMap_getScalar(params,
                                 ethConnectionParams[ETH_PARAMINDEX_ETHERTYPE].name,
                                 &UA_TYPES[UA_TYPES_UINT16]);
    if(etParam)
        etherType = *etParam;

    /* Get the interface index */
    const UA_String *interface = (const UA_String*)
        UA_KeyValueMap_getScalar(params,
                                 ethConnectionParams[ETH_PARAMINDEX_IFACE].name,
                                 &UA_TYPES[UA_TYPES_STRING]);
    if(interface->length >= 128) {
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    char ifname[128];
    memcpy(ifname, interface->data, interface->length);
    ifname[interface->length] = 0;
    int ifindex = (int)if_nametoindex(ifname);
    if(ifindex == 0) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "ETH\t| Could not find the interface %s", ifname);
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Create the socket and add the basic configuration */
    ETH_FD *conn = NULL;
    UA_FD sockfd;
    if(listen && *listen)
        sockfd = socket(PF_PACKET, SOCK_RAW, htons(etherType));
    else
        sockfd = socket(PF_PACKET, SOCK_RAW, 0); /* Don't receive */
    if(sockfd == -1) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "ETH\t| Could not create a raw Ethernet socket (are you root?)");
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    res |= UA_EventLoopPOSIX_setReusable(sockfd);
    res |= UA_EventLoopPOSIX_setNonBlocking(sockfd);
    res |= UA_EventLoopPOSIX_setNoSigPipe(sockfd);
    if(res != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Create the FD object */
    conn = (ETH_FD*)UA_calloc(1, sizeof(ETH_FD));
    if(!conn) {
        res = UA_STATUSCODE_BADOUTOFMEMORY;
        goto cleanup;
    }

    conn->rfd.fd = sockfd;
    conn->rfd.es = &pcm->cm.eventSource;
    conn->rfd.eventSourceCB = (UA_FDCallback)ETH_connectionSocketCallback;
    conn->context = context;
    conn->application = application;
    conn->applicationCB = connectionCallback;

    /* Configure a listen or a send connection */
    if(!listen || !*listen) {
        /* Get the source address for the interface */
        struct ifreq ifr;
        memcpy(ifr.ifr_name, ifname, interface->length);
        ifr.ifr_name[interface->length] = 0;
        int result = ioctl(conn->rfd.fd, SIOCGIFHWADDR, &ifr);
        if(result == -1) {
            UA_LOG_SOCKET_ERRNO_WRAP(
               UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                            "ETH %u\t| Cannot get the source address, %s",
                            (unsigned)conn->rfd.fd, errno_str));
            res = UA_STATUSCODE_BADCONNECTIONREJECTED;
            goto cleanup;
        }
        res = ETH_openSendConnection(el, conn, params,
                                     (unsigned char*)ifr.ifr_hwaddr.sa_data,
                                     ifindex, etherType);
    } else {
        res = ETH_openListenConnection(el, conn, params, ifindex, etherType, validate);
    }

    /* Don't actually open or shut down */
    if(validate || res != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Register in the EventLoop */
    res = UA_EventLoopPOSIX_registerFD(el, &conn->rfd);
    if(res != UA_STATUSCODE_GOOD)
        goto cleanup;

    /* Register locally */
    ZIP_INSERT(UA_FDTree, &pcm->fds, &conn->rfd);
    pcm->fdsSize++;

    /* Register the listen socket in the application */
    UA_UNLOCK(&el->elMutex);
    connectionCallback(cm, (uintptr_t)sockfd, application, &conn->context,
                       UA_CONNECTIONSTATE_ESTABLISHED, &UA_KEYVALUEMAP_NULL,
                       UA_BYTESTRING_NULL);
    return UA_STATUSCODE_GOOD;

 cleanup:
    UA_close(sockfd);
    UA_free(conn);
    UA_UNLOCK(&el->elMutex);
    return res;
}

static void
ETH_shutdown(UA_POSIXConnectionManager *pcm, ETH_FD *conn) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
    UA_LOCK_ASSERT(&((UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop)->elMutex, 1);

    UA_DelayedCallback *dc = &conn->rfd.dc;
    if(dc->callback) {
        UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                    "ETH %u\t| Cannot close - already closing",
                    (unsigned)conn->rfd.fd);
        return;
    }

    /* Shutdown the socket to cancel the current select/epoll */
    shutdown(conn->rfd.fd, UA_SHUT_RDWR);

    UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                 "ETH %u\t| Shutdown called", (unsigned)conn->rfd.fd);

    dc->callback = ETH_delayedClose;
    dc->application = pcm;
    dc->context = conn;

    /* Don't use the "public" el->addDelayedCallback. It takes a lock. */
    dc->next = el->delayedCallbacks;
    el->delayedCallbacks = dc;
}

static UA_StatusCode
ETH_shutdownConnection(UA_ConnectionManager *cm, uintptr_t connectionId) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_LOCK(&el->elMutex);

    /* Get the ETH_FD */
    UA_FD fd = (UA_FD)connectionId;
    UA_RegisteredFD *rfd = ZIP_FIND(UA_FDTree, &pcm->fds, &fd);
    if(!rfd) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                       "ETH\t| Cannot close Ethernet connection %u - not found",
                       (unsigned)connectionId);
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADNOTFOUND;
    }

    ETH_shutdown(pcm, (ETH_FD*)rfd);
    UA_UNLOCK(&el->elMutex);
    return UA_STATUSCODE_GOOD;
}

#ifdef SO_TXTIME
static ssize_t
send_txtime(UA_EventLoopPOSIX *el, ETH_FD *conn, const UA_KeyValueMap *params,
            UA_DateTime txtime, const char *bytes, size_t bytesSize) {
    /* Get additiona parameters */
    const UA_UInt16 *txtime_pico = (const UA_UInt16*)
        UA_KeyValueMap_getScalar(params,
                                 ethConnectionParams[ETH_PARAMINDEX_TXTIME_PICO].name,
                                 &UA_TYPES[UA_TYPES_UINT16]);
    const UA_Boolean *txtime_drop = (const UA_Boolean*)
        UA_KeyValueMap_getScalar(params,
                                 ethConnectionParams[ETH_PARAMINDEX_TXTIME_DROP].name,
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
#ifndef SCM_DROP_IF_LATE
    if(txtime_drop) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "ETH %u\t| txtime drop_if_late not supported on the current system",
                     (unsigned)conn->rfd.fd);
        return 0;
    }
#endif


    /* Transform from 100ns since 1601 to ns since the Unix Epoch */
    UA_UInt64 transmission_time = (UA_UInt64)
        (txtime - UA_DATETIME_UNIX_EPOCH) * 100;
    if(txtime_pico)
        transmission_time += (*txtime_pico) / 1000;

    /* Structure for scattering or gathering of input/output */
    struct iovec inputOutputVec;
    inputOutputVec.iov_base = (void*)(uintptr_t)bytes;
    inputOutputVec.iov_len  = bytesSize;

    /* Specify the transmission time in the CMSG. */
    char dataPacket[CMSG_SPACE(sizeof(uint64_t))
#ifdef SCM_DROP_IF_LATE
                    + CMSG_SPACE(sizeof(uint8_t))
#endif
                    ];
    struct msghdr message;
    memset(&message, 0, sizeof(struct msghdr));
    message.msg_control    = dataPacket;
    message.msg_controllen = sizeof(dataPacket);
    message.msg_name       = (struct sockaddr*)&conn->sll;
    message.msg_namelen    = sizeof(conn->sll);
    message.msg_iov        = &inputOutputVec;
    message.msg_iovlen     = 1;

    struct cmsghdr *cmsg = CMSG_FIRSTHDR(&message);
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type  = SCM_TXTIME;
    cmsg->cmsg_len   = CMSG_LEN(sizeof(__u64));
    *((__u64*)CMSG_DATA(cmsg)) = transmission_time;

#ifdef SCM_DROP_IF_LATE
    cmsg = CMSG_NXTHDR(&message, cmsg);
    cmsg->cmsg_level = SOL_SOCKET;
    cmsg->cmsg_type = SCM_DROP_IF_LATE;
    cmsg->cmsg_len = CMSG_LEN(sizeof(uint8_t));
    *((uint8_t*)CMSG_DATA(cmsg)) = (!txtime_drop || *txtime_drop) ? 1: 0;
#endif

    /* Send */
    return sendmsg(conn->rfd.fd, &message, 0);
}
#endif

static UA_StatusCode
ETH_sendWithConnection(UA_ConnectionManager *cm, uintptr_t connectionId,
                       const UA_KeyValueMap *params, UA_ByteString *buf) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;

    UA_LOCK(&el->elMutex);

    /* Get the ETH_FD */
    UA_FD fd = (UA_FD)connectionId;
    ETH_FD *conn = (ETH_FD*)ZIP_FIND(UA_FDTree, &pcm->fds, &fd);
    if(!conn) {
        UA_UNLOCK(&el->elMutex);
        UA_EventLoopPOSIX_freeNetworkBuffer(cm, connectionId, buf);
        return UA_STATUSCODE_BADCONNECTIONREJECTED;
    }

    /* Uncover and set the Ethernet header */
    buf->data -= conn->headerSize;
    buf->length += conn->headerSize;
    memcpy(buf->data, conn->header, conn->headerSize);
    if(conn->lengthOffset) {
        UA_UInt16 *ethLength =  (UA_UInt16*)&buf->data[conn->lengthOffset];
        *ethLength = htons((UA_UInt16)(buf->length - conn->headerSize));
    }

    /* Was a txtime configured? */
    const UA_DateTime *txtime = (const UA_DateTime*)
        UA_KeyValueMap_getScalar(params, ethConnectionParams[ETH_PARAMINDEX_TXTIME].name,
                                 &UA_TYPES[UA_TYPES_DATETIME]);
    if(txtime && !conn->txtimeEnabled) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "ETH %u\t| txtime was not configured for the connection",
                     (unsigned)connectionId);
        UA_UNLOCK(&el->elMutex);
        UA_EventLoopPOSIX_freeNetworkBuffer(cm, connectionId, buf);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Prevent OS signals when sending to a closed socket */
    int flags = MSG_NOSIGNAL;

    struct pollfd tmp_poll_fd;
    tmp_poll_fd.fd = (UA_FD)connectionId;
    tmp_poll_fd.events = UA_POLLOUT;

    /* Send the full buffer. This may require several calls to send */
    size_t nWritten = 0;
    do {
        ssize_t n = 0;
        do {
            UA_LOG_DEBUG(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                         "ETH %u\t| Attempting to send", (unsigned)connectionId);
            size_t bytes_to_send = buf->length - nWritten;
#ifdef SO_TXTIME
            if(txtime) {
                n = send_txtime(el, conn, params, *txtime,
                                (const char*)buf->data + nWritten, bytes_to_send);
            } else
#endif
            {
                n = UA_sendto(conn->rfd.fd,
                              (const char*)buf->data + nWritten, bytes_to_send,
                              flags, (struct sockaddr*)&conn->sll, sizeof(conn->sll));
            }
            if(n < 0) {
                /* An error we cannot recover from? */
                if(UA_ERRNO != UA_INTERRUPTED &&
                   UA_ERRNO != UA_WOULDBLOCK &&
                   UA_ERRNO != UA_AGAIN) {
                    UA_LOG_SOCKET_ERRNO_WRAP(
                       UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                                    "ETH %u\t| Send failed with error %s",
                                    (unsigned)connectionId, errno_str));
                    ETH_shutdown(pcm, conn);
                    UA_UNLOCK(&el->elMutex);
                    UA_EventLoopPOSIX_freeNetworkBuffer(cm, connectionId, buf);
                    return UA_STATUSCODE_BADCONNECTIONCLOSED;
                }

                /* Poll for the socket resources to become available and retry
                 * (blocking) */
                int poll_ret;
                do {
                    poll_ret = UA_poll(&tmp_poll_fd, 1, 100);
                    if(poll_ret < 0 && UA_ERRNO != UA_INTERRUPTED) {
                        UA_LOG_SOCKET_ERRNO_WRAP(
                           UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                                        "ETH %u\t| Send failed with error %s",
                                        (unsigned)connectionId, errno_str));
                        ETH_shutdown(pcm, conn);
                        UA_UNLOCK(&el->elMutex);
                        UA_EventLoopPOSIX_freeNetworkBuffer(cm, connectionId, buf);
                        return UA_STATUSCODE_BADCONNECTIONCLOSED;
                    }
                } while(poll_ret <= 0);
            }
        } while(n < 0);
        nWritten += (size_t)n;
    } while(nWritten < buf->length);

    /* Free the buffer */
    UA_UNLOCK(&el->elMutex);
    UA_EventLoopPOSIX_freeNetworkBuffer(cm, connectionId, buf);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
ETH_eventSourceStart(UA_ConnectionManager *cm) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)cm->eventSource.eventLoop;
    UA_LOCK(&el->elMutex);

    /* Check the state */
    if(cm->eventSource.state != UA_EVENTSOURCESTATE_STOPPED) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                     "To start the Ethernet ConnectionManager, "
                     "it has to be registered in an EventLoop and not started");
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Check the parameters */
    UA_StatusCode res =
        UA_KeyValueRestriction_validate(el->eventLoop.logger, "ETH",
                                        ethManagerParams, ETH_MANAGERPARAMS,
                                        &cm->eventSource.params);
    if(res != UA_STATUSCODE_GOOD)
        goto finish;

    /* Allocate the rx buffer */
    res = UA_EventLoopPOSIX_allocateStaticBuffers(pcm);
    if(res != UA_STATUSCODE_GOOD)
        goto finish;

    /* Set the EventSource to the started state */
    cm->eventSource.state = UA_EVENTSOURCESTATE_STARTED;

 finish:
    UA_UNLOCK(&el->elMutex);
    return res;
}

static void *
ETH_shutdownCB(void *application, UA_RegisteredFD *rfd) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)application;
    ETH_shutdown(pcm, (ETH_FD*)rfd);
    return NULL;
}

static void
ETH_eventSourceStop(UA_ConnectionManager *cm) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)pcm->cm.eventSource.eventLoop;
    UA_LOCK(&el->elMutex);

    UA_LOG_INFO(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                "ETH\t| Shutting down the ConnectionManager");

    /* Prevent new connections to open */
    cm->eventSource.state = UA_EVENTSOURCESTATE_STOPPING;

    /* Shutdown all existing connection */
    ZIP_ITER(UA_FDTree, &pcm->fds, ETH_shutdownCB, cm);

    /* Check if stopped once more (also checking inside ETH_close, but there we
     * don't check if there is no rfd at all) */
    ETH_checkStopped(pcm);

    UA_UNLOCK(&el->elMutex);
}

static UA_StatusCode
ETH_eventSourceDelete(UA_ConnectionManager *cm) {
    UA_POSIXConnectionManager *pcm = (UA_POSIXConnectionManager*)cm;
    if(cm->eventSource.state >= UA_EVENTSOURCESTATE_STARTING) {
        UA_LOG_ERROR(cm->eventSource.eventLoop->logger, UA_LOGCATEGORY_EVENTLOOP,
                     "ETH\t| The EventSource must be stopped before it can be deleted");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_KeyValueMap_clear(&cm->eventSource.params);
    UA_ByteString_clear(&pcm->rxBuffer);
    UA_ByteString_clear(&pcm->txBuffer);
    UA_String_clear(&cm->eventSource.name);
    UA_free(cm);
    return UA_STATUSCODE_GOOD;
}

static const char *ethName = "eth";

UA_ConnectionManager *
UA_ConnectionManager_new_POSIX_Ethernet(const UA_String eventSourceName) {
    UA_POSIXConnectionManager *cm = (UA_POSIXConnectionManager*)
        UA_calloc(1, sizeof(UA_POSIXConnectionManager));
    if(!cm)
        return NULL;

    cm->cm.eventSource.eventSourceType = UA_EVENTSOURCETYPE_CONNECTIONMANAGER;
    UA_String_copy(&eventSourceName, &cm->cm.eventSource.name);
    cm->cm.eventSource.start = (UA_StatusCode (*)(UA_EventSource *))ETH_eventSourceStart;
    cm->cm.eventSource.stop = (void (*)(UA_EventSource *))ETH_eventSourceStop;
    cm->cm.eventSource.free = (UA_StatusCode (*)(UA_EventSource *))ETH_eventSourceDelete;
    cm->cm.protocol = UA_STRING((char*)(uintptr_t)ethName);
    cm->cm.openConnection = ETH_openConnection;
    cm->cm.allocNetworkBuffer = ETH_allocNetworkBuffer;
    cm->cm.freeNetworkBuffer = ETH_freeNetworkBuffer;
    cm->cm.sendWithConnection = ETH_sendWithConnection;
    cm->cm.closeConnection = ETH_shutdownConnection;
    return &cm->cm;
}

#endif /* defined(UA_ARCHITECTURE_POSIX) && defined(__linux__) */


/**** amalgamated original file "/plugins/eventloop/posix/eventloop_posix_interrupt.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 */

#include <signal.h>

/* Different implementation approaches:
 * - Linux: Use signalfd
 * - Other: Use the self-pipe trick (http://cr.yp.to/docs/selfpipe.html) */

typedef struct UA_RegisteredSignal {
#ifdef UA_HAVE_EPOLL
    /* With epoll, register each signal with a socket.
     * This has to be the first element of the struct to allow casting. */
    UA_RegisteredFD rfd;
#else
    /* Without epoll, we add the rfd to a tailq and self-pipe to trigger the
     * traversal of the tailq */
    TAILQ_ENTRY(UA_RegisteredSignal) triggeredEntry;
#endif

    LIST_ENTRY(UA_RegisteredSignal) listPointers;

    UA_InterruptCallback signalCallback;
    void *context;
    int signal; /* POSIX identifier of the interrupt signal */

    UA_Boolean active; /* Signals are only active when the EventLoop is started */
    UA_Boolean triggered;
} UA_RegisteredSignal;

typedef struct {
    UA_InterruptManager im;

    /* Registered signals */
    size_t signalsSize;
    LIST_HEAD(, UA_RegisteredSignal) signals;

#ifndef UA_HAVE_EPOLL
    UA_RegisteredFD readFD;
    UA_FD writeFD;
    TAILQ_HEAD(, UA_RegisteredSignal) triggered;
#endif
} UA_POSIXInterruptManager;

#ifndef UA_HAVE_EPOLL
/* On non-linux systems we can have at most one interrupt manager */
static UA_POSIXInterruptManager *singletonIM = NULL;
#endif

/* The following methods have to be implemented for epoll/self-pipe each. */
static void activateSignal(UA_RegisteredSignal *rs);
static void deactivateSignal(UA_RegisteredSignal *rs);

#ifdef UA_HAVE_EPOLL
#include <sys/signalfd.h>

static void
handlePOSIXInterruptEvent(UA_EventSource *es, UA_RegisteredFD *rfd, short event) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)es->eventLoop;
    (void)el;
    UA_LOCK_ASSERT(&el->elMutex, 1);

    UA_RegisteredSignal *rs = (UA_RegisteredSignal*)rfd;
    struct signalfd_siginfo fdsi;
    ssize_t s = read(rfd->fd, &fdsi, sizeof(fdsi));
    if(s < (ssize_t)sizeof(fdsi)) {
        /* A problem occured */
        deactivateSignal(rs);
        return;
    }

    /* Signal received */
    UA_LOG_DEBUG(es->eventLoop->logger, UA_LOGCATEGORY_EVENTLOOP,
                 "Interrupt %u\t| Received a signal %u",
                 (unsigned)rfd->fd, fdsi.ssi_signo);

    UA_UNLOCK(&el->elMutex);
    rs->signalCallback((UA_InterruptManager *)es, (uintptr_t)rfd->fd,
                       rs->context, &UA_KEYVALUEMAP_NULL);
    UA_LOCK(&el->elMutex);
}

static void
activateSignal(UA_RegisteredSignal *rs) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)rs->rfd.es->eventLoop;
    UA_LOCK_ASSERT(&el->elMutex, 1);

    if(rs->active)
        return;

    /* Block the normal signal handling */
    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, rs->signal);
    int res2 = sigprocmask(SIG_BLOCK, &mask, NULL);
    if(res2 == -1) {
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                           "Interrupt\t| Could not block the default "
                           "signal handling with an error: %s",
                           errno_str));
        return;
    }

    /* Create the fd */
    UA_FD newfd = signalfd(-1, &mask, 0);
    if(newfd < 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                           "Interrupt\t|Could not create a signal file "
                           "description with error: %s",
                           errno_str));
        sigprocmask(SIG_UNBLOCK, &mask, NULL); /* restore signal */
        return;
    }

    rs->rfd.fd = newfd;
    rs->rfd.eventSourceCB = handlePOSIXInterruptEvent;
    rs->rfd.listenEvents = UA_FDEVENT_IN;

    /* Register the fd in the EventLoop */
    UA_StatusCode res = UA_EventLoopPOSIX_registerFD(el, &rs->rfd);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                       "Interrupt\t|Could not register the a signal file "
                       "description in the EventLoop");
        UA_close(newfd);
        sigprocmask(SIG_UNBLOCK, &mask, NULL); /* restore signal */
        return;
    }

    rs->active = true;
}

static void
deactivateSignal(UA_RegisteredSignal *rs) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)rs->rfd.es->eventLoop;
    UA_LOCK_ASSERT(&el->elMutex, 1);

    /* Only dectivate if active */
    if(!rs->active)
        return;
    rs->active = false;

    /* Stop receiving the signal on the FD */
    UA_EventLoopPOSIX_deregisterFD(el, &rs->rfd);

    /* Unblock the signal */
    sigset_t mask;
    sigemptyset(&mask);
    sigaddset(&mask, (int)rs->signal);
    sigprocmask(SIG_UNBLOCK, &mask, NULL);

    /* Clean up locally */
    UA_close(rs->rfd.fd);
}

#else /* !UA_HAVE_EPOLL */

static void
triggerPOSIXInterruptEvent(int sig) {
    UA_assert(singletonIM != NULL);

    /* Don't take a lock. All we are doing here can be done from within a
     * (reentrant) interrupt. */

    /* Get the rs. Only use it if not already triggered. */
    UA_RegisteredSignal *rs;
    LIST_FOREACH(rs, &singletonIM->signals, listPointers) {
        if(rs->signal == sig)
            break;
    }
    if(!rs || rs->triggered || !rs->active)
        return;

    /* Add to the triggered list */
    TAILQ_INSERT_TAIL(&singletonIM->triggered, rs, triggeredEntry);
    rs->triggered = true;

#ifdef _WIN32
    /* On WIN32 we have to re-arm the signal or it will go back to SIG_DFL */
    signal(sig, triggerPOSIXInterruptEvent);
#endif

    /* Trigger the FD in the EventLoop for the self-pipe trick */
#ifdef _WIN32
    int err = send(singletonIM->writeFD, ".", 1, 0);
#else
    ssize_t err = write(singletonIM->writeFD, ".", 1);
#endif
    if(err <= 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
            UA_LOG_WARNING(singletonIM->im.eventSource.eventLoop->logger,
                           UA_LOGCATEGORY_EVENTLOOP,
                           "Error signaling the interrupt on FD %u to the EventLoop (%s)",
                           (unsigned)singletonIM->writeFD, errno_str));
    }
}

static void
activateSignal(UA_RegisteredSignal *rs) {
    UA_assert(singletonIM != NULL);
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)singletonIM->im.eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex, 1);

    /* Register the signal on the OS level */
    if(rs->active)
        return;

    void (*prev)(int);
    prev = signal(rs->signal, triggerPOSIXInterruptEvent);
    if(prev == SIG_ERR) {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(singletonIM->im.eventSource.eventLoop->logger,
                          UA_LOGCATEGORY_EVENTLOOP,
                          "Error registering the signal: %s", errno_str));
        return;
    }

    rs->active = true;
}

static void
deactivateSignal(UA_RegisteredSignal *rs) {
    UA_assert(singletonIM != NULL);
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)singletonIM->im.eventSource.eventLoop;
    UA_LOCK_ASSERT(&el->elMutex, 1);

    /* Only dectivate if active */
    if(!rs->active)
        return;

    /* Stop receiving the signal */
    signal(rs->signal, SIG_DFL);

    /* Clean up locally */
    if(rs->triggered) {
        TAILQ_REMOVE(&singletonIM->triggered, rs, triggeredEntry);
        rs->triggered = false;
    }

    rs->active = false;
}

/* Execute all triggered interrupts via the self-pipe trick from within the EventLoop */
static void
executeTriggeredPOSIXInterrupts(UA_EventSource *es, UA_RegisteredFD *rfd, short event) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX*)es->eventLoop;
    UA_LOCK_ASSERT(&el->elMutex, 1);

    /* Re-arm the socket for the next signal by reading from it */
    char buf[128];
#ifdef _WIN32
    recv(rfd->fd, buf, 128, 0); /* ignore the result */
#else
    ssize_t i;
    do {
        i = read(rfd->fd, buf, 128);
    } while(i > 0);
#endif

    UA_RegisteredSignal *rs, *rs_tmp;
    TAILQ_FOREACH_SAFE(rs, &singletonIM->triggered, triggeredEntry, rs_tmp) {
        TAILQ_REMOVE(&singletonIM->triggered, rs, triggeredEntry);
        rs->triggered = false;
        UA_UNLOCK(&el->elMutex);
        rs->signalCallback(&singletonIM->im, (uintptr_t)rs->signal,
                           rs->context, &UA_KEYVALUEMAP_NULL);
        UA_LOCK(&el->elMutex);
    }
}

#endif /* !UA_HAVE_EPOLL */

static UA_StatusCode
registerPOSIXInterrupt(UA_InterruptManager *im, uintptr_t interruptHandle,
                       const UA_KeyValueMap *params,
                       UA_InterruptCallback callback, void *interruptContext) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)im->eventSource.eventLoop;
    if(!UA_KeyValueMap_isEmpty(params)) {
        UA_LOG_ERROR(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                     "Interrupt\t| Supplied parameters invalid for the "
                     "POSIX InterruptManager");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_LOCK(&el->elMutex);

    /* Was the signal already registered? */
    int signal = (int)interruptHandle;
    UA_POSIXInterruptManager *pim = (UA_POSIXInterruptManager *)im;
    UA_RegisteredSignal *rs;
    LIST_FOREACH(rs, &pim->signals, listPointers) {
        if(rs->signal == signal)
            break;
    }
    if(rs) {
        UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_EVENTLOOP,
                       "Interrupt\t| Signal %u already registered",
                       (unsigned)interruptHandle);
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Create and populate the new context object */
    rs = (UA_RegisteredSignal *)UA_calloc(1, sizeof(UA_RegisteredSignal));
    if(!rs) {
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

#ifdef UA_HAVE_EPOLL
    rs->rfd.es = &im->eventSource;
#endif
    rs->signal = (int)interruptHandle;
    rs->signalCallback = callback;
    rs->context = interruptContext;

    /* Add to the InterruptManager */
    LIST_INSERT_HEAD(&pim->signals, rs, listPointers);
    pim->signalsSize++;

    /* Activate if we are already running */
    if(pim->im.eventSource.state == UA_EVENTSOURCESTATE_STARTED)
        activateSignal(rs);

    UA_UNLOCK(&el->elMutex);
    return UA_STATUSCODE_GOOD;
}

static void
deregisterPOSIXInterrupt(UA_InterruptManager *im, uintptr_t interruptHandle) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)im->eventSource.eventLoop;
    (void)el;
    UA_POSIXInterruptManager *pim = (UA_POSIXInterruptManager *)im;
    UA_LOCK(&el->elMutex);

    int signal = (int)interruptHandle;
    UA_RegisteredSignal *rs;
    LIST_FOREACH(rs, &pim->signals, listPointers) {
        if(rs->signal == signal)
            break;
    }
    if(rs) {
        deactivateSignal(rs);
        LIST_REMOVE(rs, listPointers);
        UA_free(rs);
    }

    UA_UNLOCK(&el->elMutex);
}

#ifdef _WIN32
/* Windows has no pipes. Use a local TCP connection for the self-pipe trick.
 * https://stackoverflow.com/a/3333565 */
static int
pair(SOCKET fds[2]) {
    struct sockaddr_in inaddr;
    struct sockaddr addr;
    SOCKET lst = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    memset(&inaddr, 0, sizeof(inaddr));
    memset(&addr, 0, sizeof(addr));
    inaddr.sin_family = AF_INET;
    inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    inaddr.sin_port = 0;
    int yes = 1;
    setsockopt(lst, SOL_SOCKET, SO_REUSEADDR, (char *)&yes, sizeof(yes));
    bind(lst, (struct sockaddr *)&inaddr, sizeof(inaddr));
    listen(lst, 1);
    int len = sizeof(inaddr);
    getsockname(lst, &addr, &len);
    fds[0] = socket(AF_INET, SOCK_STREAM, 0);
    int err = connect(fds[0], &addr, len);
    fds[1] = accept(lst, 0, 0);
    closesocket(lst);
    return err;
}
#endif

static UA_StatusCode
startPOSIXInterruptManager(UA_EventSource *es) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)es->eventLoop;
    (void)el;
    UA_LOCK(&el->elMutex);

    /* Check the state */
    if(es->state != UA_EVENTSOURCESTATE_STOPPED) {
        UA_LOG_ERROR(es->eventLoop->logger, UA_LOGCATEGORY_EVENTLOOP,
                     "Interrupt\t| To start the InterruptManager, "
                     "it has to be registered in an EventLoop and not started");
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_POSIXInterruptManager *pim = (UA_POSIXInterruptManager *)es;
    UA_LOG_DEBUG(es->eventLoop->logger, UA_LOGCATEGORY_EVENTLOOP,
                 "Interrupt\t| Starting the InterruptManager");

#ifndef UA_HAVE_EPOLL
    /* Create pipe for self-signaling */
    UA_FD pipefd[2];
#ifdef _WIN32
    int err = pair(pipefd);
#else
    int err = pipe(pipefd);
#endif
    if(err != 0) {
        UA_LOG_SOCKET_ERRNO_WRAP(
           UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                          "Interrupt\t| Could not open the pipe for "
                          "self-signaling (%s)", errno_str));
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    UA_StatusCode res = UA_STATUSCODE_GOOD;
#ifndef _WIN32
    /* Mark pipes as non-blocking */
    for(size_t i = 0; i < (sizeof(pipefd) / sizeof(*pipefd)); ++i) {
        res = UA_EventLoopPOSIX_setNonBlocking(pipefd[i]);
        if(res != UA_STATUSCODE_GOOD) {
            UA_LOG_SOCKET_ERRNO_WRAP(
                UA_LOG_WARNING(el->eventLoop.logger, UA_LOGCATEGORY_NETWORK,
                               "Interrupt\t| Could mark pipe for "
                               "self-signaling as non-blocking(%s)",
                               errno_str));
            UA_UNLOCK(&el->elMutex);
            return UA_STATUSCODE_BADINTERNALERROR;
        }
    }
#endif

    UA_LOG_DEBUG(es->eventLoop->logger, UA_LOGCATEGORY_EVENTLOOP,
                 "Interrupt\t| Socket pair for the self-pipe: %u,%u",
                 (unsigned)pipefd[0], (unsigned)pipefd[1]);

    pim->writeFD = pipefd[1];
    pim->readFD.fd = pipefd[0];
    pim->readFD.es = &pim->im.eventSource;
    pim->readFD.listenEvents = UA_FDEVENT_IN;
    pim->readFD.eventSourceCB = executeTriggeredPOSIXInterrupts;
    res = UA_EventLoopPOSIX_registerFD(el, &pim->readFD);
    if(res != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(es->eventLoop->logger, UA_LOGCATEGORY_EVENTLOOP,
                     "Interrupt\t| Could not register the InterruptManager socket");
        UA_close(pipefd[0]);
        UA_close(pipefd[1]);
        UA_UNLOCK(&el->elMutex);
        return UA_STATUSCODE_BADINTERNALERROR;
    }
#endif

    /* Activate the registered signal handlers */
    UA_RegisteredSignal*rs;
    LIST_FOREACH(rs, &pim->signals, listPointers) {
        activateSignal(rs);
    }

    /* Set the EventSource to the started state */
    es->state = UA_EVENTSOURCESTATE_STARTED;

    UA_UNLOCK(&el->elMutex);
    return UA_STATUSCODE_GOOD;
}

static void
stopPOSIXInterruptManager(UA_EventSource *es) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)es->eventLoop;
    (void)el;
    UA_LOCK(&el->elMutex);

    if(es->state != UA_EVENTSOURCESTATE_STARTED) {
        UA_UNLOCK(&el->elMutex);
        return;
    }

    UA_LOG_DEBUG(es->eventLoop->logger, UA_LOGCATEGORY_EVENTLOOP,
                 "Interrupt\t| Stopping the InterruptManager");

    /* Close all registered signals */
    UA_POSIXInterruptManager *pim = (UA_POSIXInterruptManager *)es;
    UA_RegisteredSignal*rs;
    LIST_FOREACH(rs, &pim->signals, listPointers) {
        deactivateSignal(rs);
    }

#ifndef UA_HAVE_EPOLL
    /* Close the FD for the self-pipe trick */
    UA_EventLoopPOSIX_deregisterFD(el, &pim->readFD);
    UA_close(pim->readFD.fd);
    UA_close(pim->writeFD);
#endif

    /* Immediately set to stopped */
    es->state = UA_EVENTSOURCESTATE_STOPPED;

    UA_UNLOCK(&el->elMutex);
}

static UA_StatusCode
freePOSIXInterruptmanager(UA_EventSource *es) {
    UA_EventLoopPOSIX *el = (UA_EventLoopPOSIX *)es->eventLoop;
    (void)el;
    UA_LOCK_ASSERT(&el->elMutex, 1);

    if(es->state >= UA_EVENTSOURCESTATE_STARTING) {
        UA_LOG_ERROR(es->eventLoop->logger, UA_LOGCATEGORY_EVENTLOOP,
                     "Interrupt\t| The EventSource must be stopped "
                     "before it can be deleted");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Deactivate and remove all registered signals */
    UA_POSIXInterruptManager *pim = (UA_POSIXInterruptManager *)es;
    UA_RegisteredSignal *rs, *rs_tmp;
    LIST_FOREACH_SAFE(rs, &pim->signals, listPointers, rs_tmp) {
        deactivateSignal(rs);
        LIST_REMOVE(rs, listPointers);
        UA_free(rs);
    }

    UA_String_clear(&es->name);
    UA_free(es);

#ifndef UA_HAVE_EPOLL
    singletonIM = NULL; /* Reset the global singleton pointer */
#endif

    return UA_STATUSCODE_GOOD;
}

UA_InterruptManager *
UA_InterruptManager_new_POSIX(const UA_String eventSourceName) {
#ifndef UA_HAVE_EPOLL
    /* There can be only one InterruptManager if epoll is not present */
    if(singletonIM)
        return NULL;
#endif

    UA_POSIXInterruptManager *pim = (UA_POSIXInterruptManager *)
        UA_calloc(1, sizeof(UA_POSIXInterruptManager));
    if(!pim)
        return NULL;

    LIST_INIT(&pim->signals);

#ifndef UA_HAVE_EPOLL
    TAILQ_INIT(&pim->triggered);
    singletonIM = pim; /* Register the singleton singleton pointer */
#endif

    UA_InterruptManager *im = &pim->im;
    im->eventSource.eventSourceType = UA_EVENTSOURCETYPE_INTERRUPTMANAGER;
    UA_String_copy(&eventSourceName, &im->eventSource.name);
    im->eventSource.start = startPOSIXInterruptManager;
    im->eventSource.stop = stopPOSIXInterruptManager;
    im->eventSource.free = freePOSIXInterruptmanager;
    im->registerInterrupt = registerPOSIXInterrupt;
    im->deregisterInterrupt = deregisterPOSIXInterrupt;
    return im;
}

/**** amalgamated original file "/plugins/eventloop/eventloop_mqtt.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2022 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 */

/* The MQTT ConnectionManager is architecture agnostic. It selects an existing
 * TCP ConnectionManager and uses it for the underlying TCP connections. */


#ifdef UA_ENABLE_MQTT

#include <limits.h>

#if defined(_MSC_VER)
# include <BaseTsd.h>
typedef SSIZE_T ssize_t;
#else
# include <unistd.h> /* ssize_t */
#endif

struct MQTTConnectionManager;
typedef struct MQTTConnectionManager MQTTConnectionManager;

struct MQTTBrokerConnection;
typedef struct MQTTBrokerConnection MQTTBrokerConnection;

struct MQTTTopicConnection;
typedef struct MQTTTopicConnection MQTTTopicConnection;

/* Prevent the inclusion of "mqtt_pal.h". We make the definitions inline here to remain
 * architecture and OS-agnostic. */

/* Network-endianness conversion */
static UA_INLINE uint16_t
MQTT_PAL_HTONS(uint16_t s) {
    union {uint16_t t; uint8_t b[2];} v;
    v.b[0] = (uint8_t)(s>>8);
    v.b[1] = (uint8_t)s;
    return v.t;
}

static UA_INLINE uint16_t
MQTT_PAL_NTOHS(uint16_t s) {
    union {uint16_t t; uint8_t b[2];} v;
    v.t = s;
    return (uint16_t)((uint16_t)v.b[1] + (((uint16_t)v.b[0])<<8));
}

/* Time definition (in seconds resolution) */
typedef long int mqtt_pal_time_t;
#define MQTT_PAL_TIME() (long int)(UA_DateTime_nowMonotonic() / UA_DATETIME_SEC)

/* Mutex definition (disabled) */
typedef UA_Byte mqtt_pal_mutex_t;
#define MQTT_PAL_MUTEX_INIT(mtx_ptr) *mtx_ptr = 0
#define MQTT_PAL_MUTEX_LOCK(mtx_ptr) {}
#define MQTT_PAL_MUTEX_UNLOCK(mtx_ptr) {}

/* Socket definition */
typedef MQTTBrokerConnection * mqtt_pal_socket_handle;
static ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void* buf, size_t len, int flags);
static ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void* buf, size_t bufsz, int flags);

/* Include headers and source files! We need deep integration to use the above definitions. */

#define MQTT_MESSAGE_MAXLEN (1u << 20) /* 1MB */
#define MQTT_PARAMETERSSIZE 8
#define MQTT_BROKERPARAMETERSSIZE 5 /* Parameters shared by topic connections
                                     * connected to the same broker */

static const struct {
    UA_QualifiedName name;
    const UA_DataType *type;
    UA_Boolean required;
} MQTTConnectionParameters[MQTT_PARAMETERSSIZE] = {
    {{0, UA_STRING_STATIC("address")}, &UA_TYPES[UA_TYPES_STRING], true},
    {{0, UA_STRING_STATIC("port")}, &UA_TYPES[UA_TYPES_UINT16], false},
    {{0, UA_STRING_STATIC("keep-alive")}, &UA_TYPES[UA_TYPES_UINT16], false},
    {{0, UA_STRING_STATIC("username")}, &UA_TYPES[UA_TYPES_STRING], false},
    {{0, UA_STRING_STATIC("password")}, &UA_TYPES[UA_TYPES_STRING], false},
    {{0, UA_STRING_STATIC("validate")}, &UA_TYPES[UA_TYPES_BOOLEAN], false},
    {{0, UA_STRING_STATIC("subscribe")}, &UA_TYPES[UA_TYPES_BOOLEAN], false},
    {{0, UA_STRING_STATIC("topic")}, &UA_TYPES[UA_TYPES_STRING], true}
};

/* The BrokerConnection is a stateful connection to the broker that aggregates
 * subscriptions to topics. The BrokerConnection is not directly exposed via the
 * public interface. Only TopicConnections are. */
struct MQTTBrokerConnection {
    LIST_ENTRY(MQTTBrokerConnection) next;

    /* Backpointer to the ConnectionManager, always set */
    MQTTConnectionManager *mcm;

    /* Connection ID for the underlying TCP ConnectionManager */
    uintptr_t tcpConnectionId;
    UA_ConnectionState tcpConnectionState;
    struct mqtt_client client;

    UA_DateTime lastSendTime; /* When was the last packet sent out? */
    UA_UInt16 keepalive;      /* Seconds between keepalives */
    UA_UInt64 keepAliveCallbackId; /* Registered callback to send the keepalive */

    /* Topic connections sharing the same connection to a broker */
    LIST_HEAD(, MQTTTopicConnection) topicConnections;
    uintptr_t lastTopicConnectionId;

    /* Store the connection parameters. To reconnect when necessary and to check
     * if a matching connection to the broker already exists. */
    UA_KeyValueMap params;
};

/* Connections created via the EventLoop interface are bound to an individual
 * topic. Aggregating them to BrokerConnections is hidden in the background. */
struct MQTTTopicConnection {
    LIST_ENTRY(MQTTTopicConnection) next;

    /* (Broker Connection Id * 1000) + connection Id */
    uintptr_t topicConnectionId; 
    UA_ConnectionState topicConnectionState;

    UA_String topic;      /* Name of the topic */
    UA_Boolean subscribe; /* Subscribe or publish? */

    /* Backpointer to the connection to the broker (is always set) */
    MQTTBrokerConnection *brokerConnection;

    /* Callback back into the application */
    void *application;
    void *context;
    UA_ConnectionManager_connectionCallback callback;

    /* For delayed removal */
    UA_DelayedCallback dc;
};

/* The ConnectionManager holds a linked list of connections */
struct MQTTConnectionManager {
    UA_ConnectionManager cm;
    UA_ConnectionManager *tcpCM; /* The TCP ConnectionManager to use. Set during
                                  * the start of this CM. */
    LIST_HEAD(, MQTTBrokerConnection) connections;
};

/* Send via the underlying TCP connection */
ssize_t
mqtt_pal_sendall(MQTTBrokerConnection *bc, const void* buf, size_t len, int flags) {
    if(bc->tcpConnectionState != UA_CONNECTIONSTATE_ESTABLISHED)
        return MQTT_ERROR_SOCKET_ERROR;

    UA_ByteString msg = UA_BYTESTRING_NULL;
    UA_ConnectionManager *tcpCM = bc->mcm->tcpCM;
    UA_StatusCode res = tcpCM->allocNetworkBuffer(tcpCM, bc->tcpConnectionId, &msg, len);
    if(res != UA_STATUSCODE_GOOD)
        return MQTT_ERROR_SOCKET_ERROR;
        
    memcpy(msg.data, buf, len);
    res = tcpCM->sendWithConnection(tcpCM, bc->tcpConnectionId,
                                    &UA_KEYVALUEMAP_NULL, &msg);
    if(res != UA_STATUSCODE_GOOD)
        return MQTT_ERROR_SOCKET_ERROR;

    bc->lastSendTime = UA_DateTime_nowMonotonic();
    return (ssize_t)len;
}

/* Always return zero. The received messages are "manually" added to the buffer.
 * So we don't block in the EventLoop model. */
ssize_t
mqtt_pal_recvall(MQTTBrokerConnection *bc, void* buf, size_t bufsz, int flags) {
    return 0;
}

static UA_StatusCode
MQTT_eventSourceStart(UA_ConnectionManager *cm) {
    MQTTConnectionManager *mcm = (MQTTConnectionManager*)cm;
    UA_EventLoop *el = cm->eventSource.eventLoop;
    if(!el)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Check the state */
    if(cm->eventSource.state != UA_EVENTSOURCESTATE_STOPPED) {
        UA_LOG_ERROR(el->logger, UA_LOGCATEGORY_NETWORK,
                     "MQTT\t| To start the ConnectionManager, it has to be "
                     "registered in an EventLoop and not started yet");
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Use the first TCP ConnectionManager */
    UA_String tcp = UA_STRING("tcp");
    for(UA_EventSource *es = el->eventSources; es; es = es->next) {
        if(es->eventSourceType != UA_EVENTSOURCETYPE_CONNECTIONMANAGER)
            continue;
        UA_ConnectionManager *cm2 = (UA_ConnectionManager*)es;
        if(UA_String_equal(&tcp, &cm2->protocol)) {
            mcm->tcpCM = cm2;
            cm->eventSource.state = UA_EVENTSOURCESTATE_STARTED;
            return UA_STATUSCODE_GOOD;
        }
    }
    return UA_STATUSCODE_BADINTERNALERROR;
}

static void
shutdownBrokerConnection(MQTTBrokerConnection *bc) {
    if(bc->tcpConnectionState == UA_CONNECTIONSTATE_CLOSED ||
       bc->tcpConnectionState == UA_CONNECTIONSTATE_CLOSING)
        return;

    UA_LOG_DEBUG(bc->mcm->cm.eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
                 "MQTT-TCP %u\t| Closing the broker connection",
                 (unsigned)bc->tcpConnectionId);

    /* Shutdown and delete all associated topic connections. We immediately send
     * the DISCONNECT and clear up the topic connections without sending an
     * explicit unsubscribe.
     *
     * while(bc->topicConnections)
     *     removeTopicConnection(bc->topicConnections); */

    /* Send the DISCONNECT packet */
    if(bc->tcpConnectionState == UA_CONNECTIONSTATE_ESTABLISHED) {
        mqtt_disconnect(&bc->client);
        __mqtt_send(&bc->client);
    }

    /* Close the TCP connection -> callback in the next el iteration */
    UA_ConnectionManager *tcpCM = bc->mcm->tcpCM;
    tcpCM->closeConnection(tcpCM, bc->tcpConnectionId);

    bc->tcpConnectionState = UA_CONNECTIONSTATE_CLOSING;
}

static void
MQTT_eventSourceStop(UA_ConnectionManager *cm) {
    if(cm->eventSource.state == UA_EVENTSOURCESTATE_STOPPING ||
       cm->eventSource.state == UA_EVENTSOURCESTATE_STOPPED)
        return;

    UA_LOG_INFO(cm->eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
                "MQTT\t| Shutting down the ConnectionManager");

    MQTTConnectionManager *mcm = (MQTTConnectionManager*)cm;
    if(LIST_EMPTY(&mcm->connections)) {
        cm->eventSource.state = UA_EVENTSOURCESTATE_STOPPED;
        return;
    }

    cm->eventSource.state = UA_EVENTSOURCESTATE_STOPPING;
    MQTTBrokerConnection *bc, *bc_tmp;
    LIST_FOREACH_SAFE(bc, &mcm->connections, next, bc_tmp) {
        shutdownBrokerConnection(bc);
    }
}

static UA_StatusCode
MQTT_eventSourceDelete(UA_ConnectionManager *cm) {
    UA_String_clear(&cm->eventSource.name);
    UA_free(cm);
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
MQTT_allocNetworkBuffer(UA_ConnectionManager *cm, uintptr_t connectionId,
                        UA_ByteString *buf, size_t bufSize) {
    UA_ConnectionManager *tcpCM = ((MQTTConnectionManager*)cm)->tcpCM;
    return tcpCM->allocNetworkBuffer(tcpCM, connectionId, buf, bufSize);
}

static void
MQTT_freeNetworkBuffer(UA_ConnectionManager *cm, uintptr_t connectionId,
                       UA_ByteString *buf) {
    UA_ConnectionManager *tcpCM = ((MQTTConnectionManager*)cm)->tcpCM;
    tcpCM->freeNetworkBuffer(tcpCM, connectionId, buf);
}

static void
removeTopicConnection(MQTTTopicConnection *tc) {
    UA_LOG_INFO(tc->brokerConnection->mcm->cm.eventSource.eventLoop->logger,
                UA_LOGCATEGORY_NETWORK, "MQTT %u\t| Closing the connection",
                (unsigned)tc->topicConnectionId);

    /* Send the UNSUBSCRIBE packet */
    MQTTBrokerConnection *bc = tc->brokerConnection;
    if(tc->subscribe &&
       tc->topicConnectionState == UA_CONNECTIONSTATE_ESTABLISHED &&
       bc->tcpConnectionState == UA_CONNECTIONSTATE_ESTABLISHED) {
        mqtt_unsubscribe(&bc->client, (const char*)tc->topic.data);
        __mqtt_send(&bc->client);
    }

    /* Remove from linked list */
    LIST_REMOVE(tc, next);

    /* Signal the closed connection to the application */
    UA_KeyValuePair kvp[2];
    kvp[0].key = UA_QUALIFIEDNAME(0, "topic");
    UA_Variant_setScalar(&kvp[0].value, &tc->topic, &UA_TYPES[UA_TYPES_STRING]);
    kvp[1].key = UA_QUALIFIEDNAME(0, "subscribe");
    UA_Variant_setScalar(&kvp[0].value, &tc->subscribe, &UA_TYPES[UA_TYPES_BOOLEAN]);
    UA_KeyValueMap kvm = {2, kvp};

    /* Notify the application */
    if(tc->callback)
        tc->callback(&bc->mcm->cm, tc->topicConnectionId, tc->application, &tc->context,
                     UA_CONNECTIONSTATE_CLOSING, &kvm, UA_BYTESTRING_NULL);

    /* Free the memory */
    UA_String_clear(&tc->topic);
    UA_free(tc);

    /* The last topic connection was removed. Close the broker connection. */
    if(LIST_EMPTY(&bc->topicConnections))
        shutdownBrokerConnection(bc);
}

static void
removeTopicConnectionDelayed(void *application, void *context) {
    MQTTTopicConnection *tc = (MQTTTopicConnection*)context;
    removeTopicConnection(tc);
}

static void
removeBrokerConnection(MQTTBrokerConnection *bc) {
    MQTTConnectionManager *mcm = bc->mcm;
    UA_EventLoop *el = mcm->cm.eventSource.eventLoop;

    UA_LOG_DEBUG(bc->mcm->cm.eventSource.eventLoop->logger, UA_LOGCATEGORY_NETWORK,
                 "MQTT-TCP %u\t| Removing the broker connection", (unsigned)bc->tcpConnectionId);

    /* Remove the keepalive callback */
    if(bc->keepAliveCallbackId > 0)
        el->removeCyclicCallback(el, bc->keepAliveCallbackId);
    
    /* Remove from linked list */
    LIST_REMOVE(bc, next);

    /* Shutdown and delete all associated topic connections */
    MQTTTopicConnection *tc, *tc_tmp;
    LIST_FOREACH_SAFE(tc, &bc->topicConnections, next, tc_tmp) {
        removeTopicConnection(tc);
    }

    UA_KeyValueMap_clear(&bc->params);
    UA_free(bc->client.recv_buffer.mem_start);
    UA_free(bc->client.mq.mem_start);
    UA_free(bc);

    /* Stopped and the last connection was removed? */
    if(mcm->cm.eventSource.state == UA_EVENTSOURCESTATE_STOPPING &&
       LIST_EMPTY(&mcm->connections))
        mcm->cm.eventSource.state = UA_EVENTSOURCESTATE_STOPPED;
}

/* Look for BrokerConnections with identical broker connection parameters */
static MQTTBrokerConnection *
findIdenticalBrokerConnection(MQTTConnectionManager *mcm, const UA_KeyValueMap *kvm) {
    MQTTBrokerConnection *bc;
    LIST_FOREACH(bc, &mcm->connections, next) {
        UA_Boolean found = true;
        for(size_t i = 0; i < MQTT_BROKERPARAMETERSSIZE; i++) {
            const UA_Variant *v1 = UA_KeyValueMap_get(kvm, MQTTConnectionParameters[i].name);
            const UA_Variant *v2 = UA_KeyValueMap_get(kvm, MQTTConnectionParameters[i].name);
            if(v1 == v2)
                continue;
            if(!v2)
                continue; /* Not defined in the "required params" we are searching for */
            if(!v1 || UA_order(v1, v2, &UA_TYPES[UA_TYPES_VARIANT]) != UA_ORDER_EQ) {
                found = false;
                break;
            }
        }
        if(found)
            return bc;
    }
    return NULL;
}

static MQTTBrokerConnection *
findBrokerConnection(MQTTConnectionManager *mcm, uintptr_t id) {
    uintptr_t brokerId = id / 1000;
    MQTTBrokerConnection *bc;
    LIST_FOREACH(bc, &mcm->connections, next) {
        if(bc->tcpConnectionId == brokerId)
            return bc;
    }
    return NULL;
}

static MQTTTopicConnection *
findTopicConnection(MQTTConnectionManager *mcm, uintptr_t id) {
    MQTTBrokerConnection *bc = findBrokerConnection(mcm, id);
    if(!bc)
        return NULL;
    MQTTTopicConnection *tc;
    LIST_FOREACH(tc, &bc->topicConnections, next) {
        if(tc->topicConnectionId == id)
            return tc;
    }
    return NULL;
}

static void
MQTTKeepAliveCallback(void *app, MQTTBrokerConnection *bc) {
    (void)app;
    if(bc->lastSendTime + (bc->keepalive * UA_DATETIME_SEC) > UA_DateTime_nowMonotonic())
        return;
    mqtt_ping(&bc->client);
    __mqtt_send(&bc->client);
}

static void
MQTTPublishResponseCallback(void** state, struct mqtt_response_publish *publish) {
    MQTTBrokerConnection *bc = *(MQTTBrokerConnection**)state;

    /* Find matching TopicConnection */
    UA_String topic = {publish->topic_name_size,
                       (UA_Byte*)(uintptr_t)publish->topic_name};
    UA_ByteString msg = {publish->application_message_size,
                         (UA_Byte*)(uintptr_t)publish->application_message};

    /* Forward the topic name to the application */
    UA_Boolean subscribe = true;
    UA_KeyValuePair kvp[2];
    kvp[0].key = UA_QUALIFIEDNAME(0, "topic");
    UA_Variant_setScalar(&kvp[0].value, &topic, &UA_TYPES[UA_TYPES_STRING]);
    kvp[1].key = UA_QUALIFIEDNAME(0, "subscribe");
    UA_Variant_setScalar(&kvp[1].value, &subscribe, &UA_TYPES[UA_TYPES_BOOLEAN]);
    UA_KeyValueMap kvm = {2, kvp};

    /* Notify all matching topic connections */
    MQTTTopicConnection *tc;
    LIST_FOREACH(tc, &bc->topicConnections, next) {
        if(!tc->subscribe || !UA_String_equal(&topic, &tc->topic))
            continue;

        UA_LOG_DEBUG(tc->brokerConnection->mcm->cm.eventSource.eventLoop->logger,
                     UA_LOGCATEGORY_NETWORK, "MQTT %u\t| Received a message of "
                     "%u bytes", (unsigned)tc->topicConnectionId, (unsigned)msg.length);

        /* Notify the appliation that the connection is now established. The
         * only way to know about this is to receive the first message for the
         * topic (MQTT-C recieves a SUBACK message but does not forward that
         * information). */
        if(tc->topicConnectionState != UA_CONNECTIONSTATE_ESTABLISHED) {
            tc->topicConnectionState = UA_CONNECTIONSTATE_ESTABLISHED;
            tc->callback(&bc->mcm->cm, tc->topicConnectionId,
                         tc->application, &tc->context,
                         UA_CONNECTIONSTATE_ESTABLISHED, &kvm,
                         UA_BYTESTRING_NULL);
        }

        /* Forward the received message */
        tc->callback(&bc->mcm->cm, tc->topicConnectionId, tc->application,
                     &tc->context, UA_CONNECTIONSTATE_ESTABLISHED, &kvm, msg);
    }
}

static void
MQTTNetworkCallback(UA_ConnectionManager *tcpCM, uintptr_t connectionId,
                    void *application, void **connectionContext, UA_ConnectionState state,
                    const UA_KeyValueMap *params, UA_ByteString msg) {
    MQTTBrokerConnection *bc = *(MQTTBrokerConnection**)connectionContext;
    MQTTConnectionManager *mcm = bc->mcm;
    UA_assert(bc);

    /* Set the new TCP state */
    UA_ConnectionState oldState = bc->tcpConnectionState;
    bc->tcpConnectionState = state;

    /* The first callback. Initialize the bc. */
    if(oldState == UA_CONNECTIONSTATE_CLOSED) {
        /* Store the tcp connection id */
        bc->tcpConnectionId = connectionId;

        /* Set the context pointer for the mqtt client */
        bc->client.publish_response_callback_state = bc;
    }

    UA_LOG_DEBUG(bc->mcm->cm.eventSource.eventLoop->logger,
                 UA_LOGCATEGORY_NETWORK, "MQTT-TCP %u\t| Network callback",
                 (unsigned)bc->tcpConnectionId);

    /* TCP Connection is closing. Clean up all the topic connections as well.
     * Reconnecting must be handled on the application level. */
    if(state == UA_CONNECTIONSTATE_CLOSING || state == UA_CONNECTIONSTATE_CLOSED) {
        removeBrokerConnection(bc);
        return;
    }

    /* The connection has fully opened for the first time. Connect the MQTT client. */
    if(state == UA_CONNECTIONSTATE_ESTABLISHED &&
       oldState != UA_CONNECTIONSTATE_ESTABLISHED) {
        /* Initialize the MQTT client. We have to call mqtt_connect right afterward.
         * Otherwise the client lock is not released. */
        mqtt_init(&bc->client, bc,
                  (uint8_t*)UA_calloc(1,1024), 1024,
                  (uint8_t*)UA_calloc(1,1024), 1024,
                  MQTTPublishResponseCallback);

        /* Queue the connect message */
        enum MQTTErrors err = mqtt_connect(&bc->client, NULL, NULL, NULL, 0,
                                           NULL, NULL, MQTT_CONNECT_CLEAN_SESSION, 400);
        if(err != MQTT_OK) {
            bc->tcpConnectionState = UA_CONNECTIONSTATE_OPENING; /* avoid sending DISCONNECT */
            shutdownBrokerConnection(bc);
            return;
        }

        /* Handle topic connections already registered on the opening broker
         * connection */
        MQTTTopicConnection *tc;
        LIST_FOREACH(tc, &bc->topicConnections, next) {
            if(tc->subscribe) {
                /* Subscribe-connections call mqtt_subscribe but wait until the
                 * first received message to signal that they successfully
                 * opened */
                err = mqtt_subscribe(&bc->client, (const char*)tc->topic.data, 0);
                if(err == MQTT_OK)
                    err = (enum MQTTErrors)__mqtt_send(&bc->client);
                if(err != MQTT_OK)
                    removeTopicConnection(tc);
                UA_LOG_INFO(bc->mcm->cm.eventSource.eventLoop->logger,
                            UA_LOGCATEGORY_NETWORK, "MQTT %u\t| Created connection "
                            "subscribed on topic \"%s\"",
                            (unsigned)tc->topicConnectionId, (char*)tc->topic.data);
            } else {
                /* Publish-connections are signaling their state to the
                 * application immediately with a callback */
                UA_LOG_INFO(bc->mcm->cm.eventSource.eventLoop->logger,
                            UA_LOGCATEGORY_NETWORK, "MQTT %u\t| Created connection "
                            "publishing on topic \"%s\"",
                            (unsigned)tc->topicConnectionId, (char*)tc->topic.data);
                tc->topicConnectionState = UA_CONNECTIONSTATE_ESTABLISHED;
                tc->callback(&mcm->cm, tc->topicConnectionId, tc->application, &tc->context,
                             tc->topicConnectionState, &UA_KEYVALUEMAP_NULL,
                             UA_BYTESTRING_NULL);
            }
        }
    }

    /* No message to process? */
    if(msg.length == 0)
        return;

    /* Append the received message to the receive buffer. Increase the recv
     * buffer if necessary. */
    if(bc->client.recv_buffer.curr_sz < msg.length) {
        if(bc->client.recv_buffer.mem_size + msg.length > MQTT_MESSAGE_MAXLEN)
            return;
        uint8_t *mem = (uint8_t*)
            UA_realloc(bc->client.recv_buffer.mem_start,
                       bc->client.recv_buffer.mem_size + msg.length);
        if(!mem)
            return;
        size_t prev_len = bc->client.recv_buffer.mem_size - bc->client.recv_buffer.curr_sz;
        bc->client.recv_buffer.mem_start = mem;
        bc->client.recv_buffer.mem_size += msg.length;
        bc->client.recv_buffer.curr = &mem[prev_len];
        bc->client.recv_buffer.curr_sz += msg.length;
    }
    memcpy(bc->client.recv_buffer.curr, msg.data, msg.length);
    bc->client.recv_buffer.curr += msg.length;
    bc->client.recv_buffer.curr_sz -= msg.length;

    /* Process the message. The internal mqtt_pal_recvall does nothing (as we
     * already have added the message to the buffer. But then the entire buffer
     * is processed. */
    __mqtt_recv(&bc->client);
}

static MQTTBrokerConnection *
createBrokerConnection(MQTTConnectionManager *mcm, const UA_KeyValueMap *params,
                       UA_Boolean validate) {
    /* Allocate connection memory */
    MQTTBrokerConnection *bc = (MQTTBrokerConnection*)
        UA_calloc(1, sizeof(MQTTBrokerConnection));
    if(!bc)
        return NULL;

    /* Copy the parameters */
    UA_StatusCode res = UA_KeyValueMap_copy(params, &bc->params);

    bc->mcm = mcm;

    /* Add to the linked list (use removeBrokerConnection from here on) */
    LIST_INSERT_HEAD(&mcm->connections, bc, next);

    /* Extract the parameters */
    UA_String *broker = (UA_String*)(uintptr_t)
        UA_KeyValueMap_getScalar(params,
                                 UA_QUALIFIEDNAME(0, "address"),
                                 &UA_TYPES[UA_TYPES_STRING]);
    UA_assert(broker != NULL);

    UA_UInt16 *port = (UA_UInt16*)(uintptr_t)
        UA_KeyValueMap_getScalar(params,
                                 UA_QUALIFIEDNAME(0, "port"),
                                 &UA_TYPES[UA_TYPES_UINT16]);
    UA_UInt16 _port = 1883;
    if(!port)
        port = &_port;

    const UA_UInt16 *keepAlive = (const UA_UInt16*)
        UA_KeyValueMap_getScalar(params,
                                 UA_QUALIFIEDNAME(0, "keep-alive"),
                                 &UA_TYPES[UA_TYPES_UINT16]);

    /* Register the KeepAlive */
    bc->keepalive = 400; /* Default */
    if(keepAlive && *keepAlive > 0)
        bc->keepalive = *keepAlive;

    /* Open the Connection. This also sets the broker connection id to the TCP id. */
    UA_KeyValuePair tcpParams[3];
    tcpParams[0].key = UA_QUALIFIEDNAME(0, "address");
    UA_Variant_setScalar(&tcpParams[0].value, broker, &UA_TYPES[UA_TYPES_STRING]);
    tcpParams[1].key = UA_QUALIFIEDNAME(0, "port");
    UA_Variant_setScalar(&tcpParams[1].value, port, &UA_TYPES[UA_TYPES_UINT16]);
    tcpParams[2].key = UA_QUALIFIEDNAME(0, "validate");
    UA_Variant_setScalar(&tcpParams[2].value, &validate, &UA_TYPES[UA_TYPES_BOOLEAN]);
    UA_KeyValueMap kvm = {3, tcpParams};

    UA_ConnectionManager *tcpCM = mcm->tcpCM;
    res = tcpCM->openConnection(tcpCM, &kvm, NULL, bc, MQTTNetworkCallback);
    if(res != UA_STATUSCODE_GOOD) {
        removeBrokerConnection(bc);
        return NULL;
    }

    /* Return non-null to indicate success */
    if(validate) {
        removeBrokerConnection(bc);
        return (MQTTBrokerConnection*)0x01;
    }

    UA_EventLoop *el = mcm->cm.eventSource.eventLoop;
    res = el->addCyclicCallback(el, (UA_Callback)MQTTKeepAliveCallback, NULL, bc,
                                (UA_Double)(bc->keepalive * UA_DATETIME_SEC),
                                NULL, UA_TIMER_HANDLE_CYCLEMISS_WITH_CURRENTTIME,
                                &bc->keepAliveCallbackId);
    if(res != UA_STATUSCODE_GOOD) {
        removeBrokerConnection(bc);
        return NULL;
    }

    UA_LOG_DEBUG(bc->mcm->cm.eventSource.eventLoop->logger,
                 UA_LOGCATEGORY_NETWORK, "MQTT-TCP %u\t| Created broker connection",
                 (unsigned)bc->tcpConnectionId);

    return bc;
}

static MQTTTopicConnection *
createTopicConnection(MQTTConnectionManager *mcm, MQTTBrokerConnection *bc,
                      const UA_KeyValueMap *params,
                      void *application, void *context,
                      UA_ConnectionManager_connectionCallback connectionCallback) {
    UA_Boolean subscribe = true;
    const UA_Boolean *_subscribe= (const UA_Boolean*)
        UA_KeyValueMap_getScalar(params, UA_QUALIFIEDNAME(0, "subscribe"),
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
    if(_subscribe)
        subscribe = *_subscribe;
    const UA_String *topic = (const UA_String*)
        UA_KeyValueMap_getScalar(params, UA_QUALIFIEDNAME(0, "topic"),
                                 &UA_TYPES[UA_TYPES_STRING]);
    if(topic->length == 0)
        return NULL;

    MQTTTopicConnection *tc = (MQTTTopicConnection*)
        UA_calloc(1, sizeof(MQTTTopicConnection));
    if(!tc)
        return NULL;
    tc->application = application;
    tc->context = context;
    tc->callback = connectionCallback;
    tc->brokerConnection = bc;
    tc->topicConnectionId = (bc->tcpConnectionId * 1000) + (++bc->lastTopicConnectionId);
    tc->subscribe = subscribe;

    /* Make a null-terminated copy of the topic string to forward to the MQTT client. */
    tc->topic.data = (UA_Byte*)UA_malloc(topic->length + 1);
    if(!tc->topic.data) {
        UA_free(tc);
        return NULL;
    }
    memcpy(tc->topic.data, topic->data, topic->length);
    tc->topic.data[topic->length] = 0;
    tc->topic.length = topic->length;

    /* Subscribe the MQTT client if the client is already connected. Otherwise
     * defer mqtt_subscribe until the TCP socket is fully opened and we
     * connect. */
    if(bc->tcpConnectionState == UA_CONNECTIONSTATE_ESTABLISHED) {
        tc->topicConnectionState = UA_CONNECTIONSTATE_ESTABLISHED;
        if(subscribe) {
            enum MQTTErrors err = mqtt_subscribe(&bc->client, (const char*)topic->data, 0);
            if(err != MQTT_OK) {
                UA_String_clear(&tc->topic);
                UA_free(tc);
                return NULL;
            }
            UA_LOG_INFO(bc->mcm->cm.eventSource.eventLoop->logger,
                        UA_LOGCATEGORY_NETWORK, "MQTT %u\t| Created connection "
                        "subscribed on topic \"%s\"",
                        (unsigned)tc->topicConnectionId, (char*)topic->data);
        } else {
            UA_LOG_INFO(bc->mcm->cm.eventSource.eventLoop->logger,
                        UA_LOGCATEGORY_NETWORK, "MQTT %u\t| Created connection "
                        "publishing on topic \"%s\"",
                        (unsigned)tc->topicConnectionId, (char*)topic->data);
        }
    } else {
        tc->topicConnectionState = UA_CONNECTIONSTATE_OPENING;
    }

    /* Add to the linked list */
    LIST_INSERT_HEAD(&bc->topicConnections, tc, next);

    /* Signal the connection state. If the broker connection is not yet
     * established, then the state will be signaled again when the broker
     * connection opens fully. */
    connectionCallback(&mcm->cm, tc->topicConnectionId, application, &tc->context,
                       tc->topicConnectionState, &UA_KEYVALUEMAP_NULL,
                       UA_BYTESTRING_NULL);
    return tc;
}

static UA_StatusCode
MQTT_openConnection(UA_ConnectionManager *cm, const UA_KeyValueMap *params,
                    void *application, void *context,
                    UA_ConnectionManager_connectionCallback connectionCallback) {
    if(cm->eventSource.state != UA_EVENTSOURCESTATE_STARTED)
        return UA_STATUSCODE_BADINTERNALERROR;

    MQTTConnectionManager *mcm = (MQTTConnectionManager*)cm;

    /* Ensure the required parameters exist if required. And if they exist, they
     * have to be scalars of the correct type. */
    for(size_t i = 0; i < MQTT_PARAMETERSSIZE; i++) {
        const UA_Variant *val =
            UA_KeyValueMap_get(params, MQTTConnectionParameters[i].name);
        if((!val && MQTTConnectionParameters[i].required) ||
           (val && !UA_Variant_hasScalarType(val, MQTTConnectionParameters[i].type)))
        return UA_STATUSCODE_BADCONNECTIONREJECTED;
    }

    const UA_Boolean *validate = (const UA_Boolean*)
        UA_KeyValueMap_getScalar(params, UA_QUALIFIEDNAME(0, "validate"),
                                 &UA_TYPES[UA_TYPES_BOOLEAN]);
    if(validate && *validate)
        return (createBrokerConnection(mcm, params, true) == 0) ?
            UA_STATUSCODE_BADCONNECTIONREJECTED : UA_STATUSCODE_GOOD;

    /* Test whether an existing broker connection can be reused.
     * Otherwise create a new one. */
    MQTTBrokerConnection *bc = findIdenticalBrokerConnection(mcm, params);
    if(!bc && !(bc = createBrokerConnection(mcm, params, false)))
        return UA_STATUSCODE_BADNOTCONNECTED;

    /* Create the per-topic connection */
    MQTTTopicConnection *tc =
        createTopicConnection(mcm, bc, params, application,
                              context, connectionCallback);
    if(!tc) {
        /* If adding failed and the bc has no other topic connection -> close bc */
        if(LIST_EMPTY(&bc->topicConnections))
            shutdownBrokerConnection(bc);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
MQTT_sendWithConnection(UA_ConnectionManager *cm, uintptr_t connectionId,
                        const UA_KeyValueMap *params,
                        UA_ByteString *buf) {
    MQTTConnectionManager *mcm = (MQTTConnectionManager*)cm;
    MQTTTopicConnection *tc = findTopicConnection(mcm, connectionId);
    if(!tc) {
        UA_ByteString_clear(buf);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    MQTTBrokerConnection *bc = tc->brokerConnection;
    if(bc->tcpConnectionState != UA_CONNECTIONSTATE_ESTABLISHED) {
        UA_ByteString_clear(buf);
        return UA_STATUSCODE_BADCONNECTIONREJECTED;
    }

    UA_LOG_DEBUG(bc->mcm->cm.eventSource.eventLoop->logger,
                 UA_LOGCATEGORY_NETWORK, "MQTT %u\t| Publishing on topic \"%s\" "
                 "a message with %u bytes", (unsigned)tc->topicConnectionId,
                 (char*)tc->topic.data, (unsigned)buf->length);

    enum MQTTErrors res = mqtt_publish(&bc->client, (const char*)tc->topic.data,
                                       buf->data, buf->length, 0);
    if(UA_LIKELY(res == MQTT_OK))
        res = (enum MQTTErrors)__mqtt_send(&bc->client);
    UA_ByteString_clear(buf);
    return (res == MQTT_OK) ? UA_STATUSCODE_GOOD : UA_STATUSCODE_BADINTERNALERROR;
}

static UA_StatusCode
MQTT_shutdownConnection(UA_ConnectionManager *cm, uintptr_t connectionId) {
    MQTTConnectionManager *mcm = (MQTTConnectionManager*)cm;
    MQTTTopicConnection *tc = findTopicConnection(mcm, connectionId);
    if(!tc)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(tc->topicConnectionState == UA_CONNECTIONSTATE_CLOSING ||
       tc->topicConnectionState == UA_CONNECTIONSTATE_CLOSED)
        return UA_STATUSCODE_GOOD;

    /* TODO: Cancel the ongoing select/epoll if this was called from another
     * thread. */

    UA_EventLoop *el = tc->brokerConnection->mcm->cm.eventSource.eventLoop;
    UA_LOG_DEBUG(el->logger, UA_LOGCATEGORY_NETWORK,
                 "MQTT %u\t| Shutdown called", (unsigned)tc->topicConnectionId);

    tc->topicConnectionState = UA_CONNECTIONSTATE_CLOSING;

    /* Add a delayed callback to remove in the next iteration */
    UA_DelayedCallback *dc = &tc->dc;
    dc->callback = removeTopicConnectionDelayed;
    dc->application = NULL;
    dc->context = tc;
    el->addDelayedCallback(el, dc);

    return UA_STATUSCODE_GOOD;
}

static const char *mqttName = "mqtt";

UA_ConnectionManager *
UA_ConnectionManager_new_MQTT(const UA_String eventSourceName) {
    MQTTConnectionManager *cm = (MQTTConnectionManager*)
        UA_calloc(1, sizeof(MQTTConnectionManager));
    if(!cm)
        return NULL;

    cm->cm.eventSource.eventSourceType = UA_EVENTSOURCETYPE_CONNECTIONMANAGER;
    UA_String_copy(&eventSourceName, &cm->cm.eventSource.name);
    cm->cm.eventSource.start = (UA_StatusCode (*)(UA_EventSource *))MQTT_eventSourceStart;
    cm->cm.eventSource.stop = (void (*)(UA_EventSource *))MQTT_eventSourceStop;
    cm->cm.eventSource.free = (UA_StatusCode (*)(UA_EventSource *))MQTT_eventSourceDelete;
    cm->cm.protocol = UA_STRING((char*)(uintptr_t)mqttName);
    cm->cm.openConnection = MQTT_openConnection;
    cm->cm.allocNetworkBuffer = MQTT_allocNetworkBuffer;
    cm->cm.freeNetworkBuffer = MQTT_freeNetworkBuffer;
    cm->cm.sendWithConnection = MQTT_sendWithConnection;
    cm->cm.closeConnection = MQTT_shutdownConnection;
    return &cm->cm;
}

#endif /* UA_ENABLE_MQTT */

/**** amalgamated original file "/plugins/ua_config_json.c" ****/

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
 *
 *    Copyright 2023 (c) Fraunhofer IOSB (Author: Noel Graf)
 */

#ifdef UA_ENABLE_ENCRYPTION
#endif

#define MAX_TOKENS 256

typedef struct {
    const char *json;
    const cj5_token *tokens;
    cj5_result result;
    unsigned int tokensSize;
    size_t index;
    UA_Byte depth;
} ParsingCtx;

static UA_ByteString
getJsonPart(cj5_token tok, const char *json) {
    UA_ByteString bs;
    UA_ByteString_init(&bs);
    if(tok.type == CJ5_TOKEN_STRING) {
        bs.data = (UA_Byte*)(uintptr_t)(json + tok.start - 1);
        bs.length = (tok.end - tok.start) + 3;
        return bs;
    } else {
        bs.data = (UA_Byte*)(uintptr_t)(json + tok.start);
        bs.length = (tok.end - tok.start) + 1;
        return bs;
    }
}

/* Forward declarations*/
#define PARSE_JSON(TYPE) static UA_StatusCode                   \
    TYPE##_parseJson(ParsingCtx *ctx, void *configField, size_t *configFieldSize)

typedef UA_StatusCode
(*parseJsonSignature)(ParsingCtx *ctx, void *configField, size_t *configFieldSize);

#ifdef UA_ENABLE_ENCRYPTION
static UA_ByteString
loadCertificateFile(const char *const path);
#endif

/* The DataType "kind" is an internal type classification. It is used to
 * dispatch handling to the correct routines. */
#define UA_SERVERCONFIGFIELDKINDS 25
typedef enum {
    /* Basic Types */
    UA_SERVERCONFIGFIELD_INT64 = 0,
    UA_SERVERCONFIGFIELD_UINT16,
    UA_SERVERCONFIGFIELD_UINT32,
    UA_SERVERCONFIGFIELD_UINT64,
    UA_SERVERCONFIGFIELD_STRING,
    UA_SERVERCONFIGFIELD_LOCALIZEDTEXT,
    UA_SERVERCONFIGFIELD_DOUBLE,
    UA_SERVERCONFIGFIELD_BOOLEAN,
    UA_SERVERCONFIGFIELD_DURATION,
    UA_SERVERCONFIGFIELD_DURATIONRANGE,
    UA_SERVERCONFIGFIELD_UINT32RANGE,

    /* Advanced Types */
    UA_SERVERCONFIGFIELD_BUILDINFO,
    UA_SERVERCONFIGFIELD_APPLICATIONDESCRIPTION,
    UA_SERVERCONFIGFIELD_STRINGARRAY,
    UA_SERVERCONFIGFIELD_UINT32ARRAY,
    UA_SERVERCONFIGFIELD_DATETIME,
    UA_SERVERCONFIGFIELD_SUBSCRIPTIONCONFIGURATION,
    UA_SERVERCONFIGFIELD_TCPCONFIGURATION,
    UA_SERVERCONFIGFIELD_PUBSUBCONFIGURATION,
    UA_SERVERCONFIGFIELD_HISTORIZINGCONFIGURATION,
    UA_SERVERCONFIGFIELD_MDNSCONFIGURATION,
    UA_SERVERCONFIGFIELD_SECURITYPOLICIES,
    UA_SERVERCONFIGFIELD_SECURITYPKI,

    /* Enumerations */
    UA_SERVERCONFIGFIELD_APPLICATIONTYPE,
    UA_SERVERCONFIGFIELD_RULEHANDLING
} UA_ServerConfigFieldKind;

extern const parseJsonSignature parseJsonJumpTable[UA_SERVERCONFIGFIELDKINDS];

/*----------------------Basic Types------------------------*/
PARSE_JSON(Int64Field) {
    cj5_token tok = ctx->tokens[++ctx->index];
    UA_ByteString buf = getJsonPart(tok, ctx->json);
    UA_Int64 out;
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_INT64], NULL);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_Int64 *field = (UA_Int64*)configField;
    *field = out;
    return retval;
}
PARSE_JSON(UInt16Field) {
    cj5_token tok = ctx->tokens[++ctx->index];
    UA_ByteString buf = getJsonPart(tok, ctx->json);
    UA_UInt16 out;
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_UINT16], NULL);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_UInt16 *field = (UA_UInt16*)configField;
    *field = out;
    return retval;
}
PARSE_JSON(UInt32Field) {
    cj5_token tok = ctx->tokens[++ctx->index];
    UA_ByteString buf = getJsonPart(tok, ctx->json);
    UA_UInt32 out;
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_UINT32], NULL);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_UInt32 *field = (UA_UInt32*)configField;
    *field = out;
    return retval;
}
PARSE_JSON(UInt64Field) {
    cj5_token tok = ctx->tokens[++ctx->index];
    UA_ByteString buf = getJsonPart(tok, ctx->json);
    UA_UInt64 out;
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_UINT64], NULL);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_UInt64 *field = (UA_UInt64*)configField;
    *field = out;
    return retval;
}
PARSE_JSON(StringField) {
    cj5_token tok = ctx->tokens[++ctx->index];
    UA_ByteString buf = getJsonPart(tok, ctx->json);
    UA_String out;
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_STRING], NULL);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_String *field = (UA_String*)configField;
    if(field != NULL) {
        UA_String_clear(field);
        *field = out;
    }
    return retval;
}
PARSE_JSON(LocalizedTextField) {
    /*
     applicationName: {
        locale: "de-DE",
        text: "Test text"
    }
     */
    cj5_token tok = ctx->tokens[++ctx->index];
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    UA_String locale;
    UA_String text;
    for(size_t j = tok.size/2; j > 0; j--) {
        tok = ctx->tokens[++ctx->index];
        switch (tok.type) {
        case CJ5_TOKEN_STRING: {
            char *field = (char*)UA_malloc(tok.size + 1);
            unsigned int str_len = 0;
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field, &str_len);

            tok = ctx->tokens[++ctx->index];
            UA_ByteString buf = getJsonPart(tok, ctx->json);
            if(strcmp(field, "locale") == 0)
                retval |= UA_decodeJson(&buf, &locale, &UA_TYPES[UA_TYPES_STRING], NULL);
            else if(strcmp(field, "text") == 0)
                retval |= UA_decodeJson(&buf, &text, &UA_TYPES[UA_TYPES_STRING], NULL);
            else {
                UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Unknown field name.");
            }
            UA_free(field);
            break;
        }
        default:
            break;
        }
    }
    UA_LocalizedText out;
    out.locale = locale;
    out.text = text;
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_LocalizedText *field = (UA_LocalizedText*)configField;
    if(field != NULL) {
        UA_LocalizedText_clear(field);
        *field = out;
    }
    return retval;
}
PARSE_JSON(DoubleField) {
    cj5_token tok = ctx->tokens[++ctx->index];
    UA_ByteString buf = getJsonPart(tok, ctx->json);
    UA_Double out;
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_DOUBLE], NULL);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_Double *field = (UA_Double *)configField;
    *field = out;
    return retval;
}
PARSE_JSON(BooleanField) {
    cj5_token tok = ctx->tokens[++ctx->index];
    UA_ByteString buf = getJsonPart(tok, ctx->json);
    UA_Boolean out;
    if(tok.type != CJ5_TOKEN_BOOL) {
        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Value of type bool expected.");
        return UA_STATUSCODE_BADTYPEMISMATCH;
    }
    UA_String val = UA_STRING("true");
    if(UA_String_equal(&val, &buf)) {
        out = true;
    }else {
        out = false;
    }
    /* set server config field */
    UA_Boolean *field = (UA_Boolean *)configField;
    *field = out;
    return UA_STATUSCODE_GOOD;
}
PARSE_JSON(DurationField) {
    UA_Double double_value;
    UA_StatusCode retval = DoubleField_parseJson(ctx, &double_value, NULL);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_Duration *field = (UA_Duration*)configField;
    *field = (UA_Duration)double_value;
    return retval;
}
PARSE_JSON(DurationRangeField) {
    UA_DurationRange *field = (UA_DurationRange*)configField;
    cj5_token tok = ctx->tokens[++ctx->index];
    for(size_t j = tok.size/2; j > 0; j--) {
        tok = ctx->tokens[++ctx->index];
        switch (tok.type) {
        case CJ5_TOKEN_STRING: {
            char *field_str = (char*)UA_malloc(tok.size + 1);
            unsigned int str_len = 0;
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
            if(strcmp(field_str, "min") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_DURATION](ctx, &field->min, NULL);
            else if(strcmp(field_str, "max") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_DURATION](ctx, &field->max, NULL);
            else {
                UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Unknown field name.");
            }
            UA_free(field_str);
            break;
        }
        default:
            break;
        }
    }
    return UA_STATUSCODE_GOOD;
}
PARSE_JSON(UInt32RangeField) {
    UA_UInt32Range *field = (UA_UInt32Range*)configField;
    cj5_token tok = ctx->tokens[++ctx->index];
    for(size_t j = tok.size/2; j > 0; j--) {
        tok = ctx->tokens[++ctx->index];
        switch (tok.type) {
        case CJ5_TOKEN_STRING: {
            char *field_str = (char*)UA_malloc(tok.size + 1);
            unsigned int str_len = 0;
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
            if(strcmp(field_str, "min") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &field->min, NULL);
            else if(strcmp(field_str, "max") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &field->max, NULL);
            else {
                UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Unknown field name.");
            }
            UA_free(field_str);
            break;
        }
        default:
            break;
        }
    }
    return UA_STATUSCODE_GOOD;
}

/*----------------------Advanced Types------------------------*/
PARSE_JSON(BuildInfo) {
    UA_BuildInfo *field = (UA_BuildInfo*)configField;
    cj5_token tok = ctx->tokens[++ctx->index];
    for(size_t j = tok.size/2; j > 0; j--) {
        tok = ctx->tokens[++ctx->index];
        switch (tok.type) {
        case CJ5_TOKEN_STRING: {
            char *field_str = (char*)UA_malloc(tok.size + 1);
            unsigned int str_len = 0;
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
            if(strcmp(field_str, "productUri") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->productUri, NULL);
            else if(strcmp(field_str, "manufacturerName") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->manufacturerName, NULL);
            else if(strcmp(field_str, "productName") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->productName, NULL);
            else if(strcmp(field_str, "softwareVersion") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->softwareVersion, NULL);
            else if(strcmp(field_str, "buildNumber") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->buildNumber, NULL);
            else if(strcmp(field_str, "buildDate") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_DATETIME](ctx, &field->buildDate, NULL);
            else {
                UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Unknown field name.");
            }
            UA_free(field_str);
            break;
        }
        default:
            break;
        }
    }
    return UA_STATUSCODE_GOOD;
}
PARSE_JSON(ApplicationDescriptionField) {
    UA_ApplicationDescription *field = (UA_ApplicationDescription*)configField;
    cj5_token tok = ctx->tokens[++ctx->index];
    for(size_t j = tok.size/2; j > 0; j--) {
        tok = ctx->tokens[++ctx->index];
        switch (tok.type) {
        case CJ5_TOKEN_STRING: {
            char *field_str = (char*)UA_malloc(tok.size + 1);
            unsigned int str_len = 0;
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
            if(strcmp(field_str, "applicationUri") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->applicationUri, NULL);
            else if(strcmp(field_str, "productUri") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->productUri, NULL);
            else if(strcmp(field_str, "applicationName") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_LOCALIZEDTEXT](ctx, &field->applicationName, NULL);
            else if(strcmp(field_str, "applicationType") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_APPLICATIONTYPE](ctx, &field->applicationType, NULL);
            else if(strcmp(field_str, "gatewayServerUri") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->gatewayServerUri, NULL);
            else if(strcmp(field_str, "discoveryProfileUri") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &field->discoveryProfileUri, NULL);
            else if(strcmp(field_str, "discoveryUrls") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRINGARRAY](ctx, &field->discoveryUrls, &field->discoveryUrlsSize);
            else {
                UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Unknown field name.");
            }
            UA_free(field_str);
            break;
        }
        default:
            break;
        }
    }
    return UA_STATUSCODE_GOOD;
}
PARSE_JSON(StringArrayField) {
    if(configFieldSize == NULL) {
        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Pointer to the array size is not set.");
        return UA_STATUSCODE_BADARGUMENTSMISSING;
    }
    cj5_token tok = ctx->tokens[++ctx->index];
    UA_String *stringArray = (UA_String*)UA_malloc(sizeof(UA_String) * tok.size);
    size_t stringArraySize = 0;
    for(size_t j = tok.size; j > 0; j--) {
        UA_String out = {.length = 0, .data = NULL};;
        parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &out, NULL);
        UA_String_copy(&out, &stringArray[stringArraySize++]);
        UA_String_clear(&out);
    }
    /* Add to the config */
    UA_String **field = (UA_String**)configField;
    if(*configFieldSize > 0) {
        UA_Array_delete(*field, *configFieldSize,
                        &UA_TYPES[UA_TYPES_STRING]);
        *field = NULL;
        *configFieldSize = 0;
    }
    UA_StatusCode retval =
        UA_Array_copy(stringArray, stringArraySize,
                      (void**)field, &UA_TYPES[UA_TYPES_STRING]);
    *configFieldSize = stringArraySize;

    /* Clean up */
    UA_Array_delete(stringArray, stringArraySize, &UA_TYPES[UA_TYPES_STRING]);
    return retval;
}
PARSE_JSON(UInt32ArrayField) {
    if(configFieldSize == NULL) {
        UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Pointer to the array size is not set.");
        return UA_STATUSCODE_BADARGUMENTSMISSING;
    }
    cj5_token tok = ctx->tokens[++ctx->index];
    UA_UInt32 *numberArray = (UA_UInt32*)UA_malloc(sizeof(UA_UInt32) * tok.size);;
    size_t numberArraySize = 0;
    for(size_t j = tok.size; j > 0; j--) {
        UA_UInt32 value;
        UA_StatusCode retval = UInt32Field_parseJson(ctx, &value, NULL);
        if(retval != UA_STATUSCODE_GOOD)
            continue;
        numberArray[numberArraySize++] = value;
    }
    /* Add to the config */
    UA_UInt32 **field = (UA_UInt32**)configField;
    if(*configFieldSize > 0) {
        UA_Array_delete(*field, *configFieldSize,
                        &UA_TYPES[UA_TYPES_UINT32]);
        *field = NULL;
        *configFieldSize = 0;
    }
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(numberArraySize > 0) {
        retval = UA_Array_copy(numberArray, numberArraySize,
                          (void **)field, &UA_TYPES[UA_TYPES_UINT32]);
        *configFieldSize = numberArraySize;
    }
    /* Clean up */
    UA_Array_delete(numberArray, numberArraySize, &UA_TYPES[UA_TYPES_UINT32]);
    return retval;
}
PARSE_JSON(DateTimeField) {
    cj5_token tok = ctx->tokens[++ctx->index];
    UA_ByteString buf = getJsonPart(tok, ctx->json);
    UA_DateTime out;
    UA_DateTime_init(&out);
    UA_StatusCode retval = UA_decodeJson(&buf, &out, &UA_TYPES[UA_TYPES_DATETIME], NULL);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_DateTime *field = (UA_DateTime*)configField;
    *field = out;
    return retval;
}

PARSE_JSON(MdnsConfigurationField) {
#ifdef UA_ENABLE_DISCOVERY_MULTICAST
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
    cj5_token tok = ctx->tokens[++ctx->index];
    for(size_t j = tok.size/2; j > 0; j--) {
        tok = ctx->tokens[++ctx->index];
        switch (tok.type) {
        case CJ5_TOKEN_STRING: {
            char *field_str = (char*)UA_malloc(tok.size + 1);
            unsigned int str_len = 0;
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
            if(strcmp(field_str, "mdnsServerName") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &config->mdnsConfig.mdnsServerName, NULL);
            else if(strcmp(field_str, "serverCapabilities") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRINGARRAY](ctx, &config->mdnsConfig.serverCapabilities, &config->mdnsConfig.serverCapabilitiesSize);
            else if(strcmp(field_str, "mdnsInterfaceIP") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &config->mdnsInterfaceIP, NULL);
            else if(strcmp(field_str, "mdnsIpAddressList") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32ARRAY](ctx, &config->mdnsIpAddressList, &config->mdnsIpAddressListSize);
            else {
                UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Unknown field name.");
            }
            UA_free(field_str);
            break;
        }
        default:
        break;
        }
    }
#endif
    return UA_STATUSCODE_GOOD;
}

PARSE_JSON(SubscriptionConfigurationField) {
#ifdef UA_ENABLE_SUBSCRIPTIONS
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
    cj5_token tok = ctx->tokens[++ctx->index];
    for(size_t j = tok.size/2; j > 0; j--) {
        tok = ctx->tokens[++ctx->index];
        switch (tok.type) {
        case CJ5_TOKEN_STRING: {
            char *field_str = (char*)UA_malloc(tok.size + 1);
            unsigned int str_len = 0;
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
            if(strcmp(field_str, "maxSubscriptions") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxSubscriptions, NULL);
            else if(strcmp(field_str, "maxSubscriptionsPerSession") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxSubscriptionsPerSession, NULL);
            else if(strcmp(field_str, "publishingIntervalLimits") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_DURATIONRANGE](ctx, &config->publishingIntervalLimits, NULL);
            else if(strcmp(field_str, "lifeTimeCountLimits") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32RANGE](ctx, &config->lifeTimeCountLimits, NULL);
            else if(strcmp(field_str, "keepAliveCountLimits") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32RANGE](ctx, &config->keepAliveCountLimits, NULL);
            else if(strcmp(field_str, "maxNotificationsPerPublish") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxNotificationsPerPublish, NULL);
            else if(strcmp(field_str, "enableRetransmissionQueue") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->enableRetransmissionQueue, NULL);
            else if(strcmp(field_str, "maxRetransmissionQueueSize") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxRetransmissionQueueSize, NULL);
# ifdef UA_ENABLE_SUBSCRIPTIONS_EVENTS
            else if(strcmp(field_str, "maxEventsPerNode") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxEventsPerNode, NULL);
# endif
            else if(strcmp(field_str, "maxMonitoredItems") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxMonitoredItems, NULL);
            else if(strcmp(field_str, "maxMonitoredItemsPerSubscription") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxMonitoredItemsPerSubscription, NULL);
            else if(strcmp(field_str, "samplingIntervalLimits") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_DURATIONRANGE](ctx, &config->samplingIntervalLimits, NULL);
            else if(strcmp(field_str, "queueSizeLimits") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32RANGE](ctx, &config->queueSizeLimits, NULL);
            else if(strcmp(field_str, "maxPublishReqPerSession") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxPublishReqPerSession, NULL);
            else {
                UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Unknown field name.");
            }
            UA_free(field_str);
            break;
        }
        default:
            break;
        }
    }
#endif
    return UA_STATUSCODE_GOOD;
}

PARSE_JSON(TcpConfigurationField) {
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
    cj5_token tok = ctx->tokens[++ctx->index];
    for(size_t j = tok.size/2; j > 0; j--) {
        tok = ctx->tokens[++ctx->index];
        switch (tok.type) {
        case CJ5_TOKEN_STRING: {
            char *field_str = (char*)UA_malloc(tok.size + 1);
            unsigned int str_len = 0;
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
            if(strcmp(field_str, "tcpBufSize") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->tcpBufSize, NULL);
            else if(strcmp(field_str, "tcpMaxMsgSize") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->tcpMaxMsgSize, NULL);
            else if(strcmp(field_str, "tcpMaxChunks") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->tcpMaxChunks, NULL);
            else {
                UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Unknown field name.");
            }
            UA_free(field_str);
            break;
        }
        default:
            break;
        }
    }
    return UA_STATUSCODE_GOOD;
}

PARSE_JSON(PubsubConfigurationField) {
#ifdef UA_ENABLE_PUBSUB
    UA_PubSubConfiguration *field = (UA_PubSubConfiguration*)configField;
    cj5_token tok = ctx->tokens[++ctx->index];
    for(size_t j = tok.size/2; j > 0; j--) {
        tok = ctx->tokens[++ctx->index];
        switch (tok.type) {
        case CJ5_TOKEN_STRING: {
            char *field_str = (char*)UA_malloc(tok.size + 1);
            unsigned int str_len = 0;
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
            if(strcmp(field_str, "enableDeltaFrames") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &field->enableDeltaFrames, NULL);
#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
            else if(strcmp(field_str, "enableInformationModelMethods") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &field->enableInformationModelMethods, NULL);
#endif
            else {
                UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Unknown field name.");
            }
            UA_free(field_str);
            break;
        }
        default:
            break;
        }
    }
#endif
    return UA_STATUSCODE_GOOD;
}

PARSE_JSON(HistorizingConfigurationField) {
#ifdef UA_ENABLE_HISTORIZING
    UA_ServerConfig *config = (UA_ServerConfig*)configField;
    cj5_token tok = ctx->tokens[++ctx->index];
    for(size_t j = tok.size/2; j > 0; j--) {
        tok = ctx->tokens[++ctx->index];
        switch (tok.type) {
        case CJ5_TOKEN_STRING: {
            char *field_str = (char*)UA_malloc(tok.size + 1);
            unsigned int str_len = 0;
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
            if(strcmp(field_str, "accessHistoryDataCapability") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->accessHistoryDataCapability, NULL);
            else if(strcmp(field_str, "maxReturnDataValues") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxReturnDataValues, NULL);
            else if(strcmp(field_str, "accessHistoryEventsCapability") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->accessHistoryEventsCapability, NULL);
            else if(strcmp(field_str, "maxReturnEventValues") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](ctx, &config->maxReturnEventValues, NULL);
            else if(strcmp(field_str, "insertDataCapability") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->insertDataCapability, NULL);
            else if(strcmp(field_str, "insertEventCapability") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->insertEventCapability, NULL);
            else if(strcmp(field_str, "insertAnnotationsCapability") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->insertAnnotationsCapability, NULL);
            else if(strcmp(field_str, "replaceDataCapability") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->replaceDataCapability, NULL);
            else if(strcmp(field_str, "replaceEventCapability") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->replaceEventCapability, NULL);
            else if(strcmp(field_str, "updateDataCapability") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->updateDataCapability, NULL);
            else if(strcmp(field_str, "updateEventCapability") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->updateEventCapability, NULL);
            else if(strcmp(field_str, "deleteRawCapability") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->deleteRawCapability, NULL);
            else if(strcmp(field_str, "deleteEventCapability") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->deleteEventCapability, NULL);
            else if(strcmp(field_str, "deleteAtTimeDataCapability") == 0)
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](ctx, &config->deleteAtTimeDataCapability, NULL);
            else {
                UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Unknown field name.");
            }
            UA_free(field_str);
            break;
        }
        default:
            break;
        }
    }
#endif
    return UA_STATUSCODE_GOOD;
}

PARSE_JSON(SecurityPolciesField) {
#ifdef UA_ENABLE_ENCRYPTION
    UA_ServerConfig *config = (UA_ServerConfig*)configField;

    UA_String noneuri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#None");
    UA_String basic128Rsa15uri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15");
    UA_String basic256uri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic256");
    UA_String basic256Sha256uri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256");
    UA_String aes128sha256rsaoaepuri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Aes128_Sha256_RsaOaep");

    cj5_token tok = ctx->tokens[++ctx->index];
    for(size_t j = tok.size; j > 0; j--) {

        UA_String policy = {.length = 0, .data = NULL};
        UA_ByteString certificate = {.length = 0, .data = NULL};
        UA_ByteString privateKey = {.length = 0, .data = NULL};

        tok = ctx->tokens[++ctx->index];
        for(size_t i = tok.size / 2; i > 0; i--) {
            tok = ctx->tokens[++ctx->index];
            switch(tok.type) {
            case CJ5_TOKEN_STRING: {
                char *field_str = (char *)UA_malloc(tok.size + 1);
                unsigned int str_len = 0;
                cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
                if(strcmp(field_str, "certificate") == 0) {
                    UA_String out = {.length = 0, .data = NULL};
                    parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &out, NULL);

                    if(out.length > 0) {
                        char *certfile = (char *)UA_malloc(out.length + 1);
                        memcpy(certfile, out.data, out.length);
                        certfile[out.length] = '\0';
                        certificate = loadCertificateFile(certfile);
                        UA_String_clear(&out);
                        UA_free(certfile);
                    }
                } else if(strcmp(field_str, "privateKey") == 0) {
                    UA_String out = {.length = 0, .data = NULL};
                    parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &out, NULL);

                    if(out.length > 0) {
                        char *keyfile = (char *)UA_malloc(out.length + 1);
                        memcpy(keyfile, out.data, out.length);
                        keyfile[out.length] = '\0';
                        privateKey = loadCertificateFile(keyfile);
                        UA_String_clear(&out);
                        UA_free(keyfile);
                    }
                } else if(strcmp(field_str, "policy") == 0) {
                    parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &policy, NULL);
                } else {
                    UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Unknown field name.");
                }
                UA_free(field_str);
                break;
            }
            default:
                break;
            }
        }

        if(certificate.length == 0 || privateKey.length == 0) {
            UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
                           "Certificate and PrivateKey must be set for every policy.");
            if(policy.length > 0)
                UA_String_clear(&policy);
            if(certificate.length > 0)
                UA_ByteString_clear(&certificate);
            if(privateKey.length > 0)
                UA_ByteString_clear(&privateKey);
            return UA_STATUSCODE_BADINTERNALERROR;
        }
        UA_StatusCode retval = UA_STATUSCODE_GOOD;
        if(UA_String_equal(&policy, &noneuri)) {
            /* Nothing to do! */
        } else if(UA_String_equal(&policy, &basic128Rsa15uri)) {
            retval = UA_ServerConfig_addSecurityPolicyBasic128Rsa15(config, &certificate, &privateKey);
            if(retval != UA_STATUSCODE_GOOD) {
                UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
                               "Could not add SecurityPolicy#Basic128Rsa15 with error code %s",
                               UA_StatusCode_name(retval));
            }
        } else if(UA_String_equal(&policy, &basic256uri)) {
            retval = UA_ServerConfig_addSecurityPolicyBasic256(config, &certificate, &privateKey);
            if(retval != UA_STATUSCODE_GOOD) {
                UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
                               "Could not add SecurityPolicy#Basic256 with error code %s",
                               UA_StatusCode_name(retval));
            }
        } else if(UA_String_equal(&policy, &basic256Sha256uri)) {
            retval = UA_ServerConfig_addSecurityPolicyBasic256Sha256(config, &certificate, &privateKey);
            if(retval != UA_STATUSCODE_GOOD) {
                UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
                               "Could not add SecurityPolicy#Basic256Sha256 with error code %s",
                               UA_StatusCode_name(retval));
            }
        } else if(UA_String_equal(&policy, &aes128sha256rsaoaepuri)) {
            retval = UA_ServerConfig_addSecurityPolicyAes128Sha256RsaOaep(config, &certificate, &privateKey);
            if(retval != UA_STATUSCODE_GOOD) {
                UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND,
                               "Could not add SecurityPolicy#Aes128Sha256RsaOaep with error code %s",
                               UA_StatusCode_name(retval));
            }
        } else {
            UA_LOG_WARNING(config->logging, UA_LOGCATEGORY_USERLAND, "Unknown Security Policy.");
        }

        /* Add all Endpoints */
        UA_ServerConfig_addAllEndpoints(config);

        if(policy.length > 0)
            UA_String_clear(&policy);
        if(certificate.length > 0)
            UA_ByteString_clear(&certificate);
        if(privateKey.length > 0)
            UA_ByteString_clear(&privateKey);
    }
#endif
    return UA_STATUSCODE_GOOD;
}

PARSE_JSON(SecurityPkiField) {
#ifdef UA_ENABLE_ENCRYPTION
    UA_CertificateGroup *field = (UA_CertificateGroup*)configField;
    UA_String trustListFolder = {.length = 0, .data = NULL};
    UA_String issuerListFolder = {.length = 0, .data = NULL};
    UA_String revocationListFolder = {.length = 0, .data = NULL};

    cj5_token tok = ctx->tokens[++ctx->index];
    for(size_t i = tok.size/2; i > 0; i--) {
        tok = ctx->tokens[++ctx->index];
        switch(tok.type) {
        case CJ5_TOKEN_STRING: {
            char *field_str = (char*)UA_malloc(tok.size + 1);
            unsigned int str_len = 0;
            cj5_get_str(&ctx->result, (unsigned int)ctx->index, field_str, &str_len);
            if(strcmp(field_str, "trustListFolder") == 0) {
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &trustListFolder, NULL);
            } else if(strcmp(field_str, "issuerListFolder") == 0) {
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &issuerListFolder, NULL);
            } else if(strcmp(field_str, "revocationListFolder") == 0) {
                parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRING](ctx, &revocationListFolder, NULL);
            } else {
                UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Unknown field name.");
            }
            UA_free(field_str);
            break;
        }
        default:
            break;
        }
    }
#ifndef __linux__
    /* Currently not supported! */
    (void)field;
    return UA_STATUSCODE_GOOD;
#else
    /* set server config field */
    char *sTrustListFolder = NULL;
    char *sIssuerListFolder = NULL;
    char *sRevocationListFolder = NULL;
    if(trustListFolder.length > 0) {
        sTrustListFolder = (char*)UA_malloc(trustListFolder.length+1);
        memcpy(sTrustListFolder, trustListFolder.data, trustListFolder.length);
        sTrustListFolder[trustListFolder.length] = '\0';
    }
    if(issuerListFolder.length > 0) {
        sIssuerListFolder = (char*)UA_malloc(issuerListFolder.length+1);
        memcpy(sIssuerListFolder, issuerListFolder.data, issuerListFolder.length);
        sIssuerListFolder[issuerListFolder.length] = '\0';
    }
    if(revocationListFolder.length > 0) {
        sRevocationListFolder = (char*)UA_malloc(revocationListFolder.length+1);
        memcpy(sRevocationListFolder, revocationListFolder.data, revocationListFolder.length);
        sRevocationListFolder[revocationListFolder.length] = '\0';
    }
    if(field && field->clear)
        field->clear(field);
#ifdef UA_ENABLE_CERT_REJECTED_DIR
    UA_StatusCode retval = UA_CertificateVerification_CertFolders(field, sTrustListFolder,
                                                                  sIssuerListFolder, sRevocationListFolder, NULL);
#else
    UA_StatusCode retval = UA_CertificateVerification_CertFolders(field, sTrustListFolder,
                                                                  sIssuerListFolder, sRevocationListFolder);
#endif
    /* Clean up */
    if(sTrustListFolder)
        UA_free(sTrustListFolder);
    if(sIssuerListFolder)
        UA_free(sIssuerListFolder);
    if(sRevocationListFolder)
        UA_free(sRevocationListFolder);
    UA_String_clear(&trustListFolder);
    UA_String_clear(&issuerListFolder);
    UA_String_clear(&revocationListFolder);

    return retval;
#endif
#endif
    return UA_STATUSCODE_GOOD;
}

/*----------------------Enumerations------------------------*/
PARSE_JSON(ApplicationTypeField) {
    UA_UInt32 enum_value;
    UA_StatusCode retval = UInt32Field_parseJson(ctx, &enum_value, NULL);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_ApplicationType *field = (UA_ApplicationType*)configField;
    *field = (UA_ApplicationType)enum_value;
    return retval;
}
PARSE_JSON(RuleHandlingField) {
    UA_UInt32 enum_value;
    UA_StatusCode retval = UInt32Field_parseJson(ctx, &enum_value, NULL);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    UA_RuleHandling *field = (UA_RuleHandling*)configField;
    *field = (UA_RuleHandling)enum_value;
    return retval;
}

const parseJsonSignature parseJsonJumpTable[UA_SERVERCONFIGFIELDKINDS] = {
    /* Basic Types */
    (parseJsonSignature)Int64Field_parseJson,
    (parseJsonSignature)UInt16Field_parseJson,
    (parseJsonSignature)UInt32Field_parseJson,
    (parseJsonSignature)UInt64Field_parseJson,
    (parseJsonSignature)StringField_parseJson,
    (parseJsonSignature)LocalizedTextField_parseJson,
    (parseJsonSignature)DoubleField_parseJson,
    (parseJsonSignature)BooleanField_parseJson,
    (parseJsonSignature)DurationField_parseJson,
    (parseJsonSignature)DurationRangeField_parseJson,
    (parseJsonSignature)UInt32RangeField_parseJson,

    /* Advanced Types */
    (parseJsonSignature)BuildInfo_parseJson,
    (parseJsonSignature)ApplicationDescriptionField_parseJson,
    (parseJsonSignature)StringArrayField_parseJson,
    (parseJsonSignature)UInt32ArrayField_parseJson,
    (parseJsonSignature)DateTimeField_parseJson,
    (parseJsonSignature)SubscriptionConfigurationField_parseJson,
    (parseJsonSignature)TcpConfigurationField_parseJson,
    (parseJsonSignature)PubsubConfigurationField_parseJson,
    (parseJsonSignature)HistorizingConfigurationField_parseJson,
    (parseJsonSignature)MdnsConfigurationField_parseJson,
    (parseJsonSignature)SecurityPolciesField_parseJson,
    (parseJsonSignature)SecurityPkiField_parseJson,

    /* Enumerations */
    (parseJsonSignature)ApplicationTypeField_parseJson,
    (parseJsonSignature)RuleHandlingField_parseJson,
};

static UA_StatusCode
parseJSONConfig(UA_ServerConfig *config, UA_ByteString json_config) {
    // Parsing json config
    const char *json = (const char*)json_config.data;
    cj5_token tokens[MAX_TOKENS];
    cj5_result r = cj5_parse(json, (unsigned int)json_config.length, tokens, MAX_TOKENS, NULL);

    ParsingCtx ctx;
    ctx.json = json;
    ctx.result = r;
    ctx.tokens = r.tokens;
    ctx.tokensSize = r.num_tokens;
    ctx.index = 1; // The first token is ignored because it is known and not needed.

    size_t serverConfigSize = 0;
    if(ctx.tokens)
        serverConfigSize = (ctx.tokens[ctx.index-1].size/2);
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    for (size_t j = serverConfigSize; j > 0; j--) {
        cj5_token tok = ctx.tokens[ctx.index];
        switch (tok.type) {
            case CJ5_TOKEN_STRING: {
                char *field = (char*)UA_malloc(tok.size + 1);
                unsigned int str_len = 0;
                cj5_get_str(&ctx.result, (unsigned int)ctx.index, field, &str_len);
                if(strcmp(field, "buildInfo") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BUILDINFO](&ctx, &config->buildInfo, NULL);
                else if(strcmp(field, "applicationDescription") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_APPLICATIONDESCRIPTION](&ctx, &config->applicationDescription, NULL);
                else if(strcmp(field, "shutdownDelay") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_DOUBLE](&ctx, &config->shutdownDelay, NULL);
                else if(strcmp(field, "verifyRequestTimestamp") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_RULEHANDLING](&ctx, &config->verifyRequestTimestamp, NULL);
                else if(strcmp(field, "allowEmptyVariables") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_RULEHANDLING](&ctx, &config->allowEmptyVariables, NULL);
                else if(strcmp(field, "serverUrls") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_STRINGARRAY](&ctx, &config->serverUrls, &config->serverUrlsSize);
                else if(strcmp(field, "tcpEnabled") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->tcpEnabled, NULL);
                else if(strcmp(field, "tcp") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_TCPCONFIGURATION](&ctx, config, NULL);
                else if(strcmp(field, "securityPolicyNoneDiscoveryOnly") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->securityPolicyNoneDiscoveryOnly, NULL);
                else if(strcmp(field, "modellingRulesOnInstances") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->modellingRulesOnInstances, NULL);
                else if(strcmp(field, "maxSecureChannels") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT16](&ctx, &config->maxSecureChannels, NULL);
                else if(strcmp(field, "maxSecurityTokenLifetime") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxSecurityTokenLifetime, NULL);
                else if(strcmp(field, "maxSessions") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT16](&ctx, &config->maxSessions, NULL);
                else if(strcmp(field, "maxSessionTimeout") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_DOUBLE](&ctx, &config->maxSessionTimeout, NULL);
                else if(strcmp(field, "maxNodesPerRead") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerRead, NULL);
                else if(strcmp(field, "maxNodesPerWrite") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerWrite, NULL);
                else if(strcmp(field, "maxNodesPerMethodCall") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerMethodCall, NULL);
                else if(strcmp(field, "maxNodesPerBrowse") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerBrowse, NULL);
                else if(strcmp(field, "maxNodesPerRegisterNodes") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerRegisterNodes, NULL);
                else if(strcmp(field, "maxNodesPerTranslateBrowsePathsToNodeIds") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerTranslateBrowsePathsToNodeIds, NULL);
                else if(strcmp(field, "maxNodesPerNodeManagement") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxNodesPerNodeManagement, NULL);
                else if(strcmp(field, "maxMonitoredItemsPerCall") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxMonitoredItemsPerCall, NULL);
                else if(strcmp(field, "maxReferencesPerNode") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->maxReferencesPerNode, NULL);
                else if(strcmp(field, "reverseReconnectInterval") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->reverseReconnectInterval, NULL);

#if UA_MULTITHREADING >= 100
                else if(strcmp(field, "asyncOperationTimeout") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_DOUBLE](&ctx, &config->asyncOperationTimeout, NULL);
                else if(strcmp(field, "maxAsyncOperationQueueSize") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT64](&ctx, &config->maxAsyncOperationQueueSize, NULL);
#endif

#ifdef UA_ENABLE_DISCOVERY
                else if(strcmp(field, "discoveryCleanupTimeout") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32](&ctx, &config->discoveryCleanupTimeout, NULL);
#ifdef UA_ENABLE_DISCOVERY_MULTICAST
                else if(strcmp(field, "mdnsEnabled") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->mdnsEnabled, NULL);
                else if(strcmp(field, "mdns") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_MDNSCONFIGURATION](&ctx, config, NULL);
#if !defined(UA_HAS_GETIFADDR)
                else if(strcmp(field, "mdnsIpAddressList") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_UINT32ARRAY](&ctx, &config->mdnsIpAddressList, &config->mdnsIpAddressListSize);
#endif
#endif
#endif

#ifdef UA_ENABLE_SUBSCRIPTIONS
                else if(strcmp(field, "subscriptionsEnabled") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->subscriptionsEnabled, NULL);
                else if(strcmp(field, "subscriptions") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_SUBSCRIPTIONCONFIGURATION](&ctx, config, NULL);
# endif

#ifdef UA_ENABLE_HISTORIZING
                else if(strcmp(field, "historizingEnabled") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->historizingEnabled, NULL);
                else if(strcmp(field, "historizing") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_HISTORIZINGCONFIGURATION](&ctx, config, NULL);
#endif

#ifdef UA_ENABLE_PUBSUB
                else if(strcmp(field, "pubsubEnabled") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_BOOLEAN](&ctx, &config->pubsubEnabled, NULL);
                else if(strcmp(field, "pubsub") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_PUBSUBCONFIGURATION](&ctx, config, NULL);
#endif
#ifdef UA_ENABLE_ENCRYPTION
                else if(strcmp(field, "securityPolicies") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_SECURITYPOLICIES](&ctx, config, NULL);
                else if(strcmp(field, "secureChannelPKI") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_SECURITYPKI](&ctx, &config->secureChannelPKI, NULL);
                else if(strcmp(field, "sessionPKI") == 0)
                    retval = parseJsonJumpTable[UA_SERVERCONFIGFIELD_SECURITYPKI](&ctx, &config->sessionPKI, NULL);
#endif
                else {
                    UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "Field name '%s' unknown or misspelled. Maybe the feature is not enabled either.", field);
                }
                UA_free(field);
                if(retval != UA_STATUSCODE_GOOD) {
                    UA_LOG_ERROR(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "An error occurred while parsing the configuration file.");
                    return retval;
                }
                break;
            }
            default:
                break;
        }
        ctx.index += 1;
    }
    return retval;
}

UA_Server *
UA_Server_newFromFile(const UA_ByteString json_config) {
    UA_ServerConfig config;
    memset(&config, 0, sizeof(UA_ServerConfig));
    UA_StatusCode res = UA_ServerConfig_setDefault(&config);
    res |= parseJSONConfig(&config, json_config);
    if(res != UA_STATUSCODE_GOOD)
        return NULL;
    return UA_Server_newWithConfig(&config);
}

UA_StatusCode
UA_ServerConfig_updateFromFile(UA_ServerConfig *config, const UA_ByteString json_config) {
    UA_StatusCode res = parseJSONConfig(config, json_config);
    return res;
}

#ifdef UA_ENABLE_ENCRYPTION
static UA_ByteString
loadCertificateFile(const char *const path) {
    UA_ByteString fileContents = UA_STRING_NULL;

    /* Open the file */
    FILE *fp = fopen(path, "rb");
    if(!fp) {
        errno = 0; /* We read errno also from the tcp layer... */
        return fileContents;
    }

    /* Get the file length, allocate the data and read */
    fseek(fp, 0, SEEK_END);
    fileContents.length = (size_t)ftell(fp);
    fileContents.data = (UA_Byte *)UA_malloc(fileContents.length * sizeof(UA_Byte));
    if(fileContents.data) {
        fseek(fp, 0, SEEK_SET);
        size_t read = fread(fileContents.data, sizeof(UA_Byte), fileContents.length, fp);
        if(read != fileContents.length)
            UA_ByteString_clear(&fileContents);
    } else {
        fileContents.length = 0;
    }
    fclose(fp);

    return fileContents;
}
#endif

/**** amalgamated original file "/plugins/historydata/ua_history_data_backend_memory.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2018 (c) basysKom GmbH <opensource@basyskom.com> (Author: Peter Rustler)
 *    Copyright 2021 (c) luibass92 <luibass92@live.it> (Author: Luigi Bassetta)
 */


#include <limits.h>
#include <string.h>

typedef struct {
    UA_DateTime timestamp;
    UA_DataValue value;
} UA_DataValueMemoryStoreItem;

static void
UA_DataValueMemoryStoreItem_clear(UA_DataValueMemoryStoreItem* item) {
    UA_DateTime_clear(&item->timestamp);
    UA_DataValue_clear(&item->value);
}

typedef struct {
    UA_NodeId nodeId;
    UA_DataValueMemoryStoreItem **dataStore;
    size_t storeEnd;
    size_t storeSize;
    /* New field useful for circular buffer management */
    size_t lastInserted;
} UA_NodeIdStoreContextItem_backend_memory;

static void
UA_NodeIdStoreContextItem_clear(UA_NodeIdStoreContextItem_backend_memory* item) {
    UA_NodeId_clear(&item->nodeId);
    for (size_t i = 0; i < item->storeEnd; ++i) {
        UA_DataValueMemoryStoreItem_clear(item->dataStore[i]);
        UA_free(item->dataStore[i]);
    }
    UA_free(item->dataStore);
}

typedef struct {
    UA_NodeIdStoreContextItem_backend_memory *dataStore;
    size_t storeEnd;
    size_t storeSize;
    size_t initialStoreSize;
} UA_MemoryStoreContext;

static void
UA_MemoryStoreContext_clear(UA_MemoryStoreContext* ctx) {
    for (size_t i = 0; i < ctx->storeEnd; ++i) {
        UA_NodeIdStoreContextItem_clear(&ctx->dataStore[i]);
    }
    UA_free(ctx->dataStore);
    memset(ctx, 0, sizeof(UA_MemoryStoreContext));
}

static UA_NodeIdStoreContextItem_backend_memory *
getNewNodeIdContext_backend_memory(UA_MemoryStoreContext* context,
                                   UA_Server *server,
                                   const UA_NodeId *nodeId) {
    UA_MemoryStoreContext *ctx = (UA_MemoryStoreContext*)context;
    if (ctx->storeEnd >= ctx->storeSize) {
        size_t newStoreSize = ctx->storeSize * 2;
        if (newStoreSize == 0)
            return NULL;
        ctx->dataStore = (UA_NodeIdStoreContextItem_backend_memory*)UA_realloc(ctx->dataStore,  (newStoreSize * sizeof(UA_NodeIdStoreContextItem_backend_memory)));
        if (!ctx->dataStore) {
            ctx->storeSize = 0;
            return NULL;
        }
        ctx->storeSize = newStoreSize;
    }
    UA_NodeIdStoreContextItem_backend_memory *item = &ctx->dataStore[ctx->storeEnd];
    UA_NodeId_copy(nodeId, &item->nodeId);
    UA_DataValueMemoryStoreItem ** store = (UA_DataValueMemoryStoreItem **)UA_calloc(ctx->initialStoreSize, sizeof(UA_DataValueMemoryStoreItem*));
    if (!store) {
        UA_NodeIdStoreContextItem_clear(item);
        return NULL;
    }
    item->dataStore = store;
    item->storeSize = ctx->initialStoreSize;
    item->storeEnd = 0;
    ++ctx->storeEnd;
    return item;
}

static UA_NodeIdStoreContextItem_backend_memory *
getNodeIdStoreContextItem_backend_memory(UA_MemoryStoreContext* context,
                                         UA_Server *server,
                                         const UA_NodeId *nodeId)
{
    for (size_t i = 0; i < context->storeEnd; ++i) {
        if (UA_NodeId_equal(nodeId, &context->dataStore[i].nodeId)) {
            return &context->dataStore[i];
        }
    }
    return getNewNodeIdContext_backend_memory(context, server, nodeId);
}

static UA_Boolean
binarySearch_backend_memory(const UA_NodeIdStoreContextItem_backend_memory* item,
                            const UA_DateTime timestamp,
                            size_t *index) {
    if (item->storeEnd == 0) {
        *index = item->storeEnd;
        return false;
    }
    size_t min = 0;
    size_t max = item->storeEnd - 1;
    while (min <= max) {
        *index = (min + max) / 2;
        if (item->dataStore[*index]->timestamp == timestamp) {
            return true;
        } else if (item->dataStore[*index]->timestamp < timestamp) {
            if (*index == item->storeEnd - 1) {
                *index = item->storeEnd;
                return false;
            }
            min = *index + 1;
        } else {
            if (*index == 0)
                return false;
            max = *index - 1;
        }
    }
    *index = min;
    return false;

}

static size_t
resultSize_backend_memory(UA_Server *server,
                          void *context,
                          const UA_NodeId *sessionId,
                          void *sessionContext,
                          const UA_NodeId * nodeId,
                          size_t startIndex,
                          size_t endIndex) {
    const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId);
    if (item->storeEnd == 0
            || startIndex == item->storeEnd
            || endIndex == item->storeEnd)
        return 0;
    return endIndex - startIndex + 1;
}

static size_t
getDateTimeMatch_backend_memory(UA_Server *server,
                                void *context,
                                const UA_NodeId *sessionId,
                                void *sessionContext,
                                const UA_NodeId * nodeId,
                                const UA_DateTime timestamp,
                                const MatchStrategy strategy) {
    const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId);
    size_t current;
    UA_Boolean retval = binarySearch_backend_memory(item, timestamp, &current);

    if ((strategy == MATCH_EQUAL
         || strategy == MATCH_EQUAL_OR_AFTER
         || strategy == MATCH_EQUAL_OR_BEFORE)
            && retval)
        return current;
    switch (strategy) {
    case MATCH_AFTER:
        if (retval)
            return current+1;
        return current;
    case MATCH_EQUAL_OR_AFTER:
        return current;
    case MATCH_EQUAL_OR_BEFORE:
        // retval == true aka "equal" is handled before
        // Fall through if !retval
    case MATCH_BEFORE:
        if (current > 0)
            return current-1;
        else
            return item->storeEnd;
    default:
        break;
    }
    return item->storeEnd;
}


static UA_StatusCode
serverSetHistoryData_backend_memory(UA_Server *server,
                                    void *context,
                                    const UA_NodeId *sessionId,
                                    void *sessionContext,
                                    const UA_NodeId * nodeId,
                                    UA_Boolean historizing,
                                    const UA_DataValue *value)
{
    UA_NodeIdStoreContextItem_backend_memory *item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId);

    if (item->storeEnd >= item->storeSize) {
        size_t newStoreSize = item->storeSize == 0 ? INITIAL_MEMORY_STORE_SIZE : item->storeSize * 2;
        item->dataStore = (UA_DataValueMemoryStoreItem **)UA_realloc(item->dataStore,  (newStoreSize * sizeof(UA_DataValueMemoryStoreItem*)));
        if (!item->dataStore) {
            item->storeSize = 0;
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }
        item->storeSize = newStoreSize;
    }
    UA_DateTime timestamp = 0;
    if (value->hasSourceTimestamp) {
        timestamp = value->sourceTimestamp;
    } else if (value->hasServerTimestamp) {
        timestamp = value->serverTimestamp;
    } else {
        timestamp = UA_DateTime_now();
    }
    UA_DataValueMemoryStoreItem *newItem = (UA_DataValueMemoryStoreItem *)UA_calloc(1, sizeof(UA_DataValueMemoryStoreItem));
    newItem->timestamp = timestamp;
    UA_DataValue_copy(value, &newItem->value);
    if(!newItem->value.hasServerTimestamp) {
        newItem->value.serverTimestamp = timestamp;
        newItem->value.hasServerTimestamp = true;
    }
    size_t index = getDateTimeMatch_backend_memory(server,
                                                   context,
                                                   NULL,
                                                   NULL,
                                                   nodeId,
                                                   timestamp,
                                                   MATCH_EQUAL_OR_AFTER);
    if (item->storeEnd > 0 && index < item->storeEnd) {
        memmove(&item->dataStore[index+1], &item->dataStore[index], sizeof(UA_DataValueMemoryStoreItem*) * (item->storeEnd - index));
    }
    item->dataStore[index] = newItem;
    ++item->storeEnd;
    return UA_STATUSCODE_GOOD;
}

static void
UA_MemoryStoreContext_delete(UA_MemoryStoreContext* ctx) {
    UA_MemoryStoreContext_clear(ctx);
    UA_free(ctx);
}

static size_t
getEnd_backend_memory(UA_Server *server,
                      void *context,
                      const UA_NodeId *sessionId,
                      void *sessionContext,
                      const UA_NodeId * nodeId) {
    const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId);
    return item->storeEnd;
}

static size_t
lastIndex_backend_memory(UA_Server *server,
                         void *context,
                         const UA_NodeId *sessionId,
                         void *sessionContext,
                         const UA_NodeId * nodeId) {
    const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId);
    if (item->storeEnd == 0)
        return 0;
    return item->storeEnd - 1;
}

static size_t
firstIndex_backend_memory(UA_Server *server,
                          void *context,
                          const UA_NodeId *sessionId,
                          void *sessionContext,
                          const UA_NodeId * nodeId) {
    return 0;
}

static UA_Boolean
boundSupported_backend_memory(UA_Server *server,
                              void *context,
                              const UA_NodeId *sessionId,
                              void *sessionContext,
                              const UA_NodeId * nodeId) {
    return true;
}

static UA_Boolean
timestampsToReturnSupported_backend_memory(UA_Server *server,
                                           void *context,
                                           const UA_NodeId *sessionId,
                                           void *sessionContext,
                                           const UA_NodeId *nodeId,
                                           const UA_TimestampsToReturn timestampsToReturn) {
    const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId);
    if (item->storeEnd == 0) {
        return true;
    }
    if (timestampsToReturn == UA_TIMESTAMPSTORETURN_NEITHER
            || timestampsToReturn == UA_TIMESTAMPSTORETURN_INVALID
            || (timestampsToReturn == UA_TIMESTAMPSTORETURN_SERVER
                && !item->dataStore[0]->value.hasServerTimestamp)
            || (timestampsToReturn == UA_TIMESTAMPSTORETURN_SOURCE
                && !item->dataStore[0]->value.hasSourceTimestamp)
            || (timestampsToReturn == UA_TIMESTAMPSTORETURN_BOTH
                && !(item->dataStore[0]->value.hasSourceTimestamp
                     && item->dataStore[0]->value.hasServerTimestamp))) {
        return false;
    }
    return true;
}

static const UA_DataValue*
getDataValue_backend_memory(UA_Server *server,
                            void *context,
                            const UA_NodeId *sessionId,
                            void *sessionContext,
                            const UA_NodeId * nodeId, size_t index) {
    const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId);
    return &item->dataStore[index]->value;
}

static UA_StatusCode
UA_DataValue_backend_copyRange(const UA_DataValue *src, UA_DataValue *dst,
                               const UA_NumericRange range)
{
    memcpy(dst, src, sizeof(UA_DataValue));
    if (src->hasValue)
        return UA_Variant_copyRange(&src->value, &dst->value, range);
    return UA_STATUSCODE_BADDATAUNAVAILABLE;
}

static UA_StatusCode
copyDataValues_backend_memory(UA_Server *server,
                              void *context,
                              const UA_NodeId *sessionId,
                              void *sessionContext,
                              const UA_NodeId * nodeId,
                              size_t startIndex,
                              size_t endIndex,
                              UA_Boolean reverse,
                              size_t maxValues,
                              UA_NumericRange range,
                              UA_Boolean releaseContinuationPoints,
                              const UA_ByteString *continuationPoint,
                              UA_ByteString *outContinuationPoint,
                              size_t * providedValues,
                              UA_DataValue * values)
{
    size_t skip = 0;
    if (continuationPoint->length > 0) {
        if (continuationPoint->length == sizeof(size_t)) {
            skip = *((size_t*)(continuationPoint->data));
        } else {
            return UA_STATUSCODE_BADCONTINUATIONPOINTINVALID;
        }
    }
    const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId);
    size_t index = startIndex;
    size_t counter = 0;
    size_t skipedValues = 0;
    if (reverse) {
        while (index >= endIndex && index < item->storeEnd && counter < maxValues) {
            if (skipedValues++ >= skip) {
                if (range.dimensionsSize > 0) {
                    UA_DataValue_backend_copyRange(&item->dataStore[index]->value, &values[counter], range);
                } else {
                    UA_DataValue_copy(&item->dataStore[index]->value, &values[counter]);
                }
                ++counter;
            }
            --index;
        }
    } else {
        while (index <= endIndex && counter < maxValues) {
            if (skipedValues++ >= skip) {
                if (range.dimensionsSize > 0) {
                    UA_DataValue_backend_copyRange(&item->dataStore[index]->value, &values[counter], range);
                } else {
                    UA_DataValue_copy(&item->dataStore[index]->value, &values[counter]);
                }
                ++counter;
            }
            ++index;
        }
    }

    if (providedValues)
        *providedValues = counter;

    if ((!reverse && (endIndex-startIndex-skip+1) > counter) || (reverse && (startIndex-endIndex-skip+1) > counter)) {
        outContinuationPoint->length = sizeof(size_t);
        size_t t = sizeof(size_t);
        outContinuationPoint->data = (UA_Byte*)UA_malloc(t);
        *((size_t*)(outContinuationPoint->data)) = skip + counter;
    }

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
insertDataValue_backend_memory(UA_Server *server,
                   void *hdbContext,
                   const UA_NodeId *sessionId,
                   void *sessionContext,
                   const UA_NodeId *nodeId,
                   const UA_DataValue *value)
{
    if (!value->hasSourceTimestamp && !value->hasServerTimestamp)
        return UA_STATUSCODE_BADINVALIDTIMESTAMP;
    const UA_DateTime timestamp = value->hasSourceTimestamp ? value->sourceTimestamp : value->serverTimestamp;
    UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)hdbContext, server, nodeId);

    size_t index = getDateTimeMatch_backend_memory(server,
                                    hdbContext,
                                    sessionId,
                                    sessionContext,
                                    nodeId,
                                    timestamp,
                                    MATCH_EQUAL_OR_AFTER);
    if (item->storeEnd != index && item->dataStore[index]->timestamp == timestamp)
        return UA_STATUSCODE_BADENTRYEXISTS;

    if (item->storeEnd >= item->storeSize) {
        size_t newStoreSize = item->storeSize == 0 ? INITIAL_MEMORY_STORE_SIZE : item->storeSize * 2;
        item->dataStore = (UA_DataValueMemoryStoreItem **)UA_realloc(item->dataStore,  (newStoreSize * sizeof(UA_DataValueMemoryStoreItem*)));
        if (!item->dataStore) {
            item->storeSize = 0;
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }
        item->storeSize = newStoreSize;
    }
    UA_DataValueMemoryStoreItem *newItem = (UA_DataValueMemoryStoreItem *)UA_calloc(1, sizeof(UA_DataValueMemoryStoreItem));
    newItem->timestamp = timestamp;
    UA_DataValue_copy(value, &newItem->value);
    if(!newItem->value.hasServerTimestamp) {
        newItem->value.serverTimestamp = timestamp;
        newItem->value.hasServerTimestamp = true;
    }

    if (item->storeEnd > 0 && index < item->storeEnd) {
        memmove(&item->dataStore[index+1], &item->dataStore[index], sizeof(UA_DataValueMemoryStoreItem*) * (item->storeEnd - index));
    }
    item->dataStore[index] = newItem;
    ++item->storeEnd;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
replaceDataValue_backend_memory(UA_Server *server,
                    void *hdbContext,
                    const UA_NodeId *sessionId,
                    void *sessionContext,
                    const UA_NodeId *nodeId,
                    const UA_DataValue *value)
{
    if (!value->hasSourceTimestamp && !value->hasServerTimestamp)
        return UA_STATUSCODE_BADINVALIDTIMESTAMP;
    const UA_DateTime timestamp = value->hasSourceTimestamp ? value->sourceTimestamp : value->serverTimestamp;
    UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)hdbContext, server, nodeId);

    size_t index = getDateTimeMatch_backend_memory(server,
                                    hdbContext,
                                    sessionId,
                                    sessionContext,
                                    nodeId,
                                    timestamp,
                                    MATCH_EQUAL);
    if (index == item->storeEnd)
        return UA_STATUSCODE_BADNOENTRYEXISTS;
    UA_DataValue_clear(&item->dataStore[index]->value);
    UA_DataValue_copy(value, &item->dataStore[index]->value);
    if(!item->dataStore[index]->value.hasServerTimestamp) {
        item->dataStore[index]->value.serverTimestamp = timestamp;
        item->dataStore[index]->value.hasServerTimestamp = true;
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
updateDataValue_backend_memory(UA_Server *server,
                   void *hdbContext,
                   const UA_NodeId *sessionId,
                   void *sessionContext,
                   const UA_NodeId *nodeId,
                   const UA_DataValue *value)
{
    // we first try to replace, because it is cheap
    UA_StatusCode ret = replaceDataValue_backend_memory(server,
                                                        hdbContext,
                                                        sessionId,
                                                        sessionContext,
                                                        nodeId,
                                                        value);
    if (ret == UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_GOODENTRYREPLACED;

    ret = insertDataValue_backend_memory(server,
                                          hdbContext,
                                          sessionId,
                                          sessionContext,
                                          nodeId,
                                          value);
    if (ret == UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_GOODENTRYINSERTED;

    return ret;
}

static UA_StatusCode
removeDataValue_backend_memory(UA_Server *server,
                               void *hdbContext,
                               const UA_NodeId *sessionId,
                               void *sessionContext,
                               const UA_NodeId *nodeId,
                               UA_DateTime startTimestamp,
                               UA_DateTime endTimestamp)
{
    UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)hdbContext, server, nodeId);
    size_t storeEnd = item->storeEnd;
    // The first index which will be deleted
    size_t index1;
    // the first index which is not deleted
    size_t index2;
    if (startTimestamp > endTimestamp) {
        return UA_STATUSCODE_BADTIMESTAMPNOTSUPPORTED;
    }
    if (startTimestamp == endTimestamp) {
        index1 = getDateTimeMatch_backend_memory(server,
                                        hdbContext,
                                        sessionId,
                                        sessionContext,
                                        nodeId,
                                        startTimestamp,
                                        MATCH_EQUAL);
        if (index1 == storeEnd)
            return UA_STATUSCODE_BADNODATA;
        index2 = index1 + 1;
    } else {
        index1 = getDateTimeMatch_backend_memory(server,
                                        hdbContext,
                                        sessionId,
                                        sessionContext,
                                        nodeId,
                                        startTimestamp,
                                        MATCH_EQUAL_OR_AFTER);
        index2 = getDateTimeMatch_backend_memory(server,
                                        hdbContext,
                                        sessionId,
                                        sessionContext,
                                        nodeId,
                                        endTimestamp,
                                        MATCH_BEFORE);
        if (index2 == storeEnd || index1 == storeEnd || index1 > index2 )
            return UA_STATUSCODE_BADNODATA;
        ++index2;
    }
#ifndef __clang_analyzer__
    for (size_t i = index1; i < index2; ++i) {
        UA_DataValueMemoryStoreItem_clear(item->dataStore[i]);
        UA_free(item->dataStore[i]);
    }
    memmove(&item->dataStore[index1], &item->dataStore[index2], sizeof(UA_DataValueMemoryStoreItem*) * (item->storeEnd - index2));
    item->storeEnd -= index2 - index1;
#else
    (void)index1;
    (void)index2;
#endif
    return UA_STATUSCODE_GOOD;
}

static void
deleteMembers_backend_memory(UA_HistoryDataBackend *backend)
{
    if (backend == NULL || backend->context == NULL)
        return;
    UA_MemoryStoreContext_clear((UA_MemoryStoreContext*)backend->context);
    UA_free(backend->context);
}



UA_HistoryDataBackend
UA_HistoryDataBackend_Memory(size_t initialNodeIdStoreSize, size_t initialDataStoreSize) {
    if (initialNodeIdStoreSize == 0)
        initialNodeIdStoreSize = 1;
    if (initialDataStoreSize == 0)
        initialDataStoreSize = 1;
    UA_HistoryDataBackend result;
    memset(&result, 0, sizeof(UA_HistoryDataBackend));
    UA_MemoryStoreContext *ctx = (UA_MemoryStoreContext *)UA_calloc(1, sizeof(UA_MemoryStoreContext));
    if (!ctx)
        return result;
    ctx->dataStore = (UA_NodeIdStoreContextItem_backend_memory*)UA_calloc(initialNodeIdStoreSize, sizeof(UA_NodeIdStoreContextItem_backend_memory));
    ctx->initialStoreSize = initialDataStoreSize;
    ctx->storeSize = initialNodeIdStoreSize;
    ctx->storeEnd = 0;
    result.serverSetHistoryData = &serverSetHistoryData_backend_memory;
    result.resultSize = &resultSize_backend_memory;
    result.getEnd = &getEnd_backend_memory;
    result.lastIndex = &lastIndex_backend_memory;
    result.firstIndex = &firstIndex_backend_memory;
    result.getDateTimeMatch = &getDateTimeMatch_backend_memory;
    result.copyDataValues = &copyDataValues_backend_memory;
    result.getDataValue = &getDataValue_backend_memory;
    result.boundSupported = &boundSupported_backend_memory;
    result.timestampsToReturnSupported = &timestampsToReturnSupported_backend_memory;
    result.insertDataValue =  &insertDataValue_backend_memory;
    result.updateDataValue =  &updateDataValue_backend_memory;
    result.replaceDataValue =  &replaceDataValue_backend_memory;
    result.removeDataValue =  &removeDataValue_backend_memory;
    result.deleteMembers = &deleteMembers_backend_memory;
    result.getHistoryData = NULL;
    result.context = ctx;
    return result;
}

void
UA_HistoryDataBackend_Memory_clear(UA_HistoryDataBackend *backend)
{
    UA_MemoryStoreContext *ctx = (UA_MemoryStoreContext*)backend->context;
    UA_MemoryStoreContext_delete(ctx);
    memset(backend, 0, sizeof(UA_HistoryDataBackend));
}

/* Circular buffer implementation */

static UA_NodeIdStoreContextItem_backend_memory *
getNewNodeIdContext_backend_memory_Circular(UA_MemoryStoreContext *context,
                                            UA_Server *server,
                                            const UA_NodeId *nodeId) {
    UA_MemoryStoreContext *ctx = (UA_MemoryStoreContext *)context;
    if(ctx->storeEnd >= ctx->storeSize) {
        return NULL;
    }
    UA_NodeIdStoreContextItem_backend_memory *item = &ctx->dataStore[ctx->storeEnd];
    UA_NodeId_copy(nodeId, &item->nodeId);
    UA_DataValueMemoryStoreItem **store = (UA_DataValueMemoryStoreItem **)UA_calloc(ctx->initialStoreSize, sizeof(UA_DataValueMemoryStoreItem *));
    if(!store) {
        UA_NodeIdStoreContextItem_clear(item);
        return NULL;
    }
    item->dataStore = store;
    item->storeSize = ctx->initialStoreSize;
    item->storeEnd = 0;
    ++ctx->storeEnd;
    return item;
}

static UA_NodeIdStoreContextItem_backend_memory *
getNodeIdStoreContextItem_backend_memory_Circular(UA_MemoryStoreContext *context,
                                                  UA_Server *server,
                                                  const UA_NodeId *nodeId) {
    for(size_t i = 0; i < context->storeEnd; ++i) {
        if(UA_NodeId_equal(nodeId, &context->dataStore[i].nodeId)) {
            return &context->dataStore[i];
        }
    }
    return getNewNodeIdContext_backend_memory_Circular(context, server, nodeId);
}

static UA_StatusCode
serverSetHistoryData_backend_memory_Circular(UA_Server *server,
                                             void *context,
                                             const UA_NodeId *sessionId,
                                             void *sessionContext,
                                             const UA_NodeId *nodeId,
                                             UA_Boolean historizing,
                                             const UA_DataValue *value) {
    UA_NodeIdStoreContextItem_backend_memory *item = getNodeIdStoreContextItem_backend_memory_Circular((UA_MemoryStoreContext *)context, server, nodeId);
    if(item == NULL) {
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    if(item->lastInserted >= item->storeSize) {
        /* If the buffer size is overcomed, push new elements from the start of the buffer */
        item->lastInserted = 0;
    }
    UA_DateTime timestamp = 0;
    if(value->hasSourceTimestamp) {
        timestamp = value->sourceTimestamp;
    } else if(value->hasServerTimestamp) {
        timestamp = value->serverTimestamp;
    } else {
        timestamp = UA_DateTime_now();
    }
    UA_DataValueMemoryStoreItem *newItem = (UA_DataValueMemoryStoreItem *)UA_calloc(1, sizeof(UA_DataValueMemoryStoreItem));
    newItem->timestamp = timestamp;
    UA_DataValue_copy(value, &newItem->value);
    if(!newItem->value.hasServerTimestamp) {
        newItem->value.serverTimestamp = timestamp;
        newItem->value.hasServerTimestamp = true;
    }


    /* This implementation does NOT sort values by timestamp */

    if(item->dataStore[item->lastInserted] != NULL) {
        UA_DataValueMemoryStoreItem_clear(item->dataStore[item->lastInserted]);
        UA_free(item->dataStore[item->lastInserted]);
    }
    item->dataStore[item->lastInserted] = newItem;
    ++item->lastInserted;

    if(item->storeEnd < item->storeSize) {
        ++item->storeEnd;
    }

    return UA_STATUSCODE_GOOD;
}

static size_t
getResultSize_service_Circular(const UA_HistoryDataBackend *backend, UA_Server *server,
                               const UA_NodeId *sessionId, void *sessionContext,
                               const UA_NodeId *nodeId, UA_DateTime start,
                               UA_DateTime end, UA_UInt32 numValuesPerNode,
                               UA_Boolean returnBounds, size_t *startIndex,
                               size_t *endIndex, UA_Boolean *addFirst,
                               UA_Boolean *addLast, UA_Boolean *reverse) {
    *startIndex = 0;
    *endIndex = backend->lastIndex(server, backend->context, sessionId, sessionContext, nodeId);
    *addFirst = false;
    *addLast = false;
    if(end == LLONG_MIN) {
        *reverse = false;
    } else if(start == LLONG_MIN) {
        *reverse = true;
    } else {
        *reverse = end < start;
    }

    size_t size = 0;
    const UA_NodeIdStoreContextItem_backend_memory *item = getNodeIdStoreContextItem_backend_memory_Circular((UA_MemoryStoreContext *)backend->context, server, nodeId);
    if(item == NULL) {
        size = 0;
    } else {
        size = item->storeEnd;
    }
    return size;
}

static UA_StatusCode
getHistoryData_service_Circular(UA_Server *server,
                                const UA_NodeId *sessionId,
                                void *sessionContext,
                                const UA_HistoryDataBackend *backend,
                                const UA_DateTime start,
                                const UA_DateTime end,
                                const UA_NodeId *nodeId,
                                size_t maxSize,
                                UA_UInt32 numValuesPerNode,
                                UA_Boolean returnBounds,
                                UA_TimestampsToReturn timestampsToReturn,
                                UA_NumericRange range,
                                UA_Boolean releaseContinuationPoints,
                                const UA_ByteString *continuationPoint,
                                UA_ByteString *outContinuationPoint,
                                UA_HistoryData *historyData) {
    size_t *resultSize = &historyData->dataValuesSize;
    UA_DataValue **result = &historyData->dataValues;
    size_t skip = 0;
    UA_ByteString backendContinuationPoint;
    UA_ByteString_init(&backendContinuationPoint);
    if(continuationPoint->length > 0) {
        if(continuationPoint->length < sizeof(size_t))
            return UA_STATUSCODE_BADCONTINUATIONPOINTINVALID;
        skip = *((size_t *)(continuationPoint->data));
        backendContinuationPoint.length = continuationPoint->length - sizeof(size_t);
        backendContinuationPoint.data = continuationPoint->data + sizeof(size_t);
    }
    size_t storeEnd = backend->getEnd(server, backend->context, sessionId, sessionContext, nodeId);
    size_t startIndex;
    size_t endIndex;
    UA_Boolean addFirst;
    UA_Boolean addLast;
    UA_Boolean reverse;
    size_t _resultSize = getResultSize_service_Circular(backend,
                                                        server,
                                                        sessionId,
                                                        sessionContext,
                                                        nodeId,
                                                        start,
                                                        end,
                                                        numValuesPerNode == 0 ? 0 : numValuesPerNode + (UA_UInt32)skip,
                                                        returnBounds,
                                                        &startIndex,
                                                        &endIndex,
                                                        &addFirst,
                                                        &addLast,
                                                        &reverse);
    *resultSize = _resultSize - skip;
    if(*resultSize > maxSize) {
        *resultSize = maxSize;
    }
    UA_DataValue *outResult = (UA_DataValue *)UA_Array_new(*resultSize, &UA_TYPES[UA_TYPES_DATAVALUE]);
    if(!outResult) {
        *resultSize = 0;
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    *result = outResult;
    size_t counter = 0;
    if(addFirst) {
        if(skip == 0) {
            outResult[counter].hasStatus = true;
            outResult[counter].status = UA_STATUSCODE_BADBOUNDNOTFOUND;
            outResult[counter].hasSourceTimestamp = true;
            if(start == LLONG_MIN) {
                outResult[counter].sourceTimestamp = end;
            } else {
                outResult[counter].sourceTimestamp = start;
            }
            ++counter;
        }
    }
    UA_ByteString backendOutContinuationPoint;
    UA_ByteString_init(&backendOutContinuationPoint);
    if(endIndex != storeEnd && startIndex != storeEnd) {
        size_t retval = 0;
        size_t valueSize = *resultSize - counter;
        if(valueSize + skip > _resultSize - addFirst - addLast) {
            if(skip == 0) {
                valueSize = _resultSize - addFirst - addLast;
            } else {
                valueSize = _resultSize - skip - addLast;
            }
        }
        UA_StatusCode ret = UA_STATUSCODE_GOOD;
        if(valueSize > 0)
            ret = backend->copyDataValues(server,
                                          backend->context,
                                          sessionId,
                                          sessionContext,
                                          nodeId,
                                          startIndex,
                                          endIndex,
                                          reverse,
                                          valueSize,
                                          range,
                                          releaseContinuationPoints,
                                          &backendContinuationPoint,
                                          &backendOutContinuationPoint,
                                          &retval,
                                          &outResult[counter]);
        if(ret != UA_STATUSCODE_GOOD) {
            UA_Array_delete(outResult, *resultSize, &UA_TYPES[UA_TYPES_DATAVALUE]);
            *result = NULL;
            *resultSize = 0;
            return ret;
        }
        counter += retval;
    }
    if(addLast && counter < *resultSize) {
        outResult[counter].hasStatus = true;
        outResult[counter].status = UA_STATUSCODE_BADBOUNDNOTFOUND;
        outResult[counter].hasSourceTimestamp = true;
        if(start == LLONG_MIN && storeEnd != backend->firstIndex(server, backend->context, sessionId, sessionContext, nodeId)) {
            outResult[counter].sourceTimestamp = backend->getDataValue(server, backend->context, sessionId, sessionContext, nodeId, endIndex)->sourceTimestamp - UA_DATETIME_SEC;
        } else if(end == LLONG_MIN && storeEnd != backend->firstIndex(server, backend->context, sessionId, sessionContext, nodeId)) {
            outResult[counter].sourceTimestamp = backend->getDataValue(server, backend->context, sessionId, sessionContext, nodeId, endIndex)->sourceTimestamp + UA_DATETIME_SEC;
        } else {
            outResult[counter].sourceTimestamp = end;
        }
    }
    // there are more values
    if(skip + *resultSize < _resultSize
       // there are not more values for this request, but there are more values in
       // database
       || (backendOutContinuationPoint.length > 0 && numValuesPerNode != 0)
       // we deliver just one value which is a FIRST/LAST value
       || (skip == 0 && addFirst == true && *resultSize == 1)) {
        if(UA_ByteString_allocBuffer(outContinuationPoint, backendOutContinuationPoint.length + sizeof(size_t)) != UA_STATUSCODE_GOOD) {
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }
        *((size_t *)(outContinuationPoint->data)) = skip + *resultSize;
        if(backendOutContinuationPoint.length > 0)
            memcpy(outContinuationPoint->data + sizeof(size_t), backendOutContinuationPoint.data, backendOutContinuationPoint.length);
    }
    UA_ByteString_clear(&backendOutContinuationPoint);
    return UA_STATUSCODE_GOOD;
}

UA_HistoryDataBackend
UA_HistoryDataBackend_Memory_Circular(size_t initialNodeIdStoreSize, size_t initialDataStoreSize) {
    UA_HistoryDataBackend result = UA_HistoryDataBackend_Memory(initialNodeIdStoreSize, initialDataStoreSize);
    result.serverSetHistoryData = &serverSetHistoryData_backend_memory_Circular;
    result.getHistoryData = &getHistoryData_service_Circular;
    return result;
}

/**** amalgamated original file "/plugins/historydata/ua_history_data_gathering_default.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2018 (c) basysKom GmbH <opensource@basyskom.com> (Author: Peter Rustler)
 *    Copyright 2021 (c) luibass92 <luibass92@live.it> (Author: Luigi Bassetta)
 */


#include <string.h>

typedef struct {
    UA_NodeId nodeId;
    UA_HistorizingNodeIdSettings setting;
    UA_MonitoredItemCreateResult monitoredResult;
} UA_NodeIdStoreContextItem_gathering_default;

typedef struct {
    UA_NodeIdStoreContextItem_gathering_default *dataStore;
    size_t storeEnd;
    size_t storeSize;
} UA_NodeIdStoreContext;

static void
dataChangeCallback_gathering_default(UA_Server *server,
                                     UA_UInt32 monitoredItemId,
                                     void *monitoredItemContext,
                                     const UA_NodeId *nodeId,
                                     void *nodeContext,
                                     UA_UInt32 attributeId,
                                     const UA_DataValue *value)
{
    UA_NodeIdStoreContextItem_gathering_default *context = (UA_NodeIdStoreContextItem_gathering_default*)monitoredItemContext;
    context->setting.historizingBackend.serverSetHistoryData(server,
                                                             context->setting.historizingBackend.context,
                                                             NULL,
                                                             NULL,
                                                             nodeId,
                                                             UA_TRUE,
                                                             value);
}

static UA_NodeIdStoreContextItem_gathering_default*
getNodeIdStoreContextItem_gathering_default(UA_NodeIdStoreContext *context,
                                            const UA_NodeId *nodeId)
{
    for (size_t i = 0; i < context->storeEnd; ++i) {
        if (UA_NodeId_equal(&context->dataStore[i].nodeId, nodeId)) {
            return &context->dataStore[i];
        }
    }
    return NULL;
}

static UA_StatusCode
startPoll(UA_Server *server, UA_NodeIdStoreContextItem_gathering_default *item)
{
    UA_MonitoredItemCreateRequest monitorRequest =
            UA_MonitoredItemCreateRequest_default(item->nodeId);
    monitorRequest.requestedParameters.samplingInterval = (double)item->setting.pollingInterval;
    monitorRequest.monitoringMode = UA_MONITORINGMODE_REPORTING;
    item->monitoredResult =
            UA_Server_createDataChangeMonitoredItem(server,
                                                    UA_TIMESTAMPSTORETURN_BOTH,
                                                    monitorRequest,
                                                    item,
                                                    &dataChangeCallback_gathering_default);
    return item->monitoredResult.statusCode;
}

static UA_StatusCode
stopPoll(UA_Server *server, UA_NodeIdStoreContextItem_gathering_default *item)
{
    UA_StatusCode retval = UA_Server_deleteMonitoredItem(server, item->monitoredResult.monitoredItemId);
    UA_MonitoredItemCreateResult_init(&item->monitoredResult);
    return retval;
}

static UA_StatusCode
stopPoll_gathering_default(UA_Server *server,
                           void *context,
                           const UA_NodeId *nodeId)
{
    UA_NodeIdStoreContext *ctx = (UA_NodeIdStoreContext *)context;
    UA_NodeIdStoreContextItem_gathering_default *item = getNodeIdStoreContextItem_gathering_default(ctx, nodeId);
    if (!item) {
        return UA_STATUSCODE_BADNODEIDUNKNOWN;
    }
    if (item->setting.historizingUpdateStrategy != UA_HISTORIZINGUPDATESTRATEGY_POLL)
        return UA_STATUSCODE_BADNODEIDINVALID;
    if (item->monitoredResult.monitoredItemId == 0)
        return UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
    return stopPoll(server, item);
}

static UA_StatusCode
startPoll_gathering_default(UA_Server *server,
                            void *context,
                            const UA_NodeId *nodeId)
{
    UA_NodeIdStoreContext *ctx = (UA_NodeIdStoreContext *)context;
    UA_NodeIdStoreContextItem_gathering_default *item = getNodeIdStoreContextItem_gathering_default(ctx, nodeId);
    if (!item) {
        return UA_STATUSCODE_BADNODEIDUNKNOWN;
    }
    if (item->setting.historizingUpdateStrategy != UA_HISTORIZINGUPDATESTRATEGY_POLL)
        return UA_STATUSCODE_BADNODEIDINVALID;
    if (item->monitoredResult.monitoredItemId > 0)
        return UA_STATUSCODE_BADMONITOREDITEMIDINVALID;
    return startPoll(server, item);
}

static UA_StatusCode
registerNodeId_gathering_default(UA_Server *server,
                                 void *context,
                                 const UA_NodeId *nodeId,
                                 const UA_HistorizingNodeIdSettings setting)
{
    UA_NodeIdStoreContext *ctx = (UA_NodeIdStoreContext*)context;
    if (getNodeIdStoreContextItem_gathering_default(ctx, nodeId)) {
        return UA_STATUSCODE_BADNODEIDEXISTS;
    }
    if (ctx->storeEnd >= ctx->storeSize) {
        size_t newStoreSize = ctx->storeSize * 2;
        ctx->dataStore = (UA_NodeIdStoreContextItem_gathering_default*)UA_realloc(ctx->dataStore,  (newStoreSize * sizeof(UA_NodeIdStoreContextItem_gathering_default)));
        if (!ctx->dataStore) {
            ctx->storeSize = 0;
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }
        memset(&ctx->dataStore[ctx->storeSize], 0, (newStoreSize - ctx->storeSize) * sizeof(UA_NodeIdStoreContextItem_gathering_default));
        ctx->storeSize = newStoreSize;
    }
    UA_NodeId_copy(nodeId, &ctx->dataStore[ctx->storeEnd].nodeId);
    size_t current = ctx->storeEnd;
    ctx->dataStore[current].setting = setting;
    ++ctx->storeEnd;
    return UA_STATUSCODE_GOOD;
}

static const UA_HistorizingNodeIdSettings*
getHistorizingSetting_gathering_default(UA_Server *server,
                                        void *context,
                                        const UA_NodeId *nodeId)
{
    UA_NodeIdStoreContext *ctx = (UA_NodeIdStoreContext*)context;
    UA_NodeIdStoreContextItem_gathering_default *item = getNodeIdStoreContextItem_gathering_default(ctx, nodeId);
    if (item) {
        return &item->setting;
    }
    return NULL;
}

static void
deleteMembers_gathering_default(UA_HistoryDataGathering *gathering)
{
    if (gathering == NULL || gathering->context == NULL)
        return;
    UA_NodeIdStoreContext *ctx = (UA_NodeIdStoreContext*)gathering->context;
    for (size_t i = 0; i < ctx->storeEnd; ++i) {
        UA_NodeId_clear(&ctx->dataStore[i].nodeId);
        // There is still a monitored item present for this gathering
        // You need to remove it with UA_Server_deleteMonitoredItem
        UA_assert(ctx->dataStore[i].monitoredResult.monitoredItemId == 0);
    }
    UA_free(ctx->dataStore);
    UA_free(gathering->context);
}

static UA_Boolean
updateNodeIdSetting_gathering_default(UA_Server *server,
                                      void *context,
                                      const UA_NodeId *nodeId,
                                      const UA_HistorizingNodeIdSettings setting)
{
    UA_NodeIdStoreContext *ctx = (UA_NodeIdStoreContext*)context;
    UA_NodeIdStoreContextItem_gathering_default *item = getNodeIdStoreContextItem_gathering_default(ctx, nodeId);
    if (!item) {
        return false;
    }
    stopPoll_gathering_default(server, context, nodeId);
    item->setting = setting;
    return true;
}

static void
setValue_gathering_default(UA_Server *server,
                           void *context,
                           const UA_NodeId *sessionId,
                           void *sessionContext,
                           const UA_NodeId *nodeId,
                           UA_Boolean historizing,
                           const UA_DataValue *value)
{
    UA_NodeIdStoreContext *ctx = (UA_NodeIdStoreContext*)context;
    UA_NodeIdStoreContextItem_gathering_default *item = getNodeIdStoreContextItem_gathering_default(ctx, nodeId);
    if (!item) {
        return;
    }
    if (item->setting.historizingUpdateStrategy == UA_HISTORIZINGUPDATESTRATEGY_VALUESET) {
        item->setting.historizingBackend.serverSetHistoryData(server,
                                                              item->setting.historizingBackend.context,
                                                              sessionId,
                                                              sessionContext,
                                                              nodeId,
                                                              historizing,
                                                              value);
    }
}

UA_HistoryDataGathering
UA_HistoryDataGathering_Default(size_t initialNodeIdStoreSize)
{
    UA_HistoryDataGathering gathering;
    memset(&gathering, 0, sizeof(UA_HistoryDataGathering));
    gathering.setValue = &setValue_gathering_default;
    gathering.getHistorizingSetting = &getHistorizingSetting_gathering_default;
    gathering.registerNodeId = &registerNodeId_gathering_default;
    gathering.startPoll = &startPoll_gathering_default;
    gathering.stopPoll = &stopPoll_gathering_default;
    gathering.deleteMembers = &deleteMembers_gathering_default;
    gathering.updateNodeIdSetting = &updateNodeIdSetting_gathering_default;
    UA_NodeIdStoreContext *context = (UA_NodeIdStoreContext*)UA_calloc(1, sizeof(UA_NodeIdStoreContext));
    context->storeEnd = 0;
    context->storeSize = initialNodeIdStoreSize;
    context->dataStore = (UA_NodeIdStoreContextItem_gathering_default*)UA_calloc(initialNodeIdStoreSize, sizeof(UA_NodeIdStoreContextItem_gathering_default));
    gathering.context = context;
    return gathering;
}

/* Circular buffer implementation */

static UA_StatusCode
registerNodeId_gathering_circular(UA_Server *server, void *context,
                                  const UA_NodeId *nodeId,
                                  const UA_HistorizingNodeIdSettings setting) {
    UA_NodeIdStoreContext *ctx = (UA_NodeIdStoreContext *)context;
    if(getNodeIdStoreContextItem_gathering_default(ctx, nodeId)) {
        return UA_STATUSCODE_BADNODEIDEXISTS;
    }
    if(ctx->storeEnd >= ctx->storeSize || !ctx->dataStore) {
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    UA_NodeId_copy(nodeId, &ctx->dataStore[ctx->storeEnd].nodeId);
    size_t current = ctx->storeEnd;
    ctx->dataStore[current].setting = setting;
    ++ctx->storeEnd;
    return UA_STATUSCODE_GOOD;
}

UA_HistoryDataGathering
UA_HistoryDataGathering_Circular(size_t initialNodeIdStoreSize) {
    UA_HistoryDataGathering gathering = UA_HistoryDataGathering_Default(initialNodeIdStoreSize);
    gathering.registerNodeId = &registerNodeId_gathering_circular;
    return gathering;
}

/**** amalgamated original file "/plugins/historydata/ua_history_database_default.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2018 (c) basysKom GmbH <opensource@basyskom.com> (Author: Peter Rustler)
 */


#include <limits.h>

typedef struct {
    UA_HistoryDataGathering gathering;
} UA_HistoryDatabaseContext_default;

static size_t
getResultSize_service_default(const UA_HistoryDataBackend* backend,
                              UA_Server *server,
                              const UA_NodeId *sessionId,
                              void* sessionContext,
                              const UA_NodeId *nodeId,
                              UA_DateTime start,
                              UA_DateTime end,
                              UA_UInt32 numValuesPerNode,
                              UA_Boolean returnBounds,
                              size_t *startIndex,
                              size_t *endIndex,
                              UA_Boolean *addFirst,
                              UA_Boolean *addLast,
                              UA_Boolean *reverse)
{
    size_t storeEnd = backend->getEnd(server, backend->context, sessionId, sessionContext, nodeId);
    size_t firstIndex = backend->firstIndex(server, backend->context, sessionId, sessionContext, nodeId);
    size_t lastIndex = backend->lastIndex(server, backend->context, sessionId, sessionContext, nodeId);
    *startIndex = storeEnd;
    *endIndex = storeEnd;
    *addFirst = false;
    *addLast = false;
    if (end == LLONG_MIN) {
        *reverse = false;
    } else if (start == LLONG_MIN) {
        *reverse = true;
    } else {
        *reverse = end < start;
    }
    UA_Boolean equal = start == end;
    size_t size = 0;
    if (lastIndex != storeEnd) {
        if (equal) {
            if (returnBounds) {
                *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, start, MATCH_EQUAL_OR_BEFORE);
                if (*startIndex == storeEnd) {
                    *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, start, MATCH_AFTER);
                    *addFirst = true;
                }
                *endIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, start, MATCH_AFTER);
                size = backend->resultSize(server, backend->context, sessionId, sessionContext, nodeId, *startIndex, *endIndex);
            } else {
                *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, start, MATCH_EQUAL);
                *endIndex = *startIndex;
                if (*startIndex == storeEnd)
                    size = 0;
                else
                    size = 1;
            }
        } else if (start == LLONG_MIN) {
            *endIndex = firstIndex;
            if (returnBounds) {
                *addLast = true;
                *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, end, MATCH_EQUAL_OR_AFTER);
                if (*startIndex == storeEnd) {
                    *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, end, MATCH_EQUAL_OR_BEFORE);
                    *addFirst = true;
                }
            } else {
                *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, end, MATCH_EQUAL_OR_BEFORE);
            }
            size = backend->resultSize(server, backend->context, sessionId, sessionContext, nodeId, *endIndex, *startIndex);
        } else if (end == LLONG_MIN) {
            *endIndex = lastIndex;
            if (returnBounds) {
                *addLast = true;
                *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, start, MATCH_EQUAL_OR_BEFORE);
                if (*startIndex == storeEnd) {
                    *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, start, MATCH_AFTER);
                    *addFirst = true;
                }
            } else {
                *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, start, MATCH_EQUAL_OR_AFTER);
            }
            size = backend->resultSize(server, backend->context, sessionId, sessionContext, nodeId, *startIndex, *endIndex);
        } else if (*reverse) {
            if (returnBounds) {
                *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, start, MATCH_EQUAL_OR_AFTER);
                if (*startIndex == storeEnd) {
                    *addFirst = true;
                    *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, start, MATCH_BEFORE);
                }
                *endIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, end, MATCH_EQUAL_OR_BEFORE);
                if (*endIndex == storeEnd) {
                    *addLast = true;
                    *endIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, end, MATCH_AFTER);
                }
            } else {
                *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, start, MATCH_EQUAL_OR_BEFORE);
                *endIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, end, MATCH_AFTER);
            }
            size = backend->resultSize(server, backend->context, sessionId, sessionContext, nodeId, *endIndex, *startIndex);
        } else {
            if (returnBounds) {
                *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, start, MATCH_EQUAL_OR_BEFORE);
                if (*startIndex == storeEnd) {
                    *addFirst = true;
                    *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, start, MATCH_AFTER);
                }
                *endIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, end, MATCH_EQUAL_OR_AFTER);
                if (*endIndex == storeEnd) {
                    *addLast = true;
                    *endIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, end, MATCH_BEFORE);
                }
            } else {
                *startIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, start, MATCH_EQUAL_OR_AFTER);
                *endIndex = backend->getDateTimeMatch(server, backend->context, sessionId, sessionContext, nodeId, end, MATCH_BEFORE);
            }
            size = backend->resultSize(server, backend->context, sessionId, sessionContext, nodeId, *startIndex, *endIndex);
        }
    } else if (returnBounds) {
        *addLast = true;
        *addFirst = true;
    }

    if (*addLast)
        ++size;
    if (*addFirst)
        ++size;

    if (numValuesPerNode > 0 && size > numValuesPerNode) {
        size = numValuesPerNode;
        *addLast = false;
    }
    return size;
}

static UA_StatusCode
getHistoryData_service_default(const UA_HistoryDataBackend* backend,
                               const UA_DateTime start,
                               const UA_DateTime end,
                               UA_Server *server,
                               const UA_NodeId *sessionId,
                               void *sessionContext,
                               const UA_NodeId* nodeId,
                               size_t maxSize,
                               UA_UInt32 numValuesPerNode,
                               UA_Boolean returnBounds,
                               UA_TimestampsToReturn timestampsToReturn,
                               UA_NumericRange range,
                               UA_Boolean releaseContinuationPoints,
                               const UA_ByteString *continuationPoint,
                               UA_ByteString *outContinuationPoint,
                               size_t *resultSize,
                               UA_DataValue ** result)
{
    size_t skip = 0;
    UA_ByteString backendContinuationPoint;
    UA_ByteString_init(&backendContinuationPoint);
    if (continuationPoint->length > 0) {
        if (continuationPoint->length >= sizeof(size_t)) {
            skip = *((size_t*)(continuationPoint->data));
            if (continuationPoint->length > 0) {
                backendContinuationPoint.length = continuationPoint->length - sizeof(size_t);
                backendContinuationPoint.data = continuationPoint->data + sizeof(size_t);
            }
        } else {
            return UA_STATUSCODE_BADCONTINUATIONPOINTINVALID;
        }
    }

    size_t storeEnd = backend->getEnd(server, backend->context, sessionId, sessionContext, nodeId);
    size_t startIndex;
    size_t endIndex;
    UA_Boolean addFirst;
    UA_Boolean addLast;
    UA_Boolean reverse;
    size_t _resultSize = getResultSize_service_default(backend,
                                                       server,
                                                       sessionId,
                                                       sessionContext,
                                                       nodeId,
                                                       start,
                                                       end,
                                                       numValuesPerNode == 0 ? 0 : numValuesPerNode + (UA_UInt32)skip,
                                                       returnBounds,
                                                       &startIndex,
                                                       &endIndex,
                                                       &addFirst,
                                                       &addLast,
                                                       &reverse);
    *resultSize = _resultSize - skip;
    if (*resultSize > maxSize) {
        *resultSize = maxSize;
    }
    UA_DataValue *outResult= (UA_DataValue*)UA_Array_new(*resultSize, &UA_TYPES[UA_TYPES_DATAVALUE]);
    if (!outResult) {
        *resultSize = 0;
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    *result = outResult;

    size_t counter = 0;
    if (addFirst) {
        if (skip == 0) {
            outResult[counter].hasStatus = true;
            outResult[counter].status = UA_STATUSCODE_BADBOUNDNOTFOUND;
            outResult[counter].hasSourceTimestamp = true;
            if (start == LLONG_MIN) {
                outResult[counter].sourceTimestamp = end;
            } else {
                outResult[counter].sourceTimestamp = start;
            }
            ++counter;
        }
    }
    UA_ByteString backendOutContinuationPoint;
    UA_ByteString_init(&backendOutContinuationPoint);
    if (endIndex != storeEnd && startIndex != storeEnd) {
        size_t retval = 0;

        size_t valueSize = *resultSize - counter;
        if (valueSize + skip > _resultSize - addFirst - addLast) {
            if (skip == 0) {
                valueSize = _resultSize - addFirst - addLast;
            } else {
                valueSize = _resultSize - skip - addLast;
            }

        }

        UA_StatusCode ret = UA_STATUSCODE_GOOD;
        if (valueSize > 0)
            ret = backend->copyDataValues(server,
                                          backend->context,
                                          sessionId,
                                          sessionContext,
                                          nodeId,
                                          startIndex,
                                          endIndex,
                                          reverse,
                                          valueSize,
                                          range,
                                          releaseContinuationPoints,
                                          &backendContinuationPoint,
                                          &backendOutContinuationPoint,
                                          &retval,
                                          &outResult[counter]);
        if (ret != UA_STATUSCODE_GOOD) {
            UA_Array_delete(outResult, *resultSize, &UA_TYPES[UA_TYPES_DATAVALUE]);
            *result = NULL;
            *resultSize = 0;
            return ret;
        }
        counter += retval;
    }
    if (addLast && counter < *resultSize) {
        outResult[counter].hasStatus = true;
        outResult[counter].status = UA_STATUSCODE_BADBOUNDNOTFOUND;
        outResult[counter].hasSourceTimestamp = true;
        if (start == LLONG_MIN && storeEnd != backend->firstIndex(server, backend->context, sessionId, sessionContext, nodeId)) {
            outResult[counter].sourceTimestamp = backend->getDataValue(server, backend->context, sessionId, sessionContext, nodeId, endIndex)->sourceTimestamp - UA_DATETIME_SEC;
        } else if (end == LLONG_MIN && storeEnd != backend->firstIndex(server, backend->context, sessionId, sessionContext, nodeId)) {
            outResult[counter].sourceTimestamp = backend->getDataValue(server, backend->context, sessionId, sessionContext, nodeId, endIndex)->sourceTimestamp + UA_DATETIME_SEC;
        } else {
            outResult[counter].sourceTimestamp = end;
        }
    }
    // there are more values
    if (skip + *resultSize < _resultSize
            // there are not more values for this request, but there are more values in database
            || (backendOutContinuationPoint.length > 0
                && numValuesPerNode != 0)
            // we deliver just one value which is a FIRST/LAST value
            || (skip == 0
                && addFirst == true
                && *resultSize == 1)) {
        if(UA_ByteString_allocBuffer(outContinuationPoint, backendOutContinuationPoint.length + sizeof(size_t))
                != UA_STATUSCODE_GOOD) {
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }
        *((size_t*)(outContinuationPoint->data)) = skip + *resultSize;
        if(backendOutContinuationPoint.length > 0)
            memcpy(outContinuationPoint->data + sizeof(size_t), backendOutContinuationPoint.data, backendOutContinuationPoint.length);
    }
    UA_ByteString_clear(&backendOutContinuationPoint);
    return UA_STATUSCODE_GOOD;
}

static void
updateData_service_default(UA_Server *server,
                           void *hdbContext,
                           const UA_NodeId *sessionId,
                           void *sessionContext,
                           const UA_RequestHeader *requestHeader,
                           const UA_UpdateDataDetails *details,
                           UA_HistoryUpdateResult *result)
{
    UA_HistoryDatabaseContext_default *ctx = (UA_HistoryDatabaseContext_default*)hdbContext;
    UA_Byte accessLevel = 0;
    UA_Server_readAccessLevel(server,
                              details->nodeId,
                              &accessLevel);
    if (!(accessLevel & UA_ACCESSLEVELMASK_HISTORYWRITE)) {
        result->statusCode = UA_STATUSCODE_BADUSERACCESSDENIED;
        return;
    }

    UA_Boolean historizing = false;
    UA_Server_readHistorizing(server,
                              details->nodeId,
                              &historizing);
    if (!historizing) {
        result->statusCode = UA_STATUSCODE_BADHISTORYOPERATIONINVALID;
        return;
    }
    const UA_HistorizingNodeIdSettings *setting = ctx->gathering.getHistorizingSetting(
                server,
                ctx->gathering.context,
                &details->nodeId);

    if (!setting) {
        result->statusCode = UA_STATUSCODE_BADHISTORYOPERATIONINVALID;
        return;
    }

    UA_ServerConfig *config = UA_Server_getConfig(server);
    result->operationResultsSize = details->updateValuesSize;
    result->operationResults = (UA_StatusCode*)UA_Array_new(result->operationResultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
    for (size_t i = 0; i < details->updateValuesSize; ++i) {
        if (config->accessControl.allowHistoryUpdateUpdateData &&
            !config->accessControl.allowHistoryUpdateUpdateData(server, &config->accessControl, sessionId, sessionContext,
                                                                &details->nodeId, details->performInsertReplace,
                                                                &details->updateValues[i])) {
            result->operationResults[i] = UA_STATUSCODE_BADUSERACCESSDENIED;
            continue;
        }
        switch (details->performInsertReplace) {
        case UA_PERFORMUPDATETYPE_INSERT:
            if (!setting->historizingBackend.insertDataValue) {
                result->operationResults[i] = UA_STATUSCODE_BADHISTORYOPERATIONUNSUPPORTED;
                continue;
            }
            result->operationResults[i]
                    = setting->historizingBackend.insertDataValue(server,
                                                                  setting->historizingBackend.context,
                                                                  sessionId,
                                                                  sessionContext,
                                                                  &details->nodeId,
                                                                  &details->updateValues[i]);
            continue;
        case UA_PERFORMUPDATETYPE_REPLACE:
            if (!setting->historizingBackend.replaceDataValue) {
                result->operationResults[i] = UA_STATUSCODE_BADHISTORYOPERATIONUNSUPPORTED;
                continue;
            }
            result->operationResults[i]
                    = setting->historizingBackend.replaceDataValue(server,
                                                                   setting->historizingBackend.context,
                                                                   sessionId,
                                                                   sessionContext,
                                                                   &details->nodeId,
                                                                   &details->updateValues[i]);
            continue;
        case UA_PERFORMUPDATETYPE_UPDATE:
            if (!setting->historizingBackend.updateDataValue) {
                result->operationResults[i] = UA_STATUSCODE_BADHISTORYOPERATIONUNSUPPORTED;
                continue;
            }
            result->operationResults[i]
                    = setting->historizingBackend.updateDataValue(server,
                                                                  setting->historizingBackend.context,
                                                                  sessionId,
                                                                  sessionContext,
                                                                  &details->nodeId,
                                                                  &details->updateValues[i]);
            continue;
        default:
            result->operationResults[i] = UA_STATUSCODE_BADHISTORYOPERATIONINVALID;
            continue;
        }
    }
}


static void
deleteRawModified_service_default(UA_Server *server,
                                  void *hdbContext,
                                  const UA_NodeId *sessionId,
                                  void *sessionContext,
                                  const UA_RequestHeader *requestHeader,
                                  const UA_DeleteRawModifiedDetails *details,
                                  UA_HistoryUpdateResult *result)
{
    if (details->isDeleteModified) {
        result->statusCode = UA_STATUSCODE_BADHISTORYOPERATIONUNSUPPORTED;
        return;
    }
    UA_HistoryDatabaseContext_default *ctx = (UA_HistoryDatabaseContext_default*)hdbContext;
    UA_Byte accessLevel = 0;
    UA_Server_readAccessLevel(server,
                              details->nodeId,
                              &accessLevel);
    if (!(accessLevel & UA_ACCESSLEVELMASK_HISTORYWRITE)) {
        result->statusCode = UA_STATUSCODE_BADUSERACCESSDENIED;
        return;
    }

    UA_Boolean historizing = false;
    UA_Server_readHistorizing(server,
                              details->nodeId,
                              &historizing);
    if (!historizing) {
        result->statusCode = UA_STATUSCODE_BADHISTORYOPERATIONINVALID;
        return;
    }
    const UA_HistorizingNodeIdSettings *setting = ctx->gathering.getHistorizingSetting(
                server,
                ctx->gathering.context,
                &details->nodeId);

    if (!setting) {
        result->statusCode = UA_STATUSCODE_BADHISTORYOPERATIONINVALID;
        return;
    }
    if (!setting->historizingBackend.removeDataValue) {
        result->statusCode = UA_STATUSCODE_BADHISTORYOPERATIONUNSUPPORTED;
        return;
    }

    UA_ServerConfig *config = UA_Server_getConfig(server);
    if (config->accessControl.allowHistoryUpdateDeleteRawModified &&
        !config->accessControl.allowHistoryUpdateDeleteRawModified(server,
                 &config->accessControl, sessionId, sessionContext, &details->nodeId,
                 details->startTime, details->endTime, details->isDeleteModified)) {
        result->statusCode = UA_STATUSCODE_BADUSERACCESSDENIED;
        return;
    }

    result->statusCode
            = setting->historizingBackend.removeDataValue(server,
                                                          setting->historizingBackend.context,
                                                          sessionId,
                                                          sessionContext,
                                                          &details->nodeId,
                                                          details->startTime,
                                                          details->endTime);
}

static void
readRaw_service_default(UA_Server *server,
                        void *context,
                        const UA_NodeId *sessionId,
                        void *sessionContext,
                        const UA_RequestHeader *requestHeader,
                        const UA_ReadRawModifiedDetails *historyReadDetails,
                        UA_TimestampsToReturn timestampsToReturn,
                        UA_Boolean releaseContinuationPoints,
                        size_t nodesToReadSize,
                        const UA_HistoryReadValueId *nodesToRead,
                        UA_HistoryReadResponse *response,
                        UA_HistoryData * const * const historyData)
{
    UA_HistoryDatabaseContext_default *ctx = (UA_HistoryDatabaseContext_default*)context;
    for (size_t i = 0; i < nodesToReadSize; ++i) {
        UA_Byte accessLevel = 0;
        UA_Server_readAccessLevel(server,
                                  nodesToRead[i].nodeId,
                                  &accessLevel);
        if (!(accessLevel & UA_ACCESSLEVELMASK_HISTORYREAD)) {
            response->results[i].statusCode = UA_STATUSCODE_BADUSERACCESSDENIED;
            continue;
        }

        UA_Boolean historizing = false;
        UA_Server_readHistorizing(server,
                                  nodesToRead[i].nodeId,
                                  &historizing);
        if (!historizing) {
            response->results[i].statusCode = UA_STATUSCODE_BADHISTORYOPERATIONINVALID;
            continue;
        }

        const UA_HistorizingNodeIdSettings *setting = ctx->gathering.getHistorizingSetting(
                    server,
                    ctx->gathering.context,
                    &nodesToRead[i].nodeId);

        if (!setting) {
            response->results[i].statusCode = UA_STATUSCODE_BADHISTORYOPERATIONINVALID;
            continue;
        }

        if (historyReadDetails->returnBounds && !setting->historizingBackend.boundSupported(
                    server,
                    setting->historizingBackend.context,
                    sessionId,
                    sessionContext,
                    &nodesToRead[i].nodeId)) {
            response->results[i].statusCode = UA_STATUSCODE_BADBOUNDNOTSUPPORTED;
            continue;
        }

        if (!setting->historizingBackend.timestampsToReturnSupported(
                    server,
                    setting->historizingBackend.context,
                    sessionId,
                    sessionContext,
                    &nodesToRead[i].nodeId,
                    timestampsToReturn)) {
            response->results[i].statusCode = UA_STATUSCODE_BADTIMESTAMPNOTSUPPORTED;
            continue;
        }

        UA_NumericRange range;
        range.dimensionsSize = 0;
        range.dimensions = NULL;
        if (nodesToRead[i].indexRange.length > 0) {
            UA_StatusCode rangeParseResult = UA_NumericRange_parse(&range, nodesToRead[i].indexRange);
            if (rangeParseResult != UA_STATUSCODE_GOOD) {
                response->results[i].statusCode = rangeParseResult;
                continue;
            }
        }

        UA_StatusCode getHistoryDataStatusCode;
        if (setting->historizingBackend.getHistoryData) {
            getHistoryDataStatusCode = setting->historizingBackend.getHistoryData(
                        server,
                        sessionId,
                        sessionContext,
                        &setting->historizingBackend,
                        historyReadDetails->startTime,
                        historyReadDetails->endTime,
                        &nodesToRead[i].nodeId,
                        setting->maxHistoryDataResponseSize,
                        historyReadDetails->numValuesPerNode,
                        historyReadDetails->returnBounds,
                        timestampsToReturn,
                        range,
                        releaseContinuationPoints,
                        &nodesToRead[i].continuationPoint,
                        &response->results[i].continuationPoint,
                        historyData[i]);
        } else {
            getHistoryDataStatusCode = getHistoryData_service_default(
                        &setting->historizingBackend,
                        historyReadDetails->startTime,
                        historyReadDetails->endTime,
                        server,
                        sessionId,
                        sessionContext,
                        &nodesToRead[i].nodeId,
                        setting->maxHistoryDataResponseSize,
                        historyReadDetails->numValuesPerNode,
                        historyReadDetails->returnBounds,
                        timestampsToReturn,
                        range,
                        releaseContinuationPoints,
                        &nodesToRead[i].continuationPoint,
                        &response->results[i].continuationPoint,
                        &historyData[i]->dataValuesSize,
                        &historyData[i]->dataValues);
        }
        if (getHistoryDataStatusCode != UA_STATUSCODE_GOOD) {
            response->results[i].statusCode = getHistoryDataStatusCode;
            continue;
        }
    }
    response->responseHeader.serviceResult = UA_STATUSCODE_GOOD;
    return;
}

static void
setValue_service_default(UA_Server *server,
                         void *context,
                         const UA_NodeId *sessionId,
                         void *sessionContext,
                         const UA_NodeId *nodeId,
                         UA_Boolean historizing,
                         const UA_DataValue *value)
{
    UA_HistoryDatabaseContext_default *ctx = (UA_HistoryDatabaseContext_default*)context;
    if (ctx->gathering.setValue)
        ctx->gathering.setValue(server,
                                ctx->gathering.context,
                                sessionId,
                                sessionContext,
                                nodeId,
                                historizing,
                                value);
}

static void
clear_service_default(UA_HistoryDatabase *hdb)
{
    if (hdb == NULL || hdb->context == NULL)
        return;
    UA_HistoryDatabaseContext_default *ctx = (UA_HistoryDatabaseContext_default*)hdb->context;
    ctx->gathering.deleteMembers(&ctx->gathering);
    UA_free(ctx);
}

UA_HistoryDatabase
UA_HistoryDatabase_default(UA_HistoryDataGathering gathering)
{
    UA_HistoryDatabase hdb;
    memset(&hdb, 0, sizeof(UA_HistoryDatabase));
    UA_HistoryDatabaseContext_default *context =
            (UA_HistoryDatabaseContext_default*)
            UA_calloc(1, sizeof(UA_HistoryDatabaseContext_default));
    context->gathering = gathering;
    hdb.context = context;
    hdb.readRaw = &readRaw_service_default;
    hdb.setValue = &setValue_service_default;
    hdb.updateData = &updateData_service_default;
    hdb.deleteRawModified = &deleteRawModified_service_default;
    hdb.clear = clear_service_default;
    return hdb;
}

/**** amalgamated original file "/plugins/ua_log_syslog.c" ****/

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
 *
 *    Copyright 2020 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 */


#if defined(__linux__) || defined(__unix__)

#include <syslog.h>
#include <stdio.h>

const char *syslogLevelNames[6] = {"trace", "debug", "info",
                                   "warn", "error", "fatal"};
const char *syslogCategoryNames[UA_LOGCATEGORIES] =
    {"network", "channel", "session", "server", "client",
     "userland", "securitypolicy", "eventloop", "pubsub", "discovery"};

#ifdef __clang__
__attribute__((__format__(__printf__, 4 , 0)))
#endif
static void
UA_Log_Syslog_log(void *context, UA_LogLevel level, UA_LogCategory category,
                  const char *msg, va_list args) {
    /* Assume that context is casted to UA_LogLevel */
    if(context != NULL && (UA_LogLevel)(uintptr_t)context > level)
        return;

    int priority = LOG_INFO;
    switch(level) {
    case UA_LOGLEVEL_DEBUG:
        priority = LOG_DEBUG;
        break;
    case UA_LOGLEVEL_INFO:
        priority = LOG_INFO;
        break;
    case UA_LOGLEVEL_WARNING:
        priority = LOG_WARNING;
        break;
    case UA_LOGLEVEL_ERROR:
        priority = LOG_ERR;
        break;
    case UA_LOGLEVEL_FATAL:
        priority = LOG_CRIT;
        break;
    case UA_LOGLEVEL_TRACE:
    default:
        return;
    }

    int logLevelSlot = ((int)level / 100) - 1;
    if(logLevelSlot < 0 || logLevelSlot > 5)
        logLevelSlot = 5; /* Set to fatal if the level is outside the range */

#define LOGBUFSIZE 512
    char logbuf[LOGBUFSIZE];
    int pos = snprintf(logbuf, LOGBUFSIZE, "[%s/%s] ",
                       syslogLevelNames[logLevelSlot],
                       syslogCategoryNames[category]);
    if(pos < 0) {
        syslog(LOG_WARNING, "Log message too long for syslog");
        return;
    }
    pos = vsnprintf(&logbuf[pos], LOGBUFSIZE - (size_t)pos, msg, args);
    if(pos < 0) {
        syslog(LOG_WARNING, "Log message too long for syslog");
        return;
    }

    syslog(priority, "%s", logbuf);
}

static void
UA_Log_Syslog_clear(UA_Logger *logger) {
    /* closelog is optional. We don't use it as several loggers might be
     * instantiated in parallel. */
    /* closelog(); */
    UA_free(logger);
}

UA_Logger
UA_Log_Syslog(void) {
    return UA_Log_Syslog_withLevel(UA_LOGLEVEL_TRACE);
}

UA_Logger
UA_Log_Syslog_withLevel(UA_LogLevel minlevel) {
    UA_Logger logger = {UA_Log_Syslog_log, (void*)(uintptr_t)minlevel, NULL};
    return logger;
}

UA_Logger *
UA_Log_Syslog_new(UA_LogLevel minlevel) {
    UA_Logger *logger = (UA_Logger*)UA_malloc(sizeof(UA_Logger));
    if(!logger)
        return NULL;
    *logger = UA_Log_Syslog_withLevel(minlevel);
    logger->clear = UA_Log_Syslog_clear;
    return logger;
}

#endif

/**** amalgamated original file "/plugins/crypto/mbedtls/ua_securitypolicy_basic128rsa15.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2018-2019 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2019 (c) Kalycito Infotech Private Limited
 *    Copyright 2018 (c) HMS Industrial Networks AB (Author: Jonas Green)
 *    Copyright 2020 (c) Wind River Systems, Inc.
 *    Copyright 2020 (c) basysKom GmbH
 *
 */


#ifdef UA_ENABLE_ENCRYPTION_MBEDTLS


#include <mbedtls/aes.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
#include <mbedtls/error.h>
#include <mbedtls/md.h>
#include <mbedtls/sha1.h>
#include <mbedtls/version.h>
#include <mbedtls/x509_crt.h>

/* Notes:
 * mbedTLS' AES allows in-place encryption and decryption. Sow we don't have to
 * allocate temp buffers.
 * https://tls.mbed.org/discussions/generic/in-place-decryption-with-aes256-same-input-output-buffer
 */

#define UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN 11
#define UA_SECURITYPOLICY_BASIC128RSA15_SYM_KEY_LENGTH 16
#define UA_BASIC128RSA15_SYM_SIGNING_KEY_LENGTH 16
#define UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_BASIC128RSA15_SYM_PLAIN_TEXT_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_BASIC128RSA15_MINASYMKEYLENGTH 128
#define UA_SECURITYPOLICY_BASIC128RSA15_MAXASYMKEYLENGTH 512

typedef struct {
    UA_ByteString localCertThumbprint;

    mbedtls_ctr_drbg_context drbgContext;
    mbedtls_entropy_context entropyContext;
    mbedtls_md_context_t sha1MdContext;
    mbedtls_pk_context localPrivateKey;
} Basic128Rsa15_PolicyContext;

typedef struct {
    Basic128Rsa15_PolicyContext *policyContext;

    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;

    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    mbedtls_x509_crt remoteCertificate;
} Basic128Rsa15_ChannelContext;

/********************/
/* AsymmetricModule */
/********************/

static UA_StatusCode
asym_verify_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc,
                             const UA_ByteString *message,
                             const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    return mbedtls_verifySig_sha1(&cc->remoteCertificate, message, signature);
}

static UA_StatusCode
asym_sign_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc,
                           const UA_ByteString *message,
                           UA_ByteString *signature) {
    if(message == NULL || signature == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Basic128Rsa15_PolicyContext *pc = cc->policyContext;
    return mbedtls_sign_sha1(&pc->localPrivateKey, &pc->drbgContext,
                             message, signature);
}

static size_t
asym_getLocalSignatureSize_sp_basic128rsa15(const Basic128Rsa15_ChannelContext *cc) {
    if(cc == NULL)
        return 0;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    return mbedtls_pk_rsa(cc->policyContext->localPrivateKey)->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->policyContext->localPrivateKey));
#endif
}

static size_t
asym_getRemoteSignatureSize_sp_basic128rsa15(const Basic128Rsa15_ChannelContext *cc) {
    if(cc == NULL)
        return 0;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    return mbedtls_pk_rsa(cc->remoteCertificate.pk)->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
#endif
}

static UA_StatusCode
asym_encrypt_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc,
                              UA_ByteString *data) {
    if(cc == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    mbedtls_rsa_context *remoteRsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    mbedtls_rsa_set_padding(remoteRsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_NONE);

#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    size_t keylen = remoteRsaContext->len;
#else
    size_t keylen = mbedtls_rsa_get_len(remoteRsaContext);
#endif
    size_t plainTextBlockSize =
        keylen - UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN;
    if(data->length % plainTextBlockSize != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t blocks = data->length / plainTextBlockSize;
    UA_ByteString encrypted;
    UA_StatusCode retval = UA_ByteString_allocBuffer(&encrypted, blocks * keylen);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    size_t lenDataToEncrypt = data->length;
    size_t inOffset = 0;
    size_t offset = 0;
    size_t outLength = 0;
    Basic128Rsa15_PolicyContext *pc = cc->policyContext;
    while(lenDataToEncrypt >= plainTextBlockSize) {
        int mbedErr = mbedtls_pk_encrypt(&cc->remoteCertificate.pk,
                                         data->data + inOffset, plainTextBlockSize,
                                         encrypted.data + offset, &outLength,
                                         encrypted.length - offset,
                                         mbedtls_ctr_drbg_random,
                                         &pc->drbgContext);
        if(mbedErr) {
            UA_ByteString_clear(&encrypted);
            return UA_STATUSCODE_BADINTERNALERROR;
        }

        inOffset += plainTextBlockSize;
        offset += outLength;
        lenDataToEncrypt -= plainTextBlockSize;
    }

    memcpy(data->data, encrypted.data, offset);
    UA_ByteString_clear(&encrypted);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
asym_decrypt_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc,
                              UA_ByteString *data) {
    if(cc == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Basic128Rsa15_PolicyContext *pc = cc->policyContext;
    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(pc->localPrivateKey);
    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_NONE);
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    size_t keylen = rsaContext->len;
#else
    size_t keylen = mbedtls_rsa_get_len(rsaContext);
#endif
    if(data->length % keylen != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t inOffset = 0;
    size_t outOffset = 0;
    size_t outLength = 0;
    unsigned char buf[512];

    while(inOffset < data->length) {
        int mbedErr = mbedtls_pk_decrypt(&pc->localPrivateKey,
                                         data->data + inOffset, keylen,
                                         buf, &outLength, 512,
                                         mbedtls_ctr_drbg_random,
                                         &pc->drbgContext);
        if(mbedErr)
            return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

        memcpy(data->data + outOffset, buf, outLength);
        inOffset += keylen;
        outOffset += outLength;
    }

    data->length = outOffset;
    return UA_STATUSCODE_GOOD;
}

static size_t
asym_getLocalEncryptionKeyLength_sp_basic128rsa15(const Basic128Rsa15_ChannelContext *cc) {
    if(cc == NULL)
        return 0;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    return rsaContext->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
#endif
}

static size_t
asym_getRemoteEncryptionKeyLength_sp_basic128rsa15(const Basic128Rsa15_ChannelContext *cc) {
    return mbedtls_pk_get_len(&cc->remoteCertificate.pk) * 8;
}

static size_t
asym_getRemoteBlockSize_sp_basic128rsa15(const Basic128Rsa15_ChannelContext *cc) {
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    return rsaContext->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
#endif
}

static size_t
asym_getRemotePlainTextBlockSize_sp_basic128rsa15(const Basic128Rsa15_ChannelContext *cc) {
    if(cc == NULL)
        return 0;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    return rsaContext->len - UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk)) -
        UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN;
#endif
}

static UA_StatusCode
asym_makeThumbprint_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
                                     const UA_ByteString *certificate,
                                     UA_ByteString *thumbprint) {
    if(securityPolicy == NULL || certificate == NULL || thumbprint == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    return mbedtls_thumbprint_sha1(certificate, thumbprint);
}

static UA_StatusCode
asymmetricModule_compareCertificateThumbprint_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
                                                               const UA_ByteString *certificateThumbprint) {
    if(securityPolicy == NULL || certificateThumbprint == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Basic128Rsa15_PolicyContext *pc = (Basic128Rsa15_PolicyContext *)securityPolicy->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
        return UA_STATUSCODE_BADCERTIFICATEINVALID;

    return UA_STATUSCODE_GOOD;
}

/*******************/
/* SymmetricModule */
/*******************/

static UA_StatusCode
sym_verify_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc,
                            const UA_ByteString *message,
                            const UA_ByteString *signature) {
    if(cc == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Compute MAC */
    if(signature->length != UA_SHA1_LENGTH)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    Basic128Rsa15_PolicyContext *pc = cc->policyContext;

    unsigned char mac[UA_SHA1_LENGTH];
    if(mbedtls_hmac(&pc->sha1MdContext, &cc->remoteSymSigningKey,
                    message, mac) != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Compare with Signature */
    if(!UA_constantTimeEqual(signature->data, mac, UA_SHA1_LENGTH))
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
sym_sign_sp_basic128rsa15(const Basic128Rsa15_ChannelContext *cc,
                          const UA_ByteString *message,
                          UA_ByteString *signature) {
    if(signature->length != UA_SHA1_LENGTH)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(mbedtls_hmac(&cc->policyContext->sha1MdContext, &cc->localSymSigningKey,
                    message, signature->data) != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    return UA_STATUSCODE_GOOD;
}

static size_t
sym_getSignatureSize_sp_basic128rsa15(const void *channelContext) {
    return UA_SHA1_LENGTH;
}

static size_t
sym_getSigningKeyLength_sp_basic128rsa15(const void *const channelContext) {
    return UA_BASIC128RSA15_SYM_SIGNING_KEY_LENGTH;
}

static size_t
sym_getEncryptionKeyLength_sp_basic128rsa15(const void *channelContext) {
    return UA_SECURITYPOLICY_BASIC128RSA15_SYM_KEY_LENGTH;
}

static size_t
sym_getEncryptionBlockSize_sp_basic128rsa15(const void *const channelContext) {
    return UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_BLOCK_SIZE;
}

static size_t
sym_getPlainTextBlockSize_sp_basic128rsa15(const void *const channelContext) {
    return UA_SECURITYPOLICY_BASIC128RSA15_SYM_PLAIN_TEXT_BLOCK_SIZE;
}

static UA_StatusCode
sym_encrypt_sp_basic128rsa15(const Basic128Rsa15_ChannelContext *cc,
                             UA_ByteString *data) {
    if(cc == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(cc->localSymIv.length != UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_BLOCK_SIZE)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t plainTextBlockSize = UA_SECURITYPOLICY_BASIC128RSA15_SYM_PLAIN_TEXT_BLOCK_SIZE;
    if(data->length % plainTextBlockSize != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Keylength in bits */
    unsigned int keylength = (unsigned int)(cc->localSymEncryptingKey.length * 8);
    mbedtls_aes_context aesContext;
    int mbedErr = mbedtls_aes_setkey_enc(&aesContext, cc->localSymEncryptingKey.data, keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString ivCopy;
    UA_StatusCode retval = UA_ByteString_copy(&cc->localSymIv, &ivCopy);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_ENCRYPT, data->length,
                                    ivCopy.data, data->data, data->data);
    if(mbedErr)
        retval = UA_STATUSCODE_BADINTERNALERROR;
    UA_ByteString_clear(&ivCopy);
    return retval;
}

static UA_StatusCode
sym_decrypt_sp_basic128rsa15(const Basic128Rsa15_ChannelContext *cc,
                             UA_ByteString *data) {
    if(cc == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t encryptionBlockSize = UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_BLOCK_SIZE;
    if(cc->remoteSymIv.length != encryptionBlockSize)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(data->length % encryptionBlockSize != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned int keylength = (unsigned int)(cc->remoteSymEncryptingKey.length * 8);
    mbedtls_aes_context aesContext;
    int mbedErr = mbedtls_aes_setkey_dec(&aesContext,
                                         cc->remoteSymEncryptingKey.data, keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString ivCopy;
    UA_StatusCode retval = UA_ByteString_copy(&cc->remoteSymIv, &ivCopy);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_DECRYPT, data->length,
                                    ivCopy.data, data->data, data->data);
    if(mbedErr)
        retval = UA_STATUSCODE_BADINTERNALERROR;
    UA_ByteString_clear(&ivCopy);
    return retval;
}

static UA_StatusCode
sym_generateKey_sp_basic128rsa15(void *policyContext, const UA_ByteString *secret,
                                 const UA_ByteString *seed, UA_ByteString *out) {
    if(secret == NULL || seed == NULL || out == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic128Rsa15_PolicyContext *pc = (Basic128Rsa15_PolicyContext *)policyContext;
    return mbedtls_generateKey(&pc->sha1MdContext, secret, seed, out);
}

static UA_StatusCode
sym_generateNonce_sp_basic128rsa15(void *policyContext, UA_ByteString *out) {
    if(out == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic128Rsa15_PolicyContext *pc = (Basic128Rsa15_PolicyContext *)policyContext;
    int mbedErr = mbedtls_ctr_drbg_random(&pc->drbgContext, out->data, out->length);
    if(mbedErr)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_STATUSCODE_GOOD;
}

/*****************/
/* ChannelModule */
/*****************/

/* Assumes that the certificate has been verified externally */
static UA_StatusCode
parseRemoteCertificate_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc,
                                        const UA_ByteString *remoteCertificate) {
    if(remoteCertificate == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Parse the certificate */
    int mbedErr = mbedtls_x509_crt_parse(&cc->remoteCertificate, remoteCertificate->data,
                                         remoteCertificate->length);
    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Check the key length */
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    if(rsaContext->len < UA_SECURITYPOLICY_BASIC128RSA15_MINASYMKEYLENGTH ||
       rsaContext->len > UA_SECURITYPOLICY_BASIC128RSA15_MAXASYMKEYLENGTH)
        return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;
#else
    size_t keylen = mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
    if(keylen < UA_SECURITYPOLICY_BASIC128RSA15_MINASYMKEYLENGTH ||
       keylen > UA_SECURITYPOLICY_BASIC128RSA15_MAXASYMKEYLENGTH)
        return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;
#endif
    return UA_STATUSCODE_GOOD;
}

static void
channelContext_deleteContext_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc) {
    UA_ByteString_clear(&cc->localSymSigningKey);
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    UA_ByteString_clear(&cc->localSymIv);
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    UA_ByteString_clear(&cc->remoteSymIv);
    mbedtls_x509_crt_free(&cc->remoteCertificate);
    UA_free(cc);
}

static UA_StatusCode
channelContext_newContext_sp_basic128rsa15(const UA_SecurityPolicy *securityPolicy,
                                           const UA_ByteString *remoteCertificate,
                                           void **pp_contextData) {
    if(securityPolicy == NULL || remoteCertificate == NULL || pp_contextData == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Allocate the channel context */
    *pp_contextData = UA_malloc(sizeof(Basic128Rsa15_ChannelContext));
    if(*pp_contextData == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    Basic128Rsa15_ChannelContext *cc = (Basic128Rsa15_ChannelContext *)*pp_contextData;

    /* Initialize the channel context */
    cc->policyContext = (Basic128Rsa15_PolicyContext *)securityPolicy->policyContext;

    UA_ByteString_init(&cc->localSymSigningKey);
    UA_ByteString_init(&cc->localSymEncryptingKey);
    UA_ByteString_init(&cc->localSymIv);

    UA_ByteString_init(&cc->remoteSymSigningKey);
    UA_ByteString_init(&cc->remoteSymEncryptingKey);
    UA_ByteString_init(&cc->remoteSymIv);

    mbedtls_x509_crt_init(&cc->remoteCertificate);

    // TODO: this can be optimized so that we dont allocate memory before parsing the certificate
    UA_StatusCode retval = parseRemoteCertificate_sp_basic128rsa15(cc, remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        channelContext_deleteContext_sp_basic128rsa15(cc);
        *pp_contextData = NULL;
    }
    return retval;
}

static UA_StatusCode
channelContext_setLocalSymEncryptingKey_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc,
                                                         const UA_ByteString *key) {
    if(key == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
channelContext_setLocalSymSigningKey_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc,
                                                      const UA_ByteString *key) {
    if(key == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}


static UA_StatusCode
channelContext_setLocalSymIv_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc,
                                              const UA_ByteString *iv) {
    if(iv == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static UA_StatusCode
channelContext_setRemoteSymEncryptingKey_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc,
                                                          const UA_ByteString *key) {
    if(key == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
channelContext_setRemoteSymSigningKey_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc,
                                                       const UA_ByteString *key) {
    if(key == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
channelContext_setRemoteSymIv_sp_basic128rsa15(Basic128Rsa15_ChannelContext *cc,
                                               const UA_ByteString *iv) {
    if(iv == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(iv, &cc->remoteSymIv);
}

static UA_StatusCode
channelContext_compareCertificate_sp_basic128rsa15(const Basic128Rsa15_ChannelContext *cc,
                                                   const UA_ByteString *certificate) {
    if(cc == NULL || certificate == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    mbedtls_x509_crt cert;
    mbedtls_x509_crt_init(&cert);
    int mbedErr = mbedtls_x509_crt_parse(&cert, certificate->data, certificate->length);
    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(cert.raw.len != cc->remoteCertificate.raw.len ||
       memcmp(cert.raw.p, cc->remoteCertificate.raw.p, cert.raw.len) != 0)
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    mbedtls_x509_crt_free(&cert);
    return retval;
}

static void
clear_sp_basic128rsa15(UA_SecurityPolicy *securityPolicy) {
    if(securityPolicy == NULL)
        return;

    UA_ByteString_clear(&securityPolicy->localCertificate);

    if(securityPolicy->policyContext == NULL)
        return;

    /* delete all allocated members in the context */
    Basic128Rsa15_PolicyContext *pc = (Basic128Rsa15_PolicyContext *)
        securityPolicy->policyContext;

    mbedtls_ctr_drbg_free(&pc->drbgContext);
    mbedtls_entropy_free(&pc->entropyContext);
    mbedtls_pk_free(&pc->localPrivateKey);
    mbedtls_md_free(&pc->sha1MdContext);
    UA_ByteString_clear(&pc->localCertThumbprint);

    UA_LOG_DEBUG(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Deleted members of EndpointContext for sp_basic128rsa15");

    UA_free(pc);
    securityPolicy->policyContext = NULL;
}

static UA_StatusCode
updateCertificateAndPrivateKey_sp_basic128rsa15(UA_SecurityPolicy *securityPolicy,
                                                const UA_ByteString newCertificate,
                                                const UA_ByteString newPrivateKey) {
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(securityPolicy->policyContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Basic128Rsa15_PolicyContext *pc = (Basic128Rsa15_PolicyContext *)securityPolicy->policyContext;

    UA_ByteString_clear(&securityPolicy->localCertificate);

    UA_StatusCode retval = UA_mbedTLS_LoadLocalCertificate(&newCertificate, &securityPolicy->localCertificate);

    if (retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Set the new private key */
    mbedtls_pk_free(&pc->localPrivateKey);
    mbedtls_pk_init(&pc->localPrivateKey);
    int mbedErr = UA_mbedTLS_LoadPrivateKey(&newPrivateKey, &pc->localPrivateKey, &pc->entropyContext);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    retval = asym_makeThumbprint_sp_basic128rsa15(securityPolicy,
                                                  &securityPolicy->localCertificate,
                                                  &pc->localCertThumbprint);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return retval;

    error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext != NULL)
        clear_sp_basic128rsa15(securityPolicy);
    return retval;
}

static UA_StatusCode
policyContext_newContext_sp_basic128rsa15(UA_SecurityPolicy *securityPolicy,
                                          const UA_ByteString localPrivateKey) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if (localPrivateKey.length == 0) {
        UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                     "Can not initialize security policy. Private key is empty.");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    Basic128Rsa15_PolicyContext *pc = (Basic128Rsa15_PolicyContext *)
        UA_malloc(sizeof(Basic128Rsa15_PolicyContext));
    securityPolicy->policyContext = (void *)pc;
    if(!pc) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto error;
    }

    /* Initialize the PolicyContext */
    memset(pc, 0, sizeof(Basic128Rsa15_PolicyContext));
    mbedtls_ctr_drbg_init(&pc->drbgContext);
    mbedtls_entropy_init(&pc->entropyContext);
    mbedtls_pk_init(&pc->localPrivateKey);
    mbedtls_md_init(&pc->sha1MdContext);

    /* Initialized the message digest */
    const mbedtls_md_info_t *const mdInfo = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
    int mbedErr = mbedtls_md_setup(&pc->sha1MdContext, mdInfo, MBEDTLS_MD_SHA1);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto error;
    }

    mbedErr = mbedtls_entropy_self_test(0);

    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Seed the RNG */
    char *personalization = "open62541-drbg";
    mbedErr = mbedtls_ctr_drbg_seed(&pc->drbgContext, mbedtls_entropy_func,
                                    &pc->entropyContext,
                                    (const unsigned char *)personalization, 14);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Set the private key */
    mbedErr = UA_mbedTLS_LoadPrivateKey(&localPrivateKey, &pc->localPrivateKey, &pc->entropyContext);

    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Set the local certificate thumbprint */
    retval = UA_ByteString_allocBuffer(&pc->localCertThumbprint, UA_SHA1_LENGTH);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;
    retval = asym_makeThumbprint_sp_basic128rsa15(securityPolicy,
                                                  &securityPolicy->localCertificate,
                                                  &pc->localCertThumbprint);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return UA_STATUSCODE_GOOD;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not create securityContext: %s", UA_StatusCode_name(retval));
    if(securityPolicy->policyContext != NULL)
        clear_sp_basic128rsa15(securityPolicy);
    return retval;
}

UA_StatusCode
UA_SecurityPolicy_Basic128Rsa15(UA_SecurityPolicy *policy, const UA_ByteString localCertificate,
                                const UA_ByteString localPrivateKey, const UA_Logger *logger) {
    memset(policy, 0, sizeof(UA_SecurityPolicy));
    policy->logger = logger;

    policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15\0");
    policy->securityLevel = 0;

    UA_SecurityPolicyAsymmetricModule *const asymmetricModule = &policy->asymmetricModule;
    UA_SecurityPolicySymmetricModule *const symmetricModule = &policy->symmetricModule;
    UA_SecurityPolicyChannelModule *const channelModule = &policy->channelModule;

    UA_StatusCode retval = UA_mbedTLS_LoadLocalCertificate(&localCertificate, &policy->localCertificate);

    if (retval != UA_STATUSCODE_GOOD)
        return retval;

    /* AsymmetricModule */
    UA_SecurityPolicySignatureAlgorithm *asym_signatureAlgorithm =
        &asymmetricModule->cryptoModule.signatureAlgorithm;
    asym_signatureAlgorithm->uri =
        UA_STRING("http://www.w3.org/2000/09/xmldsig#rsa-sha1\0");
    asym_signatureAlgorithm->verify =
        (UA_StatusCode (*)(void *, const UA_ByteString *, const UA_ByteString *))asym_verify_sp_basic128rsa15;
    asym_signatureAlgorithm->sign =
        (UA_StatusCode (*)(void *, const UA_ByteString *, UA_ByteString *))asym_sign_sp_basic128rsa15;
    asym_signatureAlgorithm->getLocalSignatureSize =
        (size_t (*)(const void *))asym_getLocalSignatureSize_sp_basic128rsa15;
    asym_signatureAlgorithm->getRemoteSignatureSize =
        (size_t (*)(const void *))asym_getRemoteSignatureSize_sp_basic128rsa15;
    asym_signatureAlgorithm->getLocalKeyLength = NULL; // TODO: Write function
    asym_signatureAlgorithm->getRemoteKeyLength = NULL; // TODO: Write function

    UA_SecurityPolicyEncryptionAlgorithm *asym_encryptionAlgorithm =
        &asymmetricModule->cryptoModule.encryptionAlgorithm;
    asym_encryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-1_5");
    asym_encryptionAlgorithm->encrypt =
        (UA_StatusCode(*)(void *, UA_ByteString *))asym_encrypt_sp_basic128rsa15;
    asym_encryptionAlgorithm->decrypt =
        (UA_StatusCode(*)(void *, UA_ByteString *)) asym_decrypt_sp_basic128rsa15;
    asym_encryptionAlgorithm->getLocalKeyLength =
        (size_t (*)(const void *))asym_getLocalEncryptionKeyLength_sp_basic128rsa15;
    asym_encryptionAlgorithm->getRemoteKeyLength =
        (size_t (*)(const void *))asym_getRemoteEncryptionKeyLength_sp_basic128rsa15;
    asym_encryptionAlgorithm->getRemoteBlockSize =
        (size_t (*)(const void *))asym_getRemoteBlockSize_sp_basic128rsa15;
    asym_encryptionAlgorithm->getRemotePlainTextBlockSize =
        (size_t (*)(const void *))asym_getRemotePlainTextBlockSize_sp_basic128rsa15;

    asymmetricModule->makeCertificateThumbprint = asym_makeThumbprint_sp_basic128rsa15;
    asymmetricModule->compareCertificateThumbprint =
        asymmetricModule_compareCertificateThumbprint_sp_basic128rsa15;

    /* SymmetricModule */
    symmetricModule->generateKey = sym_generateKey_sp_basic128rsa15;
    symmetricModule->generateNonce = sym_generateNonce_sp_basic128rsa15;

    UA_SecurityPolicySignatureAlgorithm *sym_signatureAlgorithm =
        &symmetricModule->cryptoModule.signatureAlgorithm;
    sym_signatureAlgorithm->uri =
        UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha1\0");
    sym_signatureAlgorithm->verify =
        (UA_StatusCode (*)(void *, const UA_ByteString *,
                           const UA_ByteString *))sym_verify_sp_basic128rsa15;
    sym_signatureAlgorithm->sign =
        (UA_StatusCode (*)(void *, const UA_ByteString *, UA_ByteString *))sym_sign_sp_basic128rsa15;
    sym_signatureAlgorithm->getLocalSignatureSize = sym_getSignatureSize_sp_basic128rsa15;
    sym_signatureAlgorithm->getRemoteSignatureSize = sym_getSignatureSize_sp_basic128rsa15;
    sym_signatureAlgorithm->getLocalKeyLength =
        (size_t (*)(const void *))sym_getSigningKeyLength_sp_basic128rsa15;
    sym_signatureAlgorithm->getRemoteKeyLength =
        (size_t (*)(const void *))sym_getSigningKeyLength_sp_basic128rsa15;

    UA_SecurityPolicyEncryptionAlgorithm *sym_encryptionAlgorithm =
        &symmetricModule->cryptoModule.encryptionAlgorithm;
    sym_encryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes128-cbc");
    sym_encryptionAlgorithm->encrypt =
        (UA_StatusCode(*)(void *, UA_ByteString *))sym_encrypt_sp_basic128rsa15;
    sym_encryptionAlgorithm->decrypt =
        (UA_StatusCode(*)(void *, UA_ByteString *))sym_decrypt_sp_basic128rsa15;
    sym_encryptionAlgorithm->getLocalKeyLength = sym_getEncryptionKeyLength_sp_basic128rsa15;
    sym_encryptionAlgorithm->getRemoteKeyLength = sym_getEncryptionKeyLength_sp_basic128rsa15;
    sym_encryptionAlgorithm->getRemoteBlockSize =
        (size_t (*)(const void *))sym_getEncryptionBlockSize_sp_basic128rsa15;
    sym_encryptionAlgorithm->getRemotePlainTextBlockSize =
        (size_t (*)(const void *))sym_getPlainTextBlockSize_sp_basic128rsa15;
    symmetricModule->secureChannelNonceLength = 16;

    // Use the same signature algorithm as the asymmetric component for certificate signing (see standard)
    policy->certificateSigningAlgorithm = policy->asymmetricModule.cryptoModule.signatureAlgorithm;

    /* ChannelModule */
    channelModule->newContext = channelContext_newContext_sp_basic128rsa15;
    channelModule->deleteContext = (void (*)(void *))
        channelContext_deleteContext_sp_basic128rsa15;

    channelModule->setLocalSymEncryptingKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setLocalSymEncryptingKey_sp_basic128rsa15;
    channelModule->setLocalSymSigningKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setLocalSymSigningKey_sp_basic128rsa15;
    channelModule->setLocalSymIv = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setLocalSymIv_sp_basic128rsa15;

    channelModule->setRemoteSymEncryptingKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setRemoteSymEncryptingKey_sp_basic128rsa15;
    channelModule->setRemoteSymSigningKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setRemoteSymSigningKey_sp_basic128rsa15;
    channelModule->setRemoteSymIv = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setRemoteSymIv_sp_basic128rsa15;

    channelModule->compareCertificate = (UA_StatusCode (*)(const void *, const UA_ByteString *))
        channelContext_compareCertificate_sp_basic128rsa15;

    policy->updateCertificateAndPrivateKey = updateCertificateAndPrivateKey_sp_basic128rsa15;
    policy->clear = clear_sp_basic128rsa15;

    UA_StatusCode res = policyContext_newContext_sp_basic128rsa15(policy, localPrivateKey);
    if(res != UA_STATUSCODE_GOOD)
        clear_sp_basic128rsa15(policy);

    return res;
}

#endif

/**** amalgamated original file "/plugins/crypto/mbedtls/ua_securitypolicy_basic256.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2018 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2018 (c) Daniel Feist, Precitec GmbH & Co. KG
 *    Copyright 2019 (c) Kalycito Infotech Private Limited
 *    Copyright 2020 (c) Wind River Systems, Inc.
 *    Copyright 2020 (c) basysKom GmbH
 *
 */


#ifdef UA_ENABLE_ENCRYPTION_MBEDTLS


#include <mbedtls/aes.h>
#include <mbedtls/entropy.h>
#include <mbedtls/error.h>
#include <mbedtls/sha1.h>
#include <mbedtls/version.h>

/* Notes:
 * mbedTLS' AES allows in-place encryption and decryption. Sow we don't have to
 * allocate temp buffers.
 * https://tls.mbed.org/discussions/generic/in-place-decryption-with-aes256-same-input-output-buffer
 */

#define UA_SECURITYPOLICY_BASIC256SHA1_RSAPADDING_LEN 42
#define UA_SHA1_LENGTH 20
#define UA_BASIC256_SYM_SIGNING_KEY_LENGTH 24
#define UA_SECURITYPOLICY_BASIC256_SYM_KEY_LENGTH 32
#define UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_BASIC256_SYM_PLAIN_TEXT_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_BASIC256_MINASYMKEYLENGTH 128
#define UA_SECURITYPOLICY_BASIC256_MAXASYMKEYLENGTH 512

typedef struct {
    UA_ByteString localCertThumbprint;

    mbedtls_ctr_drbg_context drbgContext;
    mbedtls_entropy_context entropyContext;
    mbedtls_md_context_t sha1MdContext;
    mbedtls_pk_context localPrivateKey;
} Basic256_PolicyContext;

typedef struct {
    Basic256_PolicyContext *policyContext;

    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;

    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    mbedtls_x509_crt remoteCertificate;
} Basic256_ChannelContext;

/********************/
/* AsymmetricModule */
/********************/

/* VERIFY AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 */
static UA_StatusCode
asym_verify_sp_basic256(Basic256_ChannelContext *cc,
                        const UA_ByteString *message,
                        const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    return mbedtls_verifySig_sha1(&cc->remoteCertificate, message, signature);
}

/* AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 */
static UA_StatusCode
asym_sign_sp_basic256(Basic256_ChannelContext *cc,
                      const UA_ByteString *message,
                      UA_ByteString *signature) {
    if(message == NULL || signature == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Basic256_PolicyContext *pc = cc->policyContext;
    return mbedtls_sign_sha1(&pc->localPrivateKey, &pc->drbgContext,
                             message, signature);
}

static size_t
asym_getLocalSignatureSize_sp_basic256(const Basic256_ChannelContext *cc) {
    if(cc == NULL)
        return 0;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    return mbedtls_pk_rsa(cc->policyContext->localPrivateKey)->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->policyContext->localPrivateKey));
#endif
}

static size_t
asym_getRemoteSignatureSize_sp_basic256(const Basic256_ChannelContext *cc) {
    if(cc == NULL)
        return 0;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    return mbedtls_pk_rsa(cc->remoteCertificate.pk)->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
#endif
}

static size_t
asym_getRemotePlainTextBlockSize_sp_basic256(const Basic256_ChannelContext *cc) {
    if(cc == NULL)
        return 0;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    return rsaContext->len - UA_SECURITYPOLICY_BASIC256SHA1_RSAPADDING_LEN;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk)) -
        UA_SECURITYPOLICY_BASIC256SHA1_RSAPADDING_LEN;
#endif
}

/* AsymmetricEncryptionAlgorithm_RSA-OAEP-SHA1 */
static UA_StatusCode
asym_encrypt_sp_basic256(Basic256_ChannelContext *cc,
                         UA_ByteString *data) {
    if(cc == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    const size_t plainTextBlockSize = asym_getRemotePlainTextBlockSize_sp_basic256(cc);

    mbedtls_rsa_context *remoteRsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    mbedtls_rsa_set_padding(remoteRsaContext, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1);

    return mbedtls_encrypt_rsaOaep(remoteRsaContext, &cc->policyContext->drbgContext,
                                   data, plainTextBlockSize);
}

/* AsymmetricEncryptionAlgorithm_RSA-OAEP-SHA1 */
static UA_StatusCode
asym_decrypt_sp_basic256(Basic256_ChannelContext *cc,
                         UA_ByteString *data) {
    if(cc == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    return mbedtls_decrypt_rsaOaep(&cc->policyContext->localPrivateKey,
                                   &cc->policyContext->drbgContext, data, MBEDTLS_MD_SHA1);
}

static size_t
asym_getLocalEncryptionKeyLength_sp_basic256(const Basic256_ChannelContext *cc) {
    return mbedtls_pk_get_len(&cc->policyContext->localPrivateKey) * 8;
}

static size_t
asym_getRemoteEncryptionKeyLength_sp_basic256(const Basic256_ChannelContext *cc) {
    return mbedtls_pk_get_len(&cc->remoteCertificate.pk) * 8;
}

static size_t
asym_getRemoteBlockSize_sp_basic256(const Basic256_ChannelContext *cc) {
    if(cc == NULL)
        return 0;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    return rsaContext->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
#endif
}

static UA_StatusCode
asym_makeThumbprint_sp_basic256(const UA_SecurityPolicy *securityPolicy,
                                const UA_ByteString *certificate,
                                UA_ByteString *thumbprint) {
    if(securityPolicy == NULL || certificate == NULL || thumbprint == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    return mbedtls_thumbprint_sha1(certificate, thumbprint);
}

static UA_StatusCode
asymmetricModule_compareCertificateThumbprint_sp_basic256(const UA_SecurityPolicy *securityPolicy,
                                                          const UA_ByteString *certificateThumbprint) {
    if(securityPolicy == NULL || certificateThumbprint == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Basic256_PolicyContext *pc = (Basic256_PolicyContext *)securityPolicy->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
        return UA_STATUSCODE_BADCERTIFICATEINVALID;

    return UA_STATUSCODE_GOOD;
}

/*******************/
/* SymmetricModule */
/*******************/

static UA_StatusCode
sym_verify_sp_basic256(Basic256_ChannelContext *cc,
                       const UA_ByteString *message,
                       const UA_ByteString *signature) {
    if(cc == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Compute MAC */
    if(signature->length != UA_SHA1_LENGTH)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    Basic256_PolicyContext *pc = cc->policyContext;

    unsigned char mac[UA_SHA1_LENGTH];
    if(mbedtls_hmac(&pc->sha1MdContext, &cc->remoteSymSigningKey,
                    message, mac) != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Compare with Signature */
    if(!UA_constantTimeEqual(signature->data, mac, UA_SHA1_LENGTH))
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
sym_sign_sp_basic256(const Basic256_ChannelContext *cc,
                     const UA_ByteString *message, UA_ByteString *signature) {
    if(signature->length != UA_SHA1_LENGTH)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(mbedtls_hmac(&cc->policyContext->sha1MdContext, &cc->localSymSigningKey,
                    message, signature->data) != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    return UA_STATUSCODE_GOOD;
}

static size_t
sym_getSignatureSize_sp_basic256(const void *channelContext) {
    return UA_SHA1_LENGTH;
}

static size_t
sym_getSigningKeyLength_sp_basic256(const void *const channelContext) {
    return UA_BASIC256_SYM_SIGNING_KEY_LENGTH;
}

static size_t
sym_getEncryptionKeyLength_sp_basic256(const void *channelContext) {
    return UA_SECURITYPOLICY_BASIC256_SYM_KEY_LENGTH;
}

static size_t
sym_getEncryptionBlockSize_sp_basic256(const void *const channelContext) {
    return UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_BLOCK_SIZE;
}

static size_t
sym_getPlainTextBlockSize_sp_basic256(const void *const channelContext) {
    return UA_SECURITYPOLICY_BASIC256_SYM_PLAIN_TEXT_BLOCK_SIZE;
}

static UA_StatusCode
sym_encrypt_sp_basic256(const Basic256_ChannelContext *cc,
                        UA_ByteString *data) {
    if(cc == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(cc->localSymIv.length != UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_BLOCK_SIZE)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t plainTextBlockSize = UA_SECURITYPOLICY_BASIC256_SYM_PLAIN_TEXT_BLOCK_SIZE;
    if(data->length % plainTextBlockSize != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Keylength in bits */
    unsigned int keylength = (unsigned int)(cc->localSymEncryptingKey.length * 8);
    mbedtls_aes_context aesContext;
    int mbedErr = mbedtls_aes_setkey_enc(&aesContext, cc->localSymEncryptingKey.data, keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString ivCopy;
    UA_StatusCode retval = UA_ByteString_copy(&cc->localSymIv, &ivCopy);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_ENCRYPT, data->length,
                                    ivCopy.data, data->data, data->data);
    if(mbedErr)
        retval = UA_STATUSCODE_BADINTERNALERROR;
    UA_ByteString_clear(&ivCopy);
    return retval;
}

static UA_StatusCode
sym_decrypt_sp_basic256(const Basic256_ChannelContext *cc,
                        UA_ByteString *data) {
    if(cc == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t encryptionBlockSize = UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_BLOCK_SIZE;
    if(cc->remoteSymIv.length != encryptionBlockSize)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(data->length % encryptionBlockSize != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned int keylength = (unsigned int)(cc->remoteSymEncryptingKey.length * 8);
    mbedtls_aes_context aesContext;
    int mbedErr = mbedtls_aes_setkey_dec(&aesContext, cc->remoteSymEncryptingKey.data, keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString ivCopy;
    UA_StatusCode retval = UA_ByteString_copy(&cc->remoteSymIv, &ivCopy);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_DECRYPT, data->length,
                                    ivCopy.data, data->data, data->data);
    if(mbedErr)
        retval = UA_STATUSCODE_BADINTERNALERROR;
    UA_ByteString_clear(&ivCopy);
    return retval;
}

static UA_StatusCode
sym_generateKey_sp_basic256(void *policyContext, const UA_ByteString *secret,
                            const UA_ByteString *seed, UA_ByteString *out) {
    if(secret == NULL || seed == NULL || out == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic256_PolicyContext *pc = (Basic256_PolicyContext *)policyContext;
    return mbedtls_generateKey(&pc->sha1MdContext, secret, seed, out);
}

static UA_StatusCode
sym_generateNonce_sp_basic256(void *policyContext, UA_ByteString *out) {
    if(out == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic256_PolicyContext *pc = (Basic256_PolicyContext *)policyContext;
    int mbedErr = mbedtls_ctr_drbg_random(&pc->drbgContext, out->data, out->length);
    if(mbedErr)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_STATUSCODE_GOOD;
}

/*****************/
/* ChannelModule */
/*****************/

/* Assumes that the certificate has been verified externally */
static UA_StatusCode
parseRemoteCertificate_sp_basic256(Basic256_ChannelContext *cc,
                                   const UA_ByteString *remoteCertificate) {
    if(remoteCertificate == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Parse the certificate */
    int mbedErr = mbedtls_x509_crt_parse(&cc->remoteCertificate, remoteCertificate->data,
                                         remoteCertificate->length);
    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Check the key length */
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    size_t keylen = rsaContext->len;
#else
    size_t keylen = mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
#endif
    if(keylen < UA_SECURITYPOLICY_BASIC256_MINASYMKEYLENGTH ||
       keylen > UA_SECURITYPOLICY_BASIC256_MAXASYMKEYLENGTH)
        return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;

    return UA_STATUSCODE_GOOD;
}

static void
channelContext_deleteContext_sp_basic256(Basic256_ChannelContext *cc) {
    UA_ByteString_clear(&cc->localSymSigningKey);
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    UA_ByteString_clear(&cc->localSymIv);

    UA_ByteString_clear(&cc->remoteSymSigningKey);
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    UA_ByteString_clear(&cc->remoteSymIv);

    mbedtls_x509_crt_free(&cc->remoteCertificate);

    UA_free(cc);
}

static UA_StatusCode
channelContext_newContext_sp_basic256(const UA_SecurityPolicy *securityPolicy,
                                      const UA_ByteString *remoteCertificate,
                                      void **pp_contextData) {
    if(securityPolicy == NULL || remoteCertificate == NULL || pp_contextData == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Allocate the channel context */
    *pp_contextData = UA_malloc(sizeof(Basic256_ChannelContext));
    if(*pp_contextData == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    Basic256_ChannelContext *cc = (Basic256_ChannelContext *)*pp_contextData;

    /* Initialize the channel context */
    cc->policyContext = (Basic256_PolicyContext *)securityPolicy->policyContext;

    UA_ByteString_init(&cc->localSymSigningKey);
    UA_ByteString_init(&cc->localSymEncryptingKey);
    UA_ByteString_init(&cc->localSymIv);

    UA_ByteString_init(&cc->remoteSymSigningKey);
    UA_ByteString_init(&cc->remoteSymEncryptingKey);
    UA_ByteString_init(&cc->remoteSymIv);

    mbedtls_x509_crt_init(&cc->remoteCertificate);

    // TODO: this can be optimized so that we dont allocate memory before parsing the certificate
    UA_StatusCode retval = parseRemoteCertificate_sp_basic256(cc, remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        channelContext_deleteContext_sp_basic256(cc);
        *pp_contextData = NULL;
    }
    return retval;
}

static UA_StatusCode
channelContext_setLocalSymEncryptingKey_sp_basic256(Basic256_ChannelContext *cc,
                                                    const UA_ByteString *key) {
    if(key == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
channelContext_setLocalSymSigningKey_sp_basic256(Basic256_ChannelContext *cc,
                                                 const UA_ByteString *key) {
    if(key == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}


static UA_StatusCode
channelContext_setLocalSymIv_sp_basic256(Basic256_ChannelContext *cc,
                                         const UA_ByteString *iv) {
    if(iv == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static UA_StatusCode
channelContext_setRemoteSymEncryptingKey_sp_basic256(Basic256_ChannelContext *cc,
                                                     const UA_ByteString *key) {
    if(key == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
channelContext_setRemoteSymSigningKey_sp_basic256(Basic256_ChannelContext *cc,
                                                  const UA_ByteString *key) {
    if(key == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
channelContext_setRemoteSymIv_sp_basic256(Basic256_ChannelContext *cc,
                                          const UA_ByteString *iv) {
    if(iv == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(iv, &cc->remoteSymIv);
}

static UA_StatusCode
channelContext_compareCertificate_sp_basic256(const Basic256_ChannelContext *cc,
                                              const UA_ByteString *certificate) {
    if(cc == NULL || certificate == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    mbedtls_x509_crt cert;
    mbedtls_x509_crt_init(&cert);
    int mbedErr = mbedtls_x509_crt_parse(&cert, certificate->data, certificate->length);
    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(cert.raw.len != cc->remoteCertificate.raw.len ||
       memcmp(cert.raw.p, cc->remoteCertificate.raw.p, cert.raw.len) != 0)
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    mbedtls_x509_crt_free(&cert);
    return retval;
}

static void
clear_sp_basic256(UA_SecurityPolicy *securityPolicy) {
    if(securityPolicy == NULL)
        return;

    UA_ByteString_clear(&securityPolicy->localCertificate);

    if(securityPolicy->policyContext == NULL)
        return;

    /* delete all allocated members in the context */
    Basic256_PolicyContext *pc = (Basic256_PolicyContext *)
        securityPolicy->policyContext;

    mbedtls_ctr_drbg_free(&pc->drbgContext);
    mbedtls_entropy_free(&pc->entropyContext);
    mbedtls_pk_free(&pc->localPrivateKey);
    mbedtls_md_free(&pc->sha1MdContext);
    UA_ByteString_clear(&pc->localCertThumbprint);

    UA_LOG_DEBUG(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Deleted members of EndpointContext for sp_basic256");

    UA_free(pc);
    securityPolicy->policyContext = NULL;
}

static UA_StatusCode
updateCertificateAndPrivateKey_sp_basic256(UA_SecurityPolicy *securityPolicy,
                                           const UA_ByteString newCertificate,
                                           const UA_ByteString newPrivateKey) {
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(securityPolicy->policyContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Basic256_PolicyContext *pc = (Basic256_PolicyContext *)
        securityPolicy->policyContext;

    UA_ByteString_clear(&securityPolicy->localCertificate);

    UA_StatusCode retval = UA_mbedTLS_LoadLocalCertificate(&newCertificate, &securityPolicy->localCertificate);

    if (retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Set the new private key */
    mbedtls_pk_free(&pc->localPrivateKey);
    mbedtls_pk_init(&pc->localPrivateKey);

    int mbedErr = UA_mbedTLS_LoadPrivateKey(&newPrivateKey, &pc->localPrivateKey, &pc->entropyContext);

    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    retval = asym_makeThumbprint_sp_basic256(securityPolicy,
                                             &securityPolicy->localCertificate,
                                             &pc->localCertThumbprint);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return retval;

    error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext != NULL)
        clear_sp_basic256(securityPolicy);
    return retval;
}

static UA_StatusCode
policyContext_newContext_sp_basic256(UA_SecurityPolicy *securityPolicy,
                                     const UA_ByteString localPrivateKey) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if (localPrivateKey.length == 0) {
        UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                     "Can not initialize security policy. Private key is empty.");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    Basic256_PolicyContext *pc = (Basic256_PolicyContext *)
        UA_malloc(sizeof(Basic256_PolicyContext));
    securityPolicy->policyContext = (void *)pc;
    if(!pc) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto error;
    }

    /* Initialize the PolicyContext */
    memset(pc, 0, sizeof(Basic256_PolicyContext));
    mbedtls_ctr_drbg_init(&pc->drbgContext);
    mbedtls_entropy_init(&pc->entropyContext);
    mbedtls_pk_init(&pc->localPrivateKey);
    mbedtls_md_init(&pc->sha1MdContext);

    /* Initialized the message digest */
    const mbedtls_md_info_t *mdInfo = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
    int mbedErr = mbedtls_md_setup(&pc->sha1MdContext, mdInfo, MBEDTLS_MD_SHA1);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto error;
    }

    mbedErr = mbedtls_entropy_self_test(0);

    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Seed the RNG */
    char *personalization = "open62541-drbg";
    mbedErr = mbedtls_ctr_drbg_seed(&pc->drbgContext, mbedtls_entropy_func,
                                    &pc->entropyContext,
                                    (const unsigned char *)personalization, 14);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Set the private key */
    mbedErr = UA_mbedTLS_LoadPrivateKey(&localPrivateKey, &pc->localPrivateKey, &pc->entropyContext);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Set the local certificate thumbprint */
    retval = UA_ByteString_allocBuffer(&pc->localCertThumbprint, UA_SHA1_LENGTH);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;
    retval = asym_makeThumbprint_sp_basic256(securityPolicy,
                                             &securityPolicy->localCertificate,
                                             &pc->localCertThumbprint);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return UA_STATUSCODE_GOOD;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not create securityContext: %s", UA_StatusCode_name(retval));
    if(securityPolicy->policyContext != NULL)
        clear_sp_basic256(securityPolicy);
    return retval;
}

UA_StatusCode
UA_SecurityPolicy_Basic256(UA_SecurityPolicy *policy, const UA_ByteString localCertificate,
                           const UA_ByteString localPrivateKey, const UA_Logger *logger) {
    memset(policy, 0, sizeof(UA_SecurityPolicy));
    policy->logger = logger;

    policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic256\0");
    policy->securityLevel = 0;

    UA_SecurityPolicyAsymmetricModule *const asymmetricModule = &policy->asymmetricModule;
    UA_SecurityPolicySymmetricModule *const symmetricModule = &policy->symmetricModule;
    UA_SecurityPolicyChannelModule *const channelModule = &policy->channelModule;

    UA_StatusCode retval = UA_mbedTLS_LoadLocalCertificate(&localCertificate, &policy->localCertificate);

    if (retval != UA_STATUSCODE_GOOD)
        return retval;

    /* AsymmetricModule */
    UA_SecurityPolicySignatureAlgorithm *asym_signatureAlgorithm =
        &asymmetricModule->cryptoModule.signatureAlgorithm;
    asym_signatureAlgorithm->uri =
        UA_STRING("http://www.w3.org/2000/09/xmldsig#rsa-sha1\0");
    asym_signatureAlgorithm->verify =
        (UA_StatusCode (*)(void *, const UA_ByteString *, const UA_ByteString *))asym_verify_sp_basic256;
    asym_signatureAlgorithm->sign =
        (UA_StatusCode (*)(void *, const UA_ByteString *, UA_ByteString *))asym_sign_sp_basic256;
    asym_signatureAlgorithm->getLocalSignatureSize =
        (size_t (*)(const void *))asym_getLocalSignatureSize_sp_basic256;
    asym_signatureAlgorithm->getRemoteSignatureSize =
        (size_t (*)(const void *))asym_getRemoteSignatureSize_sp_basic256;
    asym_signatureAlgorithm->getLocalKeyLength = NULL; // TODO: Write function
    asym_signatureAlgorithm->getRemoteKeyLength = NULL; // TODO: Write function

    UA_SecurityPolicyEncryptionAlgorithm *asym_encryptionAlgorithm =
        &asymmetricModule->cryptoModule.encryptionAlgorithm;
    asym_encryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-oaep\0");
    asym_encryptionAlgorithm->encrypt =
        (UA_StatusCode(*)(void *, UA_ByteString *))asym_encrypt_sp_basic256;
    asym_encryptionAlgorithm->decrypt =
        (UA_StatusCode(*)(void *, UA_ByteString *))asym_decrypt_sp_basic256;
    asym_encryptionAlgorithm->getLocalKeyLength =
        (size_t (*)(const void *))asym_getLocalEncryptionKeyLength_sp_basic256;
    asym_encryptionAlgorithm->getRemoteKeyLength =
        (size_t (*)(const void *))asym_getRemoteEncryptionKeyLength_sp_basic256;
    asym_encryptionAlgorithm->getRemoteBlockSize =
        (size_t (*)(const void *))asym_getRemoteBlockSize_sp_basic256;
    asym_encryptionAlgorithm->getRemotePlainTextBlockSize =
        (size_t (*)(const void *))asym_getRemotePlainTextBlockSize_sp_basic256;

    asymmetricModule->makeCertificateThumbprint = asym_makeThumbprint_sp_basic256;
    asymmetricModule->compareCertificateThumbprint =
        asymmetricModule_compareCertificateThumbprint_sp_basic256;

    /* SymmetricModule */
    symmetricModule->generateKey = sym_generateKey_sp_basic256;
    symmetricModule->generateNonce = sym_generateNonce_sp_basic256;

    UA_SecurityPolicySignatureAlgorithm *sym_signatureAlgorithm =
        &symmetricModule->cryptoModule.signatureAlgorithm;
    sym_signatureAlgorithm->uri =
        UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha1\0");
    sym_signatureAlgorithm->verify =
        (UA_StatusCode (*)(void *, const UA_ByteString *,
                           const UA_ByteString *))sym_verify_sp_basic256;
    sym_signatureAlgorithm->sign =
        (UA_StatusCode (*)(void *, const UA_ByteString *, UA_ByteString *))sym_sign_sp_basic256;
    sym_signatureAlgorithm->getLocalSignatureSize = sym_getSignatureSize_sp_basic256;
    sym_signatureAlgorithm->getRemoteSignatureSize = sym_getSignatureSize_sp_basic256;
    sym_signatureAlgorithm->getLocalKeyLength =
        (size_t (*)(const void *))sym_getSigningKeyLength_sp_basic256;
    sym_signatureAlgorithm->getRemoteKeyLength =
        (size_t (*)(const void *))sym_getSigningKeyLength_sp_basic256;

    UA_SecurityPolicyEncryptionAlgorithm *sym_encryptionAlgorithm =
        &symmetricModule->cryptoModule.encryptionAlgorithm;
    sym_encryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes256-cbc\0");
    sym_encryptionAlgorithm->encrypt =
        (UA_StatusCode(*)(void *, UA_ByteString *))sym_encrypt_sp_basic256;
    sym_encryptionAlgorithm->decrypt =
        (UA_StatusCode(*)(void *, UA_ByteString *))sym_decrypt_sp_basic256;
    sym_encryptionAlgorithm->getLocalKeyLength = sym_getEncryptionKeyLength_sp_basic256;
    sym_encryptionAlgorithm->getRemoteKeyLength = sym_getEncryptionKeyLength_sp_basic256;
    sym_encryptionAlgorithm->getRemoteBlockSize =
        (size_t (*)(const void *))sym_getEncryptionBlockSize_sp_basic256;
    sym_encryptionAlgorithm->getRemotePlainTextBlockSize =
        (size_t (*)(const void *))sym_getPlainTextBlockSize_sp_basic256;
    symmetricModule->secureChannelNonceLength = 32;

    // Use the same signature algorithm as the asymmetric component for certificate signing (see standard)
    policy->certificateSigningAlgorithm = policy->asymmetricModule.cryptoModule.signatureAlgorithm;

    /* ChannelModule */
    channelModule->newContext = channelContext_newContext_sp_basic256;
    channelModule->deleteContext = (void (*)(void *))
        channelContext_deleteContext_sp_basic256;

    channelModule->setLocalSymEncryptingKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setLocalSymEncryptingKey_sp_basic256;
    channelModule->setLocalSymSigningKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setLocalSymSigningKey_sp_basic256;
    channelModule->setLocalSymIv = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setLocalSymIv_sp_basic256;

    channelModule->setRemoteSymEncryptingKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setRemoteSymEncryptingKey_sp_basic256;
    channelModule->setRemoteSymSigningKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setRemoteSymSigningKey_sp_basic256;
    channelModule->setRemoteSymIv = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setRemoteSymIv_sp_basic256;

    channelModule->compareCertificate = (UA_StatusCode (*)(const void *, const UA_ByteString *))
        channelContext_compareCertificate_sp_basic256;

    policy->updateCertificateAndPrivateKey = updateCertificateAndPrivateKey_sp_basic256;
    policy->clear = clear_sp_basic256;

    UA_StatusCode res = policyContext_newContext_sp_basic256(policy, localPrivateKey);
    if(res != UA_STATUSCODE_GOOD)
        clear_sp_basic256(policy);

    return res;
}

#endif

/**** amalgamated original file "/plugins/crypto/mbedtls/ua_securitypolicy_basic256sha256.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2018 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2018 (c) Daniel Feist, Precitec GmbH & Co. KG
 *    Copyright 2018 (c) HMS Industrial Networks AB (Author: Jonas Green)
 *    Copyright 2020 (c) Wind River Systems, Inc.
 *    Copyright 2020 (c) basysKom GmbH
 */


#ifdef UA_ENABLE_ENCRYPTION_MBEDTLS


#include <mbedtls/aes.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
#include <mbedtls/error.h>
#include <mbedtls/md.h>
#include <mbedtls/sha1.h>
#include <mbedtls/sha256.h>
#include <mbedtls/version.h>
#include <mbedtls/x509_crt.h>

/* Notes:
 * mbedTLS' AES allows in-place encryption and decryption. Sow we don't have to
 * allocate temp buffers.
 * https://tls.mbed.org/discussions/generic/in-place-decryption-with-aes256-same-input-output-buffer
 */

#define UA_SECURITYPOLICY_BASIC256SHA256_RSAPADDING_LEN 42
#define UA_SHA1_LENGTH 20
#define UA_SHA256_LENGTH 32
#define UA_BASIC256SHA256_SYM_SIGNING_KEY_LENGTH 32
#define UA_SECURITYPOLICY_BASIC256SHA256_SYM_KEY_LENGTH 32
#define UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_BASIC256SHA256_SYM_PLAIN_TEXT_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_BASIC256SHA256_MINASYMKEYLENGTH 256
#define UA_SECURITYPOLICY_BASIC256SHA256_MAXASYMKEYLENGTH 512

typedef struct {
    UA_ByteString localCertThumbprint;

    mbedtls_ctr_drbg_context drbgContext;
    mbedtls_entropy_context entropyContext;
    mbedtls_md_context_t sha256MdContext;
    mbedtls_pk_context localPrivateKey;
} Basic256Sha256_PolicyContext;

typedef struct {
    Basic256Sha256_PolicyContext *policyContext;

    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;

    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    mbedtls_x509_crt remoteCertificate;
} Basic256Sha256_ChannelContext;

/********************/
/* AsymmetricModule */
/********************/

/* VERIFY AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 */
static UA_StatusCode
asym_verify_sp_basic256sha256(Basic256Sha256_ChannelContext *cc,
                              const UA_ByteString *message,
                              const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned char hash[UA_SHA256_LENGTH];
#if MBEDTLS_VERSION_NUMBER >= 0x02070000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    // TODO check return status
    mbedtls_sha256_ret(message->data, message->length, hash, 0);
#else
    mbedtls_sha256(message->data, message->length, hash, 0);
#endif

    /* Set the RSA settings */
    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_SHA256);

    /* For RSA keys, the default padding type is PKCS#1 v1.5 in mbedtls_pk_verify() */
    /* Alternatively, use more specific function mbedtls_rsa_rsassa_pkcs1_v15_verify(), i.e. */
    /* int mbedErr = mbedtls_rsa_rsassa_pkcs1_v15_verify(rsaContext, NULL, NULL,
                                                         MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA256,
                                                         UA_SHA256_LENGTH, hash,
                                                         signature->data); */
    int mbedErr = mbedtls_pk_verify(&cc->remoteCertificate.pk,
                                    MBEDTLS_MD_SHA256, hash, UA_SHA256_LENGTH,
                                    signature->data, signature->length);

    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    return UA_STATUSCODE_GOOD;
}

/* AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 */
static UA_StatusCode
asym_sign_sp_basic256sha256(Basic256Sha256_ChannelContext *cc,
                            const UA_ByteString *message,
                            UA_ByteString *signature) {
    if(message == NULL || signature == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned char hash[UA_SHA256_LENGTH];
#if MBEDTLS_VERSION_NUMBER >= 0x02070000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    // TODO check return status
    mbedtls_sha256_ret(message->data, message->length, hash, 0);
#else
    mbedtls_sha256(message->data, message->length, hash, 0);
#endif

    Basic256Sha256_PolicyContext *pc = cc->policyContext;
    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(pc->localPrivateKey);
    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_SHA256);

    size_t sigLen = 0;

    /* For RSA keys, the default padding type is PKCS#1 v1.5 in mbedtls_pk_sign */
    /* Alternatively use more specific function mbedtls_rsa_rsassa_pkcs1_v15_sign() */
    int mbedErr = mbedtls_pk_sign(&pc->localPrivateKey,
                                  MBEDTLS_MD_SHA256, hash,
                                  UA_SHA256_LENGTH, signature->data,
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
                                  signature->length,
#endif
                                  &sigLen, mbedtls_ctr_drbg_random,
                                  &pc->drbgContext);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;
    return UA_STATUSCODE_GOOD;
}

static size_t
asym_getLocalSignatureSize_sp_basic256sha256(const Basic256Sha256_ChannelContext *cc) {
    if(cc == NULL)
        return 0;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    return mbedtls_pk_rsa(cc->policyContext->localPrivateKey)->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->policyContext->localPrivateKey));
#endif
}

static size_t
asym_getRemoteSignatureSize_sp_basic256sha256(const Basic256Sha256_ChannelContext *cc) {
    if(cc == NULL)
        return 0;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    return mbedtls_pk_rsa(cc->remoteCertificate.pk)->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
#endif
}

static size_t
asym_getRemoteBlockSize_sp_basic256sha256(const Basic256Sha256_ChannelContext *cc) {
    if(cc == NULL)
        return 0;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    return rsaContext->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
#endif
}

static size_t
asym_getRemotePlainTextBlockSize_sp_basic256sha256(const Basic256Sha256_ChannelContext *cc) {
    if(cc == NULL)
        return 0;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    return rsaContext->len - UA_SECURITYPOLICY_BASIC256SHA256_RSAPADDING_LEN;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk)) -
        UA_SECURITYPOLICY_BASIC256SHA256_RSAPADDING_LEN;
#endif
}


/* AsymmetricEncryptionAlgorithm_RSA-OAEP-SHA1 */
static UA_StatusCode
asym_encrypt_sp_basic256sha256(Basic256Sha256_ChannelContext *cc,
                               UA_ByteString *data) {
    if(cc == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    const size_t plainTextBlockSize = asym_getRemotePlainTextBlockSize_sp_basic256sha256(cc);

    mbedtls_rsa_context *remoteRsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    mbedtls_rsa_set_padding(remoteRsaContext, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1);

    return mbedtls_encrypt_rsaOaep(remoteRsaContext, &cc->policyContext->drbgContext,
                                   data, plainTextBlockSize);
}

/* AsymmetricEncryptionAlgorithm_RSA-OAEP-SHA1 */
static UA_StatusCode
asym_decrypt_sp_basic256sha256(Basic256Sha256_ChannelContext *cc,
                               UA_ByteString *data) {
    if(cc == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    return mbedtls_decrypt_rsaOaep(&cc->policyContext->localPrivateKey,
                                   &cc->policyContext->drbgContext, data, MBEDTLS_MD_SHA1);
}

static size_t
asym_getLocalEncryptionKeyLength_sp_basic256sha256(const Basic256Sha256_ChannelContext *cc) {
    return mbedtls_pk_get_len(&cc->policyContext->localPrivateKey) * 8;
}

static size_t
asym_getRemoteEncryptionKeyLength_sp_basic256sha256(const Basic256Sha256_ChannelContext *cc) {
    return mbedtls_pk_get_len(&cc->remoteCertificate.pk) * 8;
}

static UA_StatusCode
asym_makeThumbprint_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy,
                                      const UA_ByteString *certificate,
                                      UA_ByteString *thumbprint) {
    if(securityPolicy == NULL || certificate == NULL || thumbprint == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    return mbedtls_thumbprint_sha1(certificate, thumbprint);
}

static UA_StatusCode
asymmetricModule_compareCertificateThumbprint_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy,
                                                                const UA_ByteString *certificateThumbprint) {
    if(securityPolicy == NULL || certificateThumbprint == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Basic256Sha256_PolicyContext *pc = (Basic256Sha256_PolicyContext *)securityPolicy->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
        return UA_STATUSCODE_BADCERTIFICATEINVALID;

    return UA_STATUSCODE_GOOD;
}

/*******************/
/* SymmetricModule */
/*******************/

static UA_StatusCode
sym_verify_sp_basic256sha256(Basic256Sha256_ChannelContext *cc,
                             const UA_ByteString *message,
                             const UA_ByteString *signature) {
    if(cc == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Compute MAC */
    if(signature->length != UA_SHA256_LENGTH)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    Basic256Sha256_PolicyContext *pc = cc->policyContext;
    unsigned char mac[UA_SHA256_LENGTH];
    if(mbedtls_hmac(&pc->sha256MdContext, &cc->remoteSymSigningKey, message, mac) != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Compare with Signature */
    if(!UA_constantTimeEqual(signature->data, mac, UA_SHA256_LENGTH))
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
sym_sign_sp_basic256sha256(const Basic256Sha256_ChannelContext *cc,
                           const UA_ByteString *message,
                           UA_ByteString *signature) {
    if(signature->length != UA_SHA256_LENGTH)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(mbedtls_hmac(&cc->policyContext->sha256MdContext, &cc->localSymSigningKey,
                    message, signature->data) != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    return UA_STATUSCODE_GOOD;
}

static size_t
sym_getSignatureSize_sp_basic256sha256(const void *channelContext) {
    return UA_SHA256_LENGTH;
}

static size_t
sym_getSigningKeyLength_sp_basic256sha256(const void *channelContext) {
    return UA_BASIC256SHA256_SYM_SIGNING_KEY_LENGTH;
}

static size_t
sym_getEncryptionKeyLength_sp_basic256sha256(const void *channelContext) {
    return UA_SECURITYPOLICY_BASIC256SHA256_SYM_KEY_LENGTH;
}

static size_t
sym_getEncryptionBlockSize_sp_basic256sha256(const void *channelContext) {
    return UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_BLOCK_SIZE;
}

static size_t
sym_getPlainTextBlockSize_sp_basic256sha256(const void *channelContext) {
    return UA_SECURITYPOLICY_BASIC256SHA256_SYM_PLAIN_TEXT_BLOCK_SIZE;
}

static UA_StatusCode
sym_encrypt_sp_basic256sha256(const Basic256Sha256_ChannelContext *cc,
                              UA_ByteString *data) {
    if(cc == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(cc->localSymIv.length != UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_BLOCK_SIZE)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t plainTextBlockSize = UA_SECURITYPOLICY_BASIC256SHA256_SYM_PLAIN_TEXT_BLOCK_SIZE;

    if(data->length % plainTextBlockSize != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Keylength in bits */
    unsigned int keylength = (unsigned int)(cc->localSymEncryptingKey.length * 8);
    mbedtls_aes_context aesContext;
    int mbedErr = mbedtls_aes_setkey_enc(&aesContext, cc->localSymEncryptingKey.data, keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString ivCopy;
    UA_StatusCode retval = UA_ByteString_copy(&cc->localSymIv, &ivCopy);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_ENCRYPT, data->length,
                                    ivCopy.data, data->data, data->data);
    if(mbedErr)
        retval = UA_STATUSCODE_BADINTERNALERROR;
    UA_ByteString_clear(&ivCopy);
    return retval;
}

static UA_StatusCode
sym_decrypt_sp_basic256sha256(const Basic256Sha256_ChannelContext *cc,
                              UA_ByteString *data) {
    if(cc == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t encryptionBlockSize = UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_BLOCK_SIZE;
    if(cc->remoteSymIv.length != encryptionBlockSize)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(data->length % encryptionBlockSize != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned int keylength = (unsigned int)(cc->remoteSymEncryptingKey.length * 8);
    mbedtls_aes_context aesContext;
    int mbedErr = mbedtls_aes_setkey_dec(&aesContext, cc->remoteSymEncryptingKey.data, keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString ivCopy;
    UA_StatusCode retval = UA_ByteString_copy(&cc->remoteSymIv, &ivCopy);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_DECRYPT, data->length,
                                    ivCopy.data, data->data, data->data);
    if(mbedErr)
        retval = UA_STATUSCODE_BADINTERNALERROR;
    UA_ByteString_clear(&ivCopy);
    return retval;
}

static UA_StatusCode
sym_generateKey_sp_basic256sha256(void *policyContext, const UA_ByteString *secret,
                                  const UA_ByteString *seed, UA_ByteString *out) {
    if(secret == NULL || seed == NULL || out == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic256Sha256_PolicyContext *pc = (Basic256Sha256_PolicyContext *)policyContext;
    return mbedtls_generateKey(&pc->sha256MdContext, secret, seed, out);
}

static UA_StatusCode
sym_generateNonce_sp_basic256sha256(void *policyContext, UA_ByteString *out) {
    if(out == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Basic256Sha256_PolicyContext *pc = (Basic256Sha256_PolicyContext *)policyContext;
    int mbedErr = mbedtls_ctr_drbg_random(&pc->drbgContext, out->data, out->length);
    if(mbedErr)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_STATUSCODE_GOOD;
}

/*****************/
/* ChannelModule */
/*****************/

/* Assumes that the certificate has been verified externally */
static UA_StatusCode
parseRemoteCertificate_sp_basic256sha256(Basic256Sha256_ChannelContext *cc,
                                         const UA_ByteString *remoteCertificate) {
    if(remoteCertificate == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Parse the certificate */
    int mbedErr = mbedtls_x509_crt_parse(&cc->remoteCertificate, remoteCertificate->data,
                                         remoteCertificate->length);
    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Check the key length */
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    size_t keylen = rsaContext->len;
#else
    size_t keylen = mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
#endif
    if(keylen < UA_SECURITYPOLICY_BASIC256SHA256_MINASYMKEYLENGTH ||
       keylen > UA_SECURITYPOLICY_BASIC256SHA256_MAXASYMKEYLENGTH)
        return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;

    return UA_STATUSCODE_GOOD;
}

static void
channelContext_deleteContext_sp_basic256sha256(Basic256Sha256_ChannelContext *cc) {
    UA_ByteString_clear(&cc->localSymSigningKey);
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    UA_ByteString_clear(&cc->localSymIv);

    UA_ByteString_clear(&cc->remoteSymSigningKey);
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    UA_ByteString_clear(&cc->remoteSymIv);

    mbedtls_x509_crt_free(&cc->remoteCertificate);

    UA_free(cc);
}

static UA_StatusCode
channelContext_newContext_sp_basic256sha256(const UA_SecurityPolicy *securityPolicy,
                                            const UA_ByteString *remoteCertificate,
                                            void **pp_contextData) {
    if(securityPolicy == NULL || remoteCertificate == NULL || pp_contextData == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Allocate the channel context */
    *pp_contextData = UA_malloc(sizeof(Basic256Sha256_ChannelContext));
    if(*pp_contextData == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    Basic256Sha256_ChannelContext *cc = (Basic256Sha256_ChannelContext *)*pp_contextData;

    /* Initialize the channel context */
    cc->policyContext = (Basic256Sha256_PolicyContext *)securityPolicy->policyContext;

    UA_ByteString_init(&cc->localSymSigningKey);
    UA_ByteString_init(&cc->localSymEncryptingKey);
    UA_ByteString_init(&cc->localSymIv);

    UA_ByteString_init(&cc->remoteSymSigningKey);
    UA_ByteString_init(&cc->remoteSymEncryptingKey);
    UA_ByteString_init(&cc->remoteSymIv);

    mbedtls_x509_crt_init(&cc->remoteCertificate);

    // TODO: this can be optimized so that we dont allocate memory before parsing the certificate
    UA_StatusCode retval = parseRemoteCertificate_sp_basic256sha256(cc, remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        channelContext_deleteContext_sp_basic256sha256(cc);
        *pp_contextData = NULL;
    }
    return retval;
}

static UA_StatusCode
channelContext_setLocalSymEncryptingKey_sp_basic256sha256(Basic256Sha256_ChannelContext *cc,
                                                          const UA_ByteString *key) {
    if(key == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
channelContext_setLocalSymSigningKey_sp_basic256sha256(Basic256Sha256_ChannelContext *cc,
                                                       const UA_ByteString *key) {
    if(key == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}


static UA_StatusCode
channelContext_setLocalSymIv_sp_basic256sha256(Basic256Sha256_ChannelContext *cc,
                                               const UA_ByteString *iv) {
    if(iv == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static UA_StatusCode
channelContext_setRemoteSymEncryptingKey_sp_basic256sha256(Basic256Sha256_ChannelContext *cc,
                                                           const UA_ByteString *key) {
    if(key == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
channelContext_setRemoteSymSigningKey_sp_basic256sha256(Basic256Sha256_ChannelContext *cc,
                                                        const UA_ByteString *key) {
    if(key == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
channelContext_setRemoteSymIv_sp_basic256sha256(Basic256Sha256_ChannelContext *cc,
                                                const UA_ByteString *iv) {
    if(iv == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(iv, &cc->remoteSymIv);
}

static UA_StatusCode
channelContext_compareCertificate_sp_basic256sha256(const Basic256Sha256_ChannelContext *cc,
                                                    const UA_ByteString *certificate) {
    if(cc == NULL || certificate == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    mbedtls_x509_crt cert;
    mbedtls_x509_crt_init(&cert);
    int mbedErr = mbedtls_x509_crt_parse(&cert, certificate->data, certificate->length);
    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(cert.raw.len != cc->remoteCertificate.raw.len ||
       memcmp(cert.raw.p, cc->remoteCertificate.raw.p, cert.raw.len) != 0)
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    mbedtls_x509_crt_free(&cert);
    return retval;
}

static void
clear_sp_basic256sha256(UA_SecurityPolicy *securityPolicy) {
    if(securityPolicy == NULL)
        return;

    UA_ByteString_clear(&securityPolicy->localCertificate);

    if(securityPolicy->policyContext == NULL)
        return;

    /* delete all allocated members in the context */
    Basic256Sha256_PolicyContext *pc = (Basic256Sha256_PolicyContext *)
        securityPolicy->policyContext;

    mbedtls_ctr_drbg_free(&pc->drbgContext);
    mbedtls_entropy_free(&pc->entropyContext);
    mbedtls_pk_free(&pc->localPrivateKey);
    mbedtls_md_free(&pc->sha256MdContext);
    UA_ByteString_clear(&pc->localCertThumbprint);

    UA_LOG_DEBUG(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Deleted members of EndpointContext for sp_basic256sha256");

    UA_free(pc);
    securityPolicy->policyContext = NULL;
}

static UA_StatusCode
updateCertificateAndPrivateKey_sp_basic256sha256(UA_SecurityPolicy *securityPolicy,
                                                 const UA_ByteString newCertificate,
                                                 const UA_ByteString newPrivateKey) {
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(securityPolicy->policyContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Basic256Sha256_PolicyContext *pc =
            (Basic256Sha256_PolicyContext *) securityPolicy->policyContext;

    UA_ByteString_clear(&securityPolicy->localCertificate);

    UA_StatusCode retval = UA_mbedTLS_LoadLocalCertificate(&newCertificate, &securityPolicy->localCertificate);

    if (retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Set the new private key */
    mbedtls_pk_free(&pc->localPrivateKey);
    mbedtls_pk_init(&pc->localPrivateKey);
    int mbedErr = UA_mbedTLS_LoadPrivateKey(&newPrivateKey, &pc->localPrivateKey, &pc->entropyContext);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    retval = asym_makeThumbprint_sp_basic256sha256(securityPolicy,
                                                   &securityPolicy->localCertificate,
                                                   &pc->localCertThumbprint);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return retval;

    error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext != NULL)
        clear_sp_basic256sha256(securityPolicy);
    return retval;
}

static UA_StatusCode
policyContext_newContext_sp_basic256sha256(UA_SecurityPolicy *securityPolicy,
                                           const UA_ByteString localPrivateKey) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if (localPrivateKey.length == 0) {
        UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                     "Can not initialize security policy. Private key is empty.");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    Basic256Sha256_PolicyContext *pc = (Basic256Sha256_PolicyContext *)
        UA_malloc(sizeof(Basic256Sha256_PolicyContext));
    securityPolicy->policyContext = (void *)pc;
    if(!pc) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto error;
    }

    /* Initialize the PolicyContext */
    memset(pc, 0, sizeof(Basic256Sha256_PolicyContext));
    mbedtls_ctr_drbg_init(&pc->drbgContext);
    mbedtls_entropy_init(&pc->entropyContext);
    mbedtls_pk_init(&pc->localPrivateKey);
    mbedtls_md_init(&pc->sha256MdContext);

    /* Initialized the message digest */
    const mbedtls_md_info_t *const mdInfo = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
    int mbedErr = mbedtls_md_setup(&pc->sha256MdContext, mdInfo, MBEDTLS_MD_SHA256);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto error;
    }

    mbedErr = mbedtls_entropy_self_test(0);

    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Seed the RNG */
    char *personalization = "open62541-drbg";
    mbedErr = mbedtls_ctr_drbg_seed(&pc->drbgContext, mbedtls_entropy_func,
                                    &pc->entropyContext,
                                    (const unsigned char *)personalization, 14);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Set the private key */
    mbedErr = UA_mbedTLS_LoadPrivateKey(&localPrivateKey, &pc->localPrivateKey, &pc->entropyContext);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Set the local certificate thumbprint */
    retval = UA_ByteString_allocBuffer(&pc->localCertThumbprint, UA_SHA1_LENGTH);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;
    retval = asym_makeThumbprint_sp_basic256sha256(securityPolicy,
                                                  &securityPolicy->localCertificate,
                                                  &pc->localCertThumbprint);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return UA_STATUSCODE_GOOD;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not create securityContext: %s", UA_StatusCode_name(retval));
    if(securityPolicy->policyContext != NULL)
        clear_sp_basic256sha256(securityPolicy);
    return retval;
}

UA_StatusCode
UA_SecurityPolicy_Basic256Sha256(UA_SecurityPolicy *policy, const UA_ByteString localCertificate,
                                 const UA_ByteString localPrivateKey, const UA_Logger *logger) {
    memset(policy, 0, sizeof(UA_SecurityPolicy));
    policy->logger = logger;

    policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256");
    policy->securityLevel = 10;

    UA_SecurityPolicyAsymmetricModule *const asymmetricModule = &policy->asymmetricModule;
    UA_SecurityPolicySymmetricModule *const symmetricModule = &policy->symmetricModule;
    UA_SecurityPolicyChannelModule *const channelModule = &policy->channelModule;

    UA_StatusCode retval = UA_mbedTLS_LoadLocalCertificate(&localCertificate, &policy->localCertificate);

    if (retval != UA_STATUSCODE_GOOD)
        return retval;

    /* AsymmetricModule */
    UA_SecurityPolicySignatureAlgorithm *asym_signatureAlgorithm =
        &asymmetricModule->cryptoModule.signatureAlgorithm;
    asym_signatureAlgorithm->uri =
        UA_STRING("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256\0");
    asym_signatureAlgorithm->verify =
        (UA_StatusCode (*)(void *, const UA_ByteString *, const UA_ByteString *))asym_verify_sp_basic256sha256;
    asym_signatureAlgorithm->sign =
        (UA_StatusCode (*)(void *, const UA_ByteString *, UA_ByteString *))asym_sign_sp_basic256sha256;
    asym_signatureAlgorithm->getLocalSignatureSize =
        (size_t (*)(const void *))asym_getLocalSignatureSize_sp_basic256sha256;
    asym_signatureAlgorithm->getRemoteSignatureSize =
        (size_t (*)(const void *))asym_getRemoteSignatureSize_sp_basic256sha256;
    asym_signatureAlgorithm->getLocalKeyLength = NULL; // TODO: Write function
    asym_signatureAlgorithm->getRemoteKeyLength = NULL; // TODO: Write function

    UA_SecurityPolicyEncryptionAlgorithm *asym_encryptionAlgorithm =
        &asymmetricModule->cryptoModule.encryptionAlgorithm;
    asym_encryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-oaep\0");
    asym_encryptionAlgorithm->encrypt =
        (UA_StatusCode(*)(void *, UA_ByteString *))asym_encrypt_sp_basic256sha256;
    asym_encryptionAlgorithm->decrypt =
        (UA_StatusCode(*)(void *, UA_ByteString *))
            asym_decrypt_sp_basic256sha256;
    asym_encryptionAlgorithm->getLocalKeyLength =
        (size_t (*)(const void *))asym_getLocalEncryptionKeyLength_sp_basic256sha256;
    asym_encryptionAlgorithm->getRemoteKeyLength =
        (size_t (*)(const void *))asym_getRemoteEncryptionKeyLength_sp_basic256sha256;
    asym_encryptionAlgorithm->getRemoteBlockSize =
        (size_t (*)(const void *))asym_getRemoteBlockSize_sp_basic256sha256;
    asym_encryptionAlgorithm->getRemotePlainTextBlockSize =
        (size_t (*)(const void *))asym_getRemotePlainTextBlockSize_sp_basic256sha256;

    asymmetricModule->makeCertificateThumbprint = asym_makeThumbprint_sp_basic256sha256;
    asymmetricModule->compareCertificateThumbprint =
        asymmetricModule_compareCertificateThumbprint_sp_basic256sha256;

    /* SymmetricModule */
    symmetricModule->generateKey = sym_generateKey_sp_basic256sha256;
    symmetricModule->generateNonce = sym_generateNonce_sp_basic256sha256;

    UA_SecurityPolicySignatureAlgorithm *sym_signatureAlgorithm =
        &symmetricModule->cryptoModule.signatureAlgorithm;
    sym_signatureAlgorithm->uri =
        UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha2-256\0");
    sym_signatureAlgorithm->verify =
        (UA_StatusCode (*)(void *, const UA_ByteString *, const UA_ByteString *))sym_verify_sp_basic256sha256;
    sym_signatureAlgorithm->sign =
        (UA_StatusCode (*)(void *, const UA_ByteString *, UA_ByteString *))sym_sign_sp_basic256sha256;
    sym_signatureAlgorithm->getLocalSignatureSize = sym_getSignatureSize_sp_basic256sha256;
    sym_signatureAlgorithm->getRemoteSignatureSize = sym_getSignatureSize_sp_basic256sha256;
    sym_signatureAlgorithm->getLocalKeyLength =
        (size_t (*)(const void *))sym_getSigningKeyLength_sp_basic256sha256;
    sym_signatureAlgorithm->getRemoteKeyLength =
        (size_t (*)(const void *))sym_getSigningKeyLength_sp_basic256sha256;

    UA_SecurityPolicyEncryptionAlgorithm *sym_encryptionAlgorithm =
        &symmetricModule->cryptoModule.encryptionAlgorithm;
    sym_encryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes256-cbc");
    sym_encryptionAlgorithm->encrypt =
        (UA_StatusCode(*)(void *, UA_ByteString *))sym_encrypt_sp_basic256sha256;
    sym_encryptionAlgorithm->decrypt =
        (UA_StatusCode(*)(void *, UA_ByteString *))sym_decrypt_sp_basic256sha256;
    sym_encryptionAlgorithm->getLocalKeyLength = sym_getEncryptionKeyLength_sp_basic256sha256;
    sym_encryptionAlgorithm->getRemoteKeyLength = sym_getEncryptionKeyLength_sp_basic256sha256;
    sym_encryptionAlgorithm->getRemoteBlockSize =
        (size_t (*)(const void *))sym_getEncryptionBlockSize_sp_basic256sha256;
    sym_encryptionAlgorithm->getRemotePlainTextBlockSize =
        (size_t (*)(const void *))sym_getPlainTextBlockSize_sp_basic256sha256;
    symmetricModule->secureChannelNonceLength = 32;

    // Use the same signature algorithm as the asymmetric component for certificate signing (see standard)
    policy->certificateSigningAlgorithm = policy->asymmetricModule.cryptoModule.signatureAlgorithm;

    /* ChannelModule */
    channelModule->newContext = channelContext_newContext_sp_basic256sha256;
    channelModule->deleteContext = (void (*)(void *))
        channelContext_deleteContext_sp_basic256sha256;

    channelModule->setLocalSymEncryptingKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setLocalSymEncryptingKey_sp_basic256sha256;
    channelModule->setLocalSymSigningKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setLocalSymSigningKey_sp_basic256sha256;
    channelModule->setLocalSymIv = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setLocalSymIv_sp_basic256sha256;

    channelModule->setRemoteSymEncryptingKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setRemoteSymEncryptingKey_sp_basic256sha256;
    channelModule->setRemoteSymSigningKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setRemoteSymSigningKey_sp_basic256sha256;
    channelModule->setRemoteSymIv = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setRemoteSymIv_sp_basic256sha256;

    channelModule->compareCertificate = (UA_StatusCode (*)(const void *, const UA_ByteString *))
        channelContext_compareCertificate_sp_basic256sha256;

    policy->updateCertificateAndPrivateKey = updateCertificateAndPrivateKey_sp_basic256sha256;
    policy->clear = clear_sp_basic256sha256;

    UA_StatusCode res = policyContext_newContext_sp_basic256sha256(policy, localPrivateKey);
    if(res != UA_STATUSCODE_GOOD)
        clear_sp_basic256sha256(policy);

    return res;
}

#endif

/**** amalgamated original file "/plugins/crypto/mbedtls/ua_securitypolicy_aes128sha256rsaoaep.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2018 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2018 (c) Daniel Feist, Precitec GmbH & Co. KG
 *    Copyright 2018 (c) HMS Industrial Networks AB (Author: Jonas Green)
 *    Copyright 2020 (c) Wind River Systems, Inc.
 */


#ifdef UA_ENABLE_ENCRYPTION_MBEDTLS


#include <mbedtls/aes.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
#include <mbedtls/error.h>
#include <mbedtls/md.h>
#include <mbedtls/sha1.h>
#include <mbedtls/sha256.h>
#include <mbedtls/version.h>
#include <mbedtls/x509_crt.h>

/* Notes:
 * mbedTLS' AES allows in-place encryption and decryption. So we don't have to
 * allocate temp buffers.
 * https://tls.mbed.org/discussions/generic/in-place-decryption-with-aes256-same-input-output-buffer
 */

#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_RSAPADDING_LEN 42
#define UA_SHA1_LENGTH 20
#define UA_SHA256_LENGTH 32
#define UA_AES128SHA256RSAOAEP_SYM_SIGNING_KEY_LENGTH 32
#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_KEY_LENGTH 16
#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_ENCRYPTION_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_PLAIN_TEXT_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_MINASYMKEYLENGTH 256
#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_MAXASYMKEYLENGTH 512

typedef struct {
    UA_ByteString localCertThumbprint;

    mbedtls_ctr_drbg_context drbgContext;
    mbedtls_entropy_context entropyContext;
    mbedtls_md_context_t sha256MdContext;
    mbedtls_pk_context localPrivateKey;
} Aes128Sha256PsaOaep_PolicyContext;

typedef struct {
    Aes128Sha256PsaOaep_PolicyContext *policyContext;

    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;

    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    mbedtls_x509_crt remoteCertificate;
} Aes128Sha256PsaOaep_ChannelContext;

/********************/
/* AsymmetricModule */
/********************/

/* VERIFY AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 */
static UA_StatusCode
asym_verify_sp_aes128sha256rsaoaep(Aes128Sha256PsaOaep_ChannelContext *cc,
                                   const UA_ByteString *message,
                                   const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned char hash[UA_SHA256_LENGTH];
#if MBEDTLS_VERSION_NUMBER >= 0x02070000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    // TODO check return status
    mbedtls_sha256_ret(message->data, message->length, hash, 0);
#else
    mbedtls_sha256(message->data, message->length, hash, 0);
#endif

    /* Set the RSA settings */
    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_SHA256);

    /* For RSA keys, the default padding type is PKCS#1 v1.5 in mbedtls_pk_verify() */
    /* Alternatively, use more specific function mbedtls_rsa_rsassa_pkcs1_v15_verify(), i.e. */
    /* int mbedErr = mbedtls_rsa_rsassa_pkcs1_v15_verify(rsaContext, NULL, NULL,
                                                         MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA256,
                                                         UA_SHA256_LENGTH, hash,
                                                         signature->data); */
    int mbedErr = mbedtls_pk_verify(&cc->remoteCertificate.pk,
                                    MBEDTLS_MD_SHA256, hash, UA_SHA256_LENGTH,
                                    signature->data, signature->length);

    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    return UA_STATUSCODE_GOOD;
}

/* AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 */
static UA_StatusCode
asym_sign_sp_aes128sha256rsaoaep(Aes128Sha256PsaOaep_ChannelContext *cc,
                                 const UA_ByteString *message,
                                 UA_ByteString *signature) {
    if(message == NULL || signature == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned char hash[UA_SHA256_LENGTH];
#if MBEDTLS_VERSION_NUMBER >= 0x02070000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    // TODO check return status
    mbedtls_sha256_ret(message->data, message->length, hash, 0);
#else
    mbedtls_sha256(message->data, message->length, hash, 0);
#endif

    Aes128Sha256PsaOaep_PolicyContext *pc = cc->policyContext;
    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(pc->localPrivateKey);
    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_SHA256);

    size_t sigLen = 0;

    /* For RSA keys, the default padding type is PKCS#1 v1.5 in mbedtls_pk_sign */
    /* Alternatively use more specific function mbedtls_rsa_rsassa_pkcs1_v15_sign() */
    int mbedErr = mbedtls_pk_sign(&pc->localPrivateKey,
                                  MBEDTLS_MD_SHA256, hash,
                                  UA_SHA256_LENGTH, signature->data,
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
                                  signature->length,
#endif
                                  &sigLen, mbedtls_ctr_drbg_random,
                                  &pc->drbgContext);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;
    return UA_STATUSCODE_GOOD;
}

static size_t
asym_getLocalSignatureSize_sp_aes128sha256rsaoaep(const Aes128Sha256PsaOaep_ChannelContext *cc) {
    if(cc == NULL)
        return 0;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    return mbedtls_pk_rsa(cc->policyContext->localPrivateKey)->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->policyContext->localPrivateKey));
#endif
}

static size_t
asym_getRemoteSignatureSize_sp_aes128sha256rsaoaep(const Aes128Sha256PsaOaep_ChannelContext *cc) {
    if(cc == NULL)
        return 0;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    return mbedtls_pk_rsa(cc->remoteCertificate.pk)->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
#endif
}

static size_t
asym_getRemoteBlockSize_sp_aes128sha256rsaoaep(const Aes128Sha256PsaOaep_ChannelContext *cc) {
    if(cc == NULL)
        return 0;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    return mbedtls_pk_rsa(cc->remoteCertificate.pk)->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
#endif
}

static size_t
asym_getRemotePlainTextBlockSize_sp_aes128sha256rsaoaep(const Aes128Sha256PsaOaep_ChannelContext *cc) {
    if(cc == NULL)
        return 0;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    return rsaContext->len - UA_SECURITYPOLICY_AES128SHA256RSAOAEP_RSAPADDING_LEN;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk)) -
        UA_SECURITYPOLICY_AES128SHA256RSAOAEP_RSAPADDING_LEN;
#endif
}


/* AsymmetricEncryptionAlgorithm_RSA-OAEP-SHA1 */
static UA_StatusCode
asym_encrypt_sp_aes128sha256rsaoaep(Aes128Sha256PsaOaep_ChannelContext *cc,
                                    UA_ByteString *data) {
    if(cc == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    const size_t plainTextBlockSize = asym_getRemotePlainTextBlockSize_sp_aes128sha256rsaoaep(cc);

    mbedtls_rsa_context *remoteRsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    mbedtls_rsa_set_padding(remoteRsaContext, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA1);

    return mbedtls_encrypt_rsaOaep(remoteRsaContext, &cc->policyContext->drbgContext,
                                   data, plainTextBlockSize);
}

/* AsymmetricEncryptionAlgorithm_RSA-OAEP-SHA1 */
static UA_StatusCode
asym_decrypt_sp_aes128sha256rsaoaep(Aes128Sha256PsaOaep_ChannelContext *cc,
                                    UA_ByteString *data) {
    if(cc == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    return mbedtls_decrypt_rsaOaep(&cc->policyContext->localPrivateKey,
                                   &cc->policyContext->drbgContext, data, MBEDTLS_MD_SHA1);
}

static size_t
asym_getLocalEncryptionKeyLength_sp_aes128sha256rsaoaep(const Aes128Sha256PsaOaep_ChannelContext *cc) {
    return mbedtls_pk_get_len(&cc->policyContext->localPrivateKey) * 8;
}

static size_t
asym_getRemoteEncryptionKeyLength_sp_aes128sha256rsaoaep(const Aes128Sha256PsaOaep_ChannelContext *cc) {
    return mbedtls_pk_get_len(&cc->remoteCertificate.pk) * 8;
}

static UA_StatusCode
asym_makeThumbprint_sp_aes128sha256rsaoaep(const UA_SecurityPolicy *securityPolicy,
                                           const UA_ByteString *certificate,
                                           UA_ByteString *thumbprint) {
    if(securityPolicy == NULL || certificate == NULL || thumbprint == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    return mbedtls_thumbprint_sha1(certificate, thumbprint);
}

static UA_StatusCode
asymmetricModule_compareCertificateThumbprint_sp_aes128sha256rsaoaep(const UA_SecurityPolicy *securityPolicy,
                                                                     const UA_ByteString *certificateThumbprint) {
    if(securityPolicy == NULL || certificateThumbprint == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Aes128Sha256PsaOaep_PolicyContext *pc = (Aes128Sha256PsaOaep_PolicyContext *)securityPolicy->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
        return UA_STATUSCODE_BADCERTIFICATEINVALID;

    return UA_STATUSCODE_GOOD;
}

/*******************/
/* SymmetricModule */
/*******************/

static UA_StatusCode
sym_verify_sp_aes128sha256rsaoaep(Aes128Sha256PsaOaep_ChannelContext *cc,
                                  const UA_ByteString *message,
                                  const UA_ByteString *signature) {
    if(cc == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Compute MAC */
    if(signature->length != UA_SHA256_LENGTH)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    Aes128Sha256PsaOaep_PolicyContext *pc = cc->policyContext;
    unsigned char mac[UA_SHA256_LENGTH];
    if(mbedtls_hmac(&pc->sha256MdContext, &cc->remoteSymSigningKey,
                    message, mac) != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Compare with Signature */
    if(!UA_constantTimeEqual(signature->data, mac, UA_SHA256_LENGTH))
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
sym_sign_sp_aes128sha256rsaoaep(const Aes128Sha256PsaOaep_ChannelContext *cc,
                                const UA_ByteString *message,
                                UA_ByteString *signature) {
    if(signature->length != UA_SHA256_LENGTH)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(mbedtls_hmac(&cc->policyContext->sha256MdContext, &cc->localSymSigningKey,
                    message, signature->data) != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    return UA_STATUSCODE_GOOD;
}

static size_t
sym_getSignatureSize_sp_aes128sha256rsaoaep(const void *channelContext) {
    return UA_SHA256_LENGTH;
}

static size_t
sym_getSigningKeyLength_sp_aes128sha256rsaoaep(const void *channelContext) {
    return UA_AES128SHA256RSAOAEP_SYM_SIGNING_KEY_LENGTH;
}

static size_t
sym_getEncryptionKeyLength_sp_aes128sha256rsaoaep(const void *channelContext) {
    return UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_KEY_LENGTH;
}

static size_t
sym_getEncryptionBlockSize_sp_aes128sha256rsaoaep(const void *channelContext) {
    return UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_ENCRYPTION_BLOCK_SIZE;
}

static size_t
sym_getPlainTextBlockSize_sp_aes128sha256rsaoaep(const void *channelContext) {
    return UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_PLAIN_TEXT_BLOCK_SIZE;
}

static UA_StatusCode
sym_encrypt_sp_aes128sha256rsaoaep(const Aes128Sha256PsaOaep_ChannelContext *cc,
                                   UA_ByteString *data) {
    if(cc == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(cc->localSymIv.length != UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_ENCRYPTION_BLOCK_SIZE)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t plainTextBlockSize = UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_PLAIN_TEXT_BLOCK_SIZE;

    if(data->length % plainTextBlockSize != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Keylength in bits */
    unsigned int keylength = (unsigned int)(cc->localSymEncryptingKey.length * 8);
    mbedtls_aes_context aesContext;
    int mbedErr = mbedtls_aes_setkey_enc(&aesContext, cc->localSymEncryptingKey.data, keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString ivCopy;
    UA_StatusCode retval = UA_ByteString_copy(&cc->localSymIv, &ivCopy);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_ENCRYPT, data->length,
                                    ivCopy.data, data->data, data->data);
    if(mbedErr)
        retval = UA_STATUSCODE_BADINTERNALERROR;
    UA_ByteString_clear(&ivCopy);
    return retval;
}

static UA_StatusCode
sym_decrypt_sp_aes128sha256rsaoaep(const Aes128Sha256PsaOaep_ChannelContext *cc,
                                   UA_ByteString *data) {
    if(cc == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t encryptionBlockSize = UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_ENCRYPTION_BLOCK_SIZE;

    if(cc->remoteSymIv.length != encryptionBlockSize)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(data->length % encryptionBlockSize != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned int keylength = (unsigned int)(cc->remoteSymEncryptingKey.length * 8);
    mbedtls_aes_context aesContext;
    int mbedErr = mbedtls_aes_setkey_dec(&aesContext, cc->remoteSymEncryptingKey.data, keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString ivCopy;
    UA_StatusCode retval = UA_ByteString_copy(&cc->remoteSymIv, &ivCopy);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_DECRYPT, data->length,
                                    ivCopy.data, data->data, data->data);
    if(mbedErr)
        retval = UA_STATUSCODE_BADINTERNALERROR;
    UA_ByteString_clear(&ivCopy);
    return retval;
}

static UA_StatusCode
sym_generateKey_sp_aes128sha256rsaoaep(void *policyContext, const UA_ByteString *secret,
                                       const UA_ByteString *seed, UA_ByteString *out) {
    if(secret == NULL || seed == NULL || out == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes128Sha256PsaOaep_PolicyContext *pc = (Aes128Sha256PsaOaep_PolicyContext *)policyContext;
    return mbedtls_generateKey(&pc->sha256MdContext, secret, seed, out);
}

static UA_StatusCode
sym_generateNonce_sp_aes128sha256rsaoaep(void *policyContext, UA_ByteString *out) {
    if(out == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes128Sha256PsaOaep_PolicyContext *pc =
        (Aes128Sha256PsaOaep_PolicyContext *)policyContext;
    int mbedErr = mbedtls_ctr_drbg_random(&pc->drbgContext, out->data, out->length);
    if(mbedErr)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_STATUSCODE_GOOD;
}

/*****************/
/* ChannelModule */
/*****************/

/* Assumes that the certificate has been verified externally */
static UA_StatusCode
parseRemoteCertificate_sp_aes128sha256rsaoaep(Aes128Sha256PsaOaep_ChannelContext *cc,
                                              const UA_ByteString *remoteCertificate) {
    if(remoteCertificate == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Parse the certificate */
    int mbedErr = mbedtls_x509_crt_parse(&cc->remoteCertificate, remoteCertificate->data,
                                         remoteCertificate->length);
    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Check the key length */
    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    size_t keylen = rsaContext->len;
#else
    size_t keylen = mbedtls_rsa_get_len(rsaContext);
#endif
    if(keylen < UA_SECURITYPOLICY_AES128SHA256RSAOAEP_MINASYMKEYLENGTH ||
       keylen > UA_SECURITYPOLICY_AES128SHA256RSAOAEP_MAXASYMKEYLENGTH)
        return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;
    return UA_STATUSCODE_GOOD;
}

static void
channelContext_deleteContext_sp_aes128sha256rsaoaep(Aes128Sha256PsaOaep_ChannelContext *cc) {
    UA_ByteString_clear(&cc->localSymSigningKey);
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    UA_ByteString_clear(&cc->localSymIv);

    UA_ByteString_clear(&cc->remoteSymSigningKey);
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    UA_ByteString_clear(&cc->remoteSymIv);

    mbedtls_x509_crt_free(&cc->remoteCertificate);

    UA_free(cc);
}

static UA_StatusCode
channelContext_newContext_sp_aes128sha256rsaoaep(const UA_SecurityPolicy *securityPolicy,
                                                 const UA_ByteString *remoteCertificate,
                                                 void **pp_contextData) {
    if(securityPolicy == NULL || remoteCertificate == NULL || pp_contextData == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Allocate the channel context */
    *pp_contextData = UA_malloc(sizeof(Aes128Sha256PsaOaep_ChannelContext));
    if(*pp_contextData == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    Aes128Sha256PsaOaep_ChannelContext *cc = (Aes128Sha256PsaOaep_ChannelContext *)*pp_contextData;

    /* Initialize the channel context */
    cc->policyContext = (Aes128Sha256PsaOaep_PolicyContext *)securityPolicy->policyContext;

    UA_ByteString_init(&cc->localSymSigningKey);
    UA_ByteString_init(&cc->localSymEncryptingKey);
    UA_ByteString_init(&cc->localSymIv);

    UA_ByteString_init(&cc->remoteSymSigningKey);
    UA_ByteString_init(&cc->remoteSymEncryptingKey);
    UA_ByteString_init(&cc->remoteSymIv);

    mbedtls_x509_crt_init(&cc->remoteCertificate);

    // TODO: this can be optimized so that we dont allocate memory before parsing the certificate
    UA_StatusCode retval = parseRemoteCertificate_sp_aes128sha256rsaoaep(cc, remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        channelContext_deleteContext_sp_aes128sha256rsaoaep(cc);
        *pp_contextData = NULL;
    }
    return retval;
}

static UA_StatusCode
channelContext_setLocalSymEncryptingKey_sp_aes128sha256rsaoaep(Aes128Sha256PsaOaep_ChannelContext *cc,
                                                               const UA_ByteString *key) {
    if(key == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
channelContext_setLocalSymSigningKey_sp_aes128sha256rsaoaep(Aes128Sha256PsaOaep_ChannelContext *cc,
                                                            const UA_ByteString *key) {
    if(key == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}


static UA_StatusCode
channelContext_setLocalSymIv_sp_aes128sha256rsaoaep(Aes128Sha256PsaOaep_ChannelContext *cc,
                                                    const UA_ByteString *iv) {
    if(iv == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static UA_StatusCode
channelContext_setRemoteSymEncryptingKey_sp_aes128sha256rsaoaep(Aes128Sha256PsaOaep_ChannelContext *cc,
                                                                const UA_ByteString *key) {
    if(key == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
channelContext_setRemoteSymSigningKey_sp_aes128sha256rsaoaep(Aes128Sha256PsaOaep_ChannelContext *cc,
                                                             const UA_ByteString *key) {
    if(key == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
channelContext_setRemoteSymIv_sp_aes128sha256rsaoaep(Aes128Sha256PsaOaep_ChannelContext *cc,
                                                     const UA_ByteString *iv) {
    if(iv == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(iv, &cc->remoteSymIv);
}

static UA_StatusCode
channelContext_compareCertificate_sp_aes128sha256rsaoaep(const Aes128Sha256PsaOaep_ChannelContext *cc,
                                                         const UA_ByteString *certificate) {
    if(cc == NULL || certificate == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    mbedtls_x509_crt cert;
    mbedtls_x509_crt_init(&cert);
    int mbedErr = mbedtls_x509_crt_parse(&cert, certificate->data, certificate->length);
    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(cert.raw.len != cc->remoteCertificate.raw.len ||
       memcmp(cert.raw.p, cc->remoteCertificate.raw.p, cert.raw.len) != 0)
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    mbedtls_x509_crt_free(&cert);
    return retval;
}

static void
clear_sp_aes128sha256rsaoaep(UA_SecurityPolicy *securityPolicy) {
    if(securityPolicy == NULL)
        return;

    UA_ByteString_clear(&securityPolicy->localCertificate);

    if(securityPolicy->policyContext == NULL)
        return;

    /* delete all allocated members in the context */
    Aes128Sha256PsaOaep_PolicyContext *pc = (Aes128Sha256PsaOaep_PolicyContext *)
        securityPolicy->policyContext;

    mbedtls_ctr_drbg_free(&pc->drbgContext);
    mbedtls_entropy_free(&pc->entropyContext);
    mbedtls_pk_free(&pc->localPrivateKey);
    mbedtls_md_free(&pc->sha256MdContext);
    UA_ByteString_clear(&pc->localCertThumbprint);

    UA_LOG_DEBUG(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Deleted members of EndpointContext for sp_aes128sha256rsaoaep");

    UA_free(pc);
    securityPolicy->policyContext = NULL;
}

static UA_StatusCode
updateCertificateAndPrivateKey_sp_aes128sha256rsaoaep(UA_SecurityPolicy *securityPolicy,
                                                      const UA_ByteString newCertificate,
                                                      const UA_ByteString newPrivateKey) {
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(securityPolicy->policyContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Aes128Sha256PsaOaep_PolicyContext *pc =
            (Aes128Sha256PsaOaep_PolicyContext *) securityPolicy->policyContext;

    UA_ByteString_clear(&securityPolicy->localCertificate);

    UA_StatusCode retval = UA_ByteString_allocBuffer(&securityPolicy->localCertificate,
                                                     newCertificate.length + 1);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    memcpy(securityPolicy->localCertificate.data, newCertificate.data, newCertificate.length);
    securityPolicy->localCertificate.data[newCertificate.length] = '\0';
    securityPolicy->localCertificate.length--;

    /* Set the new private key */
    mbedtls_pk_free(&pc->localPrivateKey);
    mbedtls_pk_init(&pc->localPrivateKey);
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    int mbedErr = mbedtls_pk_parse_key(&pc->localPrivateKey, newPrivateKey.data,
                                       newPrivateKey.length, NULL, 0);
#else
    int mbedErr = mbedtls_pk_parse_key(&pc->localPrivateKey, newPrivateKey.data,
                                       newPrivateKey.length, NULL, 0, mbedtls_entropy_func, &pc->drbgContext);
#endif
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    retval = asym_makeThumbprint_sp_aes128sha256rsaoaep(securityPolicy,
                                                        &securityPolicy->localCertificate,
                                                        &pc->localCertThumbprint);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return retval;

    error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext != NULL)
        clear_sp_aes128sha256rsaoaep(securityPolicy);
    return retval;
}

static UA_StatusCode
policyContext_newContext_sp_aes128sha256rsaoaep(UA_SecurityPolicy *securityPolicy,
                                                const UA_ByteString localPrivateKey) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if (localPrivateKey.length == 0) {
        UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                     "Can not initialize security policy. Private key is empty.");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    Aes128Sha256PsaOaep_PolicyContext *pc = (Aes128Sha256PsaOaep_PolicyContext *)
        UA_malloc(sizeof(Aes128Sha256PsaOaep_PolicyContext));
    securityPolicy->policyContext = (void *)pc;
    if(!pc) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto error;
    }

    /* Initialize the PolicyContext */
    memset(pc, 0, sizeof(Aes128Sha256PsaOaep_PolicyContext));
    mbedtls_ctr_drbg_init(&pc->drbgContext);
    mbedtls_entropy_init(&pc->entropyContext);
    mbedtls_pk_init(&pc->localPrivateKey);
    mbedtls_md_init(&pc->sha256MdContext);

    /* Initialized the message digest */
    const mbedtls_md_info_t *const mdInfo = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
    int mbedErr = mbedtls_md_setup(&pc->sha256MdContext, mdInfo, MBEDTLS_MD_SHA256);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto error;
    }

    mbedErr = mbedtls_entropy_self_test(0);

    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Seed the RNG */
    char *personalization = "open62541-drbg";
    mbedErr = mbedtls_ctr_drbg_seed(&pc->drbgContext, mbedtls_entropy_func,
                                    &pc->entropyContext,
                                    (const unsigned char *)personalization, 14);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Set the private key */
    mbedErr = UA_mbedTLS_LoadPrivateKey(&localPrivateKey, &pc->localPrivateKey, &pc->entropyContext);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Set the local certificate thumbprint */
    retval = UA_ByteString_allocBuffer(&pc->localCertThumbprint, UA_SHA1_LENGTH);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;
    retval = asym_makeThumbprint_sp_aes128sha256rsaoaep(securityPolicy,
                                                        &securityPolicy->localCertificate,
                                                        &pc->localCertThumbprint);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return UA_STATUSCODE_GOOD;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not create securityContext: %s", UA_StatusCode_name(retval));
    if(securityPolicy->policyContext != NULL)
        clear_sp_aes128sha256rsaoaep(securityPolicy);
    return retval;
}

UA_StatusCode
UA_SecurityPolicy_Aes128Sha256RsaOaep(UA_SecurityPolicy *policy, const UA_ByteString localCertificate,
                                 const UA_ByteString localPrivateKey, const UA_Logger *logger) {
    memset(policy, 0, sizeof(UA_SecurityPolicy));
    policy->logger = logger;

    policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Aes128_Sha256_RsaOaep");
    policy->securityLevel = 30;

    UA_SecurityPolicyAsymmetricModule *const asymmetricModule = &policy->asymmetricModule;
    UA_SecurityPolicySymmetricModule *const symmetricModule = &policy->symmetricModule;
    UA_SecurityPolicyChannelModule *const channelModule = &policy->channelModule;

    UA_StatusCode retval = UA_mbedTLS_LoadLocalCertificate(&localCertificate, &policy->localCertificate);

    if (retval != UA_STATUSCODE_GOOD)
        return retval;

    /* AsymmetricModule */
    UA_SecurityPolicySignatureAlgorithm *asym_signatureAlgorithm =
        &asymmetricModule->cryptoModule.signatureAlgorithm;
    asym_signatureAlgorithm->uri =
        UA_STRING("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256\0");
    asym_signatureAlgorithm->verify =
        (UA_StatusCode (*)(void *, const UA_ByteString *, const UA_ByteString *))asym_verify_sp_aes128sha256rsaoaep;
    asym_signatureAlgorithm->sign =
        (UA_StatusCode (*)(void *, const UA_ByteString *, UA_ByteString *))asym_sign_sp_aes128sha256rsaoaep;
    asym_signatureAlgorithm->getLocalSignatureSize =
        (size_t (*)(const void *))asym_getLocalSignatureSize_sp_aes128sha256rsaoaep;
    asym_signatureAlgorithm->getRemoteSignatureSize =
        (size_t (*)(const void *))asym_getRemoteSignatureSize_sp_aes128sha256rsaoaep;
    asym_signatureAlgorithm->getLocalKeyLength = NULL; // TODO: Write function
    asym_signatureAlgorithm->getRemoteKeyLength = NULL; // TODO: Write function

    UA_SecurityPolicyEncryptionAlgorithm *asym_encryptionAlgorithm =
        &asymmetricModule->cryptoModule.encryptionAlgorithm;
    asym_encryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-oaep\0");
    asym_encryptionAlgorithm->encrypt =
        (UA_StatusCode(*)(void *, UA_ByteString *))asym_encrypt_sp_aes128sha256rsaoaep;
    asym_encryptionAlgorithm->decrypt =
        (UA_StatusCode(*)(void *, UA_ByteString *)) asym_decrypt_sp_aes128sha256rsaoaep;
    asym_encryptionAlgorithm->getLocalKeyLength =
        (size_t (*)(const void *))asym_getLocalEncryptionKeyLength_sp_aes128sha256rsaoaep;
    asym_encryptionAlgorithm->getRemoteKeyLength =
        (size_t (*)(const void *))asym_getRemoteEncryptionKeyLength_sp_aes128sha256rsaoaep;
    asym_encryptionAlgorithm->getRemoteBlockSize = (size_t (*)(const void *))asym_getRemoteBlockSize_sp_aes128sha256rsaoaep;
    asym_encryptionAlgorithm->getRemotePlainTextBlockSize =
        (size_t (*)(const void *))asym_getRemotePlainTextBlockSize_sp_aes128sha256rsaoaep;

    asymmetricModule->makeCertificateThumbprint = asym_makeThumbprint_sp_aes128sha256rsaoaep;
    asymmetricModule->compareCertificateThumbprint =
        asymmetricModule_compareCertificateThumbprint_sp_aes128sha256rsaoaep;

    /* SymmetricModule */
    symmetricModule->generateKey = sym_generateKey_sp_aes128sha256rsaoaep;
    symmetricModule->generateNonce = sym_generateNonce_sp_aes128sha256rsaoaep;

    UA_SecurityPolicySignatureAlgorithm *sym_signatureAlgorithm =
        &symmetricModule->cryptoModule.signatureAlgorithm;
    sym_signatureAlgorithm->uri =
        UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha1\0");
    sym_signatureAlgorithm->verify =
        (UA_StatusCode (*)(void *, const UA_ByteString *, const UA_ByteString *))sym_verify_sp_aes128sha256rsaoaep;
    sym_signatureAlgorithm->sign =
        (UA_StatusCode (*)(void *, const UA_ByteString *, UA_ByteString *))sym_sign_sp_aes128sha256rsaoaep;
    sym_signatureAlgorithm->getLocalSignatureSize = sym_getSignatureSize_sp_aes128sha256rsaoaep;
    sym_signatureAlgorithm->getRemoteSignatureSize = sym_getSignatureSize_sp_aes128sha256rsaoaep;
    sym_signatureAlgorithm->getLocalKeyLength =
        (size_t (*)(const void *))sym_getSigningKeyLength_sp_aes128sha256rsaoaep;
    sym_signatureAlgorithm->getRemoteKeyLength =
        (size_t (*)(const void *))sym_getSigningKeyLength_sp_aes128sha256rsaoaep;

    UA_SecurityPolicyEncryptionAlgorithm *sym_encryptionAlgorithm =
        &symmetricModule->cryptoModule.encryptionAlgorithm;
    sym_encryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes128-cbc");
    sym_encryptionAlgorithm->encrypt =
        (UA_StatusCode(*)(void *, UA_ByteString *))sym_encrypt_sp_aes128sha256rsaoaep;
    sym_encryptionAlgorithm->decrypt =
        (UA_StatusCode(*)(void *, UA_ByteString *))sym_decrypt_sp_aes128sha256rsaoaep;
    sym_encryptionAlgorithm->getLocalKeyLength = sym_getEncryptionKeyLength_sp_aes128sha256rsaoaep;
    sym_encryptionAlgorithm->getRemoteKeyLength = sym_getEncryptionKeyLength_sp_aes128sha256rsaoaep;
    sym_encryptionAlgorithm->getRemoteBlockSize =
        (size_t (*)(const void *))sym_getEncryptionBlockSize_sp_aes128sha256rsaoaep;
    sym_encryptionAlgorithm->getRemotePlainTextBlockSize =
        (size_t (*)(const void *))sym_getPlainTextBlockSize_sp_aes128sha256rsaoaep;
    symmetricModule->secureChannelNonceLength = 32;

    // Use the same signature algorithm as the asymmetric component for certificate signing (see standard)
    policy->certificateSigningAlgorithm = policy->asymmetricModule.cryptoModule.signatureAlgorithm;

    /* ChannelModule */
    channelModule->newContext = channelContext_newContext_sp_aes128sha256rsaoaep;
    channelModule->deleteContext = (void (*)(void *))
        channelContext_deleteContext_sp_aes128sha256rsaoaep;

    channelModule->setLocalSymEncryptingKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setLocalSymEncryptingKey_sp_aes128sha256rsaoaep;
    channelModule->setLocalSymSigningKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setLocalSymSigningKey_sp_aes128sha256rsaoaep;
    channelModule->setLocalSymIv = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setLocalSymIv_sp_aes128sha256rsaoaep;

    channelModule->setRemoteSymEncryptingKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setRemoteSymEncryptingKey_sp_aes128sha256rsaoaep;
    channelModule->setRemoteSymSigningKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setRemoteSymSigningKey_sp_aes128sha256rsaoaep;
    channelModule->setRemoteSymIv = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setRemoteSymIv_sp_aes128sha256rsaoaep;

    channelModule->compareCertificate = (UA_StatusCode (*)(const void *, const UA_ByteString *))
        channelContext_compareCertificate_sp_aes128sha256rsaoaep;

    policy->updateCertificateAndPrivateKey = updateCertificateAndPrivateKey_sp_aes128sha256rsaoaep;
    policy->clear = clear_sp_aes128sha256rsaoaep;

    UA_StatusCode res = policyContext_newContext_sp_aes128sha256rsaoaep(policy, localPrivateKey);
    if(res != UA_STATUSCODE_GOOD)
        clear_sp_aes128sha256rsaoaep(policy);

    return res;
}

#endif

/**** amalgamated original file "/plugins/crypto/mbedtls/ua_securitypolicy_aes256sha256rsapss.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2022 (c) Fraunhofer IOSB (Author: Noel Graf)
 */


#ifdef UA_ENABLE_ENCRYPTION_MBEDTLS


#include <mbedtls/aes.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/entropy.h>
#include <mbedtls/error.h>
#include <mbedtls/md.h>
#include <mbedtls/sha1.h>
#include <mbedtls/sha256.h>
#include <mbedtls/version.h>
#include <mbedtls/x509_crt.h>

/* Notes:
 * mbedTLS' AES allows in-place encryption and decryption. So we don't have to
 * allocate temp buffers.
 * https://tls.mbed.org/discussions/generic/in-place-decryption-with-aes256-same-input-output-buffer
 */

#define UA_SHA1_LENGTH 20
#define UA_SHA256_LENGTH 32
#define UA_SECURITYPOLICY_AES256SHA256RSAPSS_RSAPADDING_LEN 66 /* UA_SHA256_LENGTH * 2 + 2 */
#define UA_AES256SHA256RSAPSS_SYM_SIGNING_KEY_LENGTH 32
#define UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_KEY_LENGTH 32 /*16*/
#define UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_ENCRYPTION_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_PLAIN_TEXT_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_AES256SHA256RSAPSS_MINASYMKEYLENGTH 256
#define UA_SECURITYPOLICY_AES256SHA256RSAPSS_MAXASYMKEYLENGTH 512

typedef struct {
    UA_ByteString localCertThumbprint;

    mbedtls_ctr_drbg_context drbgContext;
    mbedtls_entropy_context entropyContext;
    mbedtls_md_context_t sha256MdContext;
    mbedtls_pk_context localPrivateKey;
} Aes256Sha256RsaPss_PolicyContext;

typedef struct {
    Aes256Sha256RsaPss_PolicyContext *policyContext;

    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;

    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    mbedtls_x509_crt remoteCertificate;
} Aes256Sha256RsaPss_ChannelContext;

/********************/
/* AsymmetricModule */
/********************/

/* VERIFY AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 */
static UA_StatusCode
asym_verify_sp_aes256sha256rsapss(Aes256Sha256RsaPss_ChannelContext *cc,
                                   const UA_ByteString *message,
                                   const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned char hash[UA_SHA256_LENGTH];
#if MBEDTLS_VERSION_NUMBER >= 0x02070000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    // TODO check return status
    mbedtls_sha256_ret(message->data, message->length, hash, 0);
#else
    mbedtls_sha256(message->data, message->length, hash, 0);
#endif

    /* Set the RSA settings */
    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);

#if MBEDTLS_VERSION_NUMBER < 0x03000000
    Aes256Sha256RsaPss_PolicyContext *pc = cc->policyContext;
    int mbedErr = mbedtls_rsa_pkcs1_verify(rsaContext, mbedtls_ctr_drbg_random, &pc->drbgContext,
                                                MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA256, UA_SHA256_LENGTH,
                                                hash, signature->data);
#else
    int mbedErr = mbedtls_rsa_pkcs1_verify(rsaContext, MBEDTLS_MD_SHA256,
                                         UA_SHA256_LENGTH, hash, signature->data);
#endif

    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    return UA_STATUSCODE_GOOD;
}

/* AsymmetricSignatureAlgorithm_RSA-PSS-SHA2-256 */
static UA_StatusCode
asym_sign_sp_aes256sha256rsapss(Aes256Sha256RsaPss_ChannelContext *cc,
                                 const UA_ByteString *message,
                                 UA_ByteString *signature) {
    if(message == NULL || signature == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned char hash[UA_SHA256_LENGTH];
#if MBEDTLS_VERSION_NUMBER >= 0x02070000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    // TODO check return status
    mbedtls_sha256_ret(message->data, message->length, hash, 0);
#else
    mbedtls_sha256(message->data, message->length, hash, 0);
#endif

    Aes256Sha256RsaPss_PolicyContext *pc = cc->policyContext;
    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(pc->localPrivateKey);
    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);

#if MBEDTLS_VERSION_NUMBER < 0x03000000
    int mbedErr =  mbedtls_rsa_pkcs1_sign(rsaContext, mbedtls_ctr_drbg_random, &pc->drbgContext,
                                          MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_SHA256, UA_SHA256_LENGTH,
                                          hash, signature->data);
#else
    int mbedErr =  mbedtls_rsa_pkcs1_sign(rsaContext, mbedtls_ctr_drbg_random, &pc->drbgContext,
                                          MBEDTLS_MD_SHA256, UA_SHA256_LENGTH,
                                          hash, signature->data);
#endif


    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;
    return UA_STATUSCODE_GOOD;
}

static size_t
asym_getLocalSignatureSize_sp_aes256sha256rsapss(const Aes256Sha256RsaPss_ChannelContext *cc) {
    if(cc == NULL)
        return 0;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    return mbedtls_pk_rsa(cc->policyContext->localPrivateKey)->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->policyContext->localPrivateKey));
#endif
}

static size_t
asym_getRemoteSignatureSize_sp_aes256sha256rsapss(const Aes256Sha256RsaPss_ChannelContext *cc) {
    if(cc == NULL)
        return 0;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    return mbedtls_pk_rsa(cc->remoteCertificate.pk)->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
#endif
}

static size_t
asym_getRemoteBlockSize_sp_aes256sha256rsapss(const Aes256Sha256RsaPss_ChannelContext *cc) {
    if(cc == NULL)
        return 0;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    return mbedtls_pk_rsa(cc->remoteCertificate.pk)->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
#endif
}

static size_t
asym_getRemotePlainTextBlockSize_sp_aes256sha256rsapss(const Aes256Sha256RsaPss_ChannelContext *cc) {
    if(cc == NULL)
        return 0;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    mbedtls_rsa_context *const rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    return rsaContext->len - UA_SECURITYPOLICY_AES256SHA256RSAPSS_RSAPADDING_LEN;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk)) -
        UA_SECURITYPOLICY_AES256SHA256RSAPSS_RSAPADDING_LEN;
#endif
}


/* AsymmetricEncryptionAlgorithm_RSA-OAEP-SHA2 */
static UA_StatusCode
asym_encrypt_sp_aes256sha256rsapss(Aes256Sha256RsaPss_ChannelContext *cc,
                                    UA_ByteString *data) {
    if(cc == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    const size_t plainTextBlockSize = asym_getRemotePlainTextBlockSize_sp_aes256sha256rsapss(cc);

    mbedtls_rsa_context *remoteRsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    mbedtls_rsa_set_padding(remoteRsaContext, MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);

    return mbedtls_encrypt_rsaOaep(remoteRsaContext, &cc->policyContext->drbgContext,
                                   data, plainTextBlockSize);
}

/* AsymmetricEncryptionAlgorithm_RSA-OAEP-SHA2 */
static UA_StatusCode
asym_decrypt_sp_aes256sha256rsapss(Aes256Sha256RsaPss_ChannelContext *cc,
                                    UA_ByteString *data) {
    if(cc == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    return mbedtls_decrypt_rsaOaep(&cc->policyContext->localPrivateKey,
                                   &cc->policyContext->drbgContext, data, MBEDTLS_MD_SHA256);
}

static size_t
asym_getLocalEncryptionKeyLength_sp_aes256sha256rsapss(const Aes256Sha256RsaPss_ChannelContext *cc) {
    return mbedtls_pk_get_len(&cc->policyContext->localPrivateKey) * 8;
}

static size_t
asym_getRemoteEncryptionKeyLength_sp_aes256sha256rsapss(const Aes256Sha256RsaPss_ChannelContext *cc) {
    return mbedtls_pk_get_len(&cc->remoteCertificate.pk) * 8;
}

static UA_StatusCode
asym_makeThumbprint_sp_aes256sha256rsapss(const UA_SecurityPolicy *securityPolicy,
                                           const UA_ByteString *certificate,
                                           UA_ByteString *thumbprint) {
    if(securityPolicy == NULL || certificate == NULL || thumbprint == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    return mbedtls_thumbprint_sha1(certificate, thumbprint);
}

static UA_StatusCode
asymmetricModule_compareCertificateThumbprint_sp_aes256sha256rsapss(const UA_SecurityPolicy *securityPolicy,
                                                                     const UA_ByteString *certificateThumbprint) {
    if(securityPolicy == NULL || certificateThumbprint == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Aes256Sha256RsaPss_PolicyContext *pc = (Aes256Sha256RsaPss_PolicyContext *)securityPolicy->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
        return UA_STATUSCODE_BADCERTIFICATEINVALID;

    return UA_STATUSCODE_GOOD;
}

/*******************/
/* SymmetricModule */
/*******************/

static UA_StatusCode
sym_verify_sp_aes256sha256rsapss(Aes256Sha256RsaPss_ChannelContext *cc,
                                  const UA_ByteString *message,
                                  const UA_ByteString *signature) {
    if(cc == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Compute MAC */
    if(signature->length != UA_SHA256_LENGTH)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    Aes256Sha256RsaPss_PolicyContext *pc = cc->policyContext;
    unsigned char mac[UA_SHA256_LENGTH];
    if(mbedtls_hmac(&pc->sha256MdContext, &cc->remoteSymSigningKey, message, mac) != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Compare with Signature */
    if(!UA_constantTimeEqual(signature->data, mac, UA_SHA256_LENGTH))
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
sym_sign_sp_aes256sha256rsapss(const Aes256Sha256RsaPss_ChannelContext *cc,
                                const UA_ByteString *message,
                                UA_ByteString *signature) {
    if(signature->length != UA_SHA256_LENGTH)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(mbedtls_hmac(&cc->policyContext->sha256MdContext, &cc->localSymSigningKey,
                    message, signature->data) != UA_STATUSCODE_GOOD)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    return UA_STATUSCODE_GOOD;
}

static size_t
sym_getSignatureSize_sp_aes256sha256rsapss(const void *channelContext) {
    return UA_SHA256_LENGTH;
}

static size_t
sym_getSigningKeyLength_sp_aes256sha256rsapss(const void *channelContext) {
    return UA_AES256SHA256RSAPSS_SYM_SIGNING_KEY_LENGTH;
}

static size_t
sym_getEncryptionKeyLength_sp_aes256sha256rsapss(const void *channelContext) {
    return UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_KEY_LENGTH;
}

static size_t
sym_getEncryptionBlockSize_sp_aes256sha256rsapss(const void *channelContext) {
    return UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_ENCRYPTION_BLOCK_SIZE;
}

static size_t
sym_getPlainTextBlockSize_sp_aes256sha256rsapss(const void *channelContext) {
    return UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_PLAIN_TEXT_BLOCK_SIZE;
}

static UA_StatusCode
sym_encrypt_sp_aes256sha256rsapss(const Aes256Sha256RsaPss_ChannelContext *cc,
                                   UA_ByteString *data) {
    if(cc == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(cc->localSymIv.length != UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_ENCRYPTION_BLOCK_SIZE)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t plainTextBlockSize = UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_PLAIN_TEXT_BLOCK_SIZE;

    if(data->length % plainTextBlockSize != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Keylength in bits */
    unsigned int keylength = (unsigned int)(cc->localSymEncryptingKey.length * 8);
    mbedtls_aes_context aesContext;
    int mbedErr = mbedtls_aes_setkey_enc(&aesContext, cc->localSymEncryptingKey.data, keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString ivCopy;
    UA_StatusCode retval = UA_ByteString_copy(&cc->localSymIv, &ivCopy);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_ENCRYPT, data->length,
                                    ivCopy.data, data->data, data->data);
    if(mbedErr)
        retval = UA_STATUSCODE_BADINTERNALERROR;
    UA_ByteString_clear(&ivCopy);
    return retval;
}

static UA_StatusCode
sym_decrypt_sp_aes256sha256rsapss(const Aes256Sha256RsaPss_ChannelContext *cc,
                                   UA_ByteString *data) {
    if(cc == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    size_t encryptionBlockSize = UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_ENCRYPTION_BLOCK_SIZE;

    if(cc->remoteSymIv.length != encryptionBlockSize)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(data->length % encryptionBlockSize != 0)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned int keylength = (unsigned int)(cc->remoteSymEncryptingKey.length * 8);
    mbedtls_aes_context aesContext;
    int mbedErr = mbedtls_aes_setkey_dec(&aesContext, cc->remoteSymEncryptingKey.data, keylength);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString ivCopy;
    UA_StatusCode retval = UA_ByteString_copy(&cc->remoteSymIv, &ivCopy);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    mbedErr = mbedtls_aes_crypt_cbc(&aesContext, MBEDTLS_AES_DECRYPT, data->length,
                                    ivCopy.data, data->data, data->data);
    if(mbedErr)
        retval = UA_STATUSCODE_BADINTERNALERROR;
    UA_ByteString_clear(&ivCopy);
    return retval;
}

static UA_StatusCode
sym_generateKey_sp_aes256sha256rsapss(void *policyContext, const UA_ByteString *secret,
                                       const UA_ByteString *seed, UA_ByteString *out) {
    if(secret == NULL || seed == NULL || out == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes256Sha256RsaPss_PolicyContext *pc = (Aes256Sha256RsaPss_PolicyContext *)policyContext;
    return mbedtls_generateKey(&pc->sha256MdContext, secret, seed, out);
}

static UA_StatusCode
sym_generateNonce_sp_aes256sha256rsapss(void *policyContext, UA_ByteString *out) {
    if(out == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Aes256Sha256RsaPss_PolicyContext *pc =
        (Aes256Sha256RsaPss_PolicyContext *)policyContext;
    int mbedErr = mbedtls_ctr_drbg_random(&pc->drbgContext, out->data, out->length);
    if(mbedErr)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_STATUSCODE_GOOD;
}

/***********************************/
/* CertificateSigningAlgorithms    */
/***********************************/

static UA_StatusCode
asym_cert_verify_sp_aes256sha256rsapss(Aes256Sha256RsaPss_ChannelContext *cc,
                                   const UA_ByteString *message,
                                   const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned char hash[UA_SHA256_LENGTH];
#if MBEDTLS_VERSION_NUMBER >= 0x02070000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    // TODO check return status
    mbedtls_sha256_ret(message->data, message->length, hash, 0);
#else
    mbedtls_sha256(message->data, message->length, hash, 0);
#endif

    /* Set the RSA settings */
    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_SHA256);

    /* For RSA keys, the default padding type is PKCS#1 v1.5 in mbedtls_pk_verify() */
    /* Alternatively, use more specific function mbedtls_rsa_rsassa_pkcs1_v15_verify(), i.e. */
    /* int mbedErr = mbedtls_rsa_rsassa_pkcs1_v15_verify(rsaContext, NULL, NULL,
                                                         MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA256,
                                                         UA_SHA256_LENGTH, hash,
                                                         signature->data); */
    int mbedErr = mbedtls_pk_verify(&cc->remoteCertificate.pk,
                                    MBEDTLS_MD_SHA256, hash, UA_SHA256_LENGTH,
                                    signature->data, signature->length);

    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    return UA_STATUSCODE_GOOD;
}

/* AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 */
static UA_StatusCode
asym_cert_sign_sp_aes256sha256rsapss(Aes256Sha256RsaPss_ChannelContext *cc,
                                 const UA_ByteString *message,
                                 UA_ByteString *signature) {
    if(message == NULL || signature == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    unsigned char hash[UA_SHA256_LENGTH];
#if MBEDTLS_VERSION_NUMBER >= 0x02070000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    // TODO check return status
    mbedtls_sha256_ret(message->data, message->length, hash, 0);
#else
    mbedtls_sha256(message->data, message->length, hash, 0);
#endif

    Aes256Sha256RsaPss_PolicyContext *pc = cc->policyContext;
    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(pc->localPrivateKey);
    mbedtls_rsa_set_padding(rsaContext, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_SHA256);

    size_t sigLen = 0;

    /* For RSA keys, the default padding type is PKCS#1 v1.5 in mbedtls_pk_sign */
    /* Alternatively use more specific function mbedtls_rsa_rsassa_pkcs1_v15_sign() */
    int mbedErr = mbedtls_pk_sign(&pc->localPrivateKey,
                                  MBEDTLS_MD_SHA256, hash,
                                  UA_SHA256_LENGTH, signature->data,
#if MBEDTLS_VERSION_NUMBER >= 0x03000000
        signature->length,
#endif
                                  &sigLen, mbedtls_ctr_drbg_random,
                                  &pc->drbgContext);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;
    return UA_STATUSCODE_GOOD;
}

static size_t
asym_cert_getLocalSignatureSize_sp_aes256sha256rsapss(const Aes256Sha256RsaPss_ChannelContext *cc) {
    if(cc == NULL)
        return 0;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    return mbedtls_pk_rsa(cc->policyContext->localPrivateKey)->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->policyContext->localPrivateKey));
#endif
}

static size_t
asym_cert_getRemoteSignatureSize_sp_aes256sha256rsapss(const Aes256Sha256RsaPss_ChannelContext *cc) {
    if(cc == NULL)
        return 0;
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    return mbedtls_pk_rsa(cc->remoteCertificate.pk)->len;
#else
    return mbedtls_rsa_get_len(mbedtls_pk_rsa(cc->remoteCertificate.pk));
#endif
}

/*****************/
/* ChannelModule */
/*****************/

/* Assumes that the certificate has been verified externally */
static UA_StatusCode
parseRemoteCertificate_sp_aes256sha256rsapss(Aes256Sha256RsaPss_ChannelContext *cc,
                                              const UA_ByteString *remoteCertificate) {
    if(remoteCertificate == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Parse the certificate */
    int mbedErr = mbedtls_x509_crt_parse(&cc->remoteCertificate, remoteCertificate->data,
                                         remoteCertificate->length);
    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Check the key length */
    mbedtls_rsa_context *rsaContext = mbedtls_pk_rsa(cc->remoteCertificate.pk);
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    size_t keylen = rsaContext->len;
#else
    size_t keylen = mbedtls_rsa_get_len(rsaContext);
#endif
    if(keylen < UA_SECURITYPOLICY_AES256SHA256RSAPSS_MINASYMKEYLENGTH ||
       keylen > UA_SECURITYPOLICY_AES256SHA256RSAPSS_MAXASYMKEYLENGTH)
        return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;
    return UA_STATUSCODE_GOOD;
}

static void
channelContext_deleteContext_sp_aes256sha256rsapss(Aes256Sha256RsaPss_ChannelContext *cc) {
    UA_ByteString_clear(&cc->localSymSigningKey);
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    UA_ByteString_clear(&cc->localSymIv);

    UA_ByteString_clear(&cc->remoteSymSigningKey);
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    UA_ByteString_clear(&cc->remoteSymIv);

    mbedtls_x509_crt_free(&cc->remoteCertificate);

    UA_free(cc);
}

static UA_StatusCode
channelContext_newContext_sp_aes256sha256rsapss(const UA_SecurityPolicy *securityPolicy,
                                                 const UA_ByteString *remoteCertificate,
                                                 void **pp_contextData) {
    if(securityPolicy == NULL || remoteCertificate == NULL || pp_contextData == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    /* Allocate the channel context */
    *pp_contextData = UA_malloc(sizeof(Aes256Sha256RsaPss_ChannelContext));
    if(*pp_contextData == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    Aes256Sha256RsaPss_ChannelContext *cc = (Aes256Sha256RsaPss_ChannelContext *)*pp_contextData;

    /* Initialize the channel context */
    cc->policyContext = (Aes256Sha256RsaPss_PolicyContext *)securityPolicy->policyContext;

    UA_ByteString_init(&cc->localSymSigningKey);
    UA_ByteString_init(&cc->localSymEncryptingKey);
    UA_ByteString_init(&cc->localSymIv);

    UA_ByteString_init(&cc->remoteSymSigningKey);
    UA_ByteString_init(&cc->remoteSymEncryptingKey);
    UA_ByteString_init(&cc->remoteSymIv);

    mbedtls_x509_crt_init(&cc->remoteCertificate);

    // TODO: this can be optimized so that we dont allocate memory before parsing the certificate
    UA_StatusCode retval = parseRemoteCertificate_sp_aes256sha256rsapss(cc, remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        channelContext_deleteContext_sp_aes256sha256rsapss(cc);
        *pp_contextData = NULL;
    }
    return retval;
}

static UA_StatusCode
channelContext_setLocalSymEncryptingKey_sp_aes256sha256rsapss(Aes256Sha256RsaPss_ChannelContext *cc,
                                                               const UA_ByteString *key) {
    if(key == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
channelContext_setLocalSymSigningKey_sp_aes256sha256rsapss(Aes256Sha256RsaPss_ChannelContext *cc,
                                                            const UA_ByteString *key) {
    if(key == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}


static UA_StatusCode
channelContext_setLocalSymIv_sp_aes256sha256rsapss(Aes256Sha256RsaPss_ChannelContext *cc,
                                                    const UA_ByteString *iv) {
    if(iv == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static UA_StatusCode
channelContext_setRemoteSymEncryptingKey_sp_aes256sha256rsapss(Aes256Sha256RsaPss_ChannelContext *cc,
                                                                const UA_ByteString *key) {
    if(key == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
channelContext_setRemoteSymSigningKey_sp_aes256sha256rsapss(Aes256Sha256RsaPss_ChannelContext *cc,
                                                             const UA_ByteString *key) {
    if(key == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
channelContext_setRemoteSymIv_sp_aes256sha256rsapss(Aes256Sha256RsaPss_ChannelContext *cc,
                                                     const UA_ByteString *iv) {
    if(iv == NULL || cc == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(iv, &cc->remoteSymIv);
}

static UA_StatusCode
channelContext_compareCertificate_sp_aes256sha256rsapss(const Aes256Sha256RsaPss_ChannelContext *cc,
                                                         const UA_ByteString *certificate) {
    if(cc == NULL || certificate == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    mbedtls_x509_crt cert;
    mbedtls_x509_crt_init(&cert);
    int mbedErr = mbedtls_x509_crt_parse(&cert, certificate->data, certificate->length);
    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(cert.raw.len != cc->remoteCertificate.raw.len ||
       memcmp(cert.raw.p, cc->remoteCertificate.raw.p, cert.raw.len) != 0)
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    mbedtls_x509_crt_free(&cert);
    return retval;
}

static void
clear_sp_aes256sha256rsapss(UA_SecurityPolicy *securityPolicy) {
    if(securityPolicy == NULL)
        return;

    UA_ByteString_clear(&securityPolicy->localCertificate);

    if(securityPolicy->policyContext == NULL)
        return;

    /* delete all allocated members in the context */
    Aes256Sha256RsaPss_PolicyContext *pc = (Aes256Sha256RsaPss_PolicyContext *)
        securityPolicy->policyContext;

    mbedtls_ctr_drbg_free(&pc->drbgContext);
    mbedtls_entropy_free(&pc->entropyContext);
    mbedtls_pk_free(&pc->localPrivateKey);
    mbedtls_md_free(&pc->sha256MdContext);
    UA_ByteString_clear(&pc->localCertThumbprint);

    UA_LOG_DEBUG(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Deleted members of EndpointContext for sp_aes256sha256rsapss");

    UA_free(pc);
    securityPolicy->policyContext = NULL;
}

static UA_StatusCode
updateCertificateAndPrivateKey_sp_aes256sha256rsapss(UA_SecurityPolicy *securityPolicy,
                                                      const UA_ByteString newCertificate,
                                                      const UA_ByteString newPrivateKey) {
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(securityPolicy->policyContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Aes256Sha256RsaPss_PolicyContext *pc =
        (Aes256Sha256RsaPss_PolicyContext *) securityPolicy->policyContext;

    UA_ByteString_clear(&securityPolicy->localCertificate);

    UA_StatusCode retval = UA_ByteString_allocBuffer(&securityPolicy->localCertificate,
                                                     newCertificate.length + 1);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;
    memcpy(securityPolicy->localCertificate.data, newCertificate.data, newCertificate.length);
    securityPolicy->localCertificate.data[newCertificate.length] = '\0';
    securityPolicy->localCertificate.length--;

    /* Set the new private key */
    mbedtls_pk_free(&pc->localPrivateKey);
    mbedtls_pk_init(&pc->localPrivateKey);
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    int mbedErr = mbedtls_pk_parse_key(&pc->localPrivateKey, newPrivateKey.data,
                                       newPrivateKey.length, NULL, 0);
#else
    int mbedErr = mbedtls_pk_parse_key(&pc->localPrivateKey, newPrivateKey.data,
                                       newPrivateKey.length, NULL, 0, mbedtls_entropy_func, &pc->drbgContext);
#endif
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    retval = asym_makeThumbprint_sp_aes256sha256rsapss(securityPolicy,
                                                        &securityPolicy->localCertificate,
                                                        &pc->localCertThumbprint);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return retval;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext != NULL)
        clear_sp_aes256sha256rsapss(securityPolicy);
    return retval;
}

static UA_StatusCode
policyContext_newContext_sp_aes256sha256rsapss(UA_SecurityPolicy *securityPolicy,
                                                const UA_ByteString localPrivateKey) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if (localPrivateKey.length == 0) {
        UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                     "Can not initialize security policy. Private key is empty.");
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    Aes256Sha256RsaPss_PolicyContext *pc = (Aes256Sha256RsaPss_PolicyContext *)
        UA_malloc(sizeof(Aes256Sha256RsaPss_PolicyContext));
    securityPolicy->policyContext = (void *)pc;
    if(!pc) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto error;
    }

    /* Initialize the PolicyContext */
    memset(pc, 0, sizeof(Aes256Sha256RsaPss_PolicyContext));
    mbedtls_ctr_drbg_init(&pc->drbgContext);
    mbedtls_entropy_init(&pc->entropyContext);
    mbedtls_pk_init(&pc->localPrivateKey);
    mbedtls_md_init(&pc->sha256MdContext);

    /* Initialized the message digest */
    const mbedtls_md_info_t *const mdInfo = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
    int mbedErr = mbedtls_md_setup(&pc->sha256MdContext, mdInfo, MBEDTLS_MD_SHA256);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADOUTOFMEMORY;
        goto error;
    }

    mbedErr = mbedtls_entropy_self_test(0);

    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Seed the RNG */
    char *personalization = "open62541-drbg";
    mbedErr = mbedtls_ctr_drbg_seed(&pc->drbgContext, mbedtls_entropy_func,
                                    &pc->entropyContext,
                                    (const unsigned char *)personalization, 14);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Set the private key */
    mbedErr = UA_mbedTLS_LoadPrivateKey(&localPrivateKey, &pc->localPrivateKey, &pc->entropyContext);
    if(mbedErr) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    /* Set the local certificate thumbprint */
    retval = UA_ByteString_allocBuffer(&pc->localCertThumbprint, UA_SHA1_LENGTH);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;
    retval = asym_makeThumbprint_sp_aes256sha256rsapss(securityPolicy,
                                                        &securityPolicy->localCertificate,
                                                        &pc->localCertThumbprint);
    if(retval != UA_STATUSCODE_GOOD)
        goto error;

    return UA_STATUSCODE_GOOD;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not create securityContext: %s", UA_StatusCode_name(retval));
    if(securityPolicy->policyContext != NULL)
        clear_sp_aes256sha256rsapss(securityPolicy);
    return retval;
}

UA_StatusCode
UA_SecurityPolicy_Aes256Sha256RsaPss(UA_SecurityPolicy *policy, const UA_ByteString localCertificate,
                                      const UA_ByteString localPrivateKey, const UA_Logger *logger) {
    memset(policy, 0, sizeof(UA_SecurityPolicy));
    policy->logger = logger;

    policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Aes256_Sha256_RsaPss");
    policy->securityLevel = 20;

    UA_SecurityPolicyAsymmetricModule *const asymmetricModule = &policy->asymmetricModule;
    UA_SecurityPolicySymmetricModule *const symmetricModule = &policy->symmetricModule;
    UA_SecurityPolicyChannelModule *const channelModule = &policy->channelModule;

    UA_StatusCode retval = UA_mbedTLS_LoadLocalCertificate(&localCertificate, &policy->localCertificate);

    if (retval != UA_STATUSCODE_GOOD)
        return retval;

    /* AsymmetricModule */
    UA_SecurityPolicySignatureAlgorithm *asym_signatureAlgorithm =
        &asymmetricModule->cryptoModule.signatureAlgorithm;
    asym_signatureAlgorithm->uri =
        UA_STRING("http://opcfoundation.org/UA/security/rsa-pss-sha2-256\0");
    asym_signatureAlgorithm->verify =
        (UA_StatusCode (*)(void *, const UA_ByteString *, const UA_ByteString *))asym_verify_sp_aes256sha256rsapss;
    asym_signatureAlgorithm->sign =
        (UA_StatusCode (*)(void *, const UA_ByteString *, UA_ByteString *))asym_sign_sp_aes256sha256rsapss;
    asym_signatureAlgorithm->getLocalSignatureSize =
        (size_t (*)(const void *))asym_getLocalSignatureSize_sp_aes256sha256rsapss;
    asym_signatureAlgorithm->getRemoteSignatureSize =
        (size_t (*)(const void *))asym_getRemoteSignatureSize_sp_aes256sha256rsapss;
    asym_signatureAlgorithm->getLocalKeyLength = NULL; // TODO: Write function
    asym_signatureAlgorithm->getRemoteKeyLength = NULL; // TODO: Write function

    UA_SecurityPolicyEncryptionAlgorithm *asym_encryptionAlgorithm =
        &asymmetricModule->cryptoModule.encryptionAlgorithm;
    asym_encryptionAlgorithm->uri = UA_STRING("http://opcfoundation.org/UA/security/rsa-oaep-sha2-256\0");
    asym_encryptionAlgorithm->encrypt =
        (UA_StatusCode(*)(void *, UA_ByteString *))asym_encrypt_sp_aes256sha256rsapss;
    asym_encryptionAlgorithm->decrypt =
        (UA_StatusCode(*)(void *, UA_ByteString *)) asym_decrypt_sp_aes256sha256rsapss;
    asym_encryptionAlgorithm->getLocalKeyLength =
        (size_t (*)(const void *))asym_getLocalEncryptionKeyLength_sp_aes256sha256rsapss;
    asym_encryptionAlgorithm->getRemoteKeyLength =
        (size_t (*)(const void *))asym_getRemoteEncryptionKeyLength_sp_aes256sha256rsapss;
    asym_encryptionAlgorithm->getRemoteBlockSize = (size_t (*)(const void *))asym_getRemoteBlockSize_sp_aes256sha256rsapss;
    asym_encryptionAlgorithm->getRemotePlainTextBlockSize =
        (size_t (*)(const void *))asym_getRemotePlainTextBlockSize_sp_aes256sha256rsapss;

    asymmetricModule->makeCertificateThumbprint = asym_makeThumbprint_sp_aes256sha256rsapss;
    asymmetricModule->compareCertificateThumbprint =
        asymmetricModule_compareCertificateThumbprint_sp_aes256sha256rsapss;

    /* SymmetricModule */
    symmetricModule->generateKey = sym_generateKey_sp_aes256sha256rsapss;
    symmetricModule->generateNonce = sym_generateNonce_sp_aes256sha256rsapss;

    UA_SecurityPolicySignatureAlgorithm *sym_signatureAlgorithm =
        &symmetricModule->cryptoModule.signatureAlgorithm;
    sym_signatureAlgorithm->uri =
        UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha2-256\0");
    sym_signatureAlgorithm->verify =
        (UA_StatusCode (*)(void *, const UA_ByteString *, const UA_ByteString *))sym_verify_sp_aes256sha256rsapss;
    sym_signatureAlgorithm->sign =
        (UA_StatusCode (*)(void *, const UA_ByteString *, UA_ByteString *))sym_sign_sp_aes256sha256rsapss;
    sym_signatureAlgorithm->getLocalSignatureSize = sym_getSignatureSize_sp_aes256sha256rsapss;
    sym_signatureAlgorithm->getRemoteSignatureSize = sym_getSignatureSize_sp_aes256sha256rsapss;
    sym_signatureAlgorithm->getLocalKeyLength =
        (size_t (*)(const void *))sym_getSigningKeyLength_sp_aes256sha256rsapss;
    sym_signatureAlgorithm->getRemoteKeyLength =
        (size_t (*)(const void *))sym_getSigningKeyLength_sp_aes256sha256rsapss;

    UA_SecurityPolicyEncryptionAlgorithm *sym_encryptionAlgorithm =
        &symmetricModule->cryptoModule.encryptionAlgorithm;
    sym_encryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes256-cbc\0");
    sym_encryptionAlgorithm->encrypt =
        (UA_StatusCode(*)(void *, UA_ByteString *))sym_encrypt_sp_aes256sha256rsapss;
    sym_encryptionAlgorithm->decrypt =
        (UA_StatusCode(*)(void *, UA_ByteString *))sym_decrypt_sp_aes256sha256rsapss;
    sym_encryptionAlgorithm->getLocalKeyLength = sym_getEncryptionKeyLength_sp_aes256sha256rsapss;
    sym_encryptionAlgorithm->getRemoteKeyLength = sym_getEncryptionKeyLength_sp_aes256sha256rsapss;
    sym_encryptionAlgorithm->getRemoteBlockSize =
        (size_t (*)(const void *))sym_getEncryptionBlockSize_sp_aes256sha256rsapss;
    sym_encryptionAlgorithm->getRemotePlainTextBlockSize =
        (size_t (*)(const void *))sym_getPlainTextBlockSize_sp_aes256sha256rsapss;
    symmetricModule->secureChannelNonceLength = 32;

    /* Certificate Signing Algorithm */
    policy->certificateSigningAlgorithm.uri =
        UA_STRING("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256\0");
    policy->certificateSigningAlgorithm.verify =
        (UA_StatusCode (*)(void *, const UA_ByteString *, const UA_ByteString *))asym_cert_verify_sp_aes256sha256rsapss;
    policy->certificateSigningAlgorithm.sign =
        (UA_StatusCode (*)(void *, const UA_ByteString *, UA_ByteString *))asym_cert_sign_sp_aes256sha256rsapss;
    policy->certificateSigningAlgorithm.getLocalSignatureSize =
        (size_t (*)(const void *))asym_cert_getLocalSignatureSize_sp_aes256sha256rsapss;
    policy->certificateSigningAlgorithm.getRemoteSignatureSize =
        (size_t (*)(const void *))asym_cert_getRemoteSignatureSize_sp_aes256sha256rsapss;
    policy->certificateSigningAlgorithm.getLocalKeyLength = NULL; // TODO: Write function
    policy->certificateSigningAlgorithm.getRemoteKeyLength = NULL; // TODO: Write function

    /* ChannelModule */
    channelModule->newContext = channelContext_newContext_sp_aes256sha256rsapss;
    channelModule->deleteContext = (void (*)(void *))
        channelContext_deleteContext_sp_aes256sha256rsapss;

    channelModule->setLocalSymEncryptingKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setLocalSymEncryptingKey_sp_aes256sha256rsapss;
    channelModule->setLocalSymSigningKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setLocalSymSigningKey_sp_aes256sha256rsapss;
    channelModule->setLocalSymIv = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setLocalSymIv_sp_aes256sha256rsapss;

    channelModule->setRemoteSymEncryptingKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setRemoteSymEncryptingKey_sp_aes256sha256rsapss;
    channelModule->setRemoteSymSigningKey = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setRemoteSymSigningKey_sp_aes256sha256rsapss;
    channelModule->setRemoteSymIv = (UA_StatusCode (*)(void *, const UA_ByteString *))
        channelContext_setRemoteSymIv_sp_aes256sha256rsapss;

    channelModule->compareCertificate = (UA_StatusCode (*)(const void *, const UA_ByteString *))
        channelContext_compareCertificate_sp_aes256sha256rsapss;

    policy->updateCertificateAndPrivateKey = updateCertificateAndPrivateKey_sp_aes256sha256rsapss;
    policy->clear = clear_sp_aes256sha256rsapss;

    UA_StatusCode res = policyContext_newContext_sp_aes256sha256rsapss(policy, localPrivateKey);
    if(res != UA_STATUSCODE_GOOD)
        clear_sp_aes256sha256rsapss(policy);

    return res;
}

#endif

/**** amalgamated original file "/plugins/crypto/mbedtls/ua_mbedtls_create_certificate.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright (c) 2023 Fraunhofer IOSB (Author: Noel Graf)
 *
 */

#include <time.h>


#if defined(UA_ENABLE_ENCRYPTION_MBEDTLS)

#include <mbedtls/x509_crt.h>
#include <mbedtls/oid.h>
#include <mbedtls/asn1write.h>
#include <mbedtls/entropy.h>
#include <mbedtls/ctr_drbg.h>
#include <mbedtls/platform.h>
#include <mbedtls/version.h>

#define SET_OID(x, oid) \
    do { x.len = MBEDTLS_OID_SIZE(oid); x.p = (unsigned char *) oid; } while (0)

#define MBEDTLS_ASN1_CHK_CLEANUP_ADD(g, f) \
    do                                     \
    {                                      \
        if ((ret = (f)) < 0)               \
        goto cleanup;                      \
        else                               \
        (g) += ret;                        \
    } while (0)

#if MBEDTLS_VERSION_NUMBER < 0x02170000
#define MBEDTLS_X509_SAN_OTHER_NAME                      0
#define MBEDTLS_X509_SAN_RFC822_NAME                     1
#define MBEDTLS_X509_SAN_DNS_NAME                        2
#define MBEDTLS_X509_SAN_X400_ADDRESS_NAME               3
#define MBEDTLS_X509_SAN_DIRECTORY_NAME                  4
#define MBEDTLS_X509_SAN_EDI_PARTY_NAME                  5
#define MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER     6
#define MBEDTLS_X509_SAN_IP_ADDRESS                      7
#define MBEDTLS_X509_SAN_REGISTERED_ID                   8
#endif

#define MBEDTLS_SAN_MAX_LEN    64
typedef struct mbedtls_write_san_node{
    int type;
    char* host;
    size_t hostlen;
} mbedtls_write_san_node;

typedef struct mbedtls_write_san_list{
    mbedtls_write_san_node node;
    struct mbedtls_write_san_list* next;
} mbedtls_write_san_list;

static size_t mbedtls_get_san_list_deep(const mbedtls_write_san_list* sanlist);

int mbedtls_x509write_crt_set_subject_alt_name(mbedtls_x509write_cert *ctx, const mbedtls_write_san_list* sanlist);

#if MBEDTLS_VERSION_NUMBER < 0x03030000
int mbedtls_x509write_crt_set_ext_key_usage(mbedtls_x509write_cert *ctx,
                                            const mbedtls_asn1_sequence *exts);
#endif

static int write_certificate(mbedtls_x509write_cert *crt, UA_CertificateFormat certFormat,
                             UA_ByteString *outCertificate, int (*f_rng)(void *, unsigned char *, size_t),
                             void *p_rng);

static int write_private_key(mbedtls_pk_context *key, UA_CertificateFormat keyFormat, UA_ByteString *outPrivateKey);

UA_StatusCode
UA_CreateCertificate(const UA_Logger *logger, const UA_String *subject,
                     size_t subjectSize, const UA_String *subjectAltName,
                     size_t subjectAltNameSize, UA_CertificateFormat certFormat,
                     UA_KeyValueMap *params, UA_ByteString *outPrivateKey,
                     UA_ByteString *outCertificate) {
    if(!outPrivateKey || !outCertificate || !logger || !subjectAltName || !subject ||
       subjectAltNameSize == 0 || subjectSize == 0 ||
       (certFormat != UA_CERTIFICATEFORMAT_DER && certFormat != UA_CERTIFICATEFORMAT_PEM))
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    /* Use the maximum size */
    UA_UInt16 keySizeBits = 4096;
    /* Default to 1 year */
    UA_UInt16 expiresInDays = 365;

    if(params) {
        const UA_UInt16 *keySizeBitsValue = (const UA_UInt16 *)UA_KeyValueMap_getScalar(
            params, UA_QUALIFIEDNAME(0, "key-size-bits"), &UA_TYPES[UA_TYPES_UINT16]);
        if(keySizeBitsValue)
            keySizeBits = *keySizeBitsValue;

        const UA_UInt16 *expiresInDaysValue = (const UA_UInt16 *)UA_KeyValueMap_getScalar(
            params, UA_QUALIFIEDNAME(0, "expires-in-days"), &UA_TYPES[UA_TYPES_UINT16]);
        if(expiresInDaysValue)
            expiresInDays = *expiresInDaysValue;
    }

    UA_ByteString_init(outPrivateKey);
    UA_ByteString_init(outCertificate);

    mbedtls_pk_context key;
    mbedtls_ctr_drbg_context ctr_drbg;
    mbedtls_entropy_context entropy;
    const char *pers = "gen_key";
    mbedtls_x509write_cert crt;

    UA_StatusCode errRet = UA_STATUSCODE_GOOD;

    /* Set to sane values */
    mbedtls_pk_init(&key);
    mbedtls_ctr_drbg_init(&ctr_drbg);
    mbedtls_entropy_init(&entropy);
    mbedtls_x509write_crt_init(&crt);

    /* Seed the random number generator */
    if (mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)pers, strlen(pers)) != 0) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Failed to initialize the random number generator.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    /* Generate an RSA key pair */
    if (mbedtls_pk_setup(&key, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)) != 0 ||
        mbedtls_rsa_gen_key(mbedtls_pk_rsa(key), mbedtls_ctr_drbg_random, &ctr_drbg, keySizeBits, 65537) != 0) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Failed to generate RSA key pair.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    /* Setting certificate values */
    mbedtls_x509write_crt_set_version(&crt, MBEDTLS_X509_CRT_VERSION_3);
    mbedtls_x509write_crt_set_md_alg(&crt, MBEDTLS_MD_SHA256);

    size_t subject_char_len = 0;
    for(size_t i = 0; i < subjectSize; i++) {
        subject_char_len += subject[i].length;
    }
    char *subject_char = (char*)UA_malloc(subject_char_len + subjectSize);
    if(!subject_char) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Cannot allocate memory for subject. Out of memory.");
        errRet = UA_STATUSCODE_BADOUTOFMEMORY;
        goto cleanup;
    }

    size_t pos = 0;
    for(size_t i = 0; i < subjectSize; i++) {
        subject_char_len += subject[i].length;
        memcpy(subject_char + pos, subject[i].data, subject[i].length);
        pos += subject[i].length;
        if(i < subjectSize - 1)
            subject_char[pos++] = ',';
        else
            subject_char[pos++] = '\0';
    }

    if((mbedtls_x509write_crt_set_subject_name(&crt, subject_char)) != 0) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Setting subject failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        UA_free(subject_char);
        goto cleanup;
    }

    if((mbedtls_x509write_crt_set_issuer_name(&crt, subject_char)) != 0) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Setting issuer failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        UA_free(subject_char);
        goto cleanup;
    }

    UA_free(subject_char);

    mbedtls_write_san_list *cur = NULL;
    mbedtls_write_san_list *cur_tmp = NULL;
    mbedtls_write_san_list *head = NULL;
    for(size_t i = 0; i < subjectAltNameSize; i++) {
        char *sanType;
        char *sanValue;
        size_t sanValueLength;
        char *subAlt = (char *)UA_malloc(subjectAltName[i].length + 1);
        memcpy(subAlt, subjectAltName[i].data, subjectAltName[i].length);

        /* null-terminate the copied string */
        subAlt[subjectAltName[i].length] = 0;
        /* split into SAN type and value */
        sanType = strtok(subAlt, ":");
        sanValue = (char *)subjectAltName[i].data + strlen(sanType) + 1;
        sanValueLength = strlen(sanValue);

        if(sanType) {
            cur_tmp = (mbedtls_write_san_list*)mbedtls_calloc(1, sizeof(mbedtls_write_san_list));
            cur_tmp->next = NULL;
            cur_tmp->node.host = sanValue;
            cur_tmp->node.hostlen = sanValueLength;

            if(strcmp(sanType, "DNS") == 0) {
                cur_tmp->node.type = MBEDTLS_X509_SAN_DNS_NAME;
            } else if(strcmp(sanType, "URI") == 0) {
                cur_tmp->node.type = MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER;
            } else if(strcmp(sanType, "IP") == 0) {
                uint8_t ip[4] = {0};
                if(UA_inet_pton(AF_INET, sanValue, ip) <= 0) {
                    UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURECHANNEL, "IP SAN preparation failed");
                    mbedtls_free(cur_tmp);
                    UA_free(subAlt);
                    continue;
                }
                cur_tmp->node.type = MBEDTLS_X509_SAN_IP_ADDRESS;
                cur_tmp->node.host = (char *)ip;
                cur_tmp->node.hostlen = sizeof(ip);
            } else if(strcmp(sanType, "RFC822") == 0) {
                cur_tmp->node.type = MBEDTLS_X509_SAN_RFC822_NAME;
            } else {
                UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURECHANNEL, "Given an unsupported SAN");
                mbedtls_free(cur_tmp);
                UA_free(subAlt);
                continue;
            }
        } else {
            UA_LOG_WARNING(logger, UA_LOGCATEGORY_SECURECHANNEL, "Invalid Input format");
            UA_free(subAlt);
            continue;
        }

        if(!cur) {
            cur = cur_tmp;
            head = cur_tmp;
        } else {
            cur->next = cur_tmp;
            cur = cur->next;
        }

        UA_free(subAlt);
    }

    if((mbedtls_x509write_crt_set_subject_alt_name(&crt, head)) != 0) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Setting subject alternative name failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        while(head != NULL) {
            cur_tmp = head->next;
            mbedtls_free(head);
            head = cur_tmp;
        }
        goto cleanup;
    }

    while(head != NULL) {
        cur_tmp = head->next;
        mbedtls_free(head);
        head = cur_tmp;
    }

#if MBEDTLS_VERSION_NUMBER >= 0x03040000
    unsigned char *serial = (unsigned char *)"1";
    size_t serial_len = 1;
    mbedtls_x509write_crt_set_serial_raw(&crt, serial, serial_len);
#else
    mbedtls_mpi serial_mpi;
    mbedtls_mpi_init(&serial_mpi);
    mbedtls_mpi_lset(&serial_mpi, 1);
    mbedtls_x509write_crt_set_serial(&crt, &serial_mpi);
    mbedtls_mpi_free(&serial_mpi);
#endif

    /* Get the current time */
    time_t rawTime;
    struct tm *timeInfo;
    time(&rawTime);
    timeInfo = gmtime(&rawTime);

    /* Format the current timestamp */
    char current_timestamp[15];  // YYYYMMDDhhmmss + '\0'
    strftime(current_timestamp, sizeof(current_timestamp), "%Y%m%d%H%M%S", timeInfo);

    /* Calculate the future timestamp */
    timeInfo->tm_mday += expiresInDays;
    time_t future_time = mktime(timeInfo);

    /* Format the future timestamp */
    char future_timestamp[15];  // YYYYMMDDhhmmss + '\0'
    strftime(future_timestamp, sizeof(future_timestamp), "%Y%m%d%H%M%S", gmtime(&future_time));

    if(mbedtls_x509write_crt_set_validity(&crt, current_timestamp, future_timestamp) != 0) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Setting 'not before' and 'not after' failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    if(mbedtls_x509write_crt_set_basic_constraints(&crt, 0, -1) != 0) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Setting basic constraints failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    if(mbedtls_x509write_crt_set_key_usage(&crt, MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_NON_REPUDIATION
                                            | MBEDTLS_X509_KU_KEY_ENCIPHERMENT | MBEDTLS_X509_KU_DATA_ENCIPHERMENT
                                            | MBEDTLS_X509_KU_KEY_CERT_SIGN | MBEDTLS_X509_KU_CRL_SIGN) != 0) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Setting key usage failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    mbedtls_asn1_sequence *ext_key_usage;
    ext_key_usage = (mbedtls_asn1_sequence *)mbedtls_calloc(1, sizeof(mbedtls_asn1_sequence));
    ext_key_usage->buf.tag = MBEDTLS_ASN1_OID;
    SET_OID(ext_key_usage->buf, MBEDTLS_OID_SERVER_AUTH);
    ext_key_usage->next = (mbedtls_asn1_sequence *)mbedtls_calloc(1, sizeof(mbedtls_asn1_sequence));
    ext_key_usage->next->buf.tag = MBEDTLS_ASN1_OID;
    SET_OID(ext_key_usage->next->buf, MBEDTLS_OID_CLIENT_AUTH);

    if(mbedtls_x509write_crt_set_ext_key_usage(&crt, ext_key_usage) != 0) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Setting extended key usage failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        mbedtls_free(ext_key_usage->next);
        mbedtls_free(ext_key_usage);
        goto cleanup;
    }

    mbedtls_free(ext_key_usage->next);
    mbedtls_free(ext_key_usage);

    mbedtls_x509write_crt_set_subject_key(&crt, &key);
    mbedtls_x509write_crt_set_issuer_key(&crt, &key);


    /* Write private key */
    if ((write_private_key(&key, certFormat, outPrivateKey)) != 0) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Writing private key failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    /* Write Certificate */
    if ((write_certificate(&crt, certFormat, outCertificate,
                                 mbedtls_ctr_drbg_random, &ctr_drbg)) != 0) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Writing certificate failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    mbedtls_ctr_drbg_free(&ctr_drbg);
    mbedtls_entropy_free(&entropy);
    mbedtls_x509write_crt_free(&crt);
    mbedtls_pk_free(&key);

cleanup:
    mbedtls_ctr_drbg_free(&ctr_drbg);
    mbedtls_entropy_free(&entropy);
    mbedtls_x509write_crt_free(&crt);
    mbedtls_pk_free(&key);
    return errRet;
}

static int write_private_key(mbedtls_pk_context *key, UA_CertificateFormat keyFormat, UA_ByteString *outPrivateKey) {
    int ret;
    unsigned char output_buf[16000];
    unsigned char *c = output_buf;
    size_t len = 0;

    memset(output_buf, 0, 16000);
    switch(keyFormat) {
    case UA_CERTIFICATEFORMAT_DER: {
        if((ret = mbedtls_pk_write_key_pem(key, output_buf, 16000)) != 0) {
            return ret;
        }

        len = strlen((char *) output_buf);
        break;
    }
    case UA_CERTIFICATEFORMAT_PEM: {
        if((ret = mbedtls_pk_write_key_der(key, output_buf, 16000)) < 0) {
            return ret;
        }

        len = ret;
        c = output_buf + sizeof(output_buf) - len;
        break;
    }
    }

    outPrivateKey->length = len;
    UA_ByteString_allocBuffer(outPrivateKey, outPrivateKey->length);
    memcpy(outPrivateKey->data, c, outPrivateKey->length);

    return 0;
}

static int write_certificate(mbedtls_x509write_cert *crt, UA_CertificateFormat certFormat,
                      UA_ByteString *outCertificate, int (*f_rng)(void *, unsigned char *, size_t),
                      void *p_rng) {
    int ret;
    unsigned char output_buf[4096];
    unsigned char *c = output_buf;
    size_t len = 0;

    memset(output_buf, 0, 4096);
    switch(certFormat) {
    case UA_CERTIFICATEFORMAT_DER: {
        if((ret = mbedtls_x509write_crt_der(crt, output_buf, 4096, f_rng, p_rng)) < 0) {
            return ret;
        }

        len = ret;
        c = output_buf + 4096 - len;
        break;
    }
    case UA_CERTIFICATEFORMAT_PEM: {
        if((ret = mbedtls_x509write_crt_pem(crt, output_buf, 4096, f_rng, p_rng)) < 0) {
            return ret;
        }

        len = strlen((char *)output_buf);
        break;
    }
    }

    outCertificate->length = len;
    UA_ByteString_allocBuffer(outCertificate, outCertificate->length);
    memcpy(outCertificate->data, c, outCertificate->length);

    return 0;
}

#if MBEDTLS_VERSION_NUMBER < 0x03030000
int mbedtls_x509write_crt_set_ext_key_usage(mbedtls_x509write_cert *ctx,
                                            const mbedtls_asn1_sequence *exts) {
    unsigned char buf[256];
    unsigned char *c = buf + sizeof(buf);
    int ret;
    size_t len = 0;
    const mbedtls_asn1_sequence *last_ext = NULL;
    const mbedtls_asn1_sequence *ext;

    memset(buf, 0, sizeof(buf));

    /* We need at least one extension: SEQUENCE SIZE (1..MAX) OF KeyPurposeId */
    if(!exts) {
        return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
    }

    /* Iterate over exts backwards, so we write them out in the requested order */
    while(last_ext != exts) {
        for(ext = exts; ext->next != last_ext; ext = ext->next) {
        }
        if(ext->buf.tag != MBEDTLS_ASN1_OID) {
            return MBEDTLS_ERR_X509_BAD_INPUT_DATA;
        }
        MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_raw_buffer(&c, buf, ext->buf.p, ext->buf.len));
        MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, ext->buf.len));
        MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&c, buf, MBEDTLS_ASN1_OID));
        last_ext = ext;
    }

    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_len(&c, buf, len));
    MBEDTLS_ASN1_CHK_ADD(len, mbedtls_asn1_write_tag(&c, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));

    return mbedtls_x509write_crt_set_extension(ctx, MBEDTLS_OID_EXTENDED_KEY_USAGE,
                                               MBEDTLS_OID_SIZE(MBEDTLS_OID_EXTENDED_KEY_USAGE), 1, c, len);
}

#endif

static size_t mbedtls_get_san_list_deep(const mbedtls_write_san_list* sanlist) {
    size_t ret = 0;
    const mbedtls_write_san_list* cur = sanlist;
    while (cur) {
        ++ret;
        cur = cur->next;
    }

    return ret;
}

int mbedtls_x509write_crt_set_subject_alt_name(mbedtls_x509write_cert *ctx, const mbedtls_write_san_list* sanlist) {
    int	ret = 0;
    size_t sandeep = 0;
    const mbedtls_write_san_list* cur = sanlist;
    unsigned char* buf;
    unsigned char* pc;
    size_t len;
    size_t buflen = 0;

    /* How many alt names to be written */
    sandeep = mbedtls_get_san_list_deep(sanlist);
    if (sandeep == 0)
        return ret;

    buflen = MBEDTLS_SAN_MAX_LEN * sandeep + sandeep;
    buf = (unsigned char *)mbedtls_calloc(1, buflen);
    if(!buf)
        return MBEDTLS_ERR_ASN1_ALLOC_FAILED;

    memset(buf, 0, buflen);
    pc = buf + buflen;

    len = 0;
    while(cur) {
        switch (cur->node.type) {
        case MBEDTLS_X509_SAN_DNS_NAME:
        case MBEDTLS_X509_SAN_RFC822_NAME:
        case MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER:
        case MBEDTLS_X509_SAN_IP_ADDRESS:
            MBEDTLS_ASN1_CHK_CLEANUP_ADD(len,
                                         mbedtls_asn1_write_raw_buffer(&pc, buf, (const unsigned char *)cur->node.host,
                                                                       cur->node.hostlen));
            MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_len(&pc, buf, cur->node.hostlen));
            MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_tag(&pc, buf,
                                                                     MBEDTLS_ASN1_CONTEXT_SPECIFIC | cur->node.type));
            break;
        default:
            /* Error out on an unsupported SAN */
            ret = MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE;
            goto cleanup;
        }

        cur = cur->next;
    }

    MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_len(&pc, buf, len));
    MBEDTLS_ASN1_CHK_CLEANUP_ADD(len, mbedtls_asn1_write_tag(&pc, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE));

    ret = mbedtls_x509write_crt_set_extension(ctx, MBEDTLS_OID_SUBJECT_ALT_NAME,
                                              MBEDTLS_OID_SIZE(MBEDTLS_OID_SUBJECT_ALT_NAME), 0, buf + buflen - len, len);

    mbedtls_free(buf);
    return ret;

cleanup:
    mbedtls_free(buf);
    return ret;
}

#endif

/**** amalgamated original file "/plugins/crypto/mbedtls/ua_certificategroup_mbedtls.c" ****/

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
 *
 *    Copyright 2018 (c) Mark Giraud, Fraunhofer IOSB
 *    Copyright 2019 (c) Kalycito Infotech Private Limited
 *    Copyright 2019 (c) Julius Pfrommer, Fraunhofer IOSB
 *    Copyright 2024 (c) Fraunhofer IOSB (Author: Noel Graf)
 */


#ifdef UA_ENABLE_ENCRYPTION_MBEDTLS


#include <mbedtls/x509.h>
#include <mbedtls/x509_crt.h>
#include <mbedtls/entropy.h>
#include <mbedtls/error.h>
#include <mbedtls/version.h>

#include <inttypes.h>

#define REMOTECERTIFICATETRUSTED 1
#define ISSUERKNOWN              2
#define DUALPARENT               3
#define PARENTFOUND              4

/* Find binary substring. Taken and adjusted from
 * http://tungchingkai.blogspot.com/2011/07/binary-strstr.html */

static const unsigned char *
bstrchr(const unsigned char *s, const unsigned char ch, size_t l) {
    /* find first occurrence of c in char s[] for length l*/
    for(; l > 0; ++s, --l) {
        if(*s == ch)
            return s;
    }
    return NULL;
}

static const unsigned char *
UA_Bstrstr(const unsigned char *s1, size_t l1, const unsigned char *s2, size_t l2) {
    /* find first occurrence of s2[] in s1[] for length l1*/
    const unsigned char *ss1 = s1;
    const unsigned char *ss2 = s2;
    /* handle special case */
    if(l1 == 0)
        return (NULL);
    if(l2 == 0)
        return s1;

    /* match prefix */
    for (; (s1 = bstrchr(s1, *s2, (uintptr_t)ss1-(uintptr_t)s1+(uintptr_t)l1)) != NULL &&
           (uintptr_t)ss1-(uintptr_t)s1+(uintptr_t)l1 != 0; ++s1) {

        /* match rest of prefix */
        const unsigned char *sc1, *sc2;
        for (sc1 = s1, sc2 = s2; ;)
            if (++sc2 >= ss2+l2)
                return s1;
            else if (*++sc1 != *sc2)
                break;
    }
    return NULL;
}

// mbedTLS expects PEM data to be null terminated
// The data length parameter must include the null terminator
static UA_ByteString copyDataFormatAware(const UA_ByteString *data)
{
    UA_ByteString result;
    UA_ByteString_init(&result);

    if (!data->length)
        return result;

    if (data->length && data->data[0] == '-') {
        UA_ByteString_allocBuffer(&result, data->length + 1);
        memcpy(result.data, data->data, data->length);
        result.data[data->length] = '\0';
    } else {
        UA_ByteString_copy(data, &result);
    }

    return result;
}

typedef struct {
    /* If the folders are defined, we use them to reload the certificates during
     * runtime */
    UA_String trustListFolder;
    UA_String issuerListFolder;
    UA_String revocationListFolder;
    UA_String rejectedListFolder;

    mbedtls_x509_crt certificateTrustList;
    mbedtls_x509_crt certificateIssuerList;
    mbedtls_x509_crl certificateRevocationList;
} CertInfo;

#ifdef __linux__ /* Linux only so far */

#include <dirent.h>
#include <limits.h>

static UA_StatusCode
fileNamesFromFolder(const UA_String *folder, size_t *pathsSize, UA_String **paths) {
    char buf[PATH_MAX + 1];
    if(folder->length > PATH_MAX)
        return UA_STATUSCODE_BADINTERNALERROR;

    memcpy(buf, folder->data, folder->length);
    buf[folder->length] = 0;

    DIR *dir = opendir(buf);
    if(!dir)
        return UA_STATUSCODE_BADINTERNALERROR;

    *paths = (UA_String*)UA_Array_new(256, &UA_TYPES[UA_TYPES_STRING]);
    if(*paths == NULL) {
        closedir(dir);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    struct dirent *ent;
    char buf2[PATH_MAX + 1];
    char *res = realpath(buf, buf2);
    if(!res) {
        closedir(dir);
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    size_t pathlen = strlen(buf2);
    *pathsSize = 0;
    while((ent = readdir (dir)) != NULL && *pathsSize < 256) {
        if(ent->d_type != DT_REG)
            continue;
        buf2[pathlen] = '/';
        buf2[pathlen+1] = 0;
        strcat(buf2, ent->d_name);
        (*paths)[*pathsSize] = UA_STRING_ALLOC(buf2);
        *pathsSize += 1;
    }
    closedir(dir);

    if(*pathsSize == 0) {
        UA_free(*paths);
        *paths = NULL;
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
reloadCertificates(const UA_CertificateGroup *certGroup, CertInfo *ci) {
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    int err = 0;
    int internalErrorFlag = 0;

    /* Load the trustlists */
    if(ci->trustListFolder.length > 0) {
        UA_LOG_INFO(certGroup->logging, UA_LOGCATEGORY_SERVER, "Reloading the trust-list");
        mbedtls_x509_crt_free(&ci->certificateTrustList);
        mbedtls_x509_crt_init(&ci->certificateTrustList);

        char f[PATH_MAX];
        memcpy(f, ci->trustListFolder.data, ci->trustListFolder.length);
        f[ci->trustListFolder.length] = 0;
        err = mbedtls_x509_crt_parse_path(&ci->certificateTrustList, f);
        if(err == 0) {
            UA_LOG_INFO(certGroup->logging, UA_LOGCATEGORY_SERVER,
                        "Loaded certificate from %s", f);
        } else {
            char errBuff[300];
            mbedtls_strerror(err, errBuff, 300);
            UA_LOG_INFO(certGroup->logging, UA_LOGCATEGORY_SERVER,
                        "Failed to load certificate from %s, mbedTLS error: %s (error code: %d)", f, errBuff, err);
            internalErrorFlag = 1;
        }
    }

    /* Load the revocationlists */
    if(ci->revocationListFolder.length > 0) {
        UA_LOG_INFO(certGroup->logging, UA_LOGCATEGORY_SERVER, "Reloading the revocation-list");
        size_t pathsSize = 0;
        UA_String *paths = NULL;
        retval = fileNamesFromFolder(&ci->revocationListFolder, &pathsSize, &paths);
        if(retval != UA_STATUSCODE_GOOD)
            return retval;
        mbedtls_x509_crl_free(&ci->certificateRevocationList);
        mbedtls_x509_crl_init(&ci->certificateRevocationList);
        for(size_t i = 0; i < pathsSize; i++) {
            char f[PATH_MAX];
            memcpy(f, paths[i].data, paths[i].length);
            f[paths[i].length] = 0;
            err = mbedtls_x509_crl_parse_file(&ci->certificateRevocationList, f);
            if(err == 0) {
                UA_LOG_INFO(certGroup->logging, UA_LOGCATEGORY_SERVER,
                            "Loaded certificate from %.*s",
                            (int)paths[i].length, paths[i].data);
            } else {
                char errBuff[300];
                mbedtls_strerror(err, errBuff, 300);
                UA_LOG_INFO(certGroup->logging, UA_LOGCATEGORY_SERVER,
                            "Failed to load certificate from %.*s, mbedTLS error: %s (error code: %d)",
                            (int)paths[i].length, paths[i].data, errBuff, err);
                internalErrorFlag = 1;
            }
        }
        UA_Array_delete(paths, pathsSize, &UA_TYPES[UA_TYPES_STRING]);
        paths = NULL;
        pathsSize = 0;
    }

    /* Load the issuerlists */
    if(ci->issuerListFolder.length > 0) {
        UA_LOG_INFO(certGroup->logging, UA_LOGCATEGORY_SERVER, "Reloading the issuer-list");
        mbedtls_x509_crt_free(&ci->certificateIssuerList);
        mbedtls_x509_crt_init(&ci->certificateIssuerList);
        char f[PATH_MAX];
        memcpy(f, ci->issuerListFolder.data, ci->issuerListFolder.length);
        f[ci->issuerListFolder.length] = 0;
        err = mbedtls_x509_crt_parse_path(&ci->certificateIssuerList, f);
        if(err == 0) {
            UA_LOG_INFO(certGroup->logging, UA_LOGCATEGORY_SERVER,
                        "Loaded certificate from %s", f);
        } else {
            char errBuff[300];
            mbedtls_strerror(err, errBuff, 300);
            UA_LOG_INFO(certGroup->logging, UA_LOGCATEGORY_SERVER,
                        "Failed to load certificate from %s, mbedTLS error: %s (error code: %d)",
                        f, errBuff, err);
            internalErrorFlag = 1;
        }
    }

    if(internalErrorFlag) {
        retval = UA_STATUSCODE_BADINTERNALERROR;
    }
    return retval;
}

#endif

static UA_StatusCode
certificateGroup_verify(UA_CertificateGroup *certGroup,
                        const UA_ByteString *certificate) {
    CertInfo *ci;
    if(!certGroup)
        return UA_STATUSCODE_BADINTERNALERROR;
    ci = (CertInfo*)certGroup->context;
    if(!ci)
        return UA_STATUSCODE_BADINTERNALERROR;

#ifdef __linux__ /* Reload certificates if folder paths are specified */
    UA_StatusCode certFlag = reloadCertificates(certGroup, ci);
    if(certFlag != UA_STATUSCODE_GOOD) {
        return certFlag;
    }
#endif

    if(ci->trustListFolder.length == 0 &&
       ci->issuerListFolder.length == 0 &&
       ci->revocationListFolder.length == 0 &&
       ci->rejectedListFolder.length == 0 &&
       ci->certificateTrustList.raw.len == 0 &&
       ci->certificateIssuerList.raw.len == 0 &&
       ci->certificateRevocationList.raw.len == 0) {
        UA_LOG_WARNING(certGroup->logging, UA_LOGCATEGORY_USERLAND,
                       "No certificate store configured. Accepting the certificate.");
        return UA_STATUSCODE_GOOD;
    }

    /* Parse the certificate */
    mbedtls_x509_crt remoteCertificate;

    /* Temporary Object to parse the trustList */
    mbedtls_x509_crt *tempCert = NULL;

    /* Temporary Object to parse the revocationList */
    mbedtls_x509_crl *tempCrl = NULL;

    /* Temporary Object to identify the parent CA when there is no intermediate CA */
    mbedtls_x509_crt *parentCert = NULL;

    /* Temporary Object to identify the parent CA when there is intermediate CA */
    mbedtls_x509_crt *parentCert_2 = NULL;

    /* Flag value to identify if the issuer certificate is found */
    int issuerKnown = 0;

    /* Flag value to identify if the parent certificate found */
    int parentFound = 0;

    mbedtls_x509_crt_init(&remoteCertificate);
    int mbedErr = mbedtls_x509_crt_parse(&remoteCertificate, certificate->data,
                                         certificate->length);
    if(mbedErr) {
        /* char errBuff[300]; */
        /* mbedtls_strerror(mbedErr, errBuff, 300); */
        /* UA_LOG_WARNING(data->policyContext->securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY, */
        /*                "Could not parse the remote certificate with error: %s", errBuff); */
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    }

    /* Verify */
    mbedtls_x509_crt_profile crtProfile = {
        MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) | MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256),
        0xFFFFFF, 0x000000, 128 * 8 // in bits
    }; // TODO: remove magic numbers

    uint32_t flags = 0;
    mbedErr = mbedtls_x509_crt_verify_with_profile(&remoteCertificate,
                                                   &ci->certificateTrustList,
                                                   &ci->certificateRevocationList,
                                                   &crtProfile, NULL, &flags, NULL, NULL);

    /* Flag to check if the remote certificate is trusted or not */
    int TRUSTED = 0;

    /* Check if the remoteCertificate is present in the trustList while mbedErr value is not zero */
    if(mbedErr && !(flags & MBEDTLS_X509_BADCERT_EXPIRED) && !(flags & MBEDTLS_X509_BADCERT_FUTURE)) {
        for(tempCert = &ci->certificateTrustList; tempCert != NULL; tempCert = tempCert->next) {
            if(remoteCertificate.raw.len == tempCert->raw.len &&
               memcmp(remoteCertificate.raw.p, tempCert->raw.p, remoteCertificate.raw.len) == 0) {
                TRUSTED = REMOTECERTIFICATETRUSTED;
                break;
            }
        }
    }

    /* If the remote certificate is present in the trustList then check if the issuer certificate
     * of remoteCertificate is present in issuerList */
    if(TRUSTED && mbedErr) {
        mbedErr = mbedtls_x509_crt_verify_with_profile(&remoteCertificate,
                                                       &ci->certificateIssuerList,
                                                       &ci->certificateRevocationList,
                                                       &crtProfile, NULL, &flags, NULL, NULL);

        /* Check if the parent certificate has a CRL file available */
        if(!mbedErr) {
            /* Flag value to identify if that there is an intermediate CA present */
            int dualParent = 0;

            /* Identify the topmost parent certificate for the remoteCertificate */
            for(parentCert = &ci->certificateIssuerList; parentCert != NULL; parentCert = parentCert->next ) {
                if(memcmp(remoteCertificate.issuer_raw.p, parentCert->subject_raw.p, parentCert->subject_raw.len) == 0) {
                    for(parentCert_2 = &ci->certificateTrustList; parentCert_2 != NULL; parentCert_2 = parentCert_2->next) {
                        if(memcmp(parentCert->issuer_raw.p, parentCert_2->subject_raw.p, parentCert_2->subject_raw.len) == 0) {
                            dualParent = DUALPARENT;
                            break;
                        }
                    }
                    parentFound = PARENTFOUND;
                }

                if(parentFound == PARENTFOUND)
                    break;
            }

            /* Check if there is an intermediate certificate between the topmost parent
             * certificate and child certificate
             * If yes the topmost parent certificate is to be checked whether it has a
             * CRL file avaiable */
            if(dualParent == DUALPARENT && parentFound == PARENTFOUND) {
                parentCert = parentCert_2;
            }

            /* If a parent certificate is found traverse the revocationList and identify
             * if there is any CRL file that corresponds to the parentCertificate */
            if(parentFound == PARENTFOUND) {
                tempCrl = &ci->certificateRevocationList;
                while(tempCrl != NULL) {
                    if(tempCrl->version != 0 &&
                       tempCrl->issuer_raw.len == parentCert->subject_raw.len &&
                       memcmp(tempCrl->issuer_raw.p,
                              parentCert->subject_raw.p,
                              tempCrl->issuer_raw.len) == 0) {
                        issuerKnown = ISSUERKNOWN;
                        break;
                    }

                    tempCrl = tempCrl->next;
                }

                /* If the CRL file corresponding to the parent certificate is not present
                 * then return UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN */
                if(!issuerKnown) {
                    return UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN;
                }

            }

        }

    }
    else if(!mbedErr && !TRUSTED) {
        /* This else if section is to identify if the parent certificate which is present in trustList
         * has CRL file corresponding to it */

        /* Identify the parent certificate of the remoteCertificate */
        for(parentCert = &ci->certificateTrustList; parentCert != NULL; parentCert = parentCert->next) {
            if(memcmp(remoteCertificate.issuer_raw.p, parentCert->subject_raw.p, parentCert->subject_raw.len) == 0) {
                parentFound = PARENTFOUND;
                break;
            }

        }

        /* If the parent certificate is found traverse the revocationList and identify
         * if there is any CRL file that corresponds to the parentCertificate */
        if(parentFound == PARENTFOUND &&
           memcmp(remoteCertificate.issuer_raw.p, remoteCertificate.subject_raw.p, remoteCertificate.subject_raw.len) != 0) {
            tempCrl = &ci->certificateRevocationList;
            while(tempCrl != NULL) {
                if(tempCrl->version != 0 &&
                   tempCrl->issuer_raw.len == parentCert->subject_raw.len &&
                   memcmp(tempCrl->issuer_raw.p,
                          parentCert->subject_raw.p,
                          tempCrl->issuer_raw.len) == 0) {
                    issuerKnown = ISSUERKNOWN;
                    break;
                }

                tempCrl = tempCrl->next;
            }

            /* If the CRL file corresponding to the parent certificate is not present
             * then return UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN */
            if(!issuerKnown) {
                return UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN;
            }

        }

    }

    // TODO: Extend verification

    /* This condition will check whether the certificate is a User certificate
     * or a CA certificate. If the MBEDTLS_X509_KU_KEY_CERT_SIGN and
     * MBEDTLS_X509_KU_CRL_SIGN of key_usage are set, then the certificate
     * shall be condidered as CA Certificate and cannot be used to establish a
     * connection. Refer the test case CTT/Security/Security Certificate Validation/029.js
     * for more details */
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    if((remoteCertificate.key_usage & MBEDTLS_X509_KU_KEY_CERT_SIGN) &&
       (remoteCertificate.key_usage & MBEDTLS_X509_KU_CRL_SIGN)) {
        return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;
    }
#else
    if((remoteCertificate.private_key_usage & MBEDTLS_X509_KU_KEY_CERT_SIGN) &&
       (remoteCertificate.private_key_usage & MBEDTLS_X509_KU_CRL_SIGN)) {
        return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;
    }
#endif


    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(mbedErr) {
#if UA_LOGLEVEL <= 400
        char buff[100];
        int len = mbedtls_x509_crt_verify_info(buff, 100, "", flags);
        UA_LOG_WARNING(certGroup->logging, UA_LOGCATEGORY_SECURITYPOLICY,
                       "Verifying the certificate failed with error: %.*s", len-1, buff);
#endif
        if(flags & (uint32_t)MBEDTLS_X509_BADCERT_NOT_TRUSTED) {
            retval = UA_STATUSCODE_BADCERTIFICATEUNTRUSTED;
        } else if(flags & (uint32_t)MBEDTLS_X509_BADCERT_FUTURE ||
                  flags & (uint32_t)MBEDTLS_X509_BADCERT_EXPIRED) {
            retval = UA_STATUSCODE_BADCERTIFICATETIMEINVALID;
        } else if(flags & (uint32_t)MBEDTLS_X509_BADCERT_REVOKED ||
                  flags & (uint32_t)MBEDTLS_X509_BADCRL_EXPIRED) {
            retval = UA_STATUSCODE_BADCERTIFICATEREVOKED;
        } else {
            retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        }

#ifdef UA_ENABLE_CERT_REJECTED_DIR
        if(ci->rejectedListFolder.length !=0) {
            char rejectedFileName[256] = {0};
            UA_ByteString thumbprint;
            UA_ByteString_allocBuffer(&thumbprint, UA_SHA1_LENGTH);
            if(mbedtls_thumbprint_sha1(certificate, &thumbprint) == UA_STATUSCODE_GOOD) {
                static const char hex2char[] = "0123456789ABCDEF";
                for (size_t pos = 0, namePos = 0; pos < thumbprint.length; pos++) {
                    rejectedFileName[namePos++] = hex2char[(thumbprint.data[pos] & 0xf0) >> 4];
                    rejectedFileName[namePos++] = hex2char[thumbprint.data[pos] & 0x0f];
                }
                strcat(rejectedFileName, ".der");
            } else {
                UA_UInt64 dt = (UA_UInt64) UA_DateTime_now();
                sprintf(rejectedFileName, "cert_%" PRIu64 ".der", dt);
            }
            UA_ByteString_clear(&thumbprint);

            char *rejectedFullFileName = (char *) calloc(ci->rejectedListFolder.length + 1 /* '/' */ + strlen(rejectedFileName) + 1, sizeof(char));
            if (rejectedFullFileName) {
                memcpy(rejectedFullFileName, ci->rejectedListFolder.data, ci->rejectedListFolder.length);
                rejectedFullFileName[ci->rejectedListFolder.length] = '/';
                memcpy(&rejectedFullFileName[ci->rejectedListFolder.length + 1], rejectedFileName, strlen(rejectedFileName));
                FILE * fp_rejectedFile = fopen(rejectedFullFileName, "wb");
                if (fp_rejectedFile) {
                    fwrite(certificate->data, sizeof(certificate->data[0]), certificate->length, fp_rejectedFile);
                    fclose(fp_rejectedFile);
                }
                free(rejectedFullFileName);
            }
        }
#endif
    }

    mbedtls_x509_crt_free(&remoteCertificate);
    return retval;
}

static void
certificateGroup_clear(UA_CertificateGroup *certGroup) {
    CertInfo *ci = (CertInfo*)certGroup->context;
    if(!ci)
        return;
    mbedtls_x509_crt_free(&ci->certificateTrustList);
    mbedtls_x509_crl_free(&ci->certificateRevocationList);
    mbedtls_x509_crt_free(&ci->certificateIssuerList);
    UA_String_clear(&ci->trustListFolder);
    UA_String_clear(&ci->issuerListFolder);
    UA_String_clear(&ci->revocationListFolder);
#ifdef UA_ENABLE_CERT_REJECTED_DIR
    UA_String_clear(&ci->rejectedListFolder);
#endif
    UA_free(ci);
    certGroup->context = NULL;
}

UA_StatusCode
UA_CertificateVerification_Trustlist(UA_CertificateGroup *certGroup,
                                     const UA_ByteString *certificateTrustList,
                                     size_t certificateTrustListSize,
                                     const UA_ByteString *certificateIssuerList,
                                     size_t certificateIssuerListSize,
                                     const UA_ByteString *certificateRevocationList,
                                     size_t certificateRevocationListSize) {

    if(certGroup == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Clear if the plugin is already initialized */
    if(certGroup->clear)
        certGroup->clear(certGroup);

    CertInfo *ci = (CertInfo*)UA_malloc(sizeof(CertInfo));
    if(!ci)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    memset(ci, 0, sizeof(CertInfo));
    mbedtls_x509_crt_init(&ci->certificateTrustList);
    mbedtls_x509_crl_init(&ci->certificateRevocationList);
    mbedtls_x509_crt_init(&ci->certificateIssuerList);

    certGroup->context = (void*)ci;
    certGroup->verifyCertificate = certificateGroup_verify;
    certGroup->clear = certificateGroup_clear;
    certGroup->getTrustList = NULL;
    certGroup->setTrustList = NULL;
    certGroup->addToTrustList = NULL;
    certGroup->removeFromTrustList = NULL;

    int err;
    UA_ByteString data;
    UA_ByteString_init(&data);

    for(size_t i = 0; i < certificateTrustListSize; i++) {
        data = copyDataFormatAware(&certificateTrustList[i]);
        err = mbedtls_x509_crt_parse(&ci->certificateTrustList,
                                     data.data,
                                     data.length);
        UA_ByteString_clear(&data);
        if(err)
            goto error;
    }
    for(size_t i = 0; i < certificateIssuerListSize; i++) {
        data = copyDataFormatAware(&certificateIssuerList[i]);
        err = mbedtls_x509_crt_parse(&ci->certificateIssuerList,
                                     data.data,
                                     data.length);
        UA_ByteString_clear(&data);
        if(err)
            goto error;
    }
    for(size_t i = 0; i < certificateRevocationListSize; i++) {
        data = copyDataFormatAware(&certificateRevocationList[i]);
        err = mbedtls_x509_crl_parse(&ci->certificateRevocationList,
                                     data.data,
                                     data.length);
        UA_ByteString_clear(&data);
        if(err)
            goto error;
    }

    return UA_STATUSCODE_GOOD;
error:
    certificateGroup_clear(certGroup);
    return UA_STATUSCODE_BADINTERNALERROR;
}

#ifdef __linux__ /* Linux only so far */

#ifdef UA_ENABLE_CERT_REJECTED_DIR
UA_StatusCode
UA_CertificateVerification_CertFolders(UA_CertificateGroup *certGroup,
                                       const char *trustListFolder,
                                       const char *issuerListFolder,
                                       const char *revocationListFolder,
                                       const char *rejectedListFolder) {
#else
UA_StatusCode
UA_CertificateVerification_CertFolders(UA_CertificateGroup *certGroup,
                                       const char *trustListFolder,
                                       const char *issuerListFolder,
                                       const char *revocationListFolder) {
#endif
    if(certGroup == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    if(certGroup->logging == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Clear if the plugin is already initialized */
    if(certGroup->clear)
        certGroup->clear(certGroup);

    CertInfo *ci = (CertInfo*)UA_malloc(sizeof(CertInfo));
    if(!ci)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    memset(ci, 0, sizeof(CertInfo));
    mbedtls_x509_crt_init(&ci->certificateTrustList);
    mbedtls_x509_crl_init(&ci->certificateRevocationList);
    mbedtls_x509_crt_init(&ci->certificateIssuerList);

    /* Only set the folder paths. They will be reloaded during runtime.
     * TODO: Add a more efficient reloading of only the changes */
    ci->trustListFolder = UA_STRING_ALLOC(trustListFolder);
    ci->issuerListFolder = UA_STRING_ALLOC(issuerListFolder);
    ci->revocationListFolder = UA_STRING_ALLOC(revocationListFolder);
#ifdef UA_ENABLE_CERT_REJECTED_DIR
    ci->rejectedListFolder = UA_STRING_ALLOC(rejectedListFolder);
#endif

    certGroup->context = (void*)ci;
    certGroup->verifyCertificate = certificateGroup_verify;
    certGroup->clear = certificateGroup_clear;
    certGroup->getTrustList = NULL;
    certGroup->setTrustList = NULL;
    certGroup->addToTrustList = NULL;
    certGroup->removeFromTrustList = NULL;

    return reloadCertificates(certGroup, ci);
}

#endif


UA_StatusCode
UA_CertificateUtils_verifyApplicationURI(UA_RuleHandling ruleHandling,
                                         const UA_ByteString *certificate,
                                         const UA_String *applicationURI) {
    /* Parse the certificate */
    mbedtls_x509_crt remoteCertificate;
    mbedtls_x509_crt_init(&remoteCertificate);
    int mbedErr = mbedtls_x509_crt_parse(&remoteCertificate, certificate->data,
                                         certificate->length);
    if(mbedErr)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Poor man's ApplicationUri verification. mbedTLS does not parse all fields
     * of the Alternative Subject Name. Instead test whether the URI-string is
     * present in the v3_ext field in general.
     *
     * TODO: Improve parsing of the Alternative Subject Name */
    UA_StatusCode retval = UA_STATUSCODE_GOOD;
    if(UA_Bstrstr(remoteCertificate.v3_ext.p, remoteCertificate.v3_ext.len,
                  applicationURI->data, applicationURI->length) == NULL)
        retval = UA_STATUSCODE_BADCERTIFICATEURIINVALID;

    if(retval != UA_STATUSCODE_GOOD && ruleHandling == UA_RULEHANDLING_DEFAULT) {
        UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
                       "The certificate's application URI could not be verified. StatusCode %s",
                       UA_StatusCode_name(retval));
        retval = UA_STATUSCODE_GOOD;
    }
    mbedtls_x509_crt_free(&remoteCertificate);
    return retval;
}

UA_StatusCode
UA_CertificateUtils_getExpirationDate(UA_ByteString *certificate,
                                      UA_DateTime *expiryDateTime) {
    mbedtls_x509_crt publicKey;
    mbedtls_x509_crt_init(&publicKey);
    int mbedErr = mbedtls_x509_crt_parse(&publicKey, certificate->data, certificate->length);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;
    UA_DateTimeStruct ts;
    ts.year = (UA_Int16)publicKey.valid_to.year;
    ts.month = (UA_UInt16)publicKey.valid_to.mon;
    ts.day = (UA_UInt16)publicKey.valid_to.day;
    ts.hour = (UA_UInt16)publicKey.valid_to.hour;
    ts.min = (UA_UInt16)publicKey.valid_to.min;
    ts.sec = (UA_UInt16)publicKey.valid_to.sec;
    ts.milliSec = 0;
    ts.microSec = 0;
    ts.nanoSec = 0;
    *expiryDateTime = UA_DateTime_fromStruct(ts);
    mbedtls_x509_crt_free(&publicKey);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_CertificateUtils_getSubjectName(UA_ByteString *certificate,
                                   UA_String *subjectName) {
    mbedtls_x509_crt publicKey;
    mbedtls_x509_crt_init(&publicKey);
    int mbedErr = mbedtls_x509_crt_parse(&publicKey, certificate->data, certificate->length);
    if(mbedErr)
        return UA_STATUSCODE_BADINTERNALERROR;
    char buf[1024];
    int res = mbedtls_x509_dn_gets(buf, 1024, &publicKey.subject);
    mbedtls_x509_crt_free(&publicKey);
    if(res < 0)
        return UA_STATUSCODE_BADINTERNALERROR;
    UA_String tmp = {(size_t)res, (UA_Byte*)buf};
    return UA_String_copy(&tmp, subjectName);
}

UA_StatusCode
UA_CertificateUtils_decryptPrivateKey(const UA_ByteString privateKey,
                                      const UA_ByteString password,
                                      UA_ByteString *outDerKey) {
    if(!outDerKey)
        return UA_STATUSCODE_BADINTERNALERROR;

    if (privateKey.length == 0) {
        *outDerKey = UA_BYTESTRING_NULL;
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    /* Already in DER format -> return verbatim */
    if(privateKey.length > 1 && privateKey.data[0] == 0x30 && privateKey.data[1] == 0x82)
        return UA_ByteString_copy(&privateKey, outDerKey);

    /* Create a null-terminated string */
    UA_ByteString nullTerminatedKey = UA_mbedTLS_CopyDataFormatAware(&privateKey);
    if(nullTerminatedKey.length != privateKey.length + 1)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Create the private-key context */
    mbedtls_pk_context ctx;
    mbedtls_pk_init(&ctx);
#if MBEDTLS_VERSION_NUMBER >= 0x02060000 && MBEDTLS_VERSION_NUMBER < 0x03000000
    int err = mbedtls_pk_parse_key(&ctx, nullTerminatedKey.data,
                                   nullTerminatedKey.length,
                                   password.data, password.length);
#else
    mbedtls_entropy_context entropy;
    mbedtls_entropy_init(&entropy);
    int err = mbedtls_pk_parse_key(&ctx, nullTerminatedKey.data,
                                   nullTerminatedKey.length,
                                   password.data, password.length,
                                   mbedtls_entropy_func, &entropy);
    mbedtls_entropy_free(&entropy);
#endif
    UA_ByteString_clear(&nullTerminatedKey);
    if(err != 0) {
        mbedtls_pk_free(&ctx);
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    }

    /* Write the DER-encoded key into a local buffer */
    unsigned char buf[2 << 13];
    size_t pos = (size_t)mbedtls_pk_write_key_der(&ctx, buf, sizeof(buf));

    /* Allocate memory */
    UA_StatusCode res = UA_ByteString_allocBuffer(outDerKey, pos);
    if(res != UA_STATUSCODE_GOOD) {
        mbedtls_pk_free(&ctx);
        return res;
    }

    /* Copy to the output */
    memcpy(outDerKey->data, &buf[sizeof(buf) - pos], pos);
    mbedtls_pk_free(&ctx);
    return UA_STATUSCODE_GOOD;
}

#endif

/**** amalgamated original file "/plugins/crypto/openssl/securitypolicy_openssl_common.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2020 (c) Wind River Systems, Inc.
 *    Copyright 2020 (c) basysKom GmbH
 *
 */



#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL)

#include <openssl/x509.h>
#include <openssl/evp.h>

_UA_BEGIN_DECLS

void saveDataToFile(const char *fileName, const UA_ByteString *str);
void UA_Openssl_Init(void);

UA_StatusCode
UA_copyCertificate(UA_ByteString *dst, const UA_ByteString *src);

UA_StatusCode
UA_OpenSSL_RSA_PKCS1_V15_SHA256_Verify(const UA_ByteString *msg,
                                       X509 *publicKeyX509,
                                       const UA_ByteString *signature);

UA_StatusCode
UA_OpenSSL_RSA_PSS_SHA256_Verify (const UA_ByteString * msg,
                                  X509 *publicKeyX509,
                                  const UA_ByteString * signature);

UA_StatusCode
UA_Openssl_X509_GetCertificateThumbprint(const UA_ByteString *certficate,
                                         UA_ByteString *pThumbprint,
                                         bool bThumbPrint);
UA_StatusCode
UA_Openssl_RSA_Oaep_Decrypt(UA_ByteString *data,
                            EVP_PKEY *privateKey);

UA_StatusCode
UA_Openssl_RSA_Oaep_Sha2_Decrypt (UA_ByteString *data,
                            EVP_PKEY *privateKey);

UA_StatusCode
UA_Openssl_RSA_OAEP_Encrypt(UA_ByteString *data, /* The data that is encrypted.
                                                    The encrypted data will overwrite
                                                    the data that was supplied.  */
                             size_t paddingSize, X509 *publicX509);

UA_StatusCode
UA_Openssl_RSA_OAEP_SHA2_Encrypt (UA_ByteString * data,
                                  size_t          paddingSize,
                                  X509 *          publicX509);

UA_StatusCode
UA_Openssl_Random_Key_PSHA256_Derive(const UA_ByteString *secret,
                                     const UA_ByteString *seed,
                                     UA_ByteString *out);

UA_StatusCode
UA_Openssl_RSA_Public_GetKeyLength(X509 *publicKeyX509, UA_Int32 *keyLen);

UA_StatusCode
UA_Openssl_RSA_PKCS1_V15_SHA256_Sign(const UA_ByteString *data,
                                     EVP_PKEY *privateKey,
                                     UA_ByteString *outSignature);

UA_StatusCode
UA_Openssl_RSA_PSS_SHA256_Sign (const UA_ByteString * message,
                                EVP_PKEY * privateKey,
                                UA_ByteString *       outSignature);

UA_StatusCode
UA_OpenSSL_HMAC_SHA256_Verify(const UA_ByteString *message,
                              const UA_ByteString *key,
                              const UA_ByteString *signature);

UA_StatusCode
UA_OpenSSL_HMAC_SHA256_Sign(const UA_ByteString *message,
                            const UA_ByteString *key,
                            UA_ByteString *signature);

UA_StatusCode
UA_OpenSSL_AES_256_CBC_Decrypt(const UA_ByteString *iv,
                               const UA_ByteString *key,
                               UA_ByteString *data  /* [in/out]*/);

UA_StatusCode
UA_OpenSSL_AES_256_CBC_Encrypt(const UA_ByteString *iv,
                               const UA_ByteString *key,
                               UA_ByteString *data  /* [in/out]*/);

UA_StatusCode
UA_OpenSSL_X509_compare(const UA_ByteString *cert, const X509 *b);

UA_StatusCode
UA_Openssl_RSA_Private_GetKeyLength(EVP_PKEY *privateKey,
                                    UA_Int32 *keyLen) ;

UA_StatusCode
UA_OpenSSL_RSA_PKCS1_V15_SHA1_Verify(const UA_ByteString *msg,
                                      X509 *publicKeyX509,
                                      const UA_ByteString *signature);

UA_StatusCode
UA_Openssl_RSA_PKCS1_V15_SHA1_Sign(const UA_ByteString *message,
                                   EVP_PKEY *privateKey,
                                   UA_ByteString *outSignature);
UA_StatusCode
UA_Openssl_Random_Key_PSHA1_Derive(const UA_ByteString *secret,
                                   const UA_ByteString *seed,
                                   UA_ByteString *out);
UA_StatusCode
UA_OpenSSL_HMAC_SHA1_Verify(const UA_ByteString *message,
                            const UA_ByteString *key,
                            const UA_ByteString *signature);

UA_StatusCode
UA_OpenSSL_HMAC_SHA1_Sign(const UA_ByteString *message,
                          const UA_ByteString *key,
                          UA_ByteString *signature);

UA_StatusCode
UA_Openssl_RSA_PKCS1_V15_Decrypt(UA_ByteString *data,
                                 EVP_PKEY *privateKey);

UA_StatusCode
UA_Openssl_RSA_PKCS1_V15_Encrypt(UA_ByteString *data,
                                 size_t paddingSize,
                                 X509 *publicX509);

UA_StatusCode
UA_OpenSSL_AES_128_CBC_Decrypt(const UA_ByteString *iv,
                               const UA_ByteString *key,
                               UA_ByteString *data  /* [in/out]*/);

UA_StatusCode
UA_OpenSSL_AES_128_CBC_Encrypt(const UA_ByteString *iv,
                               const UA_ByteString *key,
                               UA_ByteString *data  /* [in/out]*/);

EVP_PKEY *
UA_OpenSSL_LoadPrivateKey(const UA_ByteString *privateKey);

X509 *
UA_OpenSSL_LoadCertificate(const UA_ByteString *certificate);

X509 *
UA_OpenSSL_LoadDerCertificate(const UA_ByteString *certificate);

X509 *
UA_OpenSSL_LoadPemCertificate(const UA_ByteString *certificate);

UA_StatusCode
UA_OpenSSL_LoadLocalCertificate(const UA_ByteString *certificate, UA_ByteString *target);

_UA_END_DECLS

#endif /* defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL) */


/**** amalgamated original file "/plugins/crypto/openssl/ua_openssl_version_abstraction.h" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2021 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati)
 *
 */


#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL)

#include <openssl/x509.h>

#if !defined(OPENSSL_VERSION_NUMBER)
#error "OPENSSL_VERSION_NUMBER is not defined."
#endif

#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
#define X509_STORE_CTX_set0_trusted_stack(STORE_CTX, CTX_SKTRUSTED) X509_STORE_CTX_trusted_stack(STORE_CTX, CTX_SKTRUSTED)
#endif

#if OPENSSL_VERSION_NUMBER < 0x1010000fL || ( defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3050000fL)
#define X509_STORE_CTX_get_check_issued(STORE_CTX) STORE_CTX->check_issued
#endif

#if OPENSSL_VERSION_NUMBER < 0x1010000fL || ( defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3050000fL)
#define get_pkey_rsa(evp) ((evp)->pkey.rsa)
#else
#define get_pkey_rsa(evp) EVP_PKEY_get0_RSA(evp)
#endif

#if OPENSSL_VERSION_NUMBER < 0x1010000fL || defined(LIBRESSL_VERSION_NUMBER)
#define X509_get0_subject_key_id(PX509_CERT) (const ASN1_OCTET_STRING *)X509_get_ext_d2i(PX509_CERT, NID_subject_key_identifier, NULL, NULL);
#endif

#if OPENSSL_VERSION_NUMBER < 0x2000000fL || defined(LIBRESSL_VERSION_NUMBER)
#define get_error_line_data(pFile, pLine, pData, pFlags) ERR_get_error_line_data(pFile, pLine, pData, pFlags)
#else
#define get_error_line_data(pFile, pLine, pData, pFlags) ERR_get_error_all(pFile, pLine, NULL, pData, pFlags)
#endif

#endif /* defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL) */

/**** amalgamated original file "/plugins/crypto/openssl/securitypolicy_openssl_common.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2020 (c) Wind River Systems, Inc.
 *    Copyright 2020 (c) basysKom GmbH
 *    Copyright 2022 (c) Wind River Systems, Inc.
 *    Copyright 2022 (c) Fraunhofer IOSB (Author: Noel Graf)
 */

/*
modification history
--------------------
01feb20,lan  written
*/


#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL)

#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/sha.h>
#include <openssl/x509.h>
#include <openssl/hmac.h>
#include <openssl/aes.h>
#include <openssl/pem.h>


#define SHA1_DIGEST_LENGTH 20          /* 160 bits */
#define RSA_DECRYPT_BUFFER_LENGTH 2048 /* bytes */

/* Cast to prevent warnings in LibreSSL */
#define SHA256EVP() ((EVP_MD *)(uintptr_t)EVP_sha256())


/** P_SHA256 Context */
typedef struct UA_Openssl_P_SHA256_Ctx_ {
    size_t  seedLen;
    size_t  secretLen;
    UA_Byte   A[32]; /* 32 bytes of SHA256 output */
    /*
    char seed[seedLen];
    char secret[secretLen]; */
} UA_Openssl_P_SHA256_Ctx;

#define UA_Openssl_P_SHA256_SEED(ctx)   ((ctx)->A+32)
#define UA_Openssl_P_SHA256_SECRET(ctx) ((ctx)->A+32+(ctx)->seedLen)

/** P_SHA1 Context */
typedef struct UA_Openssl_P_SHA1_Ctx_ {
    size_t  seedLen;
    size_t  secretLen;
    UA_Byte A[SHA1_DIGEST_LENGTH];  /* 20 bytes of SHA1 output */
    /*
    char seed[seedLen];
    char secret[secretLen]; */
} UA_Openssl_P_SHA1_Ctx;

#define UA_Openssl_P_SHA1_SEED(ctx)   ((ctx)->A + SHA1_DIGEST_LENGTH)
#define UA_Openssl_P_SHA1_SECRET(ctx) ((ctx)->A + SHA1_DIGEST_LENGTH +(ctx)->seedLen)

void
UA_Openssl_Init (void) {
    /* VxWorks7 has initialized the openssl. */
#ifndef __VXWORKS__
    static UA_Int16 bInit = 0;
    if (bInit == 1)
        return;
#if defined(OPENSSL_API_COMPAT) && (OPENSSL_API_COMPAT < 0x10100000L)
    /* only needed, if OpenSSL < V1.1 */
    OpenSSL_add_all_algorithms ();
    ERR_load_crypto_strings ();
#endif
    bInit = 1;
#endif
}

static int UA_OpenSSL_RSA_Key_Size (EVP_PKEY * key){
#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
    return EVP_PKEY_get_size (key);
#else
    return RSA_size (get_pkey_rsa(key));
#endif
}

/* UA_copyCertificate - allocalte the buffer, copy the certificate and
 * add a NULL to the end
 */

UA_StatusCode
UA_copyCertificate (UA_ByteString * dst,
                    const UA_ByteString * src) {
    UA_StatusCode retval = UA_ByteString_allocBuffer (dst, src->length + 1);
    if (retval != UA_STATUSCODE_GOOD)
        return retval;
    (void) memcpy (dst->data, src->data, src->length);
    dst->data[dst->length - 1] = '\0';
    dst->length--;

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_OpenSSL_RSA_Public_Verify(const UA_ByteString *message,
                             const EVP_MD *evpMd, X509 *publicKeyX509,
                             UA_Int16 padding, const UA_ByteString *signature) {
    EVP_MD_CTX *mdctx = EVP_MD_CTX_create();
    if(!mdctx)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_StatusCode ret = UA_STATUSCODE_GOOD;
    EVP_PKEY *evpPublicKey = X509_get_pubkey(publicKeyX509);
    if(!evpPublicKey) {
        ret = UA_STATUSCODE_BADOUTOFMEMORY;
        goto errout;
    }

    EVP_PKEY_CTX *evpKeyCtx;
    int opensslRet = EVP_DigestVerifyInit(mdctx, &evpKeyCtx, evpMd,
                                          NULL, evpPublicKey);
    if(opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    opensslRet = EVP_PKEY_CTX_set_rsa_padding(evpKeyCtx, padding);
    if(opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    if(padding == RSA_PKCS1_PSS_PADDING) {
        opensslRet = EVP_PKEY_CTX_set_rsa_pss_saltlen(evpKeyCtx, RSA_PSS_SALTLEN_DIGEST);
        if(opensslRet != 1) {
            ret = UA_STATUSCODE_BADINTERNALERROR;
            goto errout;
        }
        opensslRet = EVP_PKEY_CTX_set_rsa_mgf1_md(evpKeyCtx, SHA256EVP());
        if(opensslRet != 1) {
            ret = UA_STATUSCODE_BADINTERNALERROR;
            goto errout;
        }
    }

    opensslRet = EVP_DigestVerifyUpdate (mdctx, message->data, message->length);
    if(opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    opensslRet = EVP_DigestVerifyFinal(mdctx, signature->data, signature->length);
    if(opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

errout:
    if(evpPublicKey)
        EVP_PKEY_free(evpPublicKey);
    if(mdctx)
        EVP_MD_CTX_destroy(mdctx);
    return ret;
}

UA_StatusCode
UA_OpenSSL_RSA_PKCS1_V15_SHA256_Verify (const UA_ByteString * msg,
                                        X509 *                publicKeyX509,
                                        const UA_ByteString * signature
                                       ) {
    return UA_OpenSSL_RSA_Public_Verify (msg, EVP_sha256(), publicKeyX509,
                                         RSA_PKCS1_PADDING, signature);
}

UA_StatusCode
UA_OpenSSL_RSA_PSS_SHA256_Verify (const UA_ByteString * msg,
                                        X509 *                publicKeyX509,
                                        const UA_ByteString * signature
) {
    return UA_OpenSSL_RSA_Public_Verify (msg, EVP_sha256(), publicKeyX509,
                                         RSA_PKCS1_PSS_PADDING, signature);
}

/* Get certificate thumbprint, and allocate the buffer. */

UA_StatusCode
UA_Openssl_X509_GetCertificateThumbprint (const UA_ByteString * certficate,
                                          UA_ByteString *       pThumbprint,
                                          bool                  bThumbPrint) {
    if (bThumbPrint) {
        pThumbprint->length = SHA_DIGEST_LENGTH;
        UA_StatusCode ret = UA_ByteString_allocBuffer (pThumbprint, pThumbprint->length);
        if (ret != UA_STATUSCODE_GOOD) {
            return ret;
            }
    }
    else {
        if (pThumbprint->length != SHA_DIGEST_LENGTH) {
            return UA_STATUSCODE_BADINTERNALERROR;
        }
    }
    X509 * x509Certificate = UA_OpenSSL_LoadCertificate(certficate);

    if (x509Certificate == NULL) {
        if (bThumbPrint) {
            UA_ByteString_clear (pThumbprint);
        }
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    if (X509_digest (x509Certificate, EVP_sha1(), pThumbprint->data, NULL)
        != 1) {
        if (bThumbPrint) {
            UA_ByteString_clear (pThumbprint);
        }
    return UA_STATUSCODE_BADINTERNALERROR;
    }
    X509_free(x509Certificate);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_Openssl_RSA_Private_Decrypt (UA_ByteString *      data,
                               EVP_PKEY *            privateKey,
                               UA_Int16              padding,
                               UA_Boolean            withSha256) {
    if (data == NULL || privateKey == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    if (privateKey == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    size_t keySize = (size_t) UA_OpenSSL_RSA_Key_Size (privateKey);
    size_t cipherOffset = 0;
    size_t outOffset = 0;
    unsigned char buf[RSA_DECRYPT_BUFFER_LENGTH];
    size_t decryptedBytes;
    EVP_PKEY_CTX * ctx;
    int opensslRet;

    ctx = EVP_PKEY_CTX_new (privateKey, NULL);
    if (ctx == NULL) {
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    opensslRet = EVP_PKEY_decrypt_init (ctx);
    if (opensslRet != 1) {
        EVP_PKEY_CTX_free (ctx);
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    opensslRet = EVP_PKEY_CTX_set_rsa_padding (ctx, padding);
    if (opensslRet != 1) {
        EVP_PKEY_CTX_free (ctx);
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    if(withSha256) {
        opensslRet = EVP_PKEY_CTX_set_rsa_oaep_md(ctx, SHA256EVP());
        if (opensslRet != 1) {
            return UA_STATUSCODE_BADINTERNALERROR;
        }
        opensslRet = EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, SHA256EVP());
        if (opensslRet != 1) {
            return UA_STATUSCODE_BADINTERNALERROR;
        }
    }

    while (cipherOffset < data->length) {
        decryptedBytes = RSA_DECRYPT_BUFFER_LENGTH;
        opensslRet = EVP_PKEY_decrypt (ctx,
                           buf,                       /* where to decrypt */
                           &decryptedBytes,
                           data->data + cipherOffset, /* what to decrypt  */
                           keySize
                           );
        if (opensslRet != 1) {
            EVP_PKEY_CTX_free (ctx);
            return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        }
        (void) memcpy(data->data + outOffset, buf, decryptedBytes);
        cipherOffset += (size_t) keySize;
        outOffset += decryptedBytes;
    }
    data->length = outOffset;
    EVP_PKEY_CTX_free (ctx);

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Openssl_RSA_Oaep_Decrypt (UA_ByteString *       data,
                             EVP_PKEY * privateKey) {
    return  UA_Openssl_RSA_Private_Decrypt (data, privateKey,
                                            RSA_PKCS1_OAEP_PADDING, false);
}

UA_StatusCode
UA_Openssl_RSA_Oaep_Sha2_Decrypt (UA_ByteString *       data,
                             EVP_PKEY * privateKey) {
    return  UA_Openssl_RSA_Private_Decrypt (data, privateKey,
                                            RSA_PKCS1_OAEP_PADDING, true);
}

static UA_StatusCode
UA_Openssl_RSA_Public_Encrypt  (const UA_ByteString * message,
                                X509 *                publicX509,
                                UA_Int16              padding,
                                size_t                paddingSize,
                                UA_ByteString *       encrypted,
                                UA_Boolean withSha256) {
    EVP_PKEY_CTX *   ctx          = NULL;
    EVP_PKEY *       evpPublicKey = NULL;
    int              opensslRet;
    UA_StatusCode    ret;
    size_t encryptedTextLen = 0;
    size_t dataPos =  0;
    size_t encryptedPos = 0;
    size_t bytesToEncrypt = 0;
    size_t encryptedBlockSize = 0;
    size_t keySize = 0;

    evpPublicKey = X509_get_pubkey (publicX509);
    if (evpPublicKey == NULL) {
        ret = UA_STATUSCODE_BADOUTOFMEMORY;
        goto errout;
    }
    ctx = EVP_PKEY_CTX_new (evpPublicKey, NULL);
    if (ctx == NULL) {
        ret = UA_STATUSCODE_BADOUTOFMEMORY;
        goto errout;
    }
    opensslRet = EVP_PKEY_encrypt_init (ctx);
    if (opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }
    opensslRet = EVP_PKEY_CTX_set_rsa_padding (ctx, padding);
    if (opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }
    if(withSha256) {
        opensslRet = EVP_PKEY_CTX_set_rsa_oaep_md(ctx, SHA256EVP());
        if (opensslRet != 1) {
            ret = UA_STATUSCODE_BADINTERNALERROR;
            goto errout;
        }
        opensslRet = EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, SHA256EVP());
        if (opensslRet != 1) {
            ret = UA_STATUSCODE_BADINTERNALERROR;
            goto errout;
        }
    }

    /* get the encrypted block size */

    keySize = (size_t) UA_OpenSSL_RSA_Key_Size (evpPublicKey);
    if (keySize == 0) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    switch (padding) {
        case RSA_PKCS1_OAEP_PADDING:
        case RSA_PKCS1_PADDING:
            if (keySize <= paddingSize) {
                ret = UA_STATUSCODE_BADINTERNALERROR;
                goto errout;
            }
            encryptedBlockSize = keySize - paddingSize;
            break;
        default:
            ret = UA_STATUSCODE_BADNOTSUPPORTED;
            goto errout;
            break;
    }

    /* encrypt in reverse order so that [data] may alias [encrypted] */

    dataPos =  message->length;
    encryptedPos = ((dataPos - 1) / encryptedBlockSize + 1) * keySize;
    bytesToEncrypt = (dataPos - 1) % encryptedBlockSize + 1;
    encryptedTextLen = encryptedPos;

    while (dataPos > 0) {
        size_t outlen = keySize;
        encryptedPos -= keySize;
        dataPos -= bytesToEncrypt;
        opensslRet = EVP_PKEY_encrypt (ctx, encrypted->data + encryptedPos, &outlen,
                                       message->data + dataPos, bytesToEncrypt);

        if (opensslRet != 1) {
            ret = UA_STATUSCODE_BADINTERNALERROR;
            goto errout;
        }
        bytesToEncrypt = encryptedBlockSize;
    }
    encrypted->length = encryptedTextLen;

    ret = UA_STATUSCODE_GOOD;
errout:
    if (evpPublicKey != NULL) {
        EVP_PKEY_free (evpPublicKey);
    }
    if (ctx != NULL) {
        EVP_PKEY_CTX_free (ctx);
    }
    return ret;
}

UA_StatusCode
UA_Openssl_RSA_OAEP_Encrypt (UA_ByteString * data,
                             size_t          paddingSize,
                             X509 *          publicX509) {
    UA_ByteString message;
    UA_StatusCode ret;

    ret = UA_ByteString_copy (data, &message);
    if (ret != UA_STATUSCODE_GOOD) {
        return ret;
    }
    ret = UA_Openssl_RSA_Public_Encrypt (&message, publicX509,
                                            RSA_PKCS1_OAEP_PADDING,
                                            paddingSize,
                                            data, false);
    UA_ByteString_clear (&message);
    return ret;
}

UA_StatusCode
UA_Openssl_RSA_OAEP_SHA2_Encrypt (UA_ByteString * data,
                             size_t          paddingSize,
                             X509 *          publicX509) {
    UA_ByteString message;
    UA_StatusCode ret;

    ret = UA_ByteString_copy (data, &message);
    if (ret != UA_STATUSCODE_GOOD) {
        return ret;
    }
    ret = UA_Openssl_RSA_Public_Encrypt (&message, publicX509,
                                         RSA_PKCS1_OAEP_PADDING,
                                         paddingSize,
                                         data, true);
    UA_ByteString_clear (&message);
    return ret;
}

static UA_Openssl_P_SHA256_Ctx *
P_SHA256_Ctx_Create (const UA_ByteString *  secret,
                     const UA_ByteString *  seed) {
    size_t size = (UA_Int32)sizeof (UA_Openssl_P_SHA256_Ctx) + secret->length +
                    seed->length;
    UA_Openssl_P_SHA256_Ctx * ctx = (UA_Openssl_P_SHA256_Ctx *) UA_malloc (size);
    if (ctx == NULL) {
        return NULL;
    }
    ctx->secretLen = secret->length;
    ctx->seedLen = seed->length;
    (void) memcpy (UA_Openssl_P_SHA256_SEED(ctx), seed->data, seed->length);
    (void) memcpy (UA_Openssl_P_SHA256_SECRET(ctx), secret->data, secret->length);
    /* A(0) = seed
       A(n) = HMAC_HASH(secret, A(n-1)) */

    if (HMAC (EVP_sha256(), secret->data, (int) secret->length, seed->data,
        seed->length, ctx->A, NULL) == NULL) {
        UA_free (ctx);
        return NULL;
    }

    return ctx;
}

static UA_StatusCode
P_SHA256_Hash_Generate (UA_Openssl_P_SHA256_Ctx * ctx,
                        UA_Byte *                 pHas
                        ) {
    /* Calculate P_SHA256(n) = HMAC_SHA256(secret, A(n)+seed) */
    if (HMAC (EVP_sha256(),UA_Openssl_P_SHA256_SECRET(ctx), (int) ctx->secretLen,
        ctx->A, sizeof (ctx->A) + ctx->seedLen, pHas, NULL) == NULL) {
            return UA_STATUSCODE_BADINTERNALERROR;
        }

    /* Calculate A(n) = HMAC_SHA256(secret, A(n-1)) */
   if (HMAC (EVP_sha256(),UA_Openssl_P_SHA256_SECRET(ctx), (int) ctx->secretLen,
        ctx->A, sizeof (ctx->A), ctx->A, NULL) == NULL) {
            return UA_STATUSCODE_BADINTERNALERROR;
        }
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Openssl_Random_Key_PSHA256_Derive (const UA_ByteString *     secret,
                                      const UA_ByteString *     seed,
                                      UA_ByteString *           out) {
    size_t keyLen = out->length;
    size_t iter   = keyLen/32 + ((keyLen%32)?1:0);
    size_t bufferLen = iter * 32;
    size_t i;
    UA_StatusCode st;

    UA_Byte * pBuffer = (UA_Byte *) UA_malloc (bufferLen);
    if (pBuffer == NULL) {
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    UA_Openssl_P_SHA256_Ctx * ctx = P_SHA256_Ctx_Create (secret, seed);
    if (ctx == NULL) {
        UA_free (pBuffer);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    for (i = 0; i < iter; i++) {
        st = P_SHA256_Hash_Generate (ctx, pBuffer + (i * 32));
        if (st != UA_STATUSCODE_GOOD) {
            UA_free (pBuffer);
            UA_free (ctx);
            return st;
        }
    }

    (void) memcpy (out->data, pBuffer, keyLen);
    UA_free (pBuffer);
    UA_free (ctx);
    return UA_STATUSCODE_GOOD;
}

/* return the key bytes */
UA_StatusCode
UA_Openssl_RSA_Public_GetKeyLength (X509 *     publicKeyX509,
                                    UA_Int32 * keyLen) {
    EVP_PKEY * evpKey = X509_get_pubkey (publicKeyX509);
    if (evpKey == NULL) {
        return  UA_STATUSCODE_BADINTERNALERROR;
    }
    *keyLen = UA_OpenSSL_RSA_Key_Size (evpKey);
    
    EVP_PKEY_free (evpKey);

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Openssl_RSA_Private_GetKeyLength (EVP_PKEY * privateKey,
                                     UA_Int32 *            keyLen) {
    if (privateKey == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }
    *keyLen = UA_OpenSSL_RSA_Key_Size (privateKey);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_Openssl_RSA_Private_Sign (const UA_ByteString * message,
                     EVP_PKEY * privateKey,
                     const EVP_MD *        evpMd,
                     UA_Int16              padding,
                     UA_ByteString *       outSignature) {
    EVP_MD_CTX *     mdctx        = NULL;
    int              opensslRet;
    EVP_PKEY_CTX *   evpKeyCtx;
    UA_StatusCode    ret;

    mdctx = EVP_MD_CTX_create ();
    if (mdctx == NULL) {
        ret = UA_STATUSCODE_BADOUTOFMEMORY;
        goto errout;
    }

    if (privateKey == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }
    opensslRet = EVP_DigestSignInit (mdctx, &evpKeyCtx, evpMd, NULL, privateKey);
    if (opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }
    EVP_PKEY_CTX_set_rsa_padding (evpKeyCtx, padding);
    if(padding == RSA_PKCS1_PSS_PADDING) {
        opensslRet = EVP_PKEY_CTX_set_rsa_pss_saltlen(evpKeyCtx, RSA_PSS_SALTLEN_DIGEST); //RSA_PSS_SALTLEN_DIGEST
        if (opensslRet != 1) {
            ret = UA_STATUSCODE_BADINTERNALERROR;
            goto errout;
        }
        opensslRet = EVP_PKEY_CTX_set_rsa_mgf1_md(evpKeyCtx, SHA256EVP());
        if (opensslRet != 1) {
            ret = UA_STATUSCODE_BADINTERNALERROR;
            goto errout;
        }
    }
    opensslRet = EVP_DigestSignUpdate (mdctx, message->data, message->length);
    if (opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }
    opensslRet = EVP_DigestSignFinal (mdctx, outSignature->data, &outSignature->length);
    if (opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    ret = UA_STATUSCODE_GOOD;
errout:
    if (mdctx != NULL) {
        EVP_MD_CTX_destroy (mdctx);
    }
    return ret;
}

UA_StatusCode
UA_Openssl_RSA_PKCS1_V15_SHA256_Sign (const UA_ByteString * message,
                                      EVP_PKEY * privateKey,
                                      UA_ByteString *       outSignature) {
    return UA_Openssl_RSA_Private_Sign (message, privateKey, EVP_sha256(),
                                        RSA_PKCS1_PADDING , outSignature);
}

UA_StatusCode
UA_Openssl_RSA_PSS_SHA256_Sign (const UA_ByteString * message,
                                      EVP_PKEY * privateKey,
                                      UA_ByteString *       outSignature) {
    return UA_Openssl_RSA_Private_Sign (message, privateKey, EVP_sha256(),
                                        RSA_PKCS1_PSS_PADDING, outSignature);
}

UA_StatusCode
UA_OpenSSL_HMAC_SHA256_Verify (const UA_ByteString *     message,
                               const UA_ByteString *     key,
                               const UA_ByteString *     signature
                              ) {
    unsigned char buf[SHA256_DIGEST_LENGTH] = {0};
    UA_ByteString mac = {SHA256_DIGEST_LENGTH, buf};

    if (HMAC (EVP_sha256(), key->data, (int) key->length, message->data, message->length,
              mac.data, (unsigned int *) &mac.length) == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    if (UA_ByteString_equal (signature, &mac)) {
        return UA_STATUSCODE_GOOD;
    }
    else {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
}

UA_StatusCode
UA_OpenSSL_HMAC_SHA256_Sign (const UA_ByteString *     message,
                             const UA_ByteString *     key,
                             UA_ByteString *           signature
                             ) {
    if (HMAC (EVP_sha256(), key->data, (int) key->length, message->data,
              message->length,
              signature->data, (unsigned int *) &(signature->length)) == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_OpenSSL_Decrypt (const UA_ByteString * iv,
                    const UA_ByteString * key,
                    const EVP_CIPHER *    cipherAlg,
                    UA_ByteString *       data  /* [in/out]*/) {
    UA_ByteString    ivCopy    = {0, NULL};
    UA_ByteString    cipherTxt = {0, NULL};
    EVP_CIPHER_CTX * ctx       = NULL;
    UA_StatusCode    ret;
    int              opensslRet;
    int              outLen;
    int              tmpLen;

    /* copy the IV because the AES_cbc_encrypt function overwrites it. */

    ret = UA_ByteString_copy (iv, &ivCopy);
    if (ret != UA_STATUSCODE_GOOD) {
        goto errout;
    }

    ret = UA_ByteString_copy (data, &cipherTxt);
    if (ret != UA_STATUSCODE_GOOD) {
        goto errout;
    }

    ctx = EVP_CIPHER_CTX_new ();
    if (ctx == NULL) {
        ret = UA_STATUSCODE_BADOUTOFMEMORY;
        goto errout;
    }

    /* call EVP_* to decrypt */

    opensslRet = EVP_DecryptInit_ex (ctx, cipherAlg, NULL, key->data, ivCopy.data);
    if (opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }
    /* EVP_DecryptFinal() will return an error code if padding is enabled
     * and the final block is not correctly formatted.
     */
    EVP_CIPHER_CTX_set_padding (ctx, 0);
    opensslRet = EVP_DecryptUpdate (ctx, data->data, &outLen,
                                    cipherTxt.data, (int) cipherTxt.length);
    if (opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }
    opensslRet = EVP_DecryptFinal_ex (ctx, data->data + outLen, &tmpLen);
    if (opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }
    outLen += tmpLen;
    data->length = (size_t) outLen;
    ret = UA_STATUSCODE_GOOD;

errout:
    UA_ByteString_clear (&ivCopy);
    UA_ByteString_clear (&cipherTxt);
    if (ctx != NULL) {
        EVP_CIPHER_CTX_free(ctx);
    }
    return ret;
}

static UA_StatusCode
UA_OpenSSL_Encrypt (const UA_ByteString * iv,
                    const UA_ByteString * key,
                    const EVP_CIPHER *    cipherAlg,
                    UA_ByteString *       data  /* [in/out]*/
                    ) {

    UA_ByteString    ivCopy   = {0, NULL};
    UA_ByteString    plainTxt = {0, NULL};
    EVP_CIPHER_CTX * ctx      = NULL;
    UA_StatusCode    ret;
    int              opensslRet;
    int              outLen;
    int              tmpLen;

    /* copy the IV because the AES_cbc_encrypt function overwrites it. */

    ret = UA_ByteString_copy (iv, &ivCopy);
    if (ret != UA_STATUSCODE_GOOD) {
        goto errout;
    }

    ret = UA_ByteString_copy (data, &plainTxt);
    if (ret != UA_STATUSCODE_GOOD) {
        goto errout;
    }

    ctx = EVP_CIPHER_CTX_new ();
    if (ctx == NULL) {
        ret = UA_STATUSCODE_BADOUTOFMEMORY;
        goto errout;
    }

    /* call EVP_* to encrypt */

    opensslRet = EVP_EncryptInit_ex (ctx, cipherAlg, NULL, key->data, ivCopy.data);
    if (opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    /* Disable padding. Padding is done in the stack before calling encryption.
     * Ensure that we have a multiple of the block size */
    if(data->length % (size_t)EVP_CIPHER_CTX_block_size(ctx)) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }
    opensslRet = EVP_CIPHER_CTX_set_padding(ctx, 0);
    if (opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    /* Encrypt the data */
    opensslRet = EVP_EncryptUpdate (ctx, data->data, &outLen,
                                    plainTxt.data, (int) plainTxt.length);
    if (opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }

    /* Encrypt-final does nothing as padding is disabled */
    opensslRet = EVP_EncryptFinal_ex(ctx, data->data + outLen, &tmpLen);
    if (opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto errout;
    }
    outLen += tmpLen;
    data->length = (size_t) outLen;
    ret = UA_STATUSCODE_GOOD;

errout:
    UA_ByteString_clear (&ivCopy);
    UA_ByteString_clear (&plainTxt);
    if (ctx != NULL) {
        EVP_CIPHER_CTX_free(ctx);
    }
    return ret;
}

UA_StatusCode
UA_OpenSSL_AES_256_CBC_Decrypt (const UA_ByteString * iv,
                                const UA_ByteString * key,
                                UA_ByteString *       data  /* [in/out]*/
                                ) {
    return UA_OpenSSL_Decrypt (iv, key, EVP_aes_256_cbc (), data);
}

UA_StatusCode
UA_OpenSSL_AES_256_CBC_Encrypt (const UA_ByteString * iv,
                            const UA_ByteString * key,
                            UA_ByteString *       data  /* [in/out]*/
                            ) {
    return UA_OpenSSL_Encrypt (iv, key, EVP_aes_256_cbc (), data);
}

UA_StatusCode
UA_OpenSSL_X509_compare (const UA_ByteString * cert,
                         const X509 *          bcert) {
    X509 * acert = UA_OpenSSL_LoadCertificate(cert);
    if (acert == NULL) {
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    }
    int opensslRet = X509_cmp (acert, bcert);
    X509_free (acert);

    if (opensslRet == 0)
        return UA_STATUSCODE_GOOD;
    return UA_STATUSCODE_UNCERTAINSUBNORMAL;
}

UA_StatusCode
UA_OpenSSL_RSA_PKCS1_V15_SHA1_Verify (const UA_ByteString * msg,
                                      X509 *                publicKeyX509,
                                      const UA_ByteString * signature) {
    return UA_OpenSSL_RSA_Public_Verify(msg, EVP_sha1(), publicKeyX509,
                                        RSA_PKCS1_PADDING, signature);
}

UA_StatusCode
UA_Openssl_RSA_PKCS1_V15_SHA1_Sign (const UA_ByteString * message,
                                    EVP_PKEY * privateKey,
                                    UA_ByteString *       outSignature) {
    return UA_Openssl_RSA_Private_Sign(message, privateKey, EVP_sha1(),
                                       RSA_PKCS1_PADDING, outSignature);
}

static UA_Openssl_P_SHA1_Ctx *
P_SHA1_Ctx_Create (const UA_ByteString *  secret,
                   const UA_ByteString *  seed) {
    size_t size = (UA_Int32)sizeof (UA_Openssl_P_SHA1_Ctx) + secret->length +
                    seed->length;
    UA_Openssl_P_SHA1_Ctx * ctx = (UA_Openssl_P_SHA1_Ctx *) UA_malloc (size);
    if (ctx == NULL) {
        return NULL;
    }

    ctx->secretLen = secret->length;
    ctx->seedLen = seed->length;
    (void) memcpy (UA_Openssl_P_SHA1_SEED(ctx), seed->data, seed->length);
    (void) memcpy (UA_Openssl_P_SHA1_SECRET(ctx), secret->data, secret->length);
    /* A(0) = seed
       A(n) = HMAC_HASH(secret, A(n-1)) */

    if (HMAC (EVP_sha1(), secret->data, (int) secret->length, seed->data,
        seed->length, ctx->A, NULL) == NULL) {
        UA_free (ctx);
        return NULL;
    }

    return ctx;
}

static UA_StatusCode
P_SHA1_Hash_Generate (UA_Openssl_P_SHA1_Ctx * ctx,
                      UA_Byte *               pHas
                      ) {
    /* Calculate P_SHA1(n) = HMAC_SHA1(secret, A(n)+seed) */
    if (HMAC (EVP_sha1 (), UA_Openssl_P_SHA1_SECRET(ctx), (int) ctx->secretLen,
        ctx->A, sizeof (ctx->A) + ctx->seedLen, pHas, NULL) == NULL) {
            return UA_STATUSCODE_BADINTERNALERROR;
        }

    /* Calculate A(n) = HMAC_SHA1(secret, A(n-1)) */
   if (HMAC (EVP_sha1(), UA_Openssl_P_SHA1_SECRET(ctx), (int) ctx->secretLen,
        ctx->A, sizeof (ctx->A), ctx->A, NULL) == NULL) {
            return UA_STATUSCODE_BADINTERNALERROR;
        }
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Openssl_Random_Key_PSHA1_Derive (const UA_ByteString *     secret,
                                   const UA_ByteString *     seed,
                                   UA_ByteString *           out) {
    size_t keyLen     = out->length;
    size_t iter       = keyLen / SHA1_DIGEST_LENGTH + ((keyLen % SHA1_DIGEST_LENGTH)?1:0);
    size_t bufferLen  = iter * SHA1_DIGEST_LENGTH;
    UA_Byte * pBuffer = (UA_Byte *) UA_malloc (bufferLen);
    if (pBuffer == NULL) {
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    UA_Openssl_P_SHA1_Ctx * ctx = P_SHA1_Ctx_Create (secret, seed);
    if (ctx == NULL) {
        UA_free (pBuffer);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    size_t i;
    UA_StatusCode st;

    for (i = 0; i < iter; i++) {
        st = P_SHA1_Hash_Generate (ctx, pBuffer + (i * SHA1_DIGEST_LENGTH));
        if (st != UA_STATUSCODE_GOOD) {
            UA_free (pBuffer);
            UA_free (ctx);
            return st;
        }
    }

    (void) memcpy (out->data, pBuffer, keyLen);
    UA_free (pBuffer);
    UA_free (ctx);

    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_OpenSSL_HMAC_SHA1_Verify (const UA_ByteString *     message,
                             const UA_ByteString *     key,
                             const UA_ByteString *     signature
                             ) {
    unsigned char buf[SHA1_DIGEST_LENGTH] = {0};
    UA_ByteString mac = {SHA1_DIGEST_LENGTH, buf};

    if(HMAC (EVP_sha1(), key->data, (int) key->length, message->data, message->length,
             mac.data, (unsigned int *) &mac.length) == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    if (UA_ByteString_equal (signature, &mac)) {
        return UA_STATUSCODE_GOOD;
    }
    else {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
}

UA_StatusCode
UA_OpenSSL_HMAC_SHA1_Sign (const UA_ByteString *     message,
                           const UA_ByteString *     key,
                           UA_ByteString *           signature
                           ) {
    if (HMAC (EVP_sha1(), key->data, (int) key->length, message->data,
              message->length,
              signature->data, (unsigned int *) &(signature->length)) == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_Openssl_RSA_PKCS1_V15_Decrypt (UA_ByteString *       data,
                                  EVP_PKEY * privateKey) {
    return  UA_Openssl_RSA_Private_Decrypt (data, privateKey,
                                            RSA_PKCS1_PADDING, false);
}

UA_StatusCode
UA_Openssl_RSA_PKCS1_V15_Encrypt (UA_ByteString * data,
                                  size_t          paddingSize,
                                  X509 *          publicX509) {
    UA_ByteString message;
    UA_StatusCode ret = UA_ByteString_copy (data, &message);
    if (ret != UA_STATUSCODE_GOOD) {
        return ret;
    }
    ret = UA_Openssl_RSA_Public_Encrypt (&message, publicX509,
                                         RSA_PKCS1_PADDING,
                                         paddingSize,
                                         data, false);
    UA_ByteString_clear (&message);
    return ret;
}

UA_StatusCode
UA_OpenSSL_AES_128_CBC_Decrypt (const UA_ByteString * iv,
                                const UA_ByteString * key,
                                UA_ByteString *       data  /* [in/out]*/
                                ) {
    return UA_OpenSSL_Decrypt (iv, key, EVP_aes_128_cbc (), data);
}

UA_StatusCode
UA_OpenSSL_AES_128_CBC_Encrypt (const UA_ByteString * iv,
                                const UA_ByteString * key,
                                UA_ByteString *       data  /* [in/out]*/
                                ) {
    return UA_OpenSSL_Encrypt (iv, key, EVP_aes_128_cbc (), data);
}

EVP_PKEY *
UA_OpenSSL_LoadPrivateKey(const UA_ByteString *privateKey) {
    const unsigned char * pkData = privateKey->data;
    long len = (long) privateKey->length;
    if(len == 0)
        return NULL;

    EVP_PKEY *result = NULL;

    if (len > 1 && pkData[0] == 0x30 && pkData[1] == 0x82) { // Magic number for DER encoded keys
        result = d2i_PrivateKey(EVP_PKEY_RSA, NULL,
                                          &pkData, len);
    } else {
        BIO *bio = NULL;
        bio = BIO_new_mem_buf((void *) privateKey->data, (int) privateKey->length);
        result = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
        BIO_free(bio);
    }

    return result;
}

X509 *
UA_OpenSSL_LoadCertificate(const UA_ByteString *certificate) {
    X509 * result = NULL;
    const unsigned char *pData = certificate->data;

    if (certificate->length > 1 && pData[0] == 0x30 && pData[1] == 0x82) { // Magic number for DER encoded files
        result = UA_OpenSSL_LoadDerCertificate(certificate);
    } else {
        result = UA_OpenSSL_LoadPemCertificate(certificate);
    }

    return result;
}

X509 *
UA_OpenSSL_LoadDerCertificate(const UA_ByteString *certificate) {
    const unsigned char *pData = certificate->data;
    return d2i_X509(NULL, &pData, (long) certificate->length);
}

X509 *
UA_OpenSSL_LoadPemCertificate(const UA_ByteString *certificate) {
    X509 * result = NULL;

    BIO* bio = NULL;
    bio = BIO_new_mem_buf((void *) certificate->data, (int) certificate->length);
    result = PEM_read_bio_X509(bio, NULL, NULL, NULL);
    BIO_free(bio);

    return result;
}

UA_StatusCode
UA_OpenSSL_LoadLocalCertificate(const UA_ByteString *certificate, UA_ByteString *target) {
    X509 *cert = UA_OpenSSL_LoadCertificate(certificate);

    if (!cert) {
        UA_ByteString_init(target);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    unsigned char *derData = NULL;
    int length = i2d_X509(cert, &derData);
    X509_free(cert);

    if (length > 0) {
        UA_ByteString temp;
        temp.length = (size_t) length;
        temp.data = derData;
        UA_ByteString_copy(&temp, target);
        OPENSSL_free(derData);
        return UA_STATUSCODE_GOOD;
    } else {
        UA_ByteString_init(target);
    }

    return UA_STATUSCODE_BADINVALIDARGUMENT;
}

#endif

/**** amalgamated original file "/plugins/crypto/openssl/ua_openssl_basic128rsa15.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2020 (c) Wind River Systems, Inc.
 *    Copyright 2020 (c) basysKom GmbH
 */


#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL)


#include <openssl/x509.h>
#include <openssl/rand.h>
#include <openssl/evp.h>

#define UA_SHA1_LENGTH                                               20
#define UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN               11
#define UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_KEY_LENGTH    16
#define UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_BLOCK_SIZE    16
#define UA_SECURITYPOLICY_BASIC128RSA15_SYM_SIGNING_KEY_LENGTH       16
#define UA_SHA1_LENGTH                                               20

typedef struct {
    EVP_PKEY *                localPrivateKey;
    UA_ByteString             localCertThumbprint;
    const UA_Logger *         logger;
} Policy_Context_Basic128Rsa15;

typedef struct {
    UA_ByteString             localSymSigningKey;
    UA_ByteString             localSymEncryptingKey;
    UA_ByteString             localSymIv;
    UA_ByteString             remoteSymSigningKey;
    UA_ByteString             remoteSymEncryptingKey;
    UA_ByteString             remoteSymIv;

    Policy_Context_Basic128Rsa15 * policyContext;
    UA_ByteString             remoteCertificate;
    X509 *                    remoteCertificateX509;
} Channel_Context_Basic128Rsa15;

static UA_StatusCode
UA_Policy_Basic128Rsa15_New_Context (UA_SecurityPolicy * securityPolicy,
                                     const UA_ByteString localPrivateKey,
                                     const UA_Logger *   logger) {
    Policy_Context_Basic128Rsa15 * context = (Policy_Context_Basic128Rsa15 *)
                                    UA_malloc (sizeof (Policy_Context_Basic128Rsa15));
    if (context == NULL) {
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    context->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&localPrivateKey);

    if (!context->localPrivateKey) {
        UA_free(context);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_StatusCode retval = UA_Openssl_X509_GetCertificateThumbprint (
                         &securityPolicy->localCertificate,
                         &context->localCertThumbprint, true
                         );
    if (retval != UA_STATUSCODE_GOOD) {
        EVP_PKEY_free(context->localPrivateKey);
        UA_free (context);
        return retval;
    }

    context->logger = logger;
    securityPolicy->policyContext = context;

    return UA_STATUSCODE_GOOD;
}

static void
UA_Policy_Basic128Rsa15_Clear_Context (UA_SecurityPolicy *policy) {
    if (policy == NULL) {
        return;
    }
    UA_ByteString_clear(&policy->localCertificate);

    Policy_Context_Basic128Rsa15 * ctx = (Policy_Context_Basic128Rsa15 *) policy->policyContext;
    if (ctx == NULL) {
        return;
    }

    /* delete all allocated members in the context */

    EVP_PKEY_free(ctx->localPrivateKey);
    UA_ByteString_clear(&ctx->localCertThumbprint);
    UA_free (ctx);

    return;
}

static UA_StatusCode
updateCertificateAndPrivateKey_sp_basic128rsa15(UA_SecurityPolicy *securityPolicy,
                                                const UA_ByteString newCertificate,
                                                const UA_ByteString newPrivateKey) {
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(securityPolicy->policyContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Policy_Context_Basic128Rsa15 *pc =
        (Policy_Context_Basic128Rsa15 *)securityPolicy->policyContext;

    UA_ByteString_clear(&securityPolicy->localCertificate);

    UA_StatusCode retval = UA_OpenSSL_LoadLocalCertificate(
        &newCertificate, &securityPolicy->localCertificate);

    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Set the new private key */
    EVP_PKEY_free(pc->localPrivateKey);

    pc->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&newPrivateKey);

    if(!pc->localPrivateKey) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    UA_ByteString_clear(&pc->localCertThumbprint);

    retval = UA_Openssl_X509_GetCertificateThumbprint(&securityPolicy->localCertificate,
                                                      &pc->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD) {
        goto error;
    }

    return retval;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext != NULL)
        UA_Policy_Basic128Rsa15_Clear_Context(securityPolicy);
    return retval;
}

/* create the channel context */

static UA_StatusCode
UA_ChannelModule_Basic128Rsa15_New_Context (const UA_SecurityPolicy * securityPolicy,
                                            const UA_ByteString *     remoteCertificate,
                                            void **                   channelContext) {
    if (securityPolicy == NULL || remoteCertificate == NULL ||
        channelContext == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
        }
    Channel_Context_Basic128Rsa15 * context = (Channel_Context_Basic128Rsa15 *)
            UA_malloc (sizeof (Channel_Context_Basic128Rsa15));
    if (context == NULL) {
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    UA_ByteString_init(&context->localSymSigningKey);
    UA_ByteString_init(&context->localSymEncryptingKey);
    UA_ByteString_init(&context->localSymIv);
    UA_ByteString_init(&context->remoteSymSigningKey);
    UA_ByteString_init(&context->remoteSymEncryptingKey);
    UA_ByteString_init(&context->remoteSymIv);

    UA_StatusCode retval = UA_copyCertificate (&context->remoteCertificate,
                                               remoteCertificate);
    if (retval != UA_STATUSCODE_GOOD) {
        UA_free (context);
        return retval;
    }

    /* decode to X509 */
    context->remoteCertificateX509 = UA_OpenSSL_LoadCertificate(&context->remoteCertificate);
    if (context->remoteCertificateX509 == NULL) {
        UA_ByteString_clear (&context->remoteCertificate);
        UA_free (context);
        return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
    }

    context->policyContext = (Policy_Context_Basic128Rsa15 *)
                             (securityPolicy->policyContext);

    *channelContext = context;

    UA_LOG_INFO (securityPolicy->logger,
                 UA_LOGCATEGORY_SECURITYPOLICY,
                 "The Basic128Rsa15 security policy channel with openssl is created.");

    return UA_STATUSCODE_GOOD;
}

/* delete the channel context */

static void
UA_ChannelModule_Basic128Rsa15_Delete_Context (void * channelContext) {
    if (channelContext != NULL) {
        Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *)
                                              channelContext;
        X509_free (cc->remoteCertificateX509);
        UA_ByteString_clear (&cc->remoteCertificate);
        UA_ByteString_clear (&cc->localSymSigningKey);
        UA_ByteString_clear (&cc->localSymEncryptingKey);
        UA_ByteString_clear (&cc->localSymIv);
        UA_ByteString_clear (&cc->remoteSymSigningKey);
        UA_ByteString_clear (&cc->remoteSymEncryptingKey);
        UA_ByteString_clear (&cc->remoteSymIv);
        UA_LOG_INFO (cc->policyContext->logger,
                 UA_LOGCATEGORY_SECURITYPOLICY,
                 "The Basic128Rsa15 security policy channel with openssl is deleted.");

        UA_free (cc);
    }
}

static UA_StatusCode
UA_ChannelModule_Basic128Rsa15_setLocalSymSigningKey (void *                channelContext,
                                                      const UA_ByteString * key) {
    if (key == NULL || channelContext == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}

static UA_StatusCode
UA_ChannelModule_Basic128Rsa15_setLocalSymEncryptingKey (void *                channelContext,
                                                         const UA_ByteString * key) {
    if (key == NULL || channelContext == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext;
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
UA_ChannelModule_Basic128Rsa15_setLocalSymIv (void *                channelContext,
                                              const UA_ByteString * iv) {
    if (iv == NULL || channelContext == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext;
    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static UA_StatusCode
UA_ChannelModule_Basic128Rsa15_setRemoteSymSigningKey (void *                channelContext,
                                                       const UA_ByteString * key) {
    if (key == NULL || channelContext == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext;
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
UA_ChannelModule_Basic128Rsa15_setRemoteSymEncryptingKey (void *                channelContext,
                                                          const UA_ByteString * key) {
    if (key == NULL || channelContext == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext;
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
UA_ChannelModule_Basic128Rsa15_setRemoteSymIv (void *                channelContext,
                                               const UA_ByteString * key) {
    if (key == NULL || channelContext == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext;
    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(key, &cc->remoteSymIv);
}

static UA_StatusCode
UA_ChannelModule_Basic128Rsa15_compareCertificate (const void *          channelContext,
                                                   const UA_ByteString * certificate) {
    if(channelContext == NULL || certificate == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    const Channel_Context_Basic128Rsa15 * cc =
                     (const Channel_Context_Basic128Rsa15 *) channelContext;
    return UA_OpenSSL_X509_compare (certificate, cc->remoteCertificateX509);
}

static UA_StatusCode
UA_Asy_Basic128Rsa15_compareCertificateThumbprint (const UA_SecurityPolicy * securityPolicy,
                                     const UA_ByteString *     certificateThumbprint) {
    if (securityPolicy == NULL || certificateThumbprint == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }
    Policy_Context_Basic128Rsa15 *pc = (Policy_Context_Basic128Rsa15 *)
                                       securityPolicy->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint)) {
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    }
    return UA_STATUSCODE_GOOD;
}

/* Generates a thumbprint for the specified certificate */

static UA_StatusCode
UA_Asy_Basic128Rsa15_makeCertificateThumbprint (const UA_SecurityPolicy * securityPolicy,
                                  const UA_ByteString *     certificate,
                                  UA_ByteString *           thumbprint) {
    return UA_Openssl_X509_GetCertificateThumbprint (certificate,
               thumbprint, false);
}

static size_t
UA_AsySig_Basic128Rsa15_getRemoteSignatureSize (const void *              channelContext) {
    if (channelContext == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    const Channel_Context_Basic128Rsa15 * cc = (const Channel_Context_Basic128Rsa15 *) channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength (cc->remoteCertificateX509, &keyLen);
    return (size_t) keyLen;
}

static size_t
UA_AsySig_Basic128Rsa15_getLocalSignatureSize (const void *              channelContext) {
    if (channelContext == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    const Channel_Context_Basic128Rsa15 * cc = (const Channel_Context_Basic128Rsa15 *) channelContext;
    Policy_Context_Basic128Rsa15 * pc = (Policy_Context_Basic128Rsa15 *) cc->policyContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Private_GetKeyLength (pc->localPrivateKey, &keyLen);

    return (size_t) keyLen;
}

static UA_StatusCode
UA_AsySig_Basic128Rsa15_Verify (void *                    channelContext,
                                const UA_ByteString *     message,
                                const UA_ByteString *     signature) {
    if (message == NULL || signature == NULL ||
        channelContext == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext;
    UA_StatusCode retval = UA_OpenSSL_RSA_PKCS1_V15_SHA1_Verify (message,
                            cc->remoteCertificateX509, signature);

    return retval;
}

static UA_StatusCode
UA_AsySig_Basic128Rsa15_Sign (void *                    channelContext,
                              const UA_ByteString *     message,
                              UA_ByteString *           signature) {
    if (channelContext == NULL || message == NULL || signature == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    const Channel_Context_Basic128Rsa15 * cc = (const Channel_Context_Basic128Rsa15 *) channelContext;
    Policy_Context_Basic128Rsa15 *pc = cc->policyContext;
    return UA_Openssl_RSA_PKCS1_V15_SHA1_Sign (message, pc->localPrivateKey, signature);
}

static size_t
UA_AsymEn_Basic128Rsa15_getRemotePlainTextBlockSize (const void *channelContext) {
    if (channelContext == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    const Channel_Context_Basic128Rsa15 * cc = (const Channel_Context_Basic128Rsa15 *) channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength (cc->remoteCertificateX509, &keyLen);
    return (size_t) keyLen - UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN;
}

static size_t
UA_AsymEn_Basic128Rsa15_getRemoteBlockSize (const void *channelContext) {
    if (channelContext == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    const Channel_Context_Basic128Rsa15 * cc = (const Channel_Context_Basic128Rsa15 *) channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength (cc->remoteCertificateX509, &keyLen);
    return (size_t) keyLen;
}

static size_t
UA_AsymEn_Basic128Rsa15_getRemoteKeyLength (const void *channelContext) {
    if (channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    const Channel_Context_Basic128Rsa15 * cc = (const Channel_Context_Basic128Rsa15 *) channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength (cc->remoteCertificateX509, &keyLen);
    return (size_t) keyLen * 8;
}

static size_t
UA_AsymEn_Basic128Rsa15_getLocalKeyLength (const void *channelContext) {
    if (channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    const Channel_Context_Basic128Rsa15 *cc = (const Channel_Context_Basic128Rsa15 *) channelContext;
    Policy_Context_Basic128Rsa15 *pc = cc->policyContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Private_GetKeyLength (pc->localPrivateKey, &keyLen);
    return (size_t) keyLen * 8;
}

static UA_StatusCode
UA_AsymEn_Basic128Rsa15_Decrypt (void *                    channelContext,
                                 UA_ByteString *           data) {
    if (channelContext == NULL || data == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext;
    UA_StatusCode ret = UA_Openssl_RSA_PKCS1_V15_Decrypt (data,
                        cc->policyContext->localPrivateKey);
    return ret;
}

static UA_StatusCode
UA_AsymEn_Basic128Rsa15_Encrypt (void *                    channelContext,
                                 UA_ByteString *           data) {
    if (channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext;
    return UA_Openssl_RSA_PKCS1_V15_Encrypt (data,
                                             UA_SECURITYPOLICY_BASIC128RSA15_RSAPADDING_LEN,
                                             cc->remoteCertificateX509);
}

static UA_StatusCode
UA_Sym_Basic128Rsa15_generateNonce(void *policyContext,
                                   UA_ByteString *out) {
    UA_Int32 rc = RAND_bytes(out->data, (int) out->length);
    if (rc != 1) {
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_Sym_Basic128Rsa15_generateKey(void *policyContext,
                                 const UA_ByteString *secret,
                                 const UA_ByteString *seed,
                                 UA_ByteString *out) {
    return UA_Openssl_Random_Key_PSHA1_Derive(secret, seed, out);
}

static size_t
UA_SymEn_Basic128Rsa15_getLocalKeyLength (const void *channelContext) {
    /* 16 bytes 128 bits */
    return UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymEn_Basic128Rsa15_getBlockSize (const void *channelContext) {
    return UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_BLOCK_SIZE;
}

static size_t
UA_SymEn_Basic128Rsa15_getRemoteKeyLength (const void * channelContext) {
    return UA_SECURITYPOLICY_BASIC128RSA15_SYM_ENCRYPTION_KEY_LENGTH;
}

static UA_StatusCode
UA_SymEn_Basic128Rsa15_Encrypt (void *channelContext,
                                UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext;
    return UA_OpenSSL_AES_128_CBC_Encrypt (&cc->localSymIv, &cc->localSymEncryptingKey, data);
}

static UA_StatusCode
UA_SymEn_Basic128Rsa15_Decrypt (void *                    channelContext,
                                UA_ByteString *           data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext;
    return UA_OpenSSL_AES_128_CBC_Decrypt (&cc->remoteSymIv, &cc->remoteSymEncryptingKey, data);
}

static size_t
UA_SymSig_Basic128Rsa15_getKeyLength (const void *channelContext) {
    return UA_SECURITYPOLICY_BASIC128RSA15_SYM_SIGNING_KEY_LENGTH;
}

static size_t
UA_SymSig_Basic128Rsa15_getSignatureSize (const void *channelContext) {
    return UA_SHA1_LENGTH;
}

static UA_StatusCode
UA_SymSig_Basic128Rsa15_Verify (void *                    channelContext,
                                const UA_ByteString *     message,
                                const UA_ByteString *     signature) {
    if (channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext;
    return UA_OpenSSL_HMAC_SHA1_Verify (message,
                                        &cc->remoteSymSigningKey,
                                        signature);
}

static UA_StatusCode
UA_SymSig_Basic128Rsa15_Sign (void *                    channelContext,
                              const UA_ByteString *     message,
                              UA_ByteString *           signature) {
    if (channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    Channel_Context_Basic128Rsa15 * cc = (Channel_Context_Basic128Rsa15 *) channelContext;
    return UA_OpenSSL_HMAC_SHA1_Sign (message, &cc->localSymSigningKey, signature);
}

/* the main entry of Basic128Rsa15 */

UA_StatusCode
UA_SecurityPolicy_Basic128Rsa15 (UA_SecurityPolicy * policy,
                                 const UA_ByteString localCertificate,
                                 const UA_ByteString localPrivateKey,
                                 const UA_Logger *   logger) {

    UA_SecurityPolicyAsymmetricModule * const asymmetricModule = &policy->asymmetricModule;
    UA_SecurityPolicySymmetricModule * const  symmetricModule = &policy->symmetricModule;
    UA_SecurityPolicyChannelModule * const    channelModule = &policy->channelModule;
    UA_StatusCode                             retval;

    UA_LOG_INFO (logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "The Basic128Rsa15 security policy with openssl is added.");

    UA_Openssl_Init ();
    memset(policy, 0, sizeof(UA_SecurityPolicy));
    policy->logger = logger;
    policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic128Rsa15\0");
    policy->securityLevel = 0;

    /* set ChannelModule context  */

    channelModule->newContext = UA_ChannelModule_Basic128Rsa15_New_Context;
    channelModule->deleteContext = UA_ChannelModule_Basic128Rsa15_Delete_Context;

    channelModule->setLocalSymSigningKey = UA_ChannelModule_Basic128Rsa15_setLocalSymSigningKey;
    channelModule->setLocalSymEncryptingKey = UA_ChannelModule_Basic128Rsa15_setLocalSymEncryptingKey;
    channelModule->setLocalSymIv = UA_ChannelModule_Basic128Rsa15_setLocalSymIv;
    channelModule->setRemoteSymSigningKey = UA_ChannelModule_Basic128Rsa15_setRemoteSymSigningKey;
    channelModule->setRemoteSymEncryptingKey = UA_ChannelModule_Basic128Rsa15_setRemoteSymEncryptingKey;
    channelModule->setRemoteSymIv = UA_ChannelModule_Basic128Rsa15_setRemoteSymIv;
    channelModule->compareCertificate = UA_ChannelModule_Basic128Rsa15_compareCertificate;

    retval = UA_OpenSSL_LoadLocalCertificate(&localCertificate, &policy->localCertificate);

    if (retval != UA_STATUSCODE_GOOD)
        return retval;

    /* asymmetricModule */

    asymmetricModule->compareCertificateThumbprint = UA_Asy_Basic128Rsa15_compareCertificateThumbprint;
    asymmetricModule->makeCertificateThumbprint = UA_Asy_Basic128Rsa15_makeCertificateThumbprint;

    /* AsymmetricModule - signature algorithm */

    UA_SecurityPolicySignatureAlgorithm * asySigAlgorithm =
                    &asymmetricModule->cryptoModule.signatureAlgorithm;
    asySigAlgorithm->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#rsa-sha1\0");
    asySigAlgorithm->getRemoteSignatureSize = UA_AsySig_Basic128Rsa15_getRemoteSignatureSize;
    asySigAlgorithm->getLocalSignatureSize = UA_AsySig_Basic128Rsa15_getLocalSignatureSize;
    asySigAlgorithm->getLocalKeyLength = NULL;
    asySigAlgorithm->getRemoteKeyLength = NULL;
    asySigAlgorithm->verify = UA_AsySig_Basic128Rsa15_Verify;
    asySigAlgorithm->sign = UA_AsySig_Basic128Rsa15_Sign;

    /*  AsymmetricModule encryption algorithm */

    UA_SecurityPolicyEncryptionAlgorithm * asymEncryAlg =
        &asymmetricModule->cryptoModule.encryptionAlgorithm;
    asymEncryAlg->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-1_5\0");
    asymEncryAlg->getRemotePlainTextBlockSize = UA_AsymEn_Basic128Rsa15_getRemotePlainTextBlockSize;
    asymEncryAlg->getRemoteBlockSize = UA_AsymEn_Basic128Rsa15_getRemoteBlockSize;
    asymEncryAlg->getRemoteKeyLength = UA_AsymEn_Basic128Rsa15_getRemoteKeyLength;
    asymEncryAlg->getLocalKeyLength = UA_AsymEn_Basic128Rsa15_getLocalKeyLength;
    asymEncryAlg->decrypt = UA_AsymEn_Basic128Rsa15_Decrypt;
    asymEncryAlg->encrypt = UA_AsymEn_Basic128Rsa15_Encrypt;

    /* SymmetricModule */

    symmetricModule->secureChannelNonceLength = 16;  /* 128 bits*/
    symmetricModule->generateNonce = UA_Sym_Basic128Rsa15_generateNonce;
    symmetricModule->generateKey = UA_Sym_Basic128Rsa15_generateKey;

    /* Symmetric encryption Algorithm */

    UA_SecurityPolicyEncryptionAlgorithm * symEncryptionAlgorithm =
        &symmetricModule->cryptoModule.encryptionAlgorithm;
    symEncryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes128-cbc\0");
    symEncryptionAlgorithm->getLocalKeyLength = UA_SymEn_Basic128Rsa15_getLocalKeyLength;
    symEncryptionAlgorithm->getRemoteKeyLength = UA_SymEn_Basic128Rsa15_getRemoteKeyLength;
    symEncryptionAlgorithm->getRemoteBlockSize = UA_SymEn_Basic128Rsa15_getBlockSize;
    symEncryptionAlgorithm->getRemotePlainTextBlockSize = UA_SymEn_Basic128Rsa15_getBlockSize;
    symEncryptionAlgorithm->decrypt = UA_SymEn_Basic128Rsa15_Decrypt;
    symEncryptionAlgorithm->encrypt = UA_SymEn_Basic128Rsa15_Encrypt;

    /* Symmetric signature Algorithm */

    UA_SecurityPolicySignatureAlgorithm * symSignatureAlgorithm =
        &symmetricModule->cryptoModule.signatureAlgorithm;
    symSignatureAlgorithm->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha1\0");
    symSignatureAlgorithm->getLocalKeyLength = UA_SymSig_Basic128Rsa15_getKeyLength;
    symSignatureAlgorithm->getRemoteKeyLength = UA_SymSig_Basic128Rsa15_getKeyLength;
    symSignatureAlgorithm->getRemoteSignatureSize = UA_SymSig_Basic128Rsa15_getSignatureSize;
    symSignatureAlgorithm->getLocalSignatureSize = UA_SymSig_Basic128Rsa15_getSignatureSize;

    symSignatureAlgorithm->verify = UA_SymSig_Basic128Rsa15_Verify;
    symSignatureAlgorithm->sign = UA_SymSig_Basic128Rsa15_Sign;

    /* set the policy context */

    retval = UA_Policy_Basic128Rsa15_New_Context (policy, localPrivateKey, logger);
    if (retval != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear (&policy->localCertificate);
        return retval;
    }
    policy->updateCertificateAndPrivateKey =
        updateCertificateAndPrivateKey_sp_basic128rsa15;
    policy->clear = UA_Policy_Basic128Rsa15_Clear_Context;

    /* Use the same signature algorithm as the asymmetric component for
       certificate signing (see standard) */
    policy->certificateSigningAlgorithm = policy->asymmetricModule.cryptoModule.signatureAlgorithm;

    return UA_STATUSCODE_GOOD;
}

#endif

/**** amalgamated original file "/plugins/crypto/openssl/ua_openssl_basic256.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2020 (c) Wind River Systems, Inc.
 *    Copyright 2020 (c) basysKom GmbH
 */


#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL)


#include <openssl/x509.h>
#include <openssl/rand.h>

#define UA_SECURITYPOLICY_BASIC256SHA1_RSAPADDING_LEN                42
#define UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_KEY_LENGTH         32
#define UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_BLOCK_SIZE         16
#define UA_SECURITYPOLICY_BASIC256_SYM_SIGNING_KEY_LENGTH            24
#define UA_SHA1_LENGTH                                               20

typedef struct {
    EVP_PKEY *                localPrivateKey;
    UA_ByteString             localCertThumbprint;
    const UA_Logger *         logger;
} Policy_Context_Basic256;

typedef struct {
    UA_ByteString             localSymSigningKey;
    UA_ByteString             localSymEncryptingKey;
    UA_ByteString             localSymIv;
    UA_ByteString             remoteSymSigningKey;
    UA_ByteString             remoteSymEncryptingKey;
    UA_ByteString             remoteSymIv;

    Policy_Context_Basic256 * policyContext;
    UA_ByteString             remoteCertificate;
    X509 *                    remoteCertificateX509;
} Channel_Context_Basic256;

static UA_StatusCode
UA_Policy_Basic256_New_Context (UA_SecurityPolicy * securityPolicy,
                                const UA_ByteString localPrivateKey,
                                const UA_Logger *   logger) {
    Policy_Context_Basic256 * context = (Policy_Context_Basic256 *)
                                    UA_malloc (sizeof (Policy_Context_Basic256));
    if (context == NULL) {
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    context->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&localPrivateKey);

    if (!context->localPrivateKey) {
        UA_free (context);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_StatusCode retval = UA_Openssl_X509_GetCertificateThumbprint (
                         &securityPolicy->localCertificate,
                         &context->localCertThumbprint, true
                         );
    if (retval != UA_STATUSCODE_GOOD) {
        EVP_PKEY_free(context->localPrivateKey);
        UA_free (context);
        return retval;
    }

    context->logger = logger;
    securityPolicy->policyContext = context;

    return UA_STATUSCODE_GOOD;
}

static void
UA_Policy_Basic256_Clear_Context (UA_SecurityPolicy *policy) {
    if (policy == NULL) {
        return;
    }
    UA_ByteString_clear(&policy->localCertificate);

    Policy_Context_Basic256 * ctx = (Policy_Context_Basic256 *) policy->policyContext;
    if (ctx == NULL) {
        return;
    }

    /* delete all allocated members in the context */

    EVP_PKEY_free(ctx->localPrivateKey);
    UA_ByteString_clear(&ctx->localCertThumbprint);
    UA_free (ctx);

    return;
}

static UA_StatusCode
updateCertificateAndPrivateKey_sp_basic256(UA_SecurityPolicy *securityPolicy,
                                           const UA_ByteString newCertificate,
                                           const UA_ByteString newPrivateKey) {
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(securityPolicy->policyContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Policy_Context_Basic256 *pc =
        (Policy_Context_Basic256 *)securityPolicy->policyContext;

    UA_ByteString_clear(&securityPolicy->localCertificate);

    UA_StatusCode retval = UA_OpenSSL_LoadLocalCertificate(
        &newCertificate, &securityPolicy->localCertificate);

    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Set the new private key */
    EVP_PKEY_free(pc->localPrivateKey);

    pc->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&newPrivateKey);

    if(!pc->localPrivateKey) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    UA_ByteString_clear(&pc->localCertThumbprint);

    retval = UA_Openssl_X509_GetCertificateThumbprint(&securityPolicy->localCertificate,
                                                      &pc->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD) {
        goto error;
    }

    return retval;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext != NULL)
        UA_Policy_Basic256_Clear_Context(securityPolicy);
    return retval;
}

/* create the channel context */

static UA_StatusCode
UA_ChannelModule_Basic256_New_Context (const UA_SecurityPolicy * securityPolicy,
                                       const UA_ByteString *     remoteCertificate,
                                       void **                   channelContext) {
    if (securityPolicy == NULL || remoteCertificate == NULL ||
        channelContext == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
        }
    Channel_Context_Basic256 * context = (Channel_Context_Basic256 *)
            UA_malloc (sizeof (Channel_Context_Basic256));
    if (context == NULL) {
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    UA_ByteString_init(&context->localSymSigningKey);
    UA_ByteString_init(&context->localSymEncryptingKey);
    UA_ByteString_init(&context->localSymIv);
    UA_ByteString_init(&context->remoteSymSigningKey);
    UA_ByteString_init(&context->remoteSymEncryptingKey);
    UA_ByteString_init(&context->remoteSymIv);

    UA_StatusCode retval = UA_copyCertificate (&context->remoteCertificate,
                                               remoteCertificate);
    if (retval != UA_STATUSCODE_GOOD) {
        UA_free (context);
        return retval;
    }

    /* decode to X509 */
    context->remoteCertificateX509 = UA_OpenSSL_LoadCertificate(&context->remoteCertificate);
    if (context->remoteCertificateX509 == NULL) {
        UA_ByteString_clear (&context->remoteCertificate);
        UA_free (context);
        return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
    }

    context->policyContext = (Policy_Context_Basic256 *)
                             (securityPolicy->policyContext);

    *channelContext = context;

    UA_LOG_INFO (securityPolicy->logger,
                 UA_LOGCATEGORY_SECURITYPOLICY,
                 "The basic256 security policy channel with openssl is created.");

    return UA_STATUSCODE_GOOD;
}

/* delete the channel context */

static void
UA_ChannelModule_Basic256_Delete_Context (void * channelContext) {
    if (channelContext != NULL) {
        Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *)
                                           channelContext;
        X509_free (cc->remoteCertificateX509);
        UA_ByteString_clear (&cc->remoteCertificate);
        UA_ByteString_clear (&cc->localSymSigningKey);
        UA_ByteString_clear (&cc->localSymEncryptingKey);
        UA_ByteString_clear (&cc->localSymIv);
        UA_ByteString_clear (&cc->remoteSymSigningKey);
        UA_ByteString_clear (&cc->remoteSymEncryptingKey);
        UA_ByteString_clear (&cc->remoteSymIv);
        UA_LOG_INFO (cc->policyContext->logger,
                 UA_LOGCATEGORY_SECURITYPOLICY,
                 "The basic256 security policy channel with openssl is deleted.");

        UA_free (cc);
    }
}

/* Compares the supplied certificate with the certificate
 * in the endpoint context
 */

static UA_StatusCode
UA_Asy_Basic256_compareCertificateThumbprint (const UA_SecurityPolicy * securityPolicy,
                                     const UA_ByteString *     certificateThumbprint) {
    if (securityPolicy == NULL || certificateThumbprint == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }
    Policy_Context_Basic256 *pc = (Policy_Context_Basic256 *)
                                  securityPolicy->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint)) {
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    }
    return UA_STATUSCODE_GOOD;
}

/* Generates a thumbprint for the specified certificate */

static UA_StatusCode
UA_Asy_Basic256_makeCertificateThumbprint (const UA_SecurityPolicy * securityPolicy,
                                  const UA_ByteString *     certificate,
                                  UA_ByteString *           thumbprint) {
    return UA_Openssl_X509_GetCertificateThumbprint (certificate,
               thumbprint, false);
}

static UA_StatusCode
UA_ChannelModule_Basic256_setLocalSymSigningKey (void *                channelContext,
                                                 const UA_ByteString * key) {
    if (key == NULL || channelContext == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}

static UA_StatusCode
UA_ChannelModule_Basic256_setLocalSymEncryptingKey (void *                channelContext,
                                                    const UA_ByteString * key) {
    if (key == NULL || channelContext == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext;
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
UA_ChannelModule_Basic256_setLocalSymIv (void *                channelContext,
                                         const UA_ByteString * iv) {
    if (iv == NULL || channelContext == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext;
    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static UA_StatusCode
UA_ChannelModule_Basic256_setRemoteSymSigningKey (void *                channelContext,
                                                  const UA_ByteString * key) {
    if (key == NULL || channelContext == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext;
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
UA_ChannelModule_Basic256_setRemoteSymEncryptingKey (void *                channelContext,
                                                     const UA_ByteString * key) {
    if (key == NULL || channelContext == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext;
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
UA_ChannelModule_Basic256_setRemoteSymIv (void *                channelContext,
                                          const UA_ByteString * key) {
    if (key == NULL || channelContext == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext;
    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(key, &cc->remoteSymIv);
}

static UA_StatusCode
UA_ChannelModule_Basic256_compareCertificate (const void *          channelContext,
                                              const UA_ByteString * certificate) {
    if(channelContext == NULL || certificate == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    const Channel_Context_Basic256 * cc =
                     (const Channel_Context_Basic256 *) channelContext;
    return UA_OpenSSL_X509_compare (certificate, cc->remoteCertificateX509);
}

static size_t
UA_AsySig_Basic256_getRemoteSignatureSize (const void *channelContext) {
    if (channelContext == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    const Channel_Context_Basic256 * cc = (const Channel_Context_Basic256 *) channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength (cc->remoteCertificateX509, &keyLen);
    return (size_t) keyLen;
}

static size_t
UA_AsySig_Basic256_getLocalSignatureSize (const void *channelContext) {
    if (channelContext == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    const Channel_Context_Basic256 * cc = (const Channel_Context_Basic256 *) channelContext;
    Policy_Context_Basic256 * pc = cc->policyContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Private_GetKeyLength (pc->localPrivateKey, &keyLen);

    return (size_t) keyLen;
}

static UA_StatusCode
UA_AsySig_Basic256_Verify (void *                    channelContext,
                           const UA_ByteString *     message,
                           const UA_ByteString *     signature) {
    if (message == NULL || signature == NULL || channelContext == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
        }

    Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext;
    UA_StatusCode retval = UA_OpenSSL_RSA_PKCS1_V15_SHA1_Verify (message,
                            cc->remoteCertificateX509, signature);
    return retval;
}

static UA_StatusCode
UA_AsySig_Basic256_Sign (void *                    channelContext,
                         const UA_ByteString *     message,
                         UA_ByteString *           signature) {
    if (channelContext == NULL || message == NULL || signature == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext;
    Policy_Context_Basic256 * pc = cc->policyContext;
    return UA_Openssl_RSA_PKCS1_V15_SHA1_Sign (message, pc->localPrivateKey,
                                               signature);
}

static size_t
UA_AsymEn_Basic256_getRemotePlainTextBlockSize (const void *channelContext) {
    if (channelContext == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    const Channel_Context_Basic256 * cc = (const Channel_Context_Basic256 *) channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength (cc->remoteCertificateX509, &keyLen);
    return (size_t) keyLen - UA_SECURITYPOLICY_BASIC256SHA1_RSAPADDING_LEN;
}

static size_t
UA_AsymEn_Basic256_getRemoteBlockSize (const void *channelContext) {
    if (channelContext == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    const Channel_Context_Basic256 * cc = (const Channel_Context_Basic256 *) channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength (cc->remoteCertificateX509, &keyLen);
    return (size_t) keyLen;
}

static size_t
UA_AsymEn_Basic256_getRemoteKeyLength (const void *channelContext) {
    if (channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    const Channel_Context_Basic256 * cc = (const Channel_Context_Basic256 *) channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength (cc->remoteCertificateX509, &keyLen);
    return (size_t) keyLen * 8;
}

static size_t
UA_AsymEn_Basic256_getLocalKeyLength (const void *channelContext) {
    if (channelContext == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    const Channel_Context_Basic256 *cc = (const Channel_Context_Basic256 *) channelContext;
    Policy_Context_Basic256 *pc = cc->policyContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Private_GetKeyLength (pc->localPrivateKey, &keyLen);

    return (size_t) keyLen * 8;
}

static UA_StatusCode
UA_AsymEn_Basic256_Decrypt (void *                    channelContext,
                            UA_ByteString *           data) {
    if (channelContext == NULL || data == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext;
    UA_StatusCode ret = UA_Openssl_RSA_Oaep_Decrypt (data,
                        cc->policyContext->localPrivateKey);
    return ret;
}

static UA_StatusCode
UA_AsymEn_Basic256_Encrypt (void *                    channelContext,
                            UA_ByteString *           data) {
    if (channelContext == NULL || data == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext;
    return UA_Openssl_RSA_OAEP_Encrypt (data, UA_SECURITYPOLICY_BASIC256SHA1_RSAPADDING_LEN,
                                        cc->remoteCertificateX509);
}

static UA_StatusCode
UA_Sym_Basic256_generateNonce(void *policyContext,
                              UA_ByteString *out) {
    UA_Int32 rc = RAND_bytes(out->data, (int) out->length);
    if (rc != 1) {
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    }
    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_Sym_Basic256_generateKey(void *policyContext, const UA_ByteString *secret,
                            const UA_ByteString *seed, UA_ByteString *out) {
    return UA_Openssl_Random_Key_PSHA1_Derive(secret, seed, out);
}

static size_t
UA_SymEn_Basic256_getLocalKeyLength (const void *              channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymEn_Basic256_getBlockSize (const void *              channelContext) {
    return UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_BLOCK_SIZE;
}

static size_t
UA_SymEn_Basic256_getRemoteKeyLength (const void * channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_BASIC256_SYM_ENCRYPTION_KEY_LENGTH;
}

static UA_StatusCode
UA_SymEn_Basic256_Encrypt (void *                    channelContext,
                           UA_ByteString *           data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext;
    return UA_OpenSSL_AES_256_CBC_Encrypt (&cc->localSymIv, &cc->localSymEncryptingKey, data);
}

static UA_StatusCode
UA_SymEn_Basic256_Decrypt (void *                    channelContext,
                           UA_ByteString *           data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext;
    return UA_OpenSSL_AES_256_CBC_Decrypt (&cc->remoteSymIv, &cc->remoteSymEncryptingKey, data);
}

static size_t
UA_SymSig_Basic256_getKeyLength (const void *              channelContext) {
    return UA_SECURITYPOLICY_BASIC256_SYM_SIGNING_KEY_LENGTH;
}

static size_t
UA_SymSig_Basic256_getSignatureSize (const void *              channelContext) {
    return UA_SHA1_LENGTH;
}

static UA_StatusCode
UA_SymSig_Basic256_Verify (void *                    channelContext,
                           const UA_ByteString *     message,
                           const UA_ByteString *     signature) {
    if (channelContext == NULL ||
       message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext;
    return UA_OpenSSL_HMAC_SHA1_Verify (message,
                                        &cc->remoteSymSigningKey,
                                        signature);
}

static UA_StatusCode
UA_SymSig_Basic256_Sign (void *                    channelContext,
                         const UA_ByteString *     message,
                         UA_ByteString *           signature) {
    if (channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    Channel_Context_Basic256 * cc = (Channel_Context_Basic256 *) channelContext;
    return UA_OpenSSL_HMAC_SHA1_Sign (message, &cc->localSymSigningKey, signature);
}

/* the main entry of Basic256 */

UA_StatusCode
UA_SecurityPolicy_Basic256 (UA_SecurityPolicy * policy,
                            const UA_ByteString localCertificate,
                            const UA_ByteString localPrivateKey,
                            const UA_Logger *   logger) {
    UA_SecurityPolicyAsymmetricModule * const asymmetricModule = &policy->asymmetricModule;
    UA_SecurityPolicySymmetricModule * const  symmetricModule = &policy->symmetricModule;
    UA_SecurityPolicyChannelModule * const    channelModule = &policy->channelModule;
    UA_StatusCode                             retval;

    UA_LOG_INFO (logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "The basic256 security policy with openssl is added.");

    UA_Openssl_Init ();
    memset(policy, 0, sizeof(UA_SecurityPolicy));
    policy->logger = logger;
    policy->policyUri = UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic256\0");
    policy->securityLevel = 0;

    /* set ChannelModule context  */

    channelModule->newContext = UA_ChannelModule_Basic256_New_Context;
    channelModule->deleteContext = UA_ChannelModule_Basic256_Delete_Context;

    channelModule->setLocalSymSigningKey = UA_ChannelModule_Basic256_setLocalSymSigningKey;
    channelModule->setLocalSymEncryptingKey = UA_ChannelModule_Basic256_setLocalSymEncryptingKey;
    channelModule->setLocalSymIv = UA_ChannelModule_Basic256_setLocalSymIv;
    channelModule->setRemoteSymSigningKey = UA_ChannelModule_Basic256_setRemoteSymSigningKey;
    channelModule->setRemoteSymEncryptingKey = UA_ChannelModule_Basic256_setRemoteSymEncryptingKey;
    channelModule->setRemoteSymIv = UA_ChannelModule_Basic256_setRemoteSymIv;
    channelModule->compareCertificate = UA_ChannelModule_Basic256_compareCertificate;

    retval = UA_OpenSSL_LoadLocalCertificate(&localCertificate, &policy->localCertificate);

    if (retval != UA_STATUSCODE_GOOD)
        return retval;

    /* asymmetricModule */

    asymmetricModule->compareCertificateThumbprint = UA_Asy_Basic256_compareCertificateThumbprint;
    asymmetricModule->makeCertificateThumbprint = UA_Asy_Basic256_makeCertificateThumbprint;

    /* AsymmetricModule - signature algorithm */

    UA_SecurityPolicySignatureAlgorithm * asySigAlgorithm =
        &asymmetricModule->cryptoModule.signatureAlgorithm;
    asySigAlgorithm->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#rsa-sha1\0");
    asySigAlgorithm->getRemoteSignatureSize = UA_AsySig_Basic256_getRemoteSignatureSize;
    asySigAlgorithm->getLocalSignatureSize = UA_AsySig_Basic256_getLocalSignatureSize;
    asySigAlgorithm->verify = UA_AsySig_Basic256_Verify;
    asySigAlgorithm->sign = UA_AsySig_Basic256_Sign;
    asySigAlgorithm->getLocalKeyLength = NULL;
    asySigAlgorithm->getRemoteKeyLength = NULL;

    /*  AsymmetricModule encryption algorithm */

    UA_SecurityPolicyEncryptionAlgorithm * asymEncryAlg =
        &asymmetricModule->cryptoModule.encryptionAlgorithm;
    asymEncryAlg->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-oaep\0");
    asymEncryAlg->getRemotePlainTextBlockSize = UA_AsymEn_Basic256_getRemotePlainTextBlockSize;
    asymEncryAlg->getRemoteBlockSize = UA_AsymEn_Basic256_getRemoteBlockSize;
    asymEncryAlg->getRemoteKeyLength = UA_AsymEn_Basic256_getRemoteKeyLength;
    asymEncryAlg->getLocalKeyLength = UA_AsymEn_Basic256_getLocalKeyLength;
    asymEncryAlg->decrypt = UA_AsymEn_Basic256_Decrypt;
    asymEncryAlg->encrypt = UA_AsymEn_Basic256_Encrypt;

    /* SymmetricModule */

    symmetricModule->secureChannelNonceLength = 32;
    symmetricModule->generateNonce = UA_Sym_Basic256_generateNonce;
    symmetricModule->generateKey = UA_Sym_Basic256_generateKey;

    /* Symmetric encryption Algorithm */

    UA_SecurityPolicyEncryptionAlgorithm * symEncryptionAlgorithm =
        &symmetricModule->cryptoModule.encryptionAlgorithm;
    symEncryptionAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#aes256-cbc\0");
    symEncryptionAlgorithm->getLocalKeyLength = UA_SymEn_Basic256_getLocalKeyLength;
    symEncryptionAlgorithm->getRemoteKeyLength = UA_SymEn_Basic256_getRemoteKeyLength;
    symEncryptionAlgorithm->getRemoteBlockSize = UA_SymEn_Basic256_getBlockSize;
    symEncryptionAlgorithm->getRemotePlainTextBlockSize = UA_SymEn_Basic256_getBlockSize;
    symEncryptionAlgorithm->decrypt = UA_SymEn_Basic256_Decrypt;
    symEncryptionAlgorithm->encrypt = UA_SymEn_Basic256_Encrypt;

    /* Symmetric signature Algorithm */

    UA_SecurityPolicySignatureAlgorithm * symSignatureAlgorithm =
        &symmetricModule->cryptoModule.signatureAlgorithm;
    symSignatureAlgorithm->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha1\0");
    symSignatureAlgorithm->getLocalKeyLength = UA_SymSig_Basic256_getKeyLength;
    symSignatureAlgorithm->getRemoteKeyLength = UA_SymSig_Basic256_getKeyLength;
    symSignatureAlgorithm->getRemoteSignatureSize = UA_SymSig_Basic256_getSignatureSize;
    symSignatureAlgorithm->getLocalSignatureSize = UA_SymSig_Basic256_getSignatureSize;
    symSignatureAlgorithm->verify = UA_SymSig_Basic256_Verify;
    symSignatureAlgorithm->sign = UA_SymSig_Basic256_Sign;

    /* set the policy context */

    retval = UA_Policy_Basic256_New_Context (policy, localPrivateKey, logger);
    if (retval != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear (&policy->localCertificate);
        return retval;
    }
    policy->updateCertificateAndPrivateKey = updateCertificateAndPrivateKey_sp_basic256;
    policy->clear = UA_Policy_Basic256_Clear_Context;

    /* Use the same signature algorithm as the asymmetric component for
       certificate signing (see standard) */
    policy->certificateSigningAlgorithm = policy->asymmetricModule.cryptoModule.signatureAlgorithm;

    return UA_STATUSCODE_GOOD;
}

#endif

/**** amalgamated original file "/plugins/crypto/openssl/ua_openssl_basic256sha256.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2020 (c) Wind River Systems, Inc.
 *    Copyright 2020 (c) basysKom GmbH
 */


#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL)


#include <openssl/hmac.h>
#include <openssl/sha.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>

#define UA_SHA256_LENGTH 32    /* 256 bit */
#define UA_SECURITYPOLICY_BASIC256SHA256_RSAPADDING_LEN 42
#define UA_SECURITYPOLICY_BASIC256SHA256_SYM_SIGNING_KEY_LENGTH 32
#define UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_KEY_LENGTH 32
#define UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_BASIC256SHA256_SYM_PLAIN_TEXT_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_BASIC256SHA256_MINASYMKEYLENGTH 256
#define UA_SECURITYPOLICY_BASIC256SHA256_MAXASYMKEYLENGTH 512

typedef struct {
    EVP_PKEY *localPrivateKey;
    UA_ByteString localCertThumbprint;
    const UA_Logger *logger;
} Policy_Context_Basic256Sha256;

typedef struct {
    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;
    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    Policy_Context_Basic256Sha256 *policyContext;
    UA_ByteString remoteCertificate;
    X509 *remoteCertificateX509; /* X509 */
} Channel_Context_Basic256Sha256;

/* create the policy context */

static UA_StatusCode
UA_Policy_New_Context(UA_SecurityPolicy * securityPolicy,
                       const UA_ByteString localPrivateKey,
                       const UA_Logger *logger) {
    Policy_Context_Basic256Sha256 *context = (Policy_Context_Basic256Sha256 *)
        UA_malloc(sizeof(Policy_Context_Basic256Sha256));
    if(context == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;
    context->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&localPrivateKey);

    if(!context->localPrivateKey) {
        UA_free(context);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_StatusCode retval =
        UA_Openssl_X509_GetCertificateThumbprint(&securityPolicy->localCertificate,
                                                 &context->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD) {
        EVP_PKEY_free(context->localPrivateKey);
        UA_free(context);
        return retval;
    }

    context->logger = logger;
    securityPolicy->policyContext = context;
    return UA_STATUSCODE_GOOD;
}

/* Clear the policy context */
static void
UA_Policy_Clear_Context(UA_SecurityPolicy *policy) {
    if(policy == NULL)
        return;

    UA_ByteString_clear(&policy->localCertificate);

    /* Delete all allocated members in the context */
    Policy_Context_Basic256Sha256 *pc =
        (Policy_Context_Basic256Sha256 *) policy->policyContext;
    EVP_PKEY_free(pc->localPrivateKey);
    UA_ByteString_clear(&pc->localCertThumbprint);
    UA_free(pc);
    return;
}

static UA_StatusCode
updateCertificateAndPrivateKey_sp_basic256sha256(UA_SecurityPolicy *securityPolicy,
                                           const UA_ByteString newCertificate,
                                           const UA_ByteString newPrivateKey) {
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(securityPolicy->policyContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Policy_Context_Basic256Sha256 *pc =
        (Policy_Context_Basic256Sha256 *)securityPolicy->policyContext;

    UA_ByteString_clear(&securityPolicy->localCertificate);

    UA_StatusCode retval = UA_OpenSSL_LoadLocalCertificate(
        &newCertificate, &securityPolicy->localCertificate);

    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Set the new private key */
    EVP_PKEY_free(pc->localPrivateKey);

    pc->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&newPrivateKey);

    if(!pc->localPrivateKey) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    UA_ByteString_clear(&pc->localCertThumbprint);

    retval = UA_Openssl_X509_GetCertificateThumbprint(&securityPolicy->localCertificate,
                                                      &pc->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD) {
        goto error;
    }

    return retval;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext != NULL)
        UA_Policy_Clear_Context(securityPolicy);
    return retval;
}

/* create the channel context */

static UA_StatusCode
UA_ChannelModule_New_Context(const UA_SecurityPolicy * securityPolicy,
                             const UA_ByteString * remoteCertificate,
                             void ** channelContext) {
    if(securityPolicy == NULL || remoteCertificate == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_Basic256Sha256 *context = (Channel_Context_Basic256Sha256 *)
        UA_malloc(sizeof(Channel_Context_Basic256Sha256));
    if(context == NULL)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    UA_ByteString_init(&context->localSymSigningKey);
    UA_ByteString_init(&context->localSymEncryptingKey);
    UA_ByteString_init(&context->localSymIv);
    UA_ByteString_init(&context->remoteSymSigningKey);
    UA_ByteString_init(&context->remoteSymEncryptingKey);
    UA_ByteString_init(&context->remoteSymIv);

    UA_StatusCode retval =
        UA_copyCertificate(&context->remoteCertificate, remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free(context);
        return retval;
    }

    /* decode to X509 */
    context->remoteCertificateX509 = UA_OpenSSL_LoadCertificate(&context->remoteCertificate);
    if(context->remoteCertificateX509 == NULL) {
        UA_ByteString_clear(&context->remoteCertificate);
        UA_free(context);
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    context->policyContext =
        (Policy_Context_Basic256Sha256 *)securityPolicy->policyContext;
    *channelContext = context;

    UA_LOG_INFO(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                "The basic256sha256 security policy channel with openssl is created.");

    return UA_STATUSCODE_GOOD;
}

/* delete the channel context */

static void
UA_ChannelModule_Delete_Context(void * channelContext) {
    if(!channelContext)
        return;

    Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *)channelContext;
    X509_free(cc->remoteCertificateX509);
    UA_ByteString_clear(&cc->remoteCertificate);
    UA_ByteString_clear(&cc->localSymSigningKey);
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    UA_ByteString_clear(&cc->localSymIv);
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    UA_ByteString_clear(&cc->remoteSymIv);

    UA_LOG_INFO(cc->policyContext->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                "The basic256sha256 security policy channel with openssl is deleted.");
    UA_free(cc);
}

/* Verifies the signature of the message using the provided keys in the context.
 * AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256 */
static UA_StatusCode
UA_AsySig_Basic256Sha256_Verify(void *channelContext,
                                const UA_ByteString *message,
                                const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_Basic256Sha256 * cc =
        (Channel_Context_Basic256Sha256 *) channelContext;
    return UA_OpenSSL_RSA_PKCS1_V15_SHA256_Verify(message, cc->remoteCertificateX509,
                                                  signature);
}

/* Compares the supplied certificate with the certificate
 * in the endpoint context
 */

static UA_StatusCode
UA_compareCertificateThumbprint(const UA_SecurityPolicy * securityPolicy,
                                const UA_ByteString * certificateThumbprint) {
    if(securityPolicy == NULL || certificateThumbprint == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    Policy_Context_Basic256Sha256 *pc = (Policy_Context_Basic256Sha256 *)
                                        securityPolicy->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    return UA_STATUSCODE_GOOD;
}

/* Generates a thumbprint for the specified certificate */

static UA_StatusCode
UA_makeCertificateThumbprint(const UA_SecurityPolicy * securityPolicy,
                             const UA_ByteString * certificate,
                             UA_ByteString * thumbprint) {
    return UA_Openssl_X509_GetCertificateThumbprint(certificate, thumbprint, false);
}

static UA_StatusCode
UA_Asym_Basic256Sha256_Decrypt(void * channelContext, UA_ByteString * data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    Channel_Context_Basic256Sha256 * cc =
        (Channel_Context_Basic256Sha256 *) channelContext;
    return UA_Openssl_RSA_Oaep_Decrypt(data, cc->policyContext->localPrivateKey);
}

static size_t
UA_Asym_Basic256Sha256_getRemoteSignatureSize(const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    const Channel_Context_Basic256Sha256 * cc =
        (const Channel_Context_Basic256Sha256 *) channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    return (size_t) keyLen;
}

static size_t
UA_AsySig_Basic256Sha256_getLocalSignatureSize(const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    const Channel_Context_Basic256Sha256 *cc =
        (const Channel_Context_Basic256Sha256 *) channelContext;
    Policy_Context_Basic256Sha256 * pc = cc->policyContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Private_GetKeyLength(pc->localPrivateKey, &keyLen);
    return (size_t) keyLen;
}

static size_t
UA_AsymEn_Basic256Sha256_getRemotePlainTextBlockSize(const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    const Channel_Context_Basic256Sha256 *cc =
        (const Channel_Context_Basic256Sha256 *) channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    return (size_t) keyLen - UA_SECURITYPOLICY_BASIC256SHA256_RSAPADDING_LEN;
}

static size_t
UA_AsymEn_Basic256Sha256_getRemoteBlockSize(const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    const Channel_Context_Basic256Sha256 * cc =
        (const Channel_Context_Basic256Sha256 *) channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    return (size_t) keyLen;
}

static size_t
UA_AsymEn_Basic256Sha256_getRemoteKeyLength(const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    const Channel_Context_Basic256Sha256 *cc =
        (const Channel_Context_Basic256Sha256 *) channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    return (size_t) keyLen * 8;
}

static UA_StatusCode
UA_Sym_Basic256Sha256_generateNonce(void *policyContext,
                                    UA_ByteString *out) {
    UA_Int32 rc = RAND_bytes(out->data, (int) out->length);
    if(rc != 1)
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    return UA_STATUSCODE_GOOD;
}

static size_t
UA_SymEn_Basic256Sha256_getLocalKeyLength(const void *channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymSig_Basic256Sha256_getLocalKeyLength(const void *channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_BASIC256SHA256_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
UA_Sym_Basic256Sha256_generateKey(void *policyContext,
                                  const UA_ByteString *secret,
                                  const UA_ByteString *seed,
                                  UA_ByteString *out) {
    return UA_Openssl_Random_Key_PSHA256_Derive(secret, seed, out);
}

static UA_StatusCode
UA_ChannelModule_Basic256Sha256_setLocalSymSigningKey(void * channelContext,
                                                      const UA_ByteString * key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}

static UA_StatusCode
UA_ChannelM_Basic256Sha256_setLocalSymEncryptingKey(void * channelContext,
                                                    const UA_ByteString * key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext;
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
UA_ChannelM_Basic256Sha256_setLocalSymIv(void * channelContext,
                                         const UA_ByteString * iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext;
    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static size_t
UA_SymEn_Basic256Sha256_getRemoteKeyLength(const void * channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymEn_Basic256Sha256_getBlockSize(const void *channelContext) {
    return UA_SECURITYPOLICY_BASIC256SHA256_SYM_ENCRYPTION_BLOCK_SIZE;
}

static size_t
UA_SymSig_Basic256Sha256_getRemoteKeyLength(const void * channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_BASIC256SHA256_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
UA_ChannelM_Basic256Sha256_setRemoteSymSigningKey(void *channelContext,
                                                  const UA_ByteString * key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext;
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
UA_ChannelM_Basic256Sha256_setRemoteSymEncryptingKey(void *channelContext,
                                                     const UA_ByteString * key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext;
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
UA_ChannelM_Basic256Sha256_setRemoteSymIv(void *channelContext,
                                          const UA_ByteString * key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext;
    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(key, &cc->remoteSymIv);
}

static UA_StatusCode
UA_AsySig_Basic256Sha256_sign(void *channelContext, const UA_ByteString * message,
                              UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Basic256Sha256 *cc = (Channel_Context_Basic256Sha256 *) channelContext;
    Policy_Context_Basic256Sha256 *pc = cc->policyContext;
    return UA_Openssl_RSA_PKCS1_V15_SHA256_Sign(message, pc->localPrivateKey, signature);
}

static UA_StatusCode
UA_AsymEn_Basic256Sha256_encrypt(void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Basic256Sha256 * cc =
        (Channel_Context_Basic256Sha256 *) channelContext;
    return UA_Openssl_RSA_OAEP_Encrypt(data, UA_SECURITYPOLICY_BASIC256SHA256_RSAPADDING_LEN,
                                       cc->remoteCertificateX509);
}

static size_t
UA_SymSig_Basic256Sha256_getRemoteSignatureSize(const void *channelContext) {
    return UA_SHA256_LENGTH;
}

static UA_StatusCode
UA_SymSig_Basic256Sha256_verify(void *channelContext, const UA_ByteString *message,
                                const UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext;
    return UA_OpenSSL_HMAC_SHA256_Verify(message, &cc->remoteSymSigningKey, signature);
}

static UA_StatusCode
UA_SymSig_Basic256Sha256_sign(void *channelContext, const UA_ByteString *message,
                              UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL || signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext;
    return UA_OpenSSL_HMAC_SHA256_Sign(message, &cc->localSymSigningKey, signature);
}

static size_t
UA_SymSig_Basic256Sha256_getLocalSignatureSize(const void * channelContext) {
    return UA_SHA256_LENGTH;
}

static UA_StatusCode
UA_SymEn_Basic256Sha256_decrypt(void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext;
    return UA_OpenSSL_AES_256_CBC_Decrypt(&cc->remoteSymIv,
                                          &cc->remoteSymEncryptingKey, data);
}

static UA_StatusCode
UA_SymEn_Basic256Sha256_encrypt(void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_Basic256Sha256 * cc = (Channel_Context_Basic256Sha256 *) channelContext;
    return UA_OpenSSL_AES_256_CBC_Encrypt(&cc->localSymIv, &cc->localSymEncryptingKey, data);
}

static UA_StatusCode
UA_ChannelM_Basic256Sha256_compareCertificate(const void *channelContext,
                                              const UA_ByteString *certificate) {
    if(channelContext == NULL || certificate == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    const Channel_Context_Basic256Sha256 * cc =
        (const Channel_Context_Basic256Sha256 *) channelContext;
    return UA_OpenSSL_X509_compare(certificate, cc->remoteCertificateX509);
}

static size_t
UA_AsymEn_Basic256Sha256_getLocalKeyLength(const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    const Channel_Context_Basic256Sha256 * cc =
        (const Channel_Context_Basic256Sha256 *) channelContext;
    Policy_Context_Basic256Sha256 *pc = cc->policyContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Private_GetKeyLength(pc->localPrivateKey, &keyLen);
    return (size_t) keyLen * 8;
}

/* the main entry of Basic256Sha256 */

UA_StatusCode
UA_SecurityPolicy_Basic256Sha256(UA_SecurityPolicy *policy,
                                 const UA_ByteString localCertificate,
                                 const UA_ByteString localPrivateKey,
                                 const UA_Logger *logger) {
    UA_SecurityPolicyAsymmetricModule *asymmetricModule = &policy->asymmetricModule;
    UA_SecurityPolicySymmetricModule *symmetricModule = &policy->symmetricModule;
    UA_SecurityPolicyChannelModule *channelModule = &policy->channelModule;
    UA_LOG_INFO(logger, UA_LOGCATEGORY_SECURITYPOLICY,
                "The basic256sha256 security policy with openssl is added.");

    UA_Openssl_Init();
    memset(policy, 0, sizeof(UA_SecurityPolicy));
    policy->logger = logger;
    policy->policyUri =
        UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256\0");
    policy->securityLevel = 10;

    /* Set ChannelModule context  */
    channelModule->newContext = UA_ChannelModule_New_Context;
    channelModule->deleteContext = UA_ChannelModule_Delete_Context;
    channelModule->setLocalSymSigningKey =
        UA_ChannelModule_Basic256Sha256_setLocalSymSigningKey;
    channelModule->setLocalSymEncryptingKey =
        UA_ChannelM_Basic256Sha256_setLocalSymEncryptingKey;
    channelModule->setLocalSymIv = UA_ChannelM_Basic256Sha256_setLocalSymIv;
    channelModule->setRemoteSymSigningKey =
        UA_ChannelM_Basic256Sha256_setRemoteSymSigningKey;
    channelModule->setRemoteSymEncryptingKey =
        UA_ChannelM_Basic256Sha256_setRemoteSymEncryptingKey;
    channelModule->setRemoteSymIv = UA_ChannelM_Basic256Sha256_setRemoteSymIv;
    channelModule->compareCertificate = UA_ChannelM_Basic256Sha256_compareCertificate;
    UA_StatusCode retval =
        UA_OpenSSL_LoadLocalCertificate(&localCertificate, &policy->localCertificate);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* AsymmetricModule - signature algorithm */
    UA_SecurityPolicySignatureAlgorithm *asySigAlgorithm =
        &asymmetricModule->cryptoModule.signatureAlgorithm;
    asySigAlgorithm->uri = UA_STRING("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256\0");
    asySigAlgorithm->verify = UA_AsySig_Basic256Sha256_Verify;
    asySigAlgorithm->sign = UA_AsySig_Basic256Sha256_sign;
    asySigAlgorithm->getLocalSignatureSize = UA_AsySig_Basic256Sha256_getLocalSignatureSize;
    asySigAlgorithm->getRemoteSignatureSize = UA_Asym_Basic256Sha256_getRemoteSignatureSize;
    asySigAlgorithm->getLocalKeyLength = NULL;
    asySigAlgorithm->getRemoteKeyLength = NULL;

    /* AsymmetricModule encryption algorithm */
    UA_SecurityPolicyEncryptionAlgorithm *asymEncryAlg =
        &asymmetricModule->cryptoModule.encryptionAlgorithm;
    asymEncryAlg->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-oaep\0");
    asymEncryAlg->encrypt = UA_AsymEn_Basic256Sha256_encrypt;
    asymEncryAlg->decrypt = UA_Asym_Basic256Sha256_Decrypt;
    asymEncryAlg->getLocalKeyLength = UA_AsymEn_Basic256Sha256_getLocalKeyLength;
    asymEncryAlg->getRemoteKeyLength = UA_AsymEn_Basic256Sha256_getRemoteKeyLength;
    asymEncryAlg->getRemoteBlockSize = UA_AsymEn_Basic256Sha256_getRemoteBlockSize;
    asymEncryAlg->getRemotePlainTextBlockSize =
            UA_AsymEn_Basic256Sha256_getRemotePlainTextBlockSize;

    /* AsymmetricModule */
    asymmetricModule->compareCertificateThumbprint = UA_compareCertificateThumbprint;
    asymmetricModule->makeCertificateThumbprint = UA_makeCertificateThumbprint;

    /* SymmetricModule */
    symmetricModule->secureChannelNonceLength = 32;
    symmetricModule->generateNonce = UA_Sym_Basic256Sha256_generateNonce;
    symmetricModule->generateKey = UA_Sym_Basic256Sha256_generateKey;

    /* Symmetric encryption Algorithm */
    UA_SecurityPolicyEncryptionAlgorithm *symEncryptionAlgorithm =
        &symmetricModule->cryptoModule.encryptionAlgorithm;
    symEncryptionAlgorithm->uri =
        UA_STRING("http://www.w3.org/2001/04/xmlenc#aes256-cbc\0");
    symEncryptionAlgorithm->encrypt = UA_SymEn_Basic256Sha256_encrypt;
    symEncryptionAlgorithm->decrypt = UA_SymEn_Basic256Sha256_decrypt;
    symEncryptionAlgorithm->getLocalKeyLength = UA_SymEn_Basic256Sha256_getLocalKeyLength;
    symEncryptionAlgorithm->getRemoteKeyLength = UA_SymEn_Basic256Sha256_getRemoteKeyLength;
    symEncryptionAlgorithm->getRemoteBlockSize = UA_SymEn_Basic256Sha256_getBlockSize;
    symEncryptionAlgorithm->getRemotePlainTextBlockSize = UA_SymEn_Basic256Sha256_getBlockSize;

    /* Symmetric signature Algorithm */
    UA_SecurityPolicySignatureAlgorithm *symSignatureAlgorithm =
        &symmetricModule->cryptoModule.signatureAlgorithm;
    symSignatureAlgorithm->uri =
        UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha2-256\0");
    symSignatureAlgorithm->verify = UA_SymSig_Basic256Sha256_verify;
    symSignatureAlgorithm->sign = UA_SymSig_Basic256Sha256_sign;
    symSignatureAlgorithm->getLocalSignatureSize =
        UA_SymSig_Basic256Sha256_getLocalSignatureSize;
    symSignatureAlgorithm->getRemoteSignatureSize =
        UA_SymSig_Basic256Sha256_getRemoteSignatureSize;
    symSignatureAlgorithm->getLocalKeyLength =
        UA_SymSig_Basic256Sha256_getLocalKeyLength;
    symSignatureAlgorithm->getRemoteKeyLength =
        UA_SymSig_Basic256Sha256_getRemoteKeyLength;

    policy->updateCertificateAndPrivateKey =
        updateCertificateAndPrivateKey_sp_basic256sha256;
    policy->clear = UA_Policy_Clear_Context;
    retval = UA_Policy_New_Context(policy, localPrivateKey, logger);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&policy->localCertificate);
        return retval;
    }

    /* Use the same signature algorithm as the asymmetric component for
     * certificate signing (see standard) */
    policy->certificateSigningAlgorithm =
        policy->asymmetricModule.cryptoModule.signatureAlgorithm;

    return UA_STATUSCODE_GOOD;
}

#endif

/**** amalgamated original file "/plugins/crypto/openssl/ua_openssl_aes128sha256rsaoaep.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2020 (c) Wind River Systems, Inc.
 */


#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL)


#include <openssl/hmac.h>
#include <openssl/sha.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>

#define UA_SHA256_LENGTH 32 /* 256 bit */
#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_RSAPADDING_LEN 42
#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_SIGNING_KEY_LENGTH 32
#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_ENCRYPTION_KEY_LENGTH 16
#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_ENCRYPTION_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_PLAIN_TEXT_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_MINASYMKEYLENGTH 256
#define UA_SECURITYPOLICY_AES128SHA256RSAOAEP_MAXASYMKEYLENGTH 512

typedef struct {
    EVP_PKEY *localPrivateKey;
    UA_ByteString localCertThumbprint;
    const UA_Logger *logger;
} Policy_Context_Aes128Sha256RsaOaep;

typedef struct {
    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;
    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    Policy_Context_Aes128Sha256RsaOaep *policyContext;
    UA_ByteString remoteCertificate;
    X509 *remoteCertificateX509; /* X509 */
} Channel_Context_Aes128Sha256RsaOaep;

/* create the policy context */

static UA_StatusCode
UA_Policy_Aes128Sha256RsaOaep_New_Context(UA_SecurityPolicy *securityPolicy,
                                          const UA_ByteString localPrivateKey,
                                          const UA_Logger *logger) {
    Policy_Context_Aes128Sha256RsaOaep *context =
        (Policy_Context_Aes128Sha256RsaOaep *)UA_malloc(
            sizeof(Policy_Context_Aes128Sha256RsaOaep));
    if(context == NULL) {
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    context->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&localPrivateKey);
    if (!context->localPrivateKey) {
        UA_free(context);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_StatusCode retval = UA_Openssl_X509_GetCertificateThumbprint(
        &securityPolicy->localCertificate, &context->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD) {
        EVP_PKEY_free(context->localPrivateKey);
        UA_free(context);
        return retval;
    }

    context->logger = logger;
    securityPolicy->policyContext = context;

    return UA_STATUSCODE_GOOD;
}

/* clear the policy context */

static void
UA_Policy_Aes128Sha256RsaOaep_Clear_Context(UA_SecurityPolicy *policy) {
    if(policy == NULL)
        return;

    UA_ByteString_clear(&policy->localCertificate);

    /* delete all allocated members in the context */

    Policy_Context_Aes128Sha256RsaOaep *pc =
        (Policy_Context_Aes128Sha256RsaOaep *)policy->policyContext;
    if (pc == NULL) {
        return;
    }

    EVP_PKEY_free(pc->localPrivateKey);
    UA_ByteString_clear(&pc->localCertThumbprint);
    UA_free(pc);

    return;
}

static UA_StatusCode
updateCertificateAndPrivateKey_sp_aes128sha256rsaoaep(UA_SecurityPolicy *securityPolicy,
                                                      const UA_ByteString newCertificate,
                                                      const UA_ByteString newPrivateKey) {
    if(securityPolicy == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    if(securityPolicy->policyContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Policy_Context_Aes128Sha256RsaOaep *pc =
        (Policy_Context_Aes128Sha256RsaOaep *)securityPolicy->policyContext;

    UA_ByteString_clear(&securityPolicy->localCertificate);

    UA_StatusCode retval = UA_OpenSSL_LoadLocalCertificate(
        &newCertificate, &securityPolicy->localCertificate);

    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* Set the new private key */
    EVP_PKEY_free(pc->localPrivateKey);

    pc->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&newPrivateKey);

    if(!pc->localPrivateKey) {
        retval = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
        goto error;
    }

    UA_ByteString_clear(&pc->localCertThumbprint);

    retval = UA_Openssl_X509_GetCertificateThumbprint(&securityPolicy->localCertificate,
                                                      &pc->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD) {
        goto error;
    }

    return retval;

error:
    UA_LOG_ERROR(securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
                 "Could not update certificate and private key");
    if(securityPolicy->policyContext != NULL)
        UA_Policy_Aes128Sha256RsaOaep_Clear_Context(securityPolicy);
    return retval;
}

/* create the channel context */

static UA_StatusCode
UA_ChannelModule_Aes128Sha256RsaOaep_New_Context(const UA_SecurityPolicy *securityPolicy,
                                                 const UA_ByteString *remoteCertificate,
                                                 void **channelContext) {
    if(securityPolicy == NULL || remoteCertificate == NULL || channelContext == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    Channel_Context_Aes128Sha256RsaOaep *context =
        (Channel_Context_Aes128Sha256RsaOaep *)UA_malloc(
            sizeof(Channel_Context_Aes128Sha256RsaOaep));
    if(context == NULL) {
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    UA_ByteString_init(&context->localSymSigningKey);
    UA_ByteString_init(&context->localSymEncryptingKey);
    UA_ByteString_init(&context->localSymIv);
    UA_ByteString_init(&context->remoteSymSigningKey);
    UA_ByteString_init(&context->remoteSymEncryptingKey);
    UA_ByteString_init(&context->remoteSymIv);

    UA_StatusCode retval =
        UA_copyCertificate(&context->remoteCertificate, remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free(context);
        return retval;
    }

    /* decode to X509 */
    context->remoteCertificateX509 = UA_OpenSSL_LoadCertificate(&context->remoteCertificate);
    if (context->remoteCertificateX509 == NULL) {
        UA_ByteString_clear (&context->remoteCertificate);
        UA_free (context);
        return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
    }

    context->policyContext =
        (Policy_Context_Aes128Sha256RsaOaep *)(securityPolicy->policyContext);

    *channelContext = context;

    UA_LOG_INFO(
        securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
        "The Aes128Sha256RsaOaep security policy channel with openssl is created.");

    return UA_STATUSCODE_GOOD;
}

/* delete the channel context */

static void
UA_ChannelModule_Aes128Sha256RsaOaep_Delete_Context(void *channelContext) {
    if(channelContext != NULL) {
        Channel_Context_Aes128Sha256RsaOaep *cc =
            (Channel_Context_Aes128Sha256RsaOaep *)channelContext;
        X509_free(cc->remoteCertificateX509);
        UA_ByteString_clear(&cc->remoteCertificate);
        UA_ByteString_clear(&cc->localSymSigningKey);
        UA_ByteString_clear(&cc->localSymEncryptingKey);
        UA_ByteString_clear(&cc->localSymIv);
        UA_ByteString_clear(&cc->remoteSymSigningKey);
        UA_ByteString_clear(&cc->remoteSymEncryptingKey);
        UA_ByteString_clear(&cc->remoteSymIv);

        UA_LOG_INFO(
            cc->policyContext->logger, UA_LOGCATEGORY_SECURITYPOLICY,
            "The Aes128Sha256RsaOaep security policy channel with openssl is deleted.");
        UA_free(cc);
    }
}

/* Verifies the signature of the message using the provided keys in the context.
 * AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256
 */

static UA_StatusCode
UA_AsySig_Aes128Sha256RsaOaep_Verify(void *channelContext, const UA_ByteString *message,
                                     const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    Channel_Context_Aes128Sha256RsaOaep *cc =
        (Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    UA_StatusCode retval = UA_OpenSSL_RSA_PKCS1_V15_SHA256_Verify(
        message, cc->remoteCertificateX509, signature);

    return retval;
}

/* Compares the supplied certificate with the certificate
 * in the endpoint context
 */

static UA_StatusCode
UA_compareCertificateThumbprint_Aes128Sha256RsaOaep(const UA_SecurityPolicy *securityPolicy,
                                                    const UA_ByteString *certificateThumbprint) {
    if(securityPolicy == NULL || certificateThumbprint == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }
    Policy_Context_Aes128Sha256RsaOaep *pc =
        (Policy_Context_Aes128Sha256RsaOaep *)securityPolicy->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    return UA_STATUSCODE_GOOD;
}

/* Generates a thumbprint for the specified certificate */

static UA_StatusCode
UA_makeCertificateThumbprint_Aes128Sha256RsaOaep(const UA_SecurityPolicy *securityPolicy,
                                                 const UA_ByteString *certificate,
                                                 UA_ByteString *thumbprint) {
    return UA_Openssl_X509_GetCertificateThumbprint(certificate, thumbprint, false);
}

static UA_StatusCode
UA_Asym_Aes128Sha256RsaOaep_Decrypt(void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    Channel_Context_Aes128Sha256RsaOaep *cc = (Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    UA_StatusCode ret = UA_Openssl_RSA_Oaep_Decrypt(data, cc->policyContext->localPrivateKey);
    return ret;
}

static size_t
UA_Asym_Aes128Sha256RsaOaep_getRemoteSignatureSize(const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    const Channel_Context_Aes128Sha256RsaOaep *cc = (const Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    return (size_t)keyLen;
}

static size_t
UA_AsySig_Aes128Sha256RsaOaep_getLocalSignatureSize(const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    const Channel_Context_Aes128Sha256RsaOaep *cc = (const Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    Policy_Context_Aes128Sha256RsaOaep *pc = cc->policyContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Private_GetKeyLength(pc->localPrivateKey, &keyLen);
    return (size_t)keyLen;
}

static size_t
UA_AsymEn_Aes128Sha256RsaOaep_getRemotePlainTextBlockSize(const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    const Channel_Context_Aes128Sha256RsaOaep *cc =
        (const Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    return (size_t)keyLen - UA_SECURITYPOLICY_AES128SHA256RSAOAEP_RSAPADDING_LEN;
}

static size_t
UA_AsymEn_Aes128Sha256RsaOaep_getRemoteBlockSize(const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    const Channel_Context_Aes128Sha256RsaOaep *cc =
        (const Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    return (size_t)keyLen;
}

static size_t
UA_AsymEn_Aes128Sha256RsaOaep_getRemoteKeyLength(const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    const Channel_Context_Aes128Sha256RsaOaep *cc =
        (const Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    return (size_t)keyLen * 8;
}

static UA_StatusCode
UA_Sym_Aes128Sha256RsaOaep_generateNonce(void *policyContext,
                                         UA_ByteString *out) {
    UA_Int32 rc = RAND_bytes(out->data, (int)out->length);
    if(rc != 1) {
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    }
    return UA_STATUSCODE_GOOD;
}

static size_t
UA_SymEn_Aes128Sha256RsaOaep_getLocalKeyLength(const void *channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymSig_Aes128Sha256RsaOaep_getLocalKeyLength(const void *channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
UA_Sym_Aes128Sha256RsaOaep_generateKey(void *policyContext,
                                       const UA_ByteString *secret,
                                       const UA_ByteString *seed, UA_ByteString *out) {
    return UA_Openssl_Random_Key_PSHA256_Derive(secret, seed, out);
}

static UA_StatusCode
UA_ChannelModule_Aes128Sha256RsaOaep_setLocalSymSigningKey(void *channelContext,
                                                           const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes128Sha256RsaOaep *cc =
        (Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}

static UA_StatusCode
UA_ChannelM_Aes128Sha256RsaOaep_setLocalSymEncryptingKey(void *channelContext,
                                                         const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes128Sha256RsaOaep *cc =
        (Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
UA_ChannelM_Aes128Sha256RsaOaep_setLocalSymIv(void *channelContext,
                                              const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes128Sha256RsaOaep *cc =
        (Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static size_t
UA_SymEn_Aes128Sha256RsaOaep_getRemoteKeyLength(const void *channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymEn_Aes128Sha256RsaOaep_getBlockSize(const void *channelContext) {
    return UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_ENCRYPTION_BLOCK_SIZE;
}

static size_t
UA_SymSig_Aes128Sha256RsaOaep_getRemoteKeyLength(const void *channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_AES128SHA256RSAOAEP_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
UA_ChannelM_Aes128Sha256RsaOaep_setRemoteSymSigningKey(void *channelContext,
                                                       const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes128Sha256RsaOaep *cc =
        (Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
UA_ChannelM_Aes128Sha256RsaOaep_setRemoteSymEncryptingKey(void *channelContext,
                                                          const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes128Sha256RsaOaep *cc =
        (Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
UA_ChannelM_Aes128Sha256RsaOaep_setRemoteSymIv(void *channelContext,
                                               const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes128Sha256RsaOaep *cc = (Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(key, &cc->remoteSymIv);
}

static UA_StatusCode
UA_AsySig_Aes128Sha256RsaOaep_sign(void *channelContext, const UA_ByteString *message,
                                   UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL ||
       signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes128Sha256RsaOaep *cc = (Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    Policy_Context_Aes128Sha256RsaOaep *pc = cc->policyContext;
    return UA_Openssl_RSA_PKCS1_V15_SHA256_Sign(message, pc->localPrivateKey, signature);
}

static UA_StatusCode
UA_AsymEn_Aes128Sha256RsaOaep_encrypt(void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes128Sha256RsaOaep *cc =
        (Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    return UA_Openssl_RSA_OAEP_Encrypt(
        data, UA_SECURITYPOLICY_AES128SHA256RSAOAEP_RSAPADDING_LEN,
        cc->remoteCertificateX509);
}

static size_t
UA_SymSig_Aes128Sha256RsaOaep_getRemoteSignatureSize(const void *channelContext) {
    return UA_SHA256_LENGTH;
}

static UA_StatusCode
UA_SymSig_Aes128Sha256RsaOaep_verify(void *channelContext, const UA_ByteString *message,
                                     const UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL ||
       signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_Aes128Sha256RsaOaep *cc =
        (Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    return UA_OpenSSL_HMAC_SHA256_Verify(message, &cc->remoteSymSigningKey, signature);
}

static UA_StatusCode
UA_SymSig_Aes128Sha256RsaOaep_sign(void *channelContext, const UA_ByteString *message,
                                   UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL ||
       signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_Aes128Sha256RsaOaep *cc =
        (Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    return UA_OpenSSL_HMAC_SHA256_Sign(message, &cc->localSymSigningKey, signature);
}

static size_t
UA_SymSig_Aes128Sha256RsaOaep_getLocalSignatureSize(const void *channelContext) {
    return UA_SHA256_LENGTH;
}

static UA_StatusCode
UA_SymEn_Aes128Sha256RsaOaep_decrypt(void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes128Sha256RsaOaep *cc =
        (Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    return UA_OpenSSL_AES_128_CBC_Decrypt(&cc->remoteSymIv, &cc->remoteSymEncryptingKey,
                                          data);
}

static UA_StatusCode
UA_SymEn_Aes128Sha256RsaOaep_encrypt(void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_Aes128Sha256RsaOaep *cc =
        (Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    return UA_OpenSSL_AES_128_CBC_Encrypt(&cc->localSymIv, &cc->localSymEncryptingKey,
                                          data);
}

static UA_StatusCode
UA_ChannelM_Aes128Sha256RsaOaep_compareCertificate(const void *channelContext,
                                                   const UA_ByteString *certificate) {
    if(channelContext == NULL || certificate == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    const Channel_Context_Aes128Sha256RsaOaep *cc = (const Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    return UA_OpenSSL_X509_compare(certificate, cc->remoteCertificateX509);
}

static size_t
UA_AsymEn_Aes128Sha256RsaOaep_getLocalKeyLength(const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    const Channel_Context_Aes128Sha256RsaOaep *cc = (const Channel_Context_Aes128Sha256RsaOaep *)channelContext;
    Policy_Context_Aes128Sha256RsaOaep *pc = cc->policyContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Private_GetKeyLength(pc->localPrivateKey, &keyLen);
    return (size_t)keyLen * 8;
}

/* the main entry of Aes128Sha256RsaOaep */

UA_StatusCode
UA_SecurityPolicy_Aes128Sha256RsaOaep(UA_SecurityPolicy *policy,
                                      const UA_ByteString localCertificate,
                                      const UA_ByteString localPrivateKey,
                                      const UA_Logger *logger) {

    UA_SecurityPolicyAsymmetricModule *const asymmetricModule = &policy->asymmetricModule;
    UA_SecurityPolicySymmetricModule *const symmetricModule = &policy->symmetricModule;
    UA_SecurityPolicyChannelModule *const channelModule = &policy->channelModule;
    UA_StatusCode retval;

    UA_LOG_INFO(logger, UA_LOGCATEGORY_SECURITYPOLICY,
                "The Aes128Sha256RsaOaep security policy with openssl is added.");

    UA_Openssl_Init();
    memset(policy, 0, sizeof(UA_SecurityPolicy));
    policy->logger = logger;
    policy->policyUri =
        UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Aes128_Sha256_RsaOaep\0");
    policy->securityLevel = 30;

    /* set ChannelModule context  */

    channelModule->newContext = UA_ChannelModule_Aes128Sha256RsaOaep_New_Context;
    channelModule->deleteContext = UA_ChannelModule_Aes128Sha256RsaOaep_Delete_Context;
    channelModule->setLocalSymSigningKey =
        UA_ChannelModule_Aes128Sha256RsaOaep_setLocalSymSigningKey;
    channelModule->setLocalSymEncryptingKey =
        UA_ChannelM_Aes128Sha256RsaOaep_setLocalSymEncryptingKey;
    channelModule->setLocalSymIv = UA_ChannelM_Aes128Sha256RsaOaep_setLocalSymIv;
    channelModule->setRemoteSymSigningKey =
        UA_ChannelM_Aes128Sha256RsaOaep_setRemoteSymSigningKey;
    channelModule->setRemoteSymEncryptingKey =
        UA_ChannelM_Aes128Sha256RsaOaep_setRemoteSymEncryptingKey;
    channelModule->setRemoteSymIv = UA_ChannelM_Aes128Sha256RsaOaep_setRemoteSymIv;
    channelModule->compareCertificate =
        UA_ChannelM_Aes128Sha256RsaOaep_compareCertificate;

    /* Copy the certificate and add a NULL to the end */

    retval = UA_copyCertificate(&policy->localCertificate, &localCertificate);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* AsymmetricModule - signature algorithm */

    UA_SecurityPolicySignatureAlgorithm *asySigAlgorithm =
        &asymmetricModule->cryptoModule.signatureAlgorithm;
    asySigAlgorithm->uri =
        UA_STRING("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256\0");
    asySigAlgorithm->verify = UA_AsySig_Aes128Sha256RsaOaep_Verify;
    asySigAlgorithm->getRemoteSignatureSize =
        UA_Asym_Aes128Sha256RsaOaep_getRemoteSignatureSize;
    asySigAlgorithm->getLocalSignatureSize =
        UA_AsySig_Aes128Sha256RsaOaep_getLocalSignatureSize;
    asySigAlgorithm->sign = UA_AsySig_Aes128Sha256RsaOaep_sign;
    asySigAlgorithm->getLocalKeyLength = NULL;
    asySigAlgorithm->getRemoteKeyLength = NULL;

    /*  AsymmetricModule encryption algorithm */

    UA_SecurityPolicyEncryptionAlgorithm *asymEncryAlg =
        &asymmetricModule->cryptoModule.encryptionAlgorithm;
    asymEncryAlg->uri = UA_STRING("http://www.w3.org/2001/04/xmlenc#rsa-oaep\0");
    asymEncryAlg->decrypt = UA_Asym_Aes128Sha256RsaOaep_Decrypt;
    asymEncryAlg->getRemotePlainTextBlockSize =
        UA_AsymEn_Aes128Sha256RsaOaep_getRemotePlainTextBlockSize;
    asymEncryAlg->getRemoteBlockSize = UA_AsymEn_Aes128Sha256RsaOaep_getRemoteBlockSize;
    asymEncryAlg->getRemoteKeyLength = UA_AsymEn_Aes128Sha256RsaOaep_getRemoteKeyLength;
    asymEncryAlg->encrypt = UA_AsymEn_Aes128Sha256RsaOaep_encrypt;
    asymEncryAlg->getLocalKeyLength = UA_AsymEn_Aes128Sha256RsaOaep_getLocalKeyLength;

    /* asymmetricModule */

    asymmetricModule->compareCertificateThumbprint =
        UA_compareCertificateThumbprint_Aes128Sha256RsaOaep;
    asymmetricModule->makeCertificateThumbprint =
        UA_makeCertificateThumbprint_Aes128Sha256RsaOaep;

    /* SymmetricModule */

    symmetricModule->secureChannelNonceLength = 32;
    symmetricModule->generateNonce = UA_Sym_Aes128Sha256RsaOaep_generateNonce;
    symmetricModule->generateKey = UA_Sym_Aes128Sha256RsaOaep_generateKey;

    /* Symmetric encryption Algorithm */

    UA_SecurityPolicyEncryptionAlgorithm *symEncryptionAlgorithm =
        &symmetricModule->cryptoModule.encryptionAlgorithm;
    symEncryptionAlgorithm->uri =
        UA_STRING("http://www.w3.org/2001/04/xmlenc#aes128-cbc\0");
    symEncryptionAlgorithm->getLocalKeyLength = UA_SymEn_Aes128Sha256RsaOaep_getLocalKeyLength;
    symEncryptionAlgorithm->getRemoteKeyLength = UA_SymEn_Aes128Sha256RsaOaep_getRemoteKeyLength;
    symEncryptionAlgorithm->getRemoteBlockSize = UA_SymEn_Aes128Sha256RsaOaep_getBlockSize;
    symEncryptionAlgorithm->getRemotePlainTextBlockSize = UA_SymEn_Aes128Sha256RsaOaep_getBlockSize;
    symEncryptionAlgorithm->decrypt = UA_SymEn_Aes128Sha256RsaOaep_decrypt;
    symEncryptionAlgorithm->encrypt = UA_SymEn_Aes128Sha256RsaOaep_encrypt;

    /* Symmetric signature Algorithm */

    UA_SecurityPolicySignatureAlgorithm *symSignatureAlgorithm =
        &symmetricModule->cryptoModule.signatureAlgorithm;
    symSignatureAlgorithm->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha2-256\0");
    symSignatureAlgorithm->getLocalKeyLength = UA_SymSig_Aes128Sha256RsaOaep_getLocalKeyLength;
    symSignatureAlgorithm->getRemoteKeyLength = UA_SymSig_Aes128Sha256RsaOaep_getRemoteKeyLength;
    symSignatureAlgorithm->getRemoteSignatureSize = UA_SymSig_Aes128Sha256RsaOaep_getRemoteSignatureSize;
    symSignatureAlgorithm->verify = UA_SymSig_Aes128Sha256RsaOaep_verify;
    symSignatureAlgorithm->sign = UA_SymSig_Aes128Sha256RsaOaep_sign;
    symSignatureAlgorithm->getLocalSignatureSize = UA_SymSig_Aes128Sha256RsaOaep_getLocalSignatureSize;

    retval = UA_Policy_Aes128Sha256RsaOaep_New_Context(policy, localPrivateKey, logger);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&policy->localCertificate);
        return retval;
    }
    policy->updateCertificateAndPrivateKey =
        updateCertificateAndPrivateKey_sp_aes128sha256rsaoaep;
    policy->clear = UA_Policy_Aes128Sha256RsaOaep_Clear_Context;

    /* Use the same signature algorithm as the asymmetric component for
       certificate signing (see standard) */

    policy->certificateSigningAlgorithm =
        policy->asymmetricModule.cryptoModule.signatureAlgorithm;

    return UA_STATUSCODE_GOOD;
}

#endif

/**** amalgamated original file "/plugins/crypto/openssl/ua_openssl_aes256sha256rsapss.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2022 (c) Fraunhofer IOSB (Author: Noel Graf)
 */


#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL)


#include <openssl/hmac.h>
#include <openssl/sha.h>
#include <openssl/rsa.h>
#include <openssl/x509.h>
#include <openssl/rand.h>
#include <openssl/rsa.h>

#define UA_SHA256_LENGTH 32 /* 256 bit */
#define UA_SECURITYPOLICY_AES256SHA256RSAPSS_RSAPADDING_LEN 66
#define UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_SIGNING_KEY_LENGTH 32
#define UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_ENCRYPTION_KEY_LENGTH 32
#define UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_ENCRYPTION_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_PLAIN_TEXT_BLOCK_SIZE 16
#define UA_SECURITYPOLICY_AES256SHA256RSAPSS_MINASYMKEYLENGTH 256
#define UA_SECURITYPOLICY_AES256SHA256RSAPSS_MAXASYMKEYLENGTH 512

typedef struct {
    EVP_PKEY *localPrivateKey;
    UA_ByteString localCertThumbprint;
    const UA_Logger *logger;
} Policy_Context_Aes256Sha256RsaPss;

typedef struct {
    UA_ByteString localSymSigningKey;
    UA_ByteString localSymEncryptingKey;
    UA_ByteString localSymIv;
    UA_ByteString remoteSymSigningKey;
    UA_ByteString remoteSymEncryptingKey;
    UA_ByteString remoteSymIv;

    Policy_Context_Aes256Sha256RsaPss *policyContext;
    UA_ByteString remoteCertificate;
    X509 *remoteCertificateX509; /* X509 */
} Channel_Context_Aes256Sha256RsaPss;

/* create the policy context */

static UA_StatusCode
UA_Policy_Aes256Sha256RsaPss_New_Context(UA_SecurityPolicy *securityPolicy,
                                          const UA_ByteString localPrivateKey,
                                          const UA_Logger *logger) {
    Policy_Context_Aes256Sha256RsaPss *context =
        (Policy_Context_Aes256Sha256RsaPss *)UA_malloc(
            sizeof(Policy_Context_Aes256Sha256RsaPss));
    if(context == NULL) {
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    context->localPrivateKey = UA_OpenSSL_LoadPrivateKey(&localPrivateKey);
    if (!context->localPrivateKey) {
        UA_free(context);
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    UA_StatusCode retval = UA_Openssl_X509_GetCertificateThumbprint(
        &securityPolicy->localCertificate, &context->localCertThumbprint, true);
    if(retval != UA_STATUSCODE_GOOD) {
        EVP_PKEY_free(context->localPrivateKey);
        UA_free(context);
        return retval;
    }

    context->logger = logger;
    securityPolicy->policyContext = context;

    return UA_STATUSCODE_GOOD;
}

/* clear the policy context */

static void
UA_Policy_Aes256Sha256RsaPss_Clear_Context(UA_SecurityPolicy *policy) {
    if(policy == NULL)
        return;

    UA_ByteString_clear(&policy->localCertificate);

    /* delete all allocated members in the context */

    Policy_Context_Aes256Sha256RsaPss *pc =
        (Policy_Context_Aes256Sha256RsaPss *)policy->policyContext;
    if (pc == NULL) {
        return;
    }

    EVP_PKEY_free(pc->localPrivateKey);
    UA_ByteString_clear(&pc->localCertThumbprint);
    UA_free(pc);

    return;
}

/* create the channel context */

static UA_StatusCode
UA_ChannelModule_Aes256Sha256RsaPss_New_Context(const UA_SecurityPolicy *securityPolicy,
                                                 const UA_ByteString *remoteCertificate,
                                                 void **channelContext) {
    if(securityPolicy == NULL || remoteCertificate == NULL || channelContext == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    Channel_Context_Aes256Sha256RsaPss *context =
        (Channel_Context_Aes256Sha256RsaPss *)UA_malloc(
            sizeof(Channel_Context_Aes256Sha256RsaPss));
    if(context == NULL) {
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    UA_ByteString_init(&context->localSymSigningKey);
    UA_ByteString_init(&context->localSymEncryptingKey);
    UA_ByteString_init(&context->localSymIv);
    UA_ByteString_init(&context->remoteSymSigningKey);
    UA_ByteString_init(&context->remoteSymEncryptingKey);
    UA_ByteString_init(&context->remoteSymIv);

    UA_StatusCode retval =
        UA_copyCertificate(&context->remoteCertificate, remoteCertificate);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_free(context);
        return retval;
    }

    /* decode to X509 */
    context->remoteCertificateX509 = UA_OpenSSL_LoadCertificate(&context->remoteCertificate);
    if (context->remoteCertificateX509 == NULL) {
        UA_ByteString_clear (&context->remoteCertificate);
        UA_free (context);
        return UA_STATUSCODE_BADCERTIFICATECHAININCOMPLETE;
    }

    context->policyContext =
        (Policy_Context_Aes256Sha256RsaPss *)(securityPolicy->policyContext);

    *channelContext = context;

    UA_LOG_INFO(
        securityPolicy->logger, UA_LOGCATEGORY_SECURITYPOLICY,
        "The Aes256Sha256RsaPss security policy channel with openssl is created.");

    return UA_STATUSCODE_GOOD;
}

/* delete the channel context */

static void
UA_ChannelModule_Aes256Sha256RsaPss_Delete_Context(void *channelContext) {
    if(channelContext != NULL) {
        Channel_Context_Aes256Sha256RsaPss *cc =
            (Channel_Context_Aes256Sha256RsaPss *)channelContext;
        X509_free(cc->remoteCertificateX509);
        UA_ByteString_clear(&cc->remoteCertificate);
        UA_ByteString_clear(&cc->localSymSigningKey);
        UA_ByteString_clear(&cc->localSymEncryptingKey);
        UA_ByteString_clear(&cc->localSymIv);
        UA_ByteString_clear(&cc->remoteSymSigningKey);
        UA_ByteString_clear(&cc->remoteSymEncryptingKey);
        UA_ByteString_clear(&cc->remoteSymIv);

        UA_LOG_INFO(
            cc->policyContext->logger, UA_LOGCATEGORY_SECURITYPOLICY,
            "The Aes256Sha256RsaPss security policy channel with openssl is deleted.");
        UA_free(cc);
    }
}

/* Verifies the signature of the message using the provided keys in the context.
 * AsymmetricSignatureAlgorithm_RSA-PKCS15-SHA2-256
 */

static UA_StatusCode
UA_AsySig_Aes256Sha256RsaPss_Verify(void *channelContext, const UA_ByteString *message,
                                     const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    Channel_Context_Aes256Sha256RsaPss *cc =
        (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    UA_StatusCode retval = UA_OpenSSL_RSA_PSS_SHA256_Verify(
        message, cc->remoteCertificateX509, signature);

    return retval;
}

/* Compares the supplied certificate with the certificate
 * in the endpoint context
 */

static UA_StatusCode
UA_compareCertificateThumbprint_Aes256Sha256RsaPss(const UA_SecurityPolicy *securityPolicy,
                                                    const UA_ByteString *certificateThumbprint) {
    if(securityPolicy == NULL || certificateThumbprint == NULL) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }
    Policy_Context_Aes256Sha256RsaPss *pc =
        (Policy_Context_Aes256Sha256RsaPss *)securityPolicy->policyContext;
    if(!UA_ByteString_equal(certificateThumbprint, &pc->localCertThumbprint))
        return UA_STATUSCODE_BADCERTIFICATEINVALID;
    return UA_STATUSCODE_GOOD;
}

/* Generates a thumbprint for the specified certificate */

static UA_StatusCode
UA_makeCertificateThumbprint_Aes256Sha256RsaPss(const UA_SecurityPolicy *securityPolicy,
                                                 const UA_ByteString *certificate,
                                                 UA_ByteString *thumbprint) {
    return UA_Openssl_X509_GetCertificateThumbprint(certificate, thumbprint, false);
}

static UA_StatusCode
UA_Asym_Aes256Sha256RsaPss_Decrypt(void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    Channel_Context_Aes256Sha256RsaPss *cc = (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    UA_StatusCode ret = UA_Openssl_RSA_Oaep_Sha2_Decrypt(data, cc->policyContext->localPrivateKey);
    return ret;
}

static size_t
UA_Asym_Aes256Sha256RsaPss_getRemoteSignatureSize(const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    const Channel_Context_Aes256Sha256RsaPss *cc = (const Channel_Context_Aes256Sha256RsaPss *)channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    return (size_t)keyLen;
}

static size_t
UA_AsySig_Aes256Sha256RsaPss_getLocalSignatureSize(const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    const Channel_Context_Aes256Sha256RsaPss *cc = (const Channel_Context_Aes256Sha256RsaPss *)channelContext;
    Policy_Context_Aes256Sha256RsaPss *pc = cc->policyContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Private_GetKeyLength(pc->localPrivateKey, &keyLen);
    return (size_t)keyLen;
}

static size_t
UA_AsymEn_Aes256Sha256RsaPss_getRemotePlainTextBlockSize(const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    const Channel_Context_Aes256Sha256RsaPss *cc =
        (const Channel_Context_Aes256Sha256RsaPss *)channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    return (size_t)keyLen - UA_SECURITYPOLICY_AES256SHA256RSAPSS_RSAPADDING_LEN;
}

static size_t
UA_AsymEn_Aes256Sha256RsaPss_getRemoteBlockSize(const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    const Channel_Context_Aes256Sha256RsaPss *cc =
        (const Channel_Context_Aes256Sha256RsaPss *)channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    return (size_t)keyLen;
}

static size_t
UA_AsymEn_Aes256Sha256RsaPss_getRemoteKeyLength(const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    const Channel_Context_Aes256Sha256RsaPss *cc =
        (const Channel_Context_Aes256Sha256RsaPss *)channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    return (size_t)keyLen * 8;
}

static UA_StatusCode
UA_Sym_Aes256Sha256RsaPss_generateNonce(void *policyContext,
                                         UA_ByteString *out) {
    UA_Int32 rc = RAND_bytes(out->data, (int)out->length);
    if(rc != 1) {
        return UA_STATUSCODE_BADUNEXPECTEDERROR;
    }
    return UA_STATUSCODE_GOOD;
}

static size_t
UA_SymEn_Aes256Sha256RsaPss_getLocalKeyLength(const void *channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymSig_Aes256Sha256RsaPss_getLocalKeyLength(const void *channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
UA_Sym_Aes256Sha256RsaPss_generateKey(void *policyContext,
                                       const UA_ByteString *secret,
                                       const UA_ByteString *seed, UA_ByteString *out) {
    return UA_Openssl_Random_Key_PSHA256_Derive(secret, seed, out);
}

static UA_StatusCode
UA_CertSig_Aes256Sha256RsaPss_Verify(void *channelContext, const UA_ByteString *message,
                                     const UA_ByteString *signature) {
    if(message == NULL || signature == NULL || channelContext == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    Channel_Context_Aes256Sha256RsaPss *cc =
        (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    UA_StatusCode retval = UA_OpenSSL_RSA_PKCS1_V15_SHA256_Verify(
        message, cc->remoteCertificateX509, signature);

    return retval;
}

static UA_StatusCode
UA_CertSig_Aes256Sha256RsaPss_sign(void *channelContext, const UA_ByteString *message,
                                   UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL ||
       signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes256Sha256RsaPss *cc = (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    Policy_Context_Aes256Sha256RsaPss *pc = cc->policyContext;
    return UA_Openssl_RSA_PKCS1_V15_SHA256_Sign(message, pc->localPrivateKey, signature);
}

static size_t
UA_CertSig_Aes256Sha256RsaPss_getRemoteSignatureSize(const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    const Channel_Context_Aes256Sha256RsaPss *cc = (const Channel_Context_Aes256Sha256RsaPss *)channelContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Public_GetKeyLength(cc->remoteCertificateX509, &keyLen);
    return (size_t)keyLen;
}

static size_t
UA_CertSig_Aes256Sha256RsaPss_getLocalSignatureSize(const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    const Channel_Context_Aes256Sha256RsaPss *cc = (const Channel_Context_Aes256Sha256RsaPss *)channelContext;
    Policy_Context_Aes256Sha256RsaPss *pc = cc->policyContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Private_GetKeyLength(pc->localPrivateKey, &keyLen);
    return (size_t)keyLen;
}

static UA_StatusCode
UA_ChannelModule_Aes256Sha256RsaPss_setLocalSymSigningKey(void *channelContext,
                                                           const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes256Sha256RsaPss *cc =
        (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    UA_ByteString_clear(&cc->localSymSigningKey);
    return UA_ByteString_copy(key, &cc->localSymSigningKey);
}

static UA_StatusCode
UA_ChannelM_Aes256Sha256RsaPss_setLocalSymEncryptingKey(void *channelContext,
                                                         const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes256Sha256RsaPss *cc =
        (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    UA_ByteString_clear(&cc->localSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->localSymEncryptingKey);
}

static UA_StatusCode
UA_ChannelM_Aes256Sha256RsaPss_setLocalSymIv(void *channelContext,
                                              const UA_ByteString *iv) {
    if(iv == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes256Sha256RsaPss *cc =
        (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    UA_ByteString_clear(&cc->localSymIv);
    return UA_ByteString_copy(iv, &cc->localSymIv);
}

static size_t
UA_SymEn_Aes256Sha256RsaPss_getRemoteKeyLength(const void *channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_ENCRYPTION_KEY_LENGTH;
}

static size_t
UA_SymEn_Aes256Sha256RsaPss_getBlockSize(const void *channelContext) {
    return UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_ENCRYPTION_BLOCK_SIZE;
}

static size_t
UA_SymSig_Aes256Sha256RsaPss_getRemoteKeyLength(const void *channelContext) {
    /* 32 bytes 256 bits */
    return UA_SECURITYPOLICY_AES256SHA256RSAPSS_SYM_SIGNING_KEY_LENGTH;
}

static UA_StatusCode
UA_ChannelM_Aes256Sha256RsaPss_setRemoteSymSigningKey(void *channelContext,
                                                       const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes256Sha256RsaPss *cc =
        (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    UA_ByteString_clear(&cc->remoteSymSigningKey);
    return UA_ByteString_copy(key, &cc->remoteSymSigningKey);
}

static UA_StatusCode
UA_ChannelM_Aes256Sha256RsaPss_setRemoteSymEncryptingKey(void *channelContext,
                                                          const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes256Sha256RsaPss *cc =
        (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    UA_ByteString_clear(&cc->remoteSymEncryptingKey);
    return UA_ByteString_copy(key, &cc->remoteSymEncryptingKey);
}

static UA_StatusCode
UA_ChannelM_Aes256Sha256RsaPss_setRemoteSymIv(void *channelContext,
                                               const UA_ByteString *key) {
    if(key == NULL || channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes256Sha256RsaPss *cc =
        (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    UA_ByteString_clear(&cc->remoteSymIv);
    return UA_ByteString_copy(key, &cc->remoteSymIv);
}

static UA_StatusCode
UA_AsySig_Aes256Sha256RsaPss_sign(void *channelContext, const UA_ByteString *message,
                                   UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL ||
       signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes256Sha256RsaPss *cc =
        (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    Policy_Context_Aes256Sha256RsaPss *pc = cc->policyContext;
    return UA_Openssl_RSA_PSS_SHA256_Sign(message, pc->localPrivateKey, signature);
}

static UA_StatusCode
UA_AsymEn_Aes256Sha256RsaPss_encrypt(void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes256Sha256RsaPss *cc =
        (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    return UA_Openssl_RSA_OAEP_SHA2_Encrypt(
        data, UA_SECURITYPOLICY_AES256SHA256RSAPSS_RSAPADDING_LEN,
        cc->remoteCertificateX509);
}

static size_t
UA_SymSig_Aes256Sha256RsaPss_getRemoteSignatureSize(const void *channelContext) {
    return UA_SHA256_LENGTH;
}

static UA_StatusCode
UA_SymSig_Aes256Sha256RsaPss_verify(void *channelContext, const UA_ByteString *message,
                                     const UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL ||
       signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_Aes256Sha256RsaPss *cc =
        (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    return UA_OpenSSL_HMAC_SHA256_Verify(message, &cc->remoteSymSigningKey, signature);
}

static UA_StatusCode
UA_SymSig_Aes256Sha256RsaPss_sign(void *channelContext, const UA_ByteString *message,
                                   UA_ByteString *signature) {
    if(channelContext == NULL || message == NULL ||
       signature == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_Aes256Sha256RsaPss *cc =
        (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    return UA_OpenSSL_HMAC_SHA256_Sign(message, &cc->localSymSigningKey, signature);
}

static size_t
UA_SymSig_Aes256Sha256RsaPss_getLocalSignatureSize(const void *channelContext) {
    return UA_SHA256_LENGTH;
}

static UA_StatusCode
UA_SymEn_Aes256Sha256RsaPss_decrypt(void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;
    Channel_Context_Aes256Sha256RsaPss *cc =
        (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    return UA_OpenSSL_AES_256_CBC_Decrypt(&cc->remoteSymIv, &cc->remoteSymEncryptingKey,
                                          data);
}

static UA_StatusCode
UA_SymEn_Aes256Sha256RsaPss_encrypt(void *channelContext, UA_ByteString *data) {
    if(channelContext == NULL || data == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    Channel_Context_Aes256Sha256RsaPss *cc =
        (Channel_Context_Aes256Sha256RsaPss *)channelContext;
    return UA_OpenSSL_AES_256_CBC_Encrypt(&cc->localSymIv, &cc->localSymEncryptingKey,
                                          data);
}

static UA_StatusCode
UA_ChannelM_Aes256Sha256RsaPss_compareCertificate(const void *channelContext,
                                                   const UA_ByteString *certificate) {
    if(channelContext == NULL || certificate == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    const Channel_Context_Aes256Sha256RsaPss *cc =
        (const Channel_Context_Aes256Sha256RsaPss *)channelContext;
    return UA_OpenSSL_X509_compare(certificate, cc->remoteCertificateX509);
}

static size_t
UA_AsymEn_Aes256Sha256RsaPss_getLocalKeyLength(const void *channelContext) {
    if(channelContext == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    const Channel_Context_Aes256Sha256RsaPss *cc =
        (const Channel_Context_Aes256Sha256RsaPss *)channelContext;
    Policy_Context_Aes256Sha256RsaPss *pc = cc->policyContext;
    UA_Int32 keyLen = 0;
    UA_Openssl_RSA_Private_GetKeyLength(pc->localPrivateKey, &keyLen);
    return (size_t)keyLen * 8;
}

/* the main entry of Aes256Sha256RsaPss */

UA_StatusCode
UA_SecurityPolicy_Aes256Sha256RsaPss(UA_SecurityPolicy *policy,
                                      const UA_ByteString localCertificate,
                                      const UA_ByteString localPrivateKey,
                                      const UA_Logger *logger) {

    UA_SecurityPolicyAsymmetricModule *const asymmetricModule = &policy->asymmetricModule;
    UA_SecurityPolicySymmetricModule *const symmetricModule = &policy->symmetricModule;
    UA_SecurityPolicyChannelModule *const channelModule = &policy->channelModule;
    UA_StatusCode retval;

    UA_LOG_INFO(logger, UA_LOGCATEGORY_SECURITYPOLICY,
                "The Aes256Sha256RsaPss security policy with openssl is added.");

    UA_Openssl_Init();
    memset(policy, 0, sizeof(UA_SecurityPolicy));
    policy->logger = logger;
    policy->policyUri =
        UA_STRING("http://opcfoundation.org/UA/SecurityPolicy#Aes256_Sha256_RsaPss\0");
    policy->securityLevel = 20;

    /* set ChannelModule context  */

    channelModule->newContext = UA_ChannelModule_Aes256Sha256RsaPss_New_Context;
    channelModule->deleteContext = UA_ChannelModule_Aes256Sha256RsaPss_Delete_Context;
    channelModule->setLocalSymSigningKey =
        UA_ChannelModule_Aes256Sha256RsaPss_setLocalSymSigningKey;
    channelModule->setLocalSymEncryptingKey =
        UA_ChannelM_Aes256Sha256RsaPss_setLocalSymEncryptingKey;
    channelModule->setLocalSymIv = UA_ChannelM_Aes256Sha256RsaPss_setLocalSymIv;
    channelModule->setRemoteSymSigningKey =
        UA_ChannelM_Aes256Sha256RsaPss_setRemoteSymSigningKey;
    channelModule->setRemoteSymEncryptingKey =
        UA_ChannelM_Aes256Sha256RsaPss_setRemoteSymEncryptingKey;
    channelModule->setRemoteSymIv = UA_ChannelM_Aes256Sha256RsaPss_setRemoteSymIv;
    channelModule->compareCertificate =
        UA_ChannelM_Aes256Sha256RsaPss_compareCertificate;

    /* Copy the certificate and add a NULL to the end */

    retval = UA_copyCertificate(&policy->localCertificate, &localCertificate);
    if(retval != UA_STATUSCODE_GOOD)
        return retval;

    /* AsymmetricModule - signature algorithm */

    UA_SecurityPolicySignatureAlgorithm *asySigAlgorithm =
        &asymmetricModule->cryptoModule.signatureAlgorithm;
    asySigAlgorithm->uri =
        UA_STRING("http://opcfoundation.org/UA/security/rsa-pss-sha2-256\0");
    asySigAlgorithm->verify = UA_AsySig_Aes256Sha256RsaPss_Verify;
    asySigAlgorithm->getRemoteSignatureSize =
        UA_Asym_Aes256Sha256RsaPss_getRemoteSignatureSize;
    asySigAlgorithm->getLocalSignatureSize =
        UA_AsySig_Aes256Sha256RsaPss_getLocalSignatureSize;
    asySigAlgorithm->sign = UA_AsySig_Aes256Sha256RsaPss_sign;
    asySigAlgorithm->getLocalKeyLength = NULL;
    asySigAlgorithm->getRemoteKeyLength = NULL;

    /*  AsymmetricModule encryption algorithm */

    UA_SecurityPolicyEncryptionAlgorithm *asymEncryAlg =
        &asymmetricModule->cryptoModule.encryptionAlgorithm;
    asymEncryAlg->uri = UA_STRING("http://opcfoundation.org/UA/security/rsa-oaep-sha2-256\0");
    asymEncryAlg->decrypt = UA_Asym_Aes256Sha256RsaPss_Decrypt;
    asymEncryAlg->getRemotePlainTextBlockSize =
        UA_AsymEn_Aes256Sha256RsaPss_getRemotePlainTextBlockSize;
    asymEncryAlg->getRemoteBlockSize = UA_AsymEn_Aes256Sha256RsaPss_getRemoteBlockSize;
    asymEncryAlg->getRemoteKeyLength = UA_AsymEn_Aes256Sha256RsaPss_getRemoteKeyLength;
    asymEncryAlg->encrypt = UA_AsymEn_Aes256Sha256RsaPss_encrypt;
    asymEncryAlg->getLocalKeyLength = UA_AsymEn_Aes256Sha256RsaPss_getLocalKeyLength;

    /* asymmetricModule */

    asymmetricModule->compareCertificateThumbprint =
        UA_compareCertificateThumbprint_Aes256Sha256RsaPss;
    asymmetricModule->makeCertificateThumbprint =
        UA_makeCertificateThumbprint_Aes256Sha256RsaPss;

    /* SymmetricModule */

    symmetricModule->secureChannelNonceLength = 32;
    symmetricModule->generateNonce = UA_Sym_Aes256Sha256RsaPss_generateNonce;
    symmetricModule->generateKey = UA_Sym_Aes256Sha256RsaPss_generateKey;

    /* Symmetric encryption Algorithm */

    UA_SecurityPolicyEncryptionAlgorithm *symEncryptionAlgorithm =
        &symmetricModule->cryptoModule.encryptionAlgorithm;
    symEncryptionAlgorithm->uri =
        UA_STRING("http://www.w3.org/2001/04/xmlenc#aes256-cbc\0");
    symEncryptionAlgorithm->getLocalKeyLength = UA_SymEn_Aes256Sha256RsaPss_getLocalKeyLength;
    symEncryptionAlgorithm->getRemoteKeyLength = UA_SymEn_Aes256Sha256RsaPss_getRemoteKeyLength;
    symEncryptionAlgorithm->getRemoteBlockSize = UA_SymEn_Aes256Sha256RsaPss_getBlockSize;
    symEncryptionAlgorithm->getRemotePlainTextBlockSize = UA_SymEn_Aes256Sha256RsaPss_getBlockSize;
    symEncryptionAlgorithm->decrypt = UA_SymEn_Aes256Sha256RsaPss_decrypt;
    symEncryptionAlgorithm->encrypt = UA_SymEn_Aes256Sha256RsaPss_encrypt;

    /* Symmetric signature Algorithm */

    UA_SecurityPolicySignatureAlgorithm *symSignatureAlgorithm =
        &symmetricModule->cryptoModule.signatureAlgorithm;
    symSignatureAlgorithm->uri = UA_STRING("http://www.w3.org/2000/09/xmldsig#hmac-sha2-256\0");
    symSignatureAlgorithm->getLocalKeyLength = UA_SymSig_Aes256Sha256RsaPss_getLocalKeyLength;
    symSignatureAlgorithm->getRemoteKeyLength = UA_SymSig_Aes256Sha256RsaPss_getRemoteKeyLength;
    symSignatureAlgorithm->getRemoteSignatureSize = UA_SymSig_Aes256Sha256RsaPss_getRemoteSignatureSize;
    symSignatureAlgorithm->verify = UA_SymSig_Aes256Sha256RsaPss_verify;
    symSignatureAlgorithm->sign = UA_SymSig_Aes256Sha256RsaPss_sign;
    symSignatureAlgorithm->getLocalSignatureSize = UA_SymSig_Aes256Sha256RsaPss_getLocalSignatureSize;

    retval = UA_Policy_Aes256Sha256RsaPss_New_Context(policy, localPrivateKey, logger);
    if(retval != UA_STATUSCODE_GOOD) {
        UA_ByteString_clear(&policy->localCertificate);
        return retval;
    }
    policy->clear = UA_Policy_Aes256Sha256RsaPss_Clear_Context;

    /* Certificate Signing Algorithm */
    policy->certificateSigningAlgorithm.uri =
        UA_STRING("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256\0");
    policy->certificateSigningAlgorithm.verify =
        (UA_StatusCode (*)(void *, const UA_ByteString *, const UA_ByteString *))UA_CertSig_Aes256Sha256RsaPss_Verify;
    policy->certificateSigningAlgorithm.sign =
        (UA_StatusCode (*)(void *, const UA_ByteString *, UA_ByteString *))UA_CertSig_Aes256Sha256RsaPss_sign;
    policy->certificateSigningAlgorithm.getLocalSignatureSize =
        (size_t (*)(const void *))UA_CertSig_Aes256Sha256RsaPss_getLocalSignatureSize;
    policy->certificateSigningAlgorithm.getRemoteSignatureSize =
        (size_t (*)(const void *))UA_CertSig_Aes256Sha256RsaPss_getRemoteSignatureSize;
    policy->certificateSigningAlgorithm.getLocalKeyLength = NULL; // TODO: Write function
    policy->certificateSigningAlgorithm.getRemoteKeyLength = NULL; // TODO: Write function

    return UA_STATUSCODE_GOOD;
}

#endif

/**** amalgamated original file "/plugins/crypto/openssl/ua_openssl_create_certificate.c" ****/

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 *    Copyright 2021 (c) Christian von Arnim, ISW University of Stuttgart (for VDW and umati)
 *    Copyright 2022 (c) Wind River Systems, Inc.
 *
 */



#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL)


#include <openssl/pem.h>
#include <openssl/x509v3.h>
#include <openssl/err.h>

/**
 * Join an array of UA_String to a single NULL-Terminated UA_String
 * separated by character sep
 */
static UA_StatusCode
join_string_with_sep(const UA_String *strings, size_t stringsSize,
                     char sep, UA_String *out) {
    if(!out)
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    UA_String_clear(out);
    size_t totalSize = stringsSize;
    for(size_t iStr = 0; iStr < stringsSize; ++iStr) {
        totalSize += strings[iStr].length;
    }

    UA_ByteString_allocBuffer(out, totalSize);
    if(!out->data) {
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    size_t pos = 0;
    for(size_t iStr = 0; iStr < stringsSize; ++iStr) {
        memcpy(&out->data[pos], strings[iStr].data, strings[iStr].length);
        pos += strings[iStr].length;
        out->data[pos] = (UA_Byte) sep;
        ++pos;
    }
    out->data[out->length-1] = 0;

    return UA_STATUSCODE_GOOD;
}

/**
 * Search for a character in a string (like strchr).
 * \todo Handle UTF-8
 *
 * \return index of the character or -1 on case of an error.
 */

static UA_Int32
UA_String_chr(const UA_String *pUaStr, char needl) {
    UA_Byte byteNeedl = (UA_Byte)needl;
    for(size_t i = 0; (size_t)i < pUaStr->length; ++i) {
        if(pUaStr->data[i] == byteNeedl) {
            return (UA_Int32) i;
        }
    }
    return -1;
}

/* char *value cannot be const due to openssl 1.0 compatibility */
static UA_StatusCode
add_x509V3ext(const UA_Logger *logger, X509 *x509, int nid, char *value) {
    X509_EXTENSION *ex;
    X509V3_CTX ctx;
    X509V3_set_ctx_nodb(&ctx);
    X509V3_set_ctx(&ctx, x509, x509, NULL, NULL, 0);
    ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value);
    if(!ex)
    {
#if UA_LOGLEVEL <= 300
        const char * file =  NULL;
        int line =  0;
        const char * data =  NULL;
        int flags =  0;
        get_error_line_data(&file, &line, &data, &flags);
        UA_LOG_INFO(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Internal SSL error file: %s:%d data: %s", file, line, data);
#endif
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    X509_add_ext(x509, ex, -1);
    X509_EXTENSION_free(ex);
    return UA_STATUSCODE_GOOD;
}

#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)

/* generate the RSA key */

static EVP_PKEY * UA_RSA_Generate_Key (size_t keySizeBits){
    return EVP_RSA_gen(keySizeBits);
}

#endif

UA_StatusCode
UA_CreateCertificate(const UA_Logger *logger, const UA_String *subject,
                     size_t subjectSize, const UA_String *subjectAltName,
                     size_t subjectAltNameSize, UA_CertificateFormat certFormat,
                     UA_KeyValueMap *params, UA_ByteString *outPrivateKey,
                     UA_ByteString *outCertificate) {
    if(!outPrivateKey || !outCertificate || !logger || !subjectAltName || !subject ||
       subjectAltNameSize == 0 || subjectSize == 0 ||
       (certFormat != UA_CERTIFICATEFORMAT_DER && certFormat != UA_CERTIFICATEFORMAT_PEM))
        return UA_STATUSCODE_BADINVALIDARGUMENT;

    /* Use the maximum size */
    UA_UInt16 keySizeBits = 4096;
    /* Default to 1 year */
    UA_UInt16 expiresInDays = 365;

    if(params) {
        const UA_UInt16 *keySizeBitsValue = (const UA_UInt16 *)UA_KeyValueMap_getScalar(
            params, UA_QUALIFIEDNAME(0, "key-size-bits"), &UA_TYPES[UA_TYPES_UINT16]);
        if(keySizeBitsValue)
            keySizeBits = *keySizeBitsValue;

        const UA_UInt16 *expiresInDaysValue = (const UA_UInt16 *)UA_KeyValueMap_getScalar(
            params, UA_QUALIFIEDNAME(0, "expires-in-days"), &UA_TYPES[UA_TYPES_UINT16]);
        if(expiresInDaysValue)
            expiresInDays = *expiresInDaysValue;
    }

    UA_ByteString_init(outPrivateKey);
    UA_ByteString_init(outCertificate);

    UA_String fullAltSubj = UA_STRING_NULL;
    UA_Int32 serial = 1;

    /** \TODO: Seed Random generator
    * See: (https://www.openssl.org/docs/man1.1.0/man3/RAND_add.html) */
    BIO *memCert = NULL;
    BIO *memPKey = NULL;

    UA_StatusCode errRet = UA_STATUSCODE_GOOD;

    X509 *x509 = X509_new();

#if (OPENSSL_VERSION_NUMBER >= 0x30000000L)
    EVP_PKEY *pkey = UA_RSA_Generate_Key(keySizeBits);
    if((pkey == NULL) || (x509 == NULL)) {
        errRet = UA_STATUSCODE_BADOUTOFMEMORY;
        goto cleanup;
    }    
#else
    BIGNUM *exponent = BN_new();
    EVP_PKEY *pkey = EVP_PKEY_new();
    RSA *rsa = RSA_new();
    if(!pkey || !x509 || !exponent || !rsa) {
        errRet = UA_STATUSCODE_BADOUTOFMEMORY;
        goto cleanup;
    }

    UA_LOG_INFO(logger, UA_LOGCATEGORY_SECURECHANNEL,
                "Create Certificate: Generating RSA key. This may take a while.");

    if(BN_set_word(exponent, RSA_F4) != 1) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Setting RSA exponent failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    if(RSA_generate_key_ex(rsa, (int) keySizeBits, exponent, NULL) != 1) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Generating RSA key failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    if(EVP_PKEY_assign_RSA(pkey, rsa) != 1) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Assign RSA key failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }
    /* rsa will be freed by pkey */
    rsa = NULL;

#endif  /* end of OPENSSL_VERSION_NUMBER >= 0x30000000L */

    /* x509v3 has version 2
     * (https://www.openssl.org/docs/man1.1.0/man3/X509_set_version.html) */
    if(X509_set_version(x509, 2) != 1) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Setting version failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    if(ASN1_INTEGER_set(X509_get_serialNumber(x509), serial) != 1) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Setting serial number failed.");
        /* Only memory errors are possible */
        errRet = UA_STATUSCODE_BADOUTOFMEMORY;
        goto cleanup;
    }

    if(X509_gmtime_adj(X509_get_notBefore(x509), 0) == NULL) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Setting 'not before' failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    if(X509_gmtime_adj(X509_get_notAfter(x509), (UA_Int64)60 * 60 * 24 * expiresInDays) ==
       NULL) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Setting 'not before' failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    if(X509_set_pubkey(x509, pkey) != 1) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Setting publik key failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    X509_NAME *name = X509_get_subject_name(x509);
    if(name == NULL) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Getting name failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    for(UA_UInt32 iSubject = 0; iSubject < subjectSize; ++iSubject) {
        UA_Int32 sep = UA_String_chr(&subject[iSubject], '=');
        char field[16];
        if(sep == -1 || sep == 0 ||
            ((size_t) sep == (subject[iSubject].length - 1)) || sep >= 15) {
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                         "Create Certificate: Subject must contain one '=' with "
                         "content before and after.");
            errRet = UA_STATUSCODE_BADINTERNALERROR;
            goto cleanup;
        }
        memcpy(field, subject[iSubject].data, (size_t) sep);
        field[sep] = 0;
        UA_Byte* pData = &subject[iSubject].data[sep + 1];
        if(X509_NAME_add_entry_by_txt(
               name, field, MBSTRING_ASC,
               (const unsigned char *)pData,
               (int) subject[iSubject].length - (int) sep - 1, -1, 0) != 1) {
            UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                         "Create Certificate: Setting subject failed.");
            errRet = UA_STATUSCODE_BADINTERNALERROR;
            goto cleanup;
        }
    }
    /* Self signed, so issuer == subject */
    if(X509_set_issuer_name(x509, name) != 1) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Setting name failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    errRet = add_x509V3ext(logger, x509, NID_basic_constraints, "CA:FALSE");
    if(errRet != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Setting 'Basic Constraints' failed.");
        goto cleanup;
    }

    /* See https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.3 for
     * possible values */
    errRet = add_x509V3ext(logger, x509, NID_key_usage,
                           "digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment,keyCertSign");
    if(errRet != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Setting 'Key Usage' failed.");
        goto cleanup;
    }

    errRet = add_x509V3ext(logger, x509, NID_ext_key_usage, "serverAuth,clientAuth");
    if(errRet != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Setting 'Extended Key Usage' failed.");
        goto cleanup;
    }

    errRet = add_x509V3ext(logger, x509, NID_subject_key_identifier, "hash");
    if(errRet != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Setting 'Subject Key Identifier' failed.");
        goto cleanup;
    }

    errRet = join_string_with_sep(subjectAltName, subjectAltNameSize, ',', &fullAltSubj);
    if(errRet != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Joining altSubject failed.");
        goto cleanup;
    }

    errRet = add_x509V3ext(logger, x509, NID_subject_alt_name, (char*) fullAltSubj.data);
    if(errRet != UA_STATUSCODE_GOOD) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Setting 'Subject Alternative Name' failed.");
        goto cleanup;
    }

    if(X509_sign(x509, pkey, EVP_sha256()) == 0) {
        UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                     "Create Certificate: Signing failed.");
        errRet = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }

    switch(certFormat) {
        case UA_CERTIFICATEFORMAT_DER: {
            unsigned char *p;
            /* Private Key */
            /* get length */
            outPrivateKey->length = (size_t)i2d_PrivateKey(pkey, NULL);
            if((int)outPrivateKey->length <= 0) {
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                            "Create Certificate: Create private DER key failed.");
                errRet = UA_STATUSCODE_BADINTERNALERROR;
                goto cleanup;
            }
            /* allocate buffer */
            UA_ByteString_allocBuffer(outPrivateKey, outPrivateKey->length);
            memset(outPrivateKey->data, 0, outPrivateKey->length);
            p = outPrivateKey->data;
            i2d_PrivateKey(pkey, &p);

            /* Certificate */
            /* get length */
            outCertificate->length = (size_t)i2d_X509(x509, NULL);
            if((int)outCertificate->length <= 0) {
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                            "Create Certificate: Create DER-certificate failed.");
                errRet = UA_STATUSCODE_BADINTERNALERROR;
                goto cleanup;
            }
            /* allocate buffer */
            UA_ByteString_allocBuffer(outCertificate, outCertificate->length);
            memset(outCertificate->data, 0, outCertificate->length);
            p = outCertificate->data;
            i2d_X509(x509, &p);
            break;
        }
        case UA_CERTIFICATEFORMAT_PEM: {
            /* Private Key */
            memPKey = BIO_new(BIO_s_mem());
            if(!memPKey) {
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                            "Create Certificate: Allocate Membuffer for PKey failed.");
                errRet = UA_STATUSCODE_BADOUTOFMEMORY;
                goto cleanup;
            }

            if(PEM_write_bio_PrivateKey(memPKey, pkey, NULL, NULL, 0, 0, NULL) != 1) {
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                            "Create Certificate: Generate PEM-PrivateKey failed.");
                errRet = UA_STATUSCODE_BADINTERNALERROR;
                goto cleanup;
            }

            UA_ByteString tmpPem = UA_BYTESTRING_NULL;
            tmpPem.length = (size_t) BIO_get_mem_data(memPKey, &tmpPem.data);
            errRet = UA_ByteString_copy(&tmpPem, outPrivateKey);
            if(errRet != UA_STATUSCODE_GOOD) {
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                            "Create Certificate: Copy PEM PKey failed.");
                goto cleanup;
            }

            /* Certificate */
            memCert = BIO_new(BIO_s_mem());
            if(!memCert) {
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                            "Create Certificate: Allocate Membuffer for Cert failed.");
                errRet = UA_STATUSCODE_BADOUTOFMEMORY;
                goto cleanup;
            }

            if(PEM_write_bio_X509(memCert, x509) != 1) {
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                            "Create Certificate: Generate PEM-Certifcate failed.");
                errRet = UA_STATUSCODE_BADINTERNALERROR;
                goto cleanup;
            }

            tmpPem.length = (size_t) BIO_get_mem_data(memCert, &tmpPem.data);
            errRet = UA_ByteString_copy(&tmpPem, outCertificate);
            if(errRet != UA_STATUSCODE_GOOD) {
                UA_LOG_ERROR(logger, UA_LOGCATEGORY_SECURECHANNEL,
                            "Create Certificate: Copy PEM Certificate failed.");
                goto cleanup;
            }
            break;
        }
    }

cleanup:
    UA_String_clear(&fullAltSubj);
#if (OPENSSL_VERSION_NUMBER < 0x30000000L)
    RSA_free(rsa);
    BN_free(exponent);    
#endif
    X509_free(x509);
    EVP_PKEY_free(pkey);
    BIO_free(memCert);
    BIO_free(memPKey);
    return errRet;
}

#endif

/**** amalgamated original file "/plugins/crypto/openssl/ua_certificategroup_openssl.c" ****/

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
 * See http://creativecommons.org/publicdomain/zero/1.0/ for more information.
 *
 *    Copyright 2020 (c) Wind River Systems, Inc.
 *    Copyright 2020 (c) basysKom GmbH
 *    Copyright 2024 (c) Fraunhofer IOSB (Author: Noel Graf)
 */



#if defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL)
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
#include <openssl/x509v3.h>
#include <openssl/pem.h>


#include <limits.h>

/* Find binary substring. Taken and adjusted from
 * http://tungchingkai.blogspot.com/2011/07/binary-strstr.html */

static const unsigned char *
bstrchr(const unsigned char *s, const unsigned char ch, size_t l) {
    /* find first occurrence of c in char s[] for length l*/
    for(; l > 0; ++s, --l) {
        if(*s == ch)
            return s;
    }
    return NULL;
}

static const unsigned char *
UA_Bstrstr(const unsigned char *s1, size_t l1, const unsigned char *s2, size_t l2) {
    /* find first occurrence of s2[] in s1[] for length l1*/
    const unsigned char *ss1 = s1;
    const unsigned char *ss2 = s2;
    /* handle special case */
    if(l1 == 0)
        return (NULL);
    if(l2 == 0)
        return s1;

    /* match prefix */
    for (; (s1 = bstrchr(s1, *s2, (uintptr_t)ss1-(uintptr_t)s1+(uintptr_t)l1)) != NULL &&
             (uintptr_t)ss1-(uintptr_t)s1+(uintptr_t)l1 != 0; ++s1) {

        /* match rest of prefix */
        const unsigned char *sc1, *sc2;
        for (sc1 = s1, sc2 = s2; ;)
            if (++sc2 >= ss2+l2)
                return s1;
            else if (*++sc1 != *sc2)
                break;
    }
    return NULL;
}

typedef struct {
    /*
     * If the folders are defined, we use them to reload the certificates during
     * runtime
     */

    UA_String             trustListFolder;
    UA_String             issuerListFolder;
    UA_String             revocationListFolder;
    /* Used with mbedTLS and UA_ENABLE_CERT_REJECTED_DIR option */
    UA_String             rejectedListFolder;

    STACK_OF(X509) *      skIssue;
    STACK_OF(X509) *      skTrusted;
    STACK_OF(X509_CRL) *  skCrls; /* Revocation list*/

    UA_CertificateGroup *certGroup;
} CertContext;

static UA_StatusCode
UA_CertContext_sk_Init (CertContext * context) {
    context->skTrusted = sk_X509_new_null();
    context->skIssue = sk_X509_new_null();
    context->skCrls = sk_X509_CRL_new_null();
    if (context->skTrusted == NULL || context->skIssue == NULL ||
        context->skCrls == NULL) {
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    return UA_STATUSCODE_GOOD;
}

static void
UA_CertContext_sk_free (CertContext * context) {
    sk_X509_pop_free (context->skTrusted, X509_free);
    sk_X509_pop_free (context->skIssue, X509_free);
    sk_X509_CRL_pop_free (context->skCrls, X509_CRL_free);
}

static UA_StatusCode
UA_CertContext_Init (CertContext * context, UA_CertificateGroup *certGroup) {
    (void) memset (context, 0, sizeof (CertContext));
    UA_ByteString_init (&context->trustListFolder);
    UA_ByteString_init (&context->issuerListFolder);
    UA_ByteString_init (&context->revocationListFolder);
    UA_ByteString_init (&context->rejectedListFolder);

    context->certGroup = certGroup;

    return UA_CertContext_sk_Init (context);
}

static void
UA_CertificateGroup_clear (UA_CertificateGroup *certGroup) {
    if (certGroup == NULL) {
        return;
    }
    CertContext * context = (CertContext *) certGroup->context;
    if (context == NULL) {
        return;
    }
    UA_ByteString_clear (&context->trustListFolder);
    UA_ByteString_clear (&context->issuerListFolder);
    UA_ByteString_clear (&context->revocationListFolder);
    UA_ByteString_clear (&context->rejectedListFolder);

    UA_CertContext_sk_free (context);
    context->certGroup = NULL;
    UA_free (context);

    certGroup->context = NULL;

    return;
}

static UA_StatusCode
UA_skTrusted_Cert2X509 (const UA_ByteString *   certificateTrustList,
                        size_t                  certificateTrustListSize,
                        CertContext *           ctx) {
    size_t                i;

    for (i = 0; i < certificateTrustListSize; i++) {
        X509 * x509 = UA_OpenSSL_LoadCertificate(&certificateTrustList[i]);

        if (x509 == NULL) {
            return UA_STATUSCODE_BADINTERNALERROR;
        }
        sk_X509_push (ctx->skTrusted, x509);
    }

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_skIssuer_Cert2X509 (const UA_ByteString *   certificateIssuerList,
                       size_t                  certificateIssuerListSize,
                       CertContext *           ctx) {
    size_t                i;

    for (i = 0; i < certificateIssuerListSize; i++) {
        X509 * x509 = UA_OpenSSL_LoadCertificate(&certificateIssuerList[i]);

        if (x509 == NULL) {
            return UA_STATUSCODE_BADINTERNALERROR;
        }
        sk_X509_push (ctx->skIssue, x509);
    }

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_skCrls_Cert2X509 (const UA_ByteString *   certificateRevocationList,
                     size_t                  certificateRevocationListSize,
                     CertContext *           ctx) {
    size_t                i;
    const unsigned char * pData;

    for (i = 0; i < certificateRevocationListSize; i++) {
        pData = certificateRevocationList[i].data;
        X509_CRL * crl = NULL;

        if (certificateRevocationList[i].length > 1 && pData[0] == 0x30 && pData[1] == 0x82) { // Magic number for DER encoded files
            crl = d2i_X509_CRL (NULL, &pData, (long) certificateRevocationList[i].length);
        } else {
            BIO* bio = NULL;
            bio = BIO_new_mem_buf((void *) certificateRevocationList[i].data,
                                  (int) certificateRevocationList[i].length);
            crl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL);
            BIO_free(bio);
        }

        if (crl == NULL) {
            return UA_STATUSCODE_BADINTERNALERROR;
        }
        sk_X509_CRL_push (ctx->skCrls, crl);
    }

    return UA_STATUSCODE_GOOD;
}

#ifdef __linux__
#include <dirent.h>

static int UA_Certificate_Filter_der_pem (const struct dirent * entry) {
    /* ignore hidden files */
    if (entry->d_name[0] == '.') return 0;

    /* check file extension */
    const char *pszFind = strrchr(entry->d_name, '.');
    if (pszFind == 0)
        return 0;
    pszFind++;
    if (strcmp (pszFind, "der") == 0 || strcmp (pszFind, "pem") == 0)
        return 1;

    return 0;
}

static int UA_Certificate_Filter_crl (const struct dirent * entry) {

    /* ignore hidden files */
    if (entry->d_name[0] == '.') return 0;

    /* check file extension */
    const char *pszFind = strrchr(entry->d_name, '.');
    if (pszFind == 0)
        return 0;
    pszFind++;
    if (strcmp (pszFind, "crl") == 0)
        return 1;

    return 0;
}

static UA_StatusCode
UA_BuildFullPath (const char * path,
                  const char * fileName,
                  size_t       fullPathBufferLength,
                  char *       fullPath) {
    size_t  pathLen = strlen (path);
    size_t  fileNameLen = strlen (fileName);
    if ((pathLen + fileNameLen + 2) > fullPathBufferLength) {
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }
    strcpy (fullPath, path);
    strcat (fullPath, "/");
    strcat (fullPath, fileName);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_loadCertFromFile (const char *     fileName,
                     UA_ByteString *  cert) {

    FILE * fp = fopen(fileName, "rb");

    if (fp == NULL)
        return UA_STATUSCODE_BADINTERNALERROR;

    fseek(fp, 0, SEEK_END);
    cert->length = (size_t)  ftell(fp);
    if (UA_ByteString_allocBuffer (cert, cert->length) != UA_STATUSCODE_GOOD) {
        fclose (fp);
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }
    fseek(fp, 0, SEEK_SET);
    size_t readLen = fread (cert->data, 1, cert->length, fp);
    if (readLen != cert->length) {
        UA_ByteString_clear (cert);
        cert->length = 0;
        fclose (fp);
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    fclose (fp);

    return UA_STATUSCODE_GOOD;
}

static UA_StatusCode
UA_ReloadCertFromFolder (CertContext * ctx) {
    UA_StatusCode    ret;
    struct dirent ** dirlist = NULL;
    int              i;
    int              numCertificates;
    char             certFile[PATH_MAX];
    UA_ByteString    strCert;
    char             folderPath[PATH_MAX];

    UA_ByteString_init (&strCert);

    if (ctx->trustListFolder.length > 0) {
        UA_LOG_INFO(ctx->certGroup->logging, UA_LOGCATEGORY_SERVER, "Reloading the trust-list");

        sk_X509_pop_free (ctx->skTrusted, X509_free);
        ctx->skTrusted = sk_X509_new_null();
        if (ctx->skTrusted == NULL) {
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }

        (void) memcpy (folderPath, ctx->trustListFolder.data,
                       ctx->trustListFolder.length);
        folderPath[ctx->trustListFolder.length] = 0;
        numCertificates = scandir(folderPath, &dirlist,
                                  UA_Certificate_Filter_der_pem,
                                  alphasort);
        for (i = 0; i < numCertificates; i++) {
            if (UA_BuildFullPath (folderPath, dirlist[i]->d_name,
                                  PATH_MAX, certFile) != UA_STATUSCODE_GOOD) {
                continue;
            }
            ret = UA_loadCertFromFile (certFile, &strCert);
            if (ret != UA_STATUSCODE_GOOD) {
                UA_LOG_INFO(ctx->certGroup->logging, UA_LOGCATEGORY_SERVER,
                            "Failed to load the certificate file %s", certFile);
                continue;  /* continue or return ? */
            }
            if (UA_skTrusted_Cert2X509 (&strCert, 1, ctx) != UA_STATUSCODE_GOOD) {
                UA_LOG_INFO (ctx->certGroup->logging, UA_LOGCATEGORY_SERVER,
                            "Failed to decode the certificate file %s", certFile);
                UA_ByteString_clear (&strCert);
                continue;  /* continue or return ? */
            }
            UA_ByteString_clear (&strCert);
        }
    }

    if (ctx->issuerListFolder.length > 0) {
        UA_LOG_INFO(ctx->certGroup->logging, UA_LOGCATEGORY_SERVER, "Reloading the issuer-list");

        sk_X509_pop_free (ctx->skIssue, X509_free);
        ctx->skIssue = sk_X509_new_null();
        if (ctx->skIssue == NULL) {
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }

        memcpy (folderPath, ctx->issuerListFolder.data, ctx->issuerListFolder.length);
        folderPath[ctx->issuerListFolder.length] = 0;
        numCertificates = scandir(folderPath, &dirlist,
                                  UA_Certificate_Filter_der_pem,
                                  alphasort);
        for (i = 0; i < numCertificates; i++) {
            if (UA_BuildFullPath (folderPath, dirlist[i]->d_name,
                                  PATH_MAX, certFile) != UA_STATUSCODE_GOOD) {
                continue;
            }
            ret = UA_loadCertFromFile (certFile, &strCert);
            if (ret != UA_STATUSCODE_GOOD) {
                UA_LOG_INFO (ctx->certGroup->logging, UA_LOGCATEGORY_SERVER,
                            "Failed to load the certificate file %s", certFile);
                continue;  /* continue or return ? */
            }
            if (UA_skIssuer_Cert2X509 (&strCert, 1, ctx) != UA_STATUSCODE_GOOD) {
                UA_LOG_INFO (ctx->certGroup->logging, UA_LOGCATEGORY_SERVER,
                            "Failed to decode the certificate file %s", certFile);
                UA_ByteString_clear (&strCert);
                continue;  /* continue or return ? */
            }
            UA_ByteString_clear (&strCert);
        }
    }

    if (ctx->revocationListFolder.length > 0) {
        UA_LOG_INFO(ctx->certGroup->logging, UA_LOGCATEGORY_SERVER, "Reloading the revocation-list");

        sk_X509_CRL_pop_free (ctx->skCrls, X509_CRL_free);
        ctx->skCrls = sk_X509_CRL_new_null();
        if (ctx->skCrls == NULL) {
            return UA_STATUSCODE_BADOUTOFMEMORY;
        }

        memcpy (folderPath, ctx->revocationListFolder.data, ctx->revocationListFolder.length);
        folderPath[ctx->revocationListFolder.length] = 0;
        numCertificates = scandir(folderPath, &dirlist,
                                  UA_Certificate_Filter_crl,
                                  alphasort);
        for (i = 0; i < numCertificates; i++) {
            if (UA_BuildFullPath (folderPath, dirlist[i]->d_name,
                                  PATH_MAX, certFile) != UA_STATUSCODE_GOOD) {
                continue;
            }
            ret = UA_loadCertFromFile (certFile, &strCert);
            if (ret != UA_STATUSCODE_GOOD) {
                UA_LOG_INFO (ctx->certGroup->logging, UA_LOGCATEGORY_SERVER,
                            "Failed to load the revocation file %s", certFile);
                continue;  /* continue or return ? */
            }
            if (UA_skCrls_Cert2X509 (&strCert, 1, ctx) != UA_STATUSCODE_GOOD) {
                UA_LOG_INFO (ctx->certGroup->logging, UA_LOGCATEGORY_SERVER,
                            "Failed to decode the revocation file %s", certFile);
                UA_ByteString_clear (&strCert);
                continue;  /* continue or return ? */
            }
            UA_ByteString_clear (&strCert);
        }
    }

    ret = UA_STATUSCODE_GOOD;
    return ret;
}

#endif  /* end of __linux__ */

static UA_StatusCode
UA_X509_Store_CTX_Error_To_UAError (int opensslErr) {
    UA_StatusCode ret;

    switch (opensslErr) {
        case X509_V_ERR_CERT_HAS_EXPIRED:
        case X509_V_ERR_CERT_NOT_YET_VALID:
        case X509_V_ERR_CRL_NOT_YET_VALID:
        case X509_V_ERR_CRL_HAS_EXPIRED:
        case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
        case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
        case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
        case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
            ret = UA_STATUSCODE_BADCERTIFICATETIMEINVALID;
            break;
        case X509_V_ERR_CERT_REVOKED:
            ret = UA_STATUSCODE_BADCERTIFICATEREVOKED;
            break;
        case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
        case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
        case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
            ret = UA_STATUSCODE_BADCERTIFICATEUNTRUSTED;
            break;
        case X509_V_ERR_CERT_SIGNATURE_FAILURE:
        case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
            ret = UA_STATUSCODE_BADSECURITYCHECKSFAILED;
            break;
        case X509_V_ERR_UNABLE_TO_GET_CRL:
            ret = UA_STATUSCODE_BADCERTIFICATEREVOCATIONUNKNOWN;
            break;
        default:
            ret = UA_STATUSCODE_BADCERTIFICATEINVALID;
            break;
        }
    return ret;
    }

static UA_StatusCode
UA_CertificateGroup_Verify(UA_CertificateGroup *certGroup,
                           const UA_ByteString *certificate) {
    X509_STORE_CTX *storeCtx = NULL;
    X509_STORE *store = NULL;
    CertContext *ctx = NULL;
    UA_StatusCode ret = UA_STATUSCODE_GOOD;

    if ((certGroup == NULL) || (certGroup->context == NULL)) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    ctx = (CertContext *) certGroup->context;

    /* Parse the certificate */
    X509 *certificateX509 = UA_OpenSSL_LoadCertificate(certificate);
    if(!certificateX509) {
        ret = UA_STATUSCODE_BADCERTIFICATEINVALID;
        goto cleanup;
    }

    /* Reload PKI folder */
#ifdef __linux__
    ret = UA_ReloadCertFromFolder (ctx);
    if(ret != UA_STATUSCODE_GOOD)
        goto cleanup;
#endif

    /* Accept the certificate without verification of no trust and issuer list
     * are loaded */
    if(sk_X509_CRL_num(ctx->skCrls) == 0 &&
       sk_X509_num(ctx->skIssue) == 0 &&
       sk_X509_num(ctx->skTrusted) == 0) {
        UA_LOG_WARNING(certGroup->logging, UA_LOGCATEGORY_USERLAND,
                       "No certificate store configured. Accepting the certificate.");
        goto cleanup;
    }

    store = X509_STORE_new();
    storeCtx = X509_STORE_CTX_new();
    if(store == NULL || storeCtx == NULL) {
        ret = UA_STATUSCODE_BADOUTOFMEMORY;
        goto cleanup;
    }

    X509_STORE_set_flags(store, 0);
    int opensslRet = X509_STORE_CTX_init(storeCtx, store, certificateX509,
                                          ctx->skIssue);
    if(opensslRet != 1) {
        ret = UA_STATUSCODE_BADINTERNALERROR;
        goto cleanup;
    }
#if defined(OPENSSL_API_COMPAT) && OPENSSL_API_COMPAT < 0x10100000L
	(void) X509_STORE_CTX_trusted_stack (storeCtx, ctx->skTrusted);
#else
	(void) X509_STORE_CTX_set0_trusted_stack (storeCtx, ctx->skTrusted);
#endif

    /* Set crls to ctx */
    if (sk_X509_CRL_num (ctx->skCrls) > 0) {
        X509_STORE_CTX_set0_crls (storeCtx, ctx->skCrls);
    }

    /* Set flag to check if the certificate has an invalid signature */
    X509_STORE_CTX_set_flags (storeCtx, X509_V_FLAG_CHECK_SS_SIGNATURE);

    if (X509_check_issued(certificateX509,certificateX509) != X509_V_OK) {
        X509_STORE_CTX_set_flags (storeCtx, X509_V_FLAG_CRL_CHECK);
    }

    /* This condition will check whether the certificate is a User certificate or a CA certificate.
     * If the KU_KEY_CERT_SIGN and KU_CRL_SIGN of key_usage are set, then the certificate shall be
     * condidered as CA Certificate and cannot be used to establish a connection. Refer the test case
     * CTT/Security/Security Certificate Validation/029.js for more details */
     /** \todo Can the ca-parameter of X509_check_purpose can be used? */
    if(X509_check_purpose(certificateX509, X509_PURPOSE_CRL_SIGN, 0) && X509_check_ca(certificateX509)) {
        return UA_STATUSCODE_BADCERTIFICATEUSENOTALLOWED;
    }

    opensslRet = X509_verify_cert (storeCtx);
    if (opensslRet == 1) {
        ret = UA_STATUSCODE_GOOD;

        /* Check if the not trusted certificate has a CRL file. If there is no CRL file available for the corresponding
         * parent certificate then return status code UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN. Refer the test
         * case CTT/Security/Security Certificate Validation/002.js */
        if (X509_check_issued(certificateX509,certificateX509) != X509_V_OK) {
            /* Free X509_STORE_CTX and reuse it for certification verification */
            if (storeCtx != NULL) {
               X509_STORE_CTX_free(storeCtx);
            }

            /* Initialised X509_STORE_CTX sructure*/
            storeCtx = X509_STORE_CTX_new();

            /* Sets up X509_STORE_CTX structure for a subsequent verification operation */
            X509_STORE_set_flags(store, 0);
            X509_STORE_CTX_init (storeCtx, store, certificateX509,ctx->skIssue);

            /* Set trust list to ctx */
            (void) X509_STORE_CTX_trusted_stack (storeCtx, ctx->skTrusted);

            /* Set crls to ctx */
            X509_STORE_CTX_set0_crls (storeCtx, ctx->skCrls);

            /* Set flags for CRL check */
            X509_STORE_CTX_set_flags (storeCtx, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);

            opensslRet = X509_verify_cert (storeCtx);
            if (opensslRet != 1) {
                opensslRet = X509_STORE_CTX_get_error (storeCtx);
                if (opensslRet == X509_V_ERR_UNABLE_TO_GET_CRL) {
                    ret = UA_STATUSCODE_BADCERTIFICATEISSUERREVOCATIONUNKNOWN;
                }
            }
        }
    }
    else {
        opensslRet = X509_STORE_CTX_get_error (storeCtx);

        /* Check the issued certificate of a CA that is not trusted but available */
        if(opensslRet == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN){
            int                     trusted_cert_len = sk_X509_num(ctx->skTrusted);
            int                     cmpVal;
            X509                    *trusted_cert;
            const ASN1_OCTET_STRING *trusted_cert_keyid;
            const ASN1_OCTET_STRING *remote_cert_keyid;

            for (int i = 0; i < trusted_cert_len; i++) {
                trusted_cert = sk_X509_value(ctx->skTrusted, i);

                /* Fetch the Subject key identifier of the certificate in trust list */
                trusted_cert_keyid = X509_get0_subject_key_id(trusted_cert);

                /* Fetch the Subject key identifier of the remote certificate */
                remote_cert_keyid = X509_get0_subject_key_id(certificateX509);

                /* Check remote certificate is present in the trust list */
                cmpVal = ASN1_OCTET_STRING_cmp(trusted_cert_keyid, remote_cert_keyid);
                if (cmpVal == 0){
                    ret = UA_STATUSCODE_GOOD;
                    goto cleanup;
                }
            }
        }

        /* Return expected OPCUA error code */
        ret = UA_X509_Store_CTX_Error_To_UAError (opensslRet);
    }

cleanup:
    if(store)
        X509_STORE_free(store);
    if(storeCtx)
        X509_STORE_CTX_free(storeCtx);
    if(certificateX509)
        X509_free(certificateX509);
    return ret;
}

/* main entry */

UA_StatusCode
UA_CertificateVerification_Trustlist(UA_CertificateGroup *certGroup,
                                     const UA_ByteString *certificateTrustList,
                                     size_t certificateTrustListSize,
                                     const UA_ByteString *certificateIssuerList,
                                     size_t certificateIssuerListSize,
                                     const UA_ByteString *certificateRevocationList,
                                     size_t certificateRevocationListSize) {
    UA_StatusCode ret;

    if (certGroup == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    if (certGroup->logging == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Clear if the plugin is already initialized */
    if(certGroup->clear)
        certGroup->clear(certGroup);

    CertContext * context = (CertContext *) UA_malloc (sizeof (CertContext));
    if (context == NULL) {
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    ret = UA_CertContext_Init (context, certGroup);
    if (ret != UA_STATUSCODE_GOOD) {
        UA_free(context);
        return ret;
    }

    certGroup->context = context;
    certGroup->verifyCertificate = UA_CertificateGroup_Verify;
    certGroup->clear = UA_CertificateGroup_clear;
    certGroup->getTrustList = NULL;
    certGroup->setTrustList = NULL;
    certGroup->addToTrustList = NULL;
    certGroup->removeFromTrustList = NULL;

    if (certificateTrustListSize > 0) {
        if (UA_skTrusted_Cert2X509 (certificateTrustList, certificateTrustListSize,
                                    context) != UA_STATUSCODE_GOOD) {
            ret = UA_STATUSCODE_BADINTERNALERROR;
            goto errout;
        }
    }

    if (certificateIssuerListSize > 0) {
        if (UA_skIssuer_Cert2X509 (certificateIssuerList, certificateIssuerListSize,
                                  context) != UA_STATUSCODE_GOOD) {
            ret = UA_STATUSCODE_BADINTERNALERROR;
            goto errout;
        }
    }

    if (certificateRevocationListSize > 0) {
        if (UA_skCrls_Cert2X509 (certificateRevocationList, certificateRevocationListSize,
                                  context) != UA_STATUSCODE_GOOD) {
            ret = UA_STATUSCODE_BADINTERNALERROR;
            goto errout;
        }
    }

    return UA_STATUSCODE_GOOD;

errout:
    UA_CertificateGroup_clear(certGroup);
    return ret;
}

#ifdef __linux__ /* Linux only so far */
UA_StatusCode
UA_CertificateVerification_CertFolders(UA_CertificateGroup *certGroup,
                                       const char *trustListFolder,
                                       const char *issuerListFolder,
                                       const char *revocationListFolder) {
    UA_StatusCode ret;
    if (certGroup == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }
    if (certGroup->logging == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Clear if the plugin is already initialized */
    if(certGroup->clear)
        certGroup->clear(certGroup);

    CertContext * context = (CertContext *) UA_malloc (sizeof (CertContext));
    if (context == NULL) {
        return UA_STATUSCODE_BADOUTOFMEMORY;
    }

    ret = UA_CertContext_Init (context, certGroup);
    if (ret != UA_STATUSCODE_GOOD) {
        UA_free(context);
        return ret;
    }

    certGroup->context = context;
    certGroup->verifyCertificate = UA_CertificateGroup_Verify;
    certGroup->clear = UA_CertificateGroup_clear;
    certGroup->getTrustList = NULL;
    certGroup->setTrustList = NULL;
    certGroup->addToTrustList = NULL;
    certGroup->removeFromTrustList = NULL;

    /* Only set the folder paths. They will be reloaded during runtime. */
    context->trustListFolder = UA_STRING_ALLOC(trustListFolder);
    context->issuerListFolder = UA_STRING_ALLOC(issuerListFolder);
    context->revocationListFolder = UA_STRING_ALLOC(revocationListFolder);

    return UA_STATUSCODE_GOOD;
}
#endif

static int
privateKeyPasswordCallback(char *buf, int size, int rwflag, void *userdata) {
    (void) rwflag;
    UA_ByteString *pw = (UA_ByteString*)userdata;
    if(pw->length <= (size_t)size)
        memcpy(buf, pw->data, pw->length);
    return (int)pw->length;
}

UA_StatusCode
UA_CertificateUtils_verifyApplicationURI(UA_RuleHandling ruleHandling,
                                         const UA_ByteString *certificate,
                                         const UA_String *applicationURI) {
    const unsigned char * pData;
    X509 *                certificateX509;
    UA_String             subjectURI = UA_STRING_NULL;
    GENERAL_NAMES *       pNames;
    int                   i;
    UA_StatusCode         ret;

    pData = certificate->data;
    if (pData == NULL) {
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    }

    certificateX509 = UA_OpenSSL_LoadCertificate(certificate);
    if (certificateX509 == NULL) {
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    }

    pNames = (GENERAL_NAMES *) X509_get_ext_d2i(certificateX509, NID_subject_alt_name,
                                                NULL, NULL);
    if (pNames == NULL) {
        X509_free (certificateX509);
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
    }

    UA_String_init(&subjectURI);

    for (i = 0; i < sk_GENERAL_NAME_num (pNames); i++) {
        GENERAL_NAME * value = sk_GENERAL_NAME_value (pNames, i);
        if (value->type == GEN_URI) {
            subjectURI.length = (size_t) (value->d.ia5->length);
            subjectURI.data = (UA_Byte *) UA_malloc (subjectURI.length);
            if (subjectURI.data == NULL) {
                X509_free (certificateX509);
                sk_GENERAL_NAME_pop_free(pNames, GENERAL_NAME_free);
                return UA_STATUSCODE_BADSECURITYCHECKSFAILED;
            }
            (void) memcpy (subjectURI.data, value->d.ia5->data, subjectURI.length);
            break;
        }

    }

    ret = UA_STATUSCODE_GOOD;
    if (UA_Bstrstr (subjectURI.data, subjectURI.length,
                    applicationURI->data, applicationURI->length) == NULL) {
        ret = UA_STATUSCODE_BADCERTIFICATEURIINVALID;
    }

    if(ret != UA_STATUSCODE_GOOD && ruleHandling == UA_RULEHANDLING_DEFAULT) {
        UA_LOG_WARNING(UA_Log_Stdout, UA_LOGCATEGORY_SERVER,
                       "The certificate's application URI could not be verified. StatusCode %s",
                       UA_StatusCode_name(ret));
        ret = UA_STATUSCODE_GOOD;
    }

    X509_free (certificateX509);
    sk_GENERAL_NAME_pop_free(pNames, GENERAL_NAME_free);
    UA_String_clear (&subjectURI);
    return ret;
}

UA_StatusCode
UA_CertificateUtils_getExpirationDate(UA_ByteString *certificate,
                                      UA_DateTime *expiryDateTime) {
    const unsigned char *pData = certificate->data;
    X509 * x509 = d2i_X509 (NULL, &pData, (long)certificate->length);
    if (x509 == NULL) {
        return UA_STATUSCODE_BADINTERNALERROR;
    }

    /* Get the certificate Expiry date */
    ASN1_TIME *not_after = X509_get_notAfter(x509);

    struct tm dtTime;
    ASN1_TIME_to_tm(not_after, &dtTime);
    X509_free(x509);

    struct mytm dateTime;
    memset(&dateTime, 0, sizeof(struct mytm));
    dateTime.tm_year = dtTime.tm_year;
    dateTime.tm_mon = dtTime.tm_mon;
    dateTime.tm_mday = dtTime.tm_mday;
    dateTime.tm_hour = dtTime.tm_hour;
    dateTime.tm_min = dtTime.tm_min;
    dateTime.tm_sec = dtTime.tm_sec;

    long long sec_epoch = __tm_to_secs(&dateTime);
    *expiryDateTime = UA_DATETIME_UNIX_EPOCH;
    *expiryDateTime += sec_epoch * UA_DATETIME_SEC;
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_CertificateUtils_getSubjectName(UA_ByteString *certificate,
                                   UA_String *subjectName) {
    const unsigned char *pData = certificate->data;
    X509 *x509 = d2i_X509 (NULL, &pData, (long)certificate->length);
    if(!x509)
        return UA_STATUSCODE_BADINTERNALERROR;
    X509_NAME *sn = X509_get_subject_name(x509);
    char buf[1024];
    *subjectName = UA_STRING_ALLOC(X509_NAME_oneline(sn, buf, 1024));
    X509_free(x509);
    return UA_STATUSCODE_GOOD;
}

UA_StatusCode
UA_CertificateUtils_decryptPrivateKey(const UA_ByteString privateKey,
                                      const UA_ByteString password,
                                      UA_ByteString *outDerKey) {
    if(!outDerKey)
        return UA_STATUSCODE_BADINTERNALERROR;

    if (privateKey.length == 0) {
        *outDerKey = UA_BYTESTRING_NULL;
        return UA_STATUSCODE_BADINVALIDARGUMENT;
    }

    /* Already in DER format -> return verbatim */
    if(privateKey.length > 1 && privateKey.data[0] == 0x30 && privateKey.data[1] == 0x82)
        return UA_ByteString_copy(&privateKey, outDerKey);

    /* Decrypt */
    BIO *bio = BIO_new_mem_buf((void*)privateKey.data, (int)privateKey.length);
    EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, NULL,
                                             privateKeyPasswordCallback,
                                             (void*)(uintptr_t)&password);
    BIO_free(bio);
    if(!pkey)
        return UA_STATUSCODE_BADSECURITYCHECKSFAILED;

    /* Write DER encoded, allocates the new memory */
    unsigned char *data = NULL;
    const int numBytes = i2d_PrivateKey(pkey, &data);
    EVP_PKEY_free(pkey);
    if(!data)
        return UA_STATUSCODE_BADOUTOFMEMORY;

    /* Copy to the data to outDerKey
     * Passing the data pointer directly causes a heap corruption on Windows
     * when outDerKey is cleared.
     */
    UA_ByteString temp = UA_BYTESTRING_NULL;
    temp.data = data;
    temp.length = (size_t)numBytes;
    const UA_StatusCode success = UA_ByteString_copy(&temp, outDerKey);
    /* OPENSSL_clear_free() is not supported by the LibreSSL version in the CI */
    OPENSSL_cleanse(data, numBytes);
    OPENSSL_free(data);
    return success;
}

#endif  /* end of defined(UA_ENABLE_ENCRYPTION_OPENSSL) || defined(UA_ENABLE_ENCRYPTION_LIBRESSL) */
