text:
#include <complex.h>
#include <stdbool.h>
#include <assert.h>
#include <string.h>
#include <stdio.h>

#ifdef _WIN32
#include <malloc.h>
#else
#include <alloca.h>
#endif

#include "num/multind.h"
#include "num/iovec.h"
#include "num/flpmath.h"
#include "num/ops_graph.h"

#include "misc/misc.h"
#include "misc/types.h"
#include "misc/debug.h"
#include "misc/shrdptr.h"
#include "misc/nested.h"
#include "misc/list.h"
#include "misc/graph.h"

#ifdef _OPENMP
#include <omp.h>
#endif

#ifdef USE_CUDA
#include "num/gpuops.h"
#endif

#include "ops.h"

#ifndef CFL_SIZE
#define CFL_SIZE sizeof(complex float)
#endif
#ifndef FL_SIZE
#define FL_SIZE sizeof(float)
#endif

struct operator_s {

	unsigned int N;
	const bool* io_flags;
	const struct iovec_s** domain;

	operator_data_t* data;
	void (*apply)(const operator_data_t* data, unsigned int N, void* args[N]);
	void (*del)(const operator_data_t* data);

	const struct graph_s* (*get_graph)(const struct operator_s* op);

	struct shared_obj_s sptr;
};

static void operator_del(const struct shared_obj_s* sptr)
{
	const struct operator_s* x = CONTAINER_OF(sptr, const struct operator_s, sptr);

	if (NULL != x->del)
		x->del(x->data);

	for (unsigned int i = 0; i < x->N; i++)
		iovec_free(x->domain[i]);

	xfree(x->domain);
	xfree(x->io_flags);
	xfree(x);
}

/**
 * Create an operator (with strides)
 */
const struct operator_s* operator_generic_create2(unsigned int N, const bool io_flags[N],
			const unsigned int D[N], const long* dims[N], const long* strs[N],
			operator_data_t* data, operator_fun_t apply, operator_del_t del, operator_get_graph_t get_graph)
{
	PTR_ALLOC(struct operator_s, op);
	PTR_ALLOC(const struct iovec_s*[N], dom);

	for (unsigned int i = 0; i < N; i++)
		(*dom)[i] = iovec_create2(D[i], dims[i], strs[i], CFL_SIZE);

	op->N = N;
	op->io_flags = ARR_CLONE(_Bool[N], io_flags);
	op->domain = *PTR_PASS(dom);
	op->data = data;
	op->apply = apply;
	op->del = del;
	op->get_graph = get_graph;

	shared_obj_init(&op->sptr, operator_del);

	return PTR_PASS(op);
}

/**
 * Create an operator (without strides)
 */
const struct operator_s* operator_generic_create(unsigned int N, const bool io_flags[N],
			const unsigned int D[N], const long* dims[N],
			operator_data_t* data, operator_fun_t apply, operator_del_t del, operator_get_graph_t get_graph)
{
	const long* strs[N];

	for (unsigned int i = 0; i < N; i++)
		strs[i] = MD_STRIDES(D[i], dims[i], CFL_SIZE);

	return operator_generic_create2(N, io_flags, D, dims, strs, data, apply, del, get_graph);
}

/**
 * Create an operator (with strides)
 */
const struct operator_s* operator_create2(unsigned int ON, const long out_dims[ON], const long out_strs[ON],
			unsigned int IN, const long in_dims[IN], const long in_strs[IN],
			operator_data_t* data, operator_fun_t apply, operator_del_t del)
{
	return operator_generic_create2(2, (bool[2]){ true, false }, (unsigned int[2]){ ON, IN },
				(const long* [2]){ out_dims, in_dims }, (const long* [2]){ out_strs, in_strs },
				data, apply, del, NULL);
}

/**
 * Create an operator (without strides)
 *
 * @param ON number of output dimensions
 * @param out_dims dimensions of output
 * @param IN number of input dimensions
 * @param in_dims dimensions of input
 * @param data data for applying the operation
 * @param apply function that applies the operation
 * @param del function that frees the data
 */
const struct operator_s* operator_create(unsigned int ON, const long out_dims[ON],
		unsigned int IN, const long in_dims[IN],
		operator_data_t* data, operator_fun_t apply, operator_del_t del)
{
	return operator_create2(ON, out_dims, MD_STRIDES(ON, out_dims, CFL_SIZE),
				IN, in_dims, MD_STRIDES(IN, in_dims, CFL_SIZE),
				data, apply, del);
}

/**
 * Increment the reference count of an operator
 *
 * @param x operator
 */
const struct operator_s* operator_ref(const struct operator_s* x)
{
	if (NULL != x)
		shared_obj_ref(&x->sptr);

	return x;
}

/**
 * Decrement the reference count of an operator
 *
 * @param x operator
 */
const struct operator_s* operator_unref(const struct operator_s* x)
{
	if (NULL != x)
		shared_obj_unref(&x->sptr);

	return x;
}

void operator_debug(enum debug_levels dl, const struct operator_s* x)
{
	int N = operator_nr_args(x);

	debug_printf(dl, "OPERATOR\n");

	for (int i = 0; i < N; i++) {

		debug_printf(dl, "%d : ", x->io_flags[i]);
		auto io = x->domain[i];
		debug_print_dims(dl, io->N, io->dims);
	}
}

/**
 * Return the data of the associated operator
 *
 * @param x operator
 */
operator_data_t* operator_get_data(const struct operator_s* x)
{
	return x->data;
}

const bool* operator_get_io_flags(const struct operator_s* x)
{
	return x->io_flags;
}

/**
 * Free the operator struct
 * Note: also frees the data if the operator's reference count is zero
 *
 * @param x operator
 */
void operator_free(const struct operator_s* x)
{
	if (NULL == x)
		return;

	shared_obj_destroy(&x->sptr);
}

/**
 * Return the number of args
 *
 * @param op operator
 */
unsigned int operator_nr_args(const struct operator_s* op)
{
	return op->N;
}

/**
 * Return the number of input args
 *
 * @param op operator
 */
unsigned int operator_nr_in_args(const struct operator_s* op)
{
	return operator_nr_args(op) - operator_nr_out_args(op);
}

/**
 * Return the number of input args
 *
 * @param op operator
 */
unsigned int operator_nr_out_args(const struct operator_s* op)
{
	unsigned int N = operator_nr_args(op);
	unsigned int O = 0;

	for (unsigned int i = 0; i < N; i++)
		if (op->io_flags[i])
			O++;

	return O;
}

/**
 * Return the iovec of arg n
 *
 * @param op operator
 * @param n  arg number
 */
const struct iovec_s* operator_arg_domain(const struct operator_s* op, unsigned int n)
{
	assert(n < op->N);
	return op->domain[n];
}

/**
 * Return the iovec of input arg n
 *
 * @param op operator
 * @param n input arg number
 */
const struct iovec_s* operator_arg_in_domain(const struct operator_s* op, unsigned int n)
{
	assert(n < operator_nr_in_args(op));

	unsigned int count = 0;
	unsigned int index = 0;

	for (; count <= n; index++)
		if (!op->io_flags[index])
			count++;

	return operator_arg_domain(op, index - 1);
}

/**
 * Return the iovec of output arg n
 *
 * @param op operator
 * @param n output arg number
 */
const struct iovec_s* operator_arg_out_codomain(const struct operator_s* op, unsigned int n)
{
	assert(n < operator_nr_out_args(op));

	unsigned int count = 0;
	unsigned int index = 0;

	for (; count <= n; index++)
		if (op->io_flags[index])
			count++;

	return operator_arg_domain(op, index - 1);
}

/**
 * Return the dimensions and strides of the domain of an operator
 *
 * @param op operator
 */
const struct iovec_s* operator_domain(const struct operator_s* op)
{
	assert(2 == op->N);
	assert(op->io_flags[0]);
	assert(!op->io_flags[1]);

	return operator_arg_domain(op, 1);
}

/**
 * Return the dimensions and strides of the codomain of an operator
 *
 * @param op operator
 */
const struct iovec_s* operator_codomain(const struct operator_s* op)
{
	assert(2 == op->N);
	assert(op->io_flags[0]);
	assert(!op->io_flags[1]);

	return operator_arg_domain(op, 0);
}

struct identity_s {

	INTERFACE(operator_data_t);

	const struct iovec_s* domain;
	const struct iovec_s* codomain;
};

static DEF_TYPEID(identity_s);

static const struct identity_s* get_identity_data(const struct operator_s* op)
{
	return CAST_MAYBE(identity_s, operator_get_data(op));
}

static void identity_apply(const operator_data_t* _data, unsigned int N, void* args[N])
{
	const auto d = CAST_DOWN(identity_s, _data);
	assert(2 == N);
	md_copy2(d->domain->N, d->domain->dims, d->codomain->strs, args[0], d->domain->strs, args[1], d->domain->size);
}

static void identity_free(const operator_data_t* _data)
{
	const auto d = CAST_DOWN(identity_s, _data);
	iovec_free(d->domain);
	iovec_free(d->codomain);
	xfree(d);
}

const struct operator_s* operator_identity_create2(unsigned int N, const long dims[N],
					const long ostrs[N], const long istrs[N])
{
	PTR_ALLOC(struct identity_s, data);
	SET_TYPEID(identity_s, data);

	data->domain = iovec_create2(N, dims, istrs, CFL_SIZE);
	data->codomain = iovec_create2(N, dims, ostrs, CFL_SIZE);

	return operator_create2(N, dims, ostrs, N, dims, istrs, CAST_UP(PTR_PASS(data)), identity_apply, identity_free);
}

/**
 * Create an Identity operator: I x
 * @param N number of dimensions
 * @param dims dimensions of input (domain)
 */
const struct operator_s* operator_identity_create(unsigned int N, const long dims[N])
{
	long strs[N];
	md_calc_strides(N, strs, dims, CFL_SIZE);
	return operator_identity_create2(N, dims, strs, strs);
}

/**
 * Create a Reshape operator: I x
 * @param A number of out dimensions
 * @param out_dims dimensions of output (codomain)
 * @param B number of in dimensions
 * @param in_dims dimensions of input (domain)
 */
const struct operator_s* operator_reshape_create(unsigned int A, const long out_dims[A], int B, const long in_dims[B])
{
	auto id = operator_identity_create(A, out_dims);
	auto result = operator_reshape(id, 1, B, in_dims);
	operator_free(id);
	return result;
}

struct op_reshape_s {

	INTERFACE(operator_data_t);

	const struct operator_s* x;
};

static DEF_TYPEID(op_reshape_s );

static const struct op_reshape_s* get_reshape_data(const struct operator_s* op)
{
	return CAST_MAYBE(op_reshape_s, operator_get_data(op));
}

static void reshape_apply(const operator_data_t* _data, unsigned int N, void* args[N])
{
	const auto d = CAST_DOWN(op_reshape_s, _data);
	operator_generic_apply_unchecked(d->x, N, args);
}

static void reshape_free(const operator_data_t* _data)
{
	const auto d = CAST_DOWN(op_reshape_s, _data);
	operator_free(d->x);
	xfree(d);
}

static const struct graph_s* operator_reshape_get_graph(const struct operator_s* op)
{
	const auto d = CAST_DOWN(op_reshape_s, op->data);
	auto result = operator_get_graph(d->x);
	for (unsigned int i = 0; i < op->N; i++)
		result = operator_graph_reshape_F(result, i, op->domain[i]->N, op->domain[i]->dims);
	return result;
}

const struct operator_s* operator_reshape(const struct operator_s* op, unsigned int i, long N, const long dims[N])
{
	PTR_ALLOC(struct op_reshape_s, data);
	SET_TYPEID(op_reshape_s, data);

	assert(md_calc_size(N, dims) == md_calc_size(operator_arg_domain(op, i)->N, operator_arg_domain(op, i)->dims));

	auto opdata_test = CAST_MAYBE(op_reshape_s, op->data);
	if (NULL != opdata_test)
		data->x = operator_ref(opdata_test->x);
	else
		data->x = operator_ref(op);

	long strs[N];
	md_calc_strides(N, strs, dims, operator_arg_domain(op, i)->size);

	unsigned int A = operator_nr_args(op);
	unsigned int D[A];
	const long* op_dims[A];
	const long* op_strs[A];

	for (unsigned int j = 0; j < A; j++) {

		auto iov = operator_arg_domain(op, j);
		D[j] = iov->N;
		op_dims[j] = iov->dims;
		op_strs[j] = iov->strs;
	}

	D[i] = N;
	op_dims[i] = dims;
	op_strs[i] = strs;

	return operator_generic_create2(A, op->io_flags, D, op_dims, op_strs, CAST_UP(PTR_PASS(data)), reshape_apply, reshape_free, operator_reshape_get_graph);
}

bool check_simple_copy(const struct operator_s* op)
{
	if (NULL != get_identity_data(op))
		return true;

	if (NULL != get_reshape_data(op))
		return check_simple_copy(get_reshape_data(op)->x);

	return false;
}

const struct operator_s* get_in_reshape(const struct operator_s* op) {

	if (NULL != get_reshape_data(op))
		return get_reshape_data(op)->x;

	return NULL;
}

struct zero_s {

	INTERFACE(operator_data_t);

	const struct iovec_s* codomain;
};

static DEF_TYPEID(zero_s);

static void zero_apply(const operator_data_t* _data, unsigned int N, void* args[N])
{
	auto d = CAST_DOWN(zero_s, _data);
	assert(1 == N);

	md_clear2(d->codomain->N, d->codomain->dims, d->codomain->strs, args[0], d->codomain->size);
}

static void zero_free(const operator_data_t* _data)
{
	auto d = CAST_DOWN(zero_s, _data);
	iovec_free(d->codomain);
	xfree(d);
}

const struct operator_s* operator_zero_create2(unsigned int N, const long dims[N], const long strs[N])
{
	PTR_ALLOC(struct zero_s, data);
	SET_TYPEID(zero_s, data);

	data->codomain = iovec_create2(N, dims, strs, CFL_SIZE);

	return operator_generic_create2(1, (bool[1]){ true }, (unsigned int[1]){ N },
			(const long*[1]){ dims },
			(const long*[2]){ strs }, CAST_UP(PTR_PASS(data)), zero_apply, zero_free, NULL);
}

const struct operator_s* operator_zero_create(unsigned int N, const long dims[N])
{
	return operator_zero_create2(N, dims, MD_STRIDES(N, dims, CFL_SIZE));
}

struct null_s {

	INTERFACE(operator_data_t);
};

static DEF_TYPEID(null_s);

static void null_apply(const operator_data_t* _data, unsigned int N, void* args[N])
{
	UNUSED(_data);
	UNUSED(args);

	assert(1 == N);
}

static void null_free(const operator_data_t* _data)
{
	xfree(CAST_DOWN(null_s, _data));
}

const struct operator_s* operator_null_create2(unsigned int N, const long dims[N], const long strs[N])
{
	PTR_ALLOC(struct null_s, data);
	SET_TYPEID(null_s, data);

	return operator_generic_create2(1, (bool[1]){ false }, (unsigned int[1]){ N },
			(const long*[1]){ dims },
			(const long*[2]){ strs }, CAST_UP(PTR_PASS(data)), null_apply, null_free, NULL);
}

const struct operator_s* operator_null_create(unsigned int N, const long dims[N])
{
	return operator_null_create2(N, dims, MD_STRIDES(N, dims, CFL_SIZE));
}

void operator_generic_apply_unchecked(const struct operator_s* op, unsigned int N, void* args[N])
{
	assert(op->N == N);
	debug_trace("ENTER %p\n", op->apply);
	op->apply(op->data, N, args);
	debug_trace("LEAVE %p\n", op->apply);
}

void operator_generic_apply_parallel_unchecked(int D, const struct operator_s* op[__VLA(D)], unsigned int N, void* args[__VLA(D)][N], int num_threads)
{
#ifdef _OPENMP
	if (0 < num_threads) {

		int max_threads = omp_get_max_threads();
		omp_set_num_threads(num_threads);

		struct cuda_threads_s* gpu_stat = gpu_threads_create(NULL);

		#pragma omp parallel
		{
			gpu_threads_enter(gpu_stat);

			for (int i = omp_get_thread_num(); i < D; i += omp_get_num_threads())
				operator_generic_apply_unchecked(op[i], N, args[i]);

			gpu_threads_leave(gpu_stat);
		}

		gpu_threads_free(gpu_stat);

		omp_set_num_threads(max_threads);

		return;
	}
#else
	UNUSED(num_threads);
#endif

	for (int i = 0; i < D; i++)
		operator_generic_apply_unchecked(op[i], N, args[i]);
}

void operator_apply_unchecked(const struct operator_s* op, complex float* dst, const complex float* src)
{
	assert(op->io_flags[0]);
	assert(!op->io_flags[1]);

	operator_generic_apply_unchecked(op, 2, (void*[2]){ (void*)dst, (void*)src });
}

void operator_apply_parallel_unchecked(int D, const struct operator_s* op[D], complex float* dst[D], const complex float* src[D], int num_threads)
{
	void* args[D][2];

	for (int i = 0; i < D; i++) {

		assert(op[i]->io_flags[0]);
		assert(!op[i]->io_flags[1]);

		args[i][0] = dst[i];
		args[i][1] = (void*)src[i];
	}

	operator_generic_apply_parallel_unchecked(D, op, 2, args, num_threads);
}

void operator_apply2(const struct operator_s* op, unsigned int ON, const long odims[ON], const long ostrs[ON], complex float* dst, const long IN, const long idims[IN], const long istrs[ON], const complex float* src)
{
	assert(2 == op->N);
	assert(iovec_check(op->domain[1], IN, idims, istrs));
	assert(iovec_check(op->domain[0], ON, odims, ostrs));

	operator_apply_unchecked(op, dst, src);
}

void operator_apply(const struct operator_s* op, unsigned int ON, const long odims[ON], complex float* dst, const long IN, const long idims[IN], const complex float* src)
{
	operator_apply2(op, ON, odims, MD_STRIDES(ON, odims, CFL_SIZE), dst,
			    IN, idims, MD_STRIDES(IN, idims, CFL_SIZE), src);
}

struct attach_data_s {

	INTERFACE(operator_data_t);

	const struct operator_s* op;

	void* ptr;
	void (*del)(const void* ptr);
};

static DEF_TYPEID(attach_data_s);

static void attach_fun(const operator_data_t* _data, unsigned int N, void* args[N])
{
	const auto op = CAST_DOWN(attach_data_s, _data)->op;

	operator_generic_apply_unchecked(op, N, args);
}

static void attach_del(const operator_data_t* _data)
{
	const auto data = CAST_DOWN(attach_data_s, _data);

	operator_free(data->op);

	data->del(data->ptr);

	xfree(data);
}

const struct operator_s* operator_attach(const struct operator_s* op, void* ptr, void (*del)(const void* ptr))
{
	unsigned int N = operator_nr_args(op);

	unsigned int D[N];
	const long* dims[N];
	const long* strs[N];

	for (unsigned int i = 0; i < N; i++) {

		const struct iovec_s* io = operator_arg_domain(op, i);

		D[i] = io->N;
		dims[i] = io->dims;
		strs[i] = io->strs;
	}

	// op = operator_ref(op);
	PTR_ALLOC(struct attach_data_s, data);
	SET_TYPEID(attach_data_s, data);

	data->op = operator_ref(op);
	data->ptr = ptr;
	data->del = del;

	return operator_generic_create2(N, op->io_flags, D, dims, strs, CAST_UP(PTR_PASS(data)), attach_fun, attach_del, NULL);
}

struct op_bind_s {

	INTERFACE(operator_data_t);

	unsigned int D;
	unsigned int arg;

	const struct operator_s* op;
	void* ptr;
};

static DEF_TYPEID(op_bind_s);

static void op_bind_apply(const operator_data_t* _data, unsigned int N, void* args[N])
{
	const auto data = CAST_DOWN(op_bind_s, _data);
	assert(data->D == N + 1);

	void* n_args[N + 1];

	for (unsigned int i = 0, j = 0; i < N; i++, j++) {

		// insert bound argument

		if (data->arg == i)
			n_args[j++] = data->ptr;

		n_args[j] = args[i];
	}

	operator_generic_apply_unchecked(data->op, N + 1, n_args);
}

static void op_bind_del(const operator_data_t* _data)
{
	const auto data = CAST_DOWN(op_bind_s, _data);

	operator_free(data->op);

	xfree(data);
}

/**
 * Create a new operator that binds argument 'arg'.
 */
const struct operator_s* operator_bind2(const struct operator_s* op, unsigned int arg,
			unsigned int N, const long dims[N], const long strs[N], void* ptr)
{
	unsigned int D = operator_nr_args(op);
	assert(arg < D);
	assert(!op->io_flags[arg]);
	assert(iovec_check(operator_arg_domain(op, arg), N, dims, strs));

	unsigned int nn[D - 1];
	const long* ndims[D - 1];
	const long* nstrs[D - 1];

	bool n_flags[D + 1];

	for (unsigned int i = 0; i < D + 1; i++)
		n_flags[i] = false;

	for (unsigned int i = 0, j = 0; i < D; i++) {

		if (arg == i)
			continue;

		nn[j] = operator_arg_domain(op, i)->N;
		ndims[j] = operator_arg_domain(op, i)->dims;
		nstrs[j] = operator_arg_domain(op, i)->strs;

		if (op->io_flags[i])
			n_flags[j] = true;

		j++;
	}

	PTR_ALLOC(struct op_bind_s, data);
	SET_TYPEID(op_bind_s, data);

	data->D = D;
	data->arg = arg;
	data->ptr = ptr;
	data->op = operator_ref(op);

	return operator_generic_create2(D - 1, n_flags,
		nn, ndims, nstrs,
		CAST_UP(PTR_PASS(data)), op_bind_apply, op_bind_del, NULL);
}

struct op_loop_s {

	INTERFACE(operator_data_t);

	unsigned int N;
	unsigned int D;
	const long** strs;
	const long** dims;
	const long* dims0;
	const struct operator_s* op;

	unsigned int parallel;
	bool gpu;
};

static DEF_TYPEID(op_loop_s);

static void op_loop_del(const operator_data_t* _data)
{
	const auto data = CAST_DOWN(op_loop_s, _data);
	operator_free(data->op);

	for (unsigned int i = 0; i < data->N; i++) {

		xfree(data->dims[i]);
		xfree(data->strs[i]);
	}

	xfree(data->strs);
	xfree(data->dims);
	xfree(data->dims0);
	xfree(data);
}

static void op_loop_fun(const operator_data_t* _data, unsigned int N, void* args[N])
{
	const auto data = CAST_DOWN(op_loop_s, _data);
	assert(N == data->N);

	if (data->gpu) {
#if defined(USE_CUDA) && defined(_OPENMP)
		int nr_cuda_devices = cuda_num_devices();
		omp_set_num_threads(nr_cuda_devices * 2);
//		fft_set_num_threads(1);
#else
		error("Both OpenMP and CUDA are necessary for op_loop_fun. At least one was not found.\n");
#endif
	}

	extern bool num_auto_parallelize;
	bool ap_save = num_auto_parallelize;
	num_auto_parallelize = false;

	struct cuda_threads_s* gpu_stat = gpu_threads_create(NULL);

	NESTED(void, op_loop_nary, (void* ptr[]))
	{
		gpu_threads_enter(gpu_stat);
		operator_generic_apply_unchecked(data->op, data->N, ptr);
		gpu_threads_leave(gpu_stat);
	};

	md_parallel_nary(N, data->D, data->dims0, data->parallel, data->strs, args, op_loop_nary);

	gpu_threads_free(gpu_stat);

	num_auto_parallelize = ap_save;
}

static void merge_dims(unsigned int D, long odims[D], const long idims1[D], const long idims2[D])
{
	md_copy_dims(D, odims, idims1);

	for (unsigned int i = 0; i < D; i++) {

		assert((1 == odims[i]) || (1 == idims2[i]));

		if (1 == odims[i])
			odims[i] = idims2[i];
	}
}

const struct operator_s* operator_loop_parallel2(unsigned int N, unsigned int D,
				const long dims[D], const long (*strs)[D],
				const struct operator_s* op,
				unsigned int flags, bool gpu)

{
	assert(N == operator_nr_args(op));

	unsigned int D2[N];
	PTR_ALLOC(long[D], dims0);
	md_copy_dims(D, *dims0, dims);

	PTR_ALLOC(const long*[N], dims2);
	PTR_ALLOC(const long*[N], strs2);

	// TODO: we should have a flag and ignore args with flag

	for (int i = 0; i < (int)N; i++) {

		const struct iovec_s* io = operator_arg_domain(op, i);

		assert((int)D == io->N);

		for (int j = 0; j < (int)D; j++) {

			assert((0 == io->strs[j]) || (io->strs[j] == strs[i][j]));
			assert((1 == io->dims[j]) == (0 == io->strs[j]));
		}

		D2[i] = D;

		PTR_ALLOC(long[D], tdims);
		merge_dims(D, *tdims, dims, io->dims);

		PTR_ALLOC(long[D], tstrs);
		md_copy_strides(D, *tstrs, strs[i]);

		(*dims2)[i] = *PTR_PASS(tdims);
		(*strs2)[i] = *PTR_PASS(tstrs);
	}

	PTR_ALLOC(struct op_loop_s, data);
	SET_TYPEID(op_loop_s, data);
	data->N = N;
	data->D = D;
	data->op = operator_ref(op);

	data->dims0 = *PTR_PASS(dims0);
	data->dims = */*PTR_PASS*/(dims2);
	data->strs = */*PTR_PASS*/(strs2);

	data->parallel = flags;
	data->gpu = gpu;

	const struct operator_s* rop = operator_generic_create2(N, op->io_flags, D2, *dims2, *strs2, CAST_UP(PTR_PASS(data)), op_loop_fun, op_loop_del, NULL);

	PTR_PASS(dims2);
	PTR_PASS(strs2);

	return rop;
}

const struct operator_s* (operator_loop2)(unsigned int N, const unsigned int D,
				const long dims[D], const long (*strs)[D],
				const struct operator_s* op)
{
	return operator_loop_parallel2(N, D, dims, strs, op, 0u, false);
}

const struct operator_s* operator_loop_parallel(unsigned int D, const long dims[D], const struct operator_s* op, unsigned int parallel, bool gpu)
{
	unsigned int N = operator_nr_args(op);
	long strs[N][D];

	for (unsigned int i = 0; i < N; i++) {

		long tdims[D];
		merge_dims(D, tdims, dims, operator_arg_domain(op, i)->dims);

		md_calc_strides(D, strs[i], tdims, operator_arg_domain(op, i)->size);
	}

	return operator_loop_parallel2(N, D, dims, strs, op, parallel, gpu);
}

const struct operator_s* operator_loop(unsigned int D, const long dims[D], const struct operator_s* op)
{
	return operator_loop_parallel(D, dims, op, 0u, false);
}

struct copy_data_s {

	INTERFACE(operator_data_t);

	const struct operator_s* op;

	const void* ref;

	unsigned int N;
	const long** strs;
};

static DEF_TYPEID(copy_data_s);

static void copy_fun(const operator_data_t* _data, unsigned int N, void* args[N])
{
	const auto data = CAST_DOWN(copy_data_s, _data);
	const struct operator_s* op = data->op;
	void* ptr[N];
	bool allocated[N];

	assert(N == operator_nr_args(op));

	for (unsigned int i = 0; i < N; i++) {

		const struct iovec_s* io = operator_arg_domain(op, i);

		allocated[i] = (!md_check_equal_dims(io->N, io->strs, data->strs[i], ~0) || ((NULL != data->ref) && !md_is_sameplace(data->ref, args[i])));

		if (allocated[i]) {

			ptr[i] = md_alloc_sameplace(io->N, io->dims, io->size, NULL == data->ref ? args[i] : data->ref);

			if (!op->io_flags[i])
				md_copy2(io->N, io->dims, io->strs, ptr[i], data->strs[i], args[i], io->size);
		} else {

			ptr[i] = args[i];
		}
	}

	operator_generic_apply_unchecked(op, N, ptr);

	for (unsigned int i = 0; i < N; i++) {

		const struct iovec_s* io = operator_arg_domain(op, i);

		if (op->io_flags[i] && allocated[i])
			md_copy2(io->N, io->dims, data->strs[i], args[i], io->strs, ptr[i], io->size);

		if (allocated[i])
			md_free(ptr[i]);
	}
}

static void copy_del(const operator_data_t* _data)
{
	const auto data = CAST_DOWN(copy_data_s, _data);

	operator_free(data->op);
	md_free(data->ref);

	for (unsigned int i = 0; i < data->N; i++)
		xfree(data->strs[i]);

	xfree(data->strs);
	xfree(data);
}

const struct operator_s* operator_copy_wrapper_sameplace(unsigned int N, const long* strs[N], const struct operator_s* op, const void* ref)
{
	assert(N == operator_nr_args(op));

	PTR_ALLOC(struct copy_data_s, data);
	SET_TYPEID(copy_data_s, data);
	data->op = operator_ref(op);

	unsigned int D[N];
	const long* dims[N];
	const long* (*strs2)[N] = TYPE_ALLOC(const long*[N]);

	for (int i = 0; i < (int)N; i++) {

		const struct iovec_s* io = operator_arg_domain(op, i);

		D[i] = io->N;
		dims[i] = io->dims;

		long (*strsx)[io->N] = TYPE_ALLOC(long[io->N]);
		md_copy_strides(io->N, *strsx, strs[i]);
		(*strs2)[i] = *strsx;

		// check for trivial strides

		long tstrs[io->N];
		md_calc_strides(io->N, tstrs, io->dims, CFL_SIZE);

		for (int i = 0; i < io->N; i++)
			if (1 != io->dims[i])
				assert(io->strs[i] == tstrs[i]);
	}

	data->N = N;
	data->strs = *strs2;
	data->ref = (NULL == ref) ? NULL : md_alloc_sameplace(1, MD_DIMS(1), FL_SIZE, ref);

	return operator_generic_create2(N, op->io_flags, D, dims, *strs2, CAST_UP(PTR_PASS(data)), copy_fun, copy_del, NULL);
}

const struct operator_s* operator_copy_wrapper(unsigned int N, const long* strs[N], const struct operator_s* op)
{
	return operator_copy_wrapper_sameplace(N, strs, op, NULL);
}

struct gpu_data_s {

	INTERFACE(operator_data_t);

	long move_flags;
	const struct operator_s* op;
};

static DEF_TYPEID(gpu_data_s);

#if defined(USE_CUDA) && defined(_OPENMP)
#include <omp.h>
#define MAX_CUDA_DEVICES 16
omp_nest_lock_t gpulock[MAX_CUDA_DEVICES];
#endif

static void gpuwrp_fun(const operator_data_t* _data, unsigned int N, void* args[N])
{
#if defined(USE_CUDA) && defined(_OPENMP)
	const auto data = CAST_DOWN(gpu_data_s, _data);
	const auto op = data->op;
	void* gpu_ptr[N];

	assert(N == operator_nr_args(op));

	debug_printf(DP_DEBUG1, "GPU start.\n");

	int nr_cuda_devices = MIN(cuda_num_devices(), MAX_CUDA_DEVICES);
	int gpun = omp_get_thread_num() % nr_cuda_devices;

	cuda_set_device(gpun);

	for (unsigned int i = 0; i < N; i++) {

		if (!MD_IS_SET(data->move_flags, i)) {

			gpu_ptr[i] = args[i];
			continue;
		}

		const struct iovec_s* io = operator_arg_domain(op, i);

		if (op->io_flags[i])
			gpu_ptr[i] = md_alloc_gpu(io->N, io->dims, io->size);
		else
			gpu_ptr[i] = md_gpu_move(io->N, io->dims, args[i], io->size);
	}

	omp_set_nest_lock(&gpulock[gpun]);
	operator_generic_apply_unchecked(op, N, gpu_ptr);
	omp_unset_nest_lock(&gpulock[gpun]);

	for (unsigned int i = 0; i < N; i++) {

		if (!MD_IS_SET(data->move_flags, i))
			continue;

		const struct iovec_s* io = operator_arg_domain(op, i);

		if (op->io_flags[i])
			md_copy(io->N, io->dims, args[i], gpu_ptr[i], io->size);

		md_free(gpu_ptr[i]);
	}

	debug_printf(DP_DEBUG1, "GPU end.\n");

#else
	UNUSED(_data); UNUSED(N); UNUSED(args);
	error("Both OpenMP and CUDA are necessary for automatic GPU execution. At least one was not found.\n");
#endif
}

static void gpuwrp_del(const operator_data_t* _data)
{
	const auto data = CAST_DOWN(gpu_data_s, _data);

	operator_free(data->op);

	xfree(data);
}

const struct operator_s* operator_gpu_wrapper2(const struct operator_s* op, long move_flags)
{
	unsigned int N = operator_nr_args(op);
	assert(N <= 8 * sizeof(move_flags));

	unsigned int D[N];
	const long* dims[N];
	const long* strs[N];

	for (unsigned int i = 0; i < N; i++) {

		const struct iovec_s* io = operator_arg_domain(op, i);

		D[i] = io->N;
		dims[i] = io->dims;
		strs[i] = io->strs;
	}

	// op = operator_ref(op);
	PTR_ALLOC(struct gpu_data_s, data);
	SET_TYPEID(gpu_data_s, data);

	data->move_flags = move_flags;
	data->op = operator_ref(op);

	return operator_generic_create2(N, op->io_flags, D, dims, strs, CAST_UP(PTR_PASS(data)), gpuwrp_fun, gpuwrp_del, NULL);
}

const struct operator_s* operator_gpu_wrapper(const struct operator_s* op)
{
	return operator_gpu_wrapper2(op, ~0L);
}

struct operator_combi_s {

	INTERFACE(operator_data_t);

	int N;
	const struct operator_s** x;
};

static DEF_TYPEID(operator_combi_s);

static void combi_apply(const operator_data_t* _data, unsigned int N, void* args[N])
{
	auto data = CAST_DOWN(operator_combi_s, _data);

	debug_printf(DP_DEBUG4, "combi apply: ops: %d args: %d\n", data->N, N);

	int off = N;

	for (int i = (int)data->N - 1; 0 <= i; i--) {

		int A = operator_nr_args(data->x[i]);

		off -= A;

		for (int a = 0; a < A; a++)
			debug_printf(DP_DEBUG4, "combi apply: op[%d].arg[%d] == %p\n", i, a, args[off + a]);

		assert(0 <= off);
		assert(off < (int)N);

		operator_generic_apply_unchecked(data->x[i], A, args + off);
	}

	assert(0 == off);
}

static void combi_free(const operator_data_t* _data)
{
	auto data = CAST_DOWN(operator_combi_s, _data);

	for (int i = 0; i < data->N; i++)
		operator_free(data->x[i]);

	xfree(data->x);
	xfree(data);
}

static const struct graph_s* operator_combi_get_graph(const struct operator_s* op)
{
	const auto d = CAST_DOWN(operator_combi_s, op->data);
	const struct graph_s* tmp_graphs[d->N];
	for (int i = 0; i < d->N; i++)
		tmp_graphs[i] = operator_get_graph(d->x[i]);
	return operator_graph_combine_F(d->N, tmp_graphs);
}

/**
 * Create a new operator that combines several others
 */
const struct operator_s* operator_combi_create(int N, const struct operator_s* x[N])
{
	PTR_ALLOC(struct operator_combi_s, c);
	SET_TYPEID(operator_combi_s, c);

	PTR_ALLOC(const struct operator_s*[N], xp);

	for (int i = 0; i < N; i++)
		(*xp)[i] = operator_ref(x[i]);

	c->x = *PTR_PASS(xp);
	c->N = N;

	int A = 0;

	for (int i = 0; i < N; i++)
		A += operator_nr_args(x[i]);

	bool io_flags[A];
	unsigned int D[A];
	const long* dims[A];
	const long* strs[A];

	int a = 0;

	for (int i = 0; i < N; i++) {

		for (int j = 0; j < (int)operator_nr_args(x[i]); j++) {

			auto iov = operator_arg_domain(x[i], j);

			D[a] = iov->N;
			dims[a] = iov->dims;
			strs[a] = iov->strs;

			io_flags[a] = x[i]->io_flags[j];
			a++;
		}
	}

	return operator_generic_create2(A, io_flags, D, dims, strs, CAST_UP(PTR_PASS(c)), combi_apply, combi_free, operator_combi_get_graph);
}

struct operator_dup_s {

	INTERFACE(operator_data_t);

	int a;
	int b;
	const struct operator_s* x;
};

static DEF_TYPEID(operator_dup_s);

static void dup_apply(const operator_data_t* _data, unsigned int N, void* args[N])
{
	auto data = CAST_DOWN(operator_dup_s, _data);

	debug_printf(DP_DEBUG4, "dup apply: duplicating %d-%d from %d (io flags: %d)\n",
				data->a, data->b, N + 1, data->x->io_flags);

	void* args2[N + 1];

	for (int i = 0, j = 0; j < (int)(N + 1); j++) {

		if (data->b == j)
			continue;

		args2[j] = args[i++];
	}

	assert(N > 0);

	auto iov = operator_arg_domain(data->x, data->a);
	auto iovb = operator_arg_domain(data->x, data->b);

	assert(iovec_check(iovb, iov->N, iov->dims, iov->strs));

	assert(N + 1 == operator_nr_args(data->x));

	args2[data->b] = args2[data->a];

	operator_generic_apply_unchecked(data->x, N + 1, args2);
}

static void dup_del(const operator_data_t* _data)
{
	auto data = CAST_DOWN(operator_dup_s, _data);

	operator_free(data->x);
	xfree(data);
}

static const struct graph_s* operator_dup_get_graph(const struct operator_s* op)
{
	const auto d = CAST_DOWN(operator_dup_s, op->data);
	return operator_graph_dup_F(operator_get_graph(d->x), d->a, d->b);
}

const struct operator_s* operator_dup_create(const struct operator_s* op, unsigned int a, unsigned int b)
{
	unsigned int N = operator_nr_args(op);

	assert(a < N);
	assert(b < N);
	assert(a != b);

	bool io_flags[N - 1];
	unsigned int D[N - 1];
	const long* dims[N - 1];
	const long* strs[N - 1];

	debug_printf(DP_DEBUG4, "Duplicating args %d-%d of %d.\n", a, b, N);

	for (unsigned int s = 0, t = 0; s < N; s++) {

		if (s == b)
			continue;

		auto io = operator_arg_domain(op, s);

		D[t] = io->N;
		dims[t] = io->dims;
		strs[t] = io->strs;

		io_flags[t] = op->io_flags[s];

		t++;
	}

	auto ioa = operator_arg_domain(op, a);
	auto iob = operator_arg_domain(op, b);

	assert((int)ioa->N == md_calc_blockdim(ioa->N, ioa->dims, ioa->strs, ioa->size));
	assert((int)iob->N == md_calc_blockdim(iob->N, iob->dims, iob->strs, iob->size));

	PTR_ALLOC(struct operator_dup_s, data);
	SET_TYPEID(operator_dup_s, data);

	data->a = a;
	data->b = b;
	data->x = operator_ref(op);

	return operator_generic_create2(N - 1, io_flags, D, dims, strs, CAST_UP(PTR_PASS(data)), dup_apply, dup_del, operator_dup_get_graph);
}

// FIXME: we should reimplement link in terms of dup and bind (caveat: gpu; io_flags)
struct operator_link_s {

	INTERFACE(operator_data_t);

	int a;
	int b;
	const struct operator_s* x;
};

static DEF_TYPEID(operator_link_s);

static void link_apply(const operator_data_t* _data, unsigned int N, void* args[N])
{
	auto data = CAST_DOWN(operator_link_s, _data);

	debug_printf(DP_DEBUG4, "link apply: linking %d-%d of %d (io flags: %d)\n",
				data->a, data->b, N + 2, data->x->io_flags);

	void* args2[N + 2];

	for (int i = 0, j = 0; j < (int)(N + 2); j++) {

		if ((data->a == j) || (data->b == j))
			continue;

		debug_printf(DP_DEBUG4, "link apply: in arg[%d] = %p\n", i, args[i]);
		debug_printf(DP_DEBUG4, "link apply: mapping %d -> %d\n", i, j);

		args2[j] = args[i++];
	}

	assert(N > 0);

	auto iov = operator_arg_domain(data->x, data->a);
	auto iovb = operator_arg_domain(data->x, data->b);

	assert(iovec_check(iovb, iov->N, iov->dims, iov->strs));

#ifdef USE_CUDA
	// Allocate tmp on GPU when one argument is on the GPU.
	// The scalar parameters of op_p may be on CPU.

	bool gpu = false;

	for (unsigned int i = 0; i < N; i++)
		gpu = gpu || cuda_ondevice(args[i]);

	void* tmp = (gpu ? md_alloc_gpu : md_alloc)(iov->N, iov->dims, iov->size);
#else
	void* tmp = md_alloc(iov->N, iov->dims, iov->size);
#endif

	assert(N + 2 == operator_nr_args(data->x));

	args2[data->a] = tmp;
	args2[data->b] = tmp;

	debug_printf(DP_DEBUG4, "link apply: %d-%d == %p\n", data->a, data->b, tmp);

	for (int i = 0; i < (int)(N + 2); i++)
		debug_printf(DP_DEBUG4, "link apply: out arg[%d] = %p\n", i, args2[i]);

	operator_generic_apply_unchecked(data->x, N + 2, args2);

	md_free(tmp);
}

static void link_del(const operator_data_t* _data)
{
	auto data = CAST_DOWN(operator_link_s, _data);

	operator_free(data->x);
	xfree(data);
}

static const struct graph_s* operator_link_get_graph(const struct operator_s* op)
{
	const auto d = CAST_DOWN(operator_link_s, op->data);
	return operator_graph_link_F(operator_get_graph(d->x), d->b, d->a);
}

const struct operator_s* operator_link_create(const struct operator_s* op, unsigned int o, unsigned int i)
{
	unsigned int N = operator_nr_args(op);

	assert(i < N);
	assert(o < N);
	assert(i != o);

	assert( op->io_flags[o]);
	assert(!op->io_flags[i]);

	auto iov = operator_arg_domain(op, i);
	auto iovb = operator_arg_domain(op, o);

	assert(iovec_check(iovb, iov->N, iov->dims, iov->strs));

	bool io_flags[N - 2];
	unsigned int D[N - 2];
	const long* dims[N - 2];
	const long* strs[N - 2];

	debug_printf(DP_DEBUG4, "Linking args %d-%d of %d.\n", i, o, N);

	for (unsigned int s = 0, t = 0; s < N; s++) {

		if ((s == i) || (s == o))
			continue;

		auto io = operator_arg_domain(op, s);

		D[t] = io->N;
		dims[t] = io->dims;
		strs[t] = io->strs;

		io_flags[t] = op->io_flags[s];

		t++;
	}

	auto ioi = operator_arg_domain(op, i);
	auto ioo = operator_arg_domain(op, o);

	assert((int)ioi->N == md_calc_blockdim(ioi->N, ioi->dims, ioi->strs, ioi->size));
	assert((int)ioo->N == md_calc_blockdim(ioo->N, ioo->dims, ioo->strs, ioo->size));

	PTR_ALLOC(struct operator_link_s, data);
	SET_TYPEID(operator_link_s, data);

	data->a = i;
	data->b = o;
	data->x = operator_ref(op);

	return operator_generic_create2(N - 2, io_flags, D, dims, strs, CAST_UP(PTR_PASS(data)), link_apply, link_del, operator_link_get_graph);
}

struct permute_data_s {

	INTERFACE(operator_data_t);

	const int* perm;
	const struct operator_s* op;
};

static DEF_TYPEID(permute_data_s);

static void permute_fun(const operator_data_t* _data, unsigned int N, void* args[N])
{
	auto data = CAST_DOWN(permute_data_s, _data);

	assert(N == operator_nr_args(data->op));

	void* ptr[N];

	for (int i = 0; i < (int)N; i++)
		ptr[data->perm[i]] = args[i];

	for (int i = 0; i < (int)N; i++)
		debug_printf(DP_DEBUG4, "permute apply: in arg[%d] = %p\n", i, args[i]);

	for (int i = 0; i < (int)N; i++)
		debug_printf(DP_DEBUG4, "permute apply: out arg[%d] = %p\n", i, ptr[i]);

	operator_generic_apply_unchecked(data->op, N, ptr);
}

static const struct graph_s* operator_permute_get_graph(const struct operator_s* op)
{
	const auto d = CAST_DOWN(permute_data_s, op->data);
	return operator_graph_permute_F(operator_get_graph(d->op), d->op->N, d->perm);
}

static void permute_del(const operator_data_t* _data)
{
	auto data = CAST_DOWN(permute_data_s, _data);

	operator_free(data->op);

	xfree(data->perm);

	xfree(data);
}

const struct operator_s* operator_permute(const struct operator_s* op, int N, const int perm[N])
{
	assert(N == (int)operator_nr_args(op));

	unsigned long flags = 0;
	bool io_flags[N];
	unsigned int D[N];
	const long* dims[N];
	const long* strs[N];

	for (int i = 0; i < N; i++) {

		assert(perm[i] < N);
		flags |= MD_BIT(perm[i]);

		const struct iovec_s* io = operator_arg_domain(op, perm[i]);

		D[i] = io->N;
		dims[i] = io->dims;
		strs[i] = io->strs;

		io_flags[i] = op->io_flags[perm[i]];
	}

	assert(((int)sizeof(flags) <= N) || (MD_BIT(N) == flags + 1));

	// op = operator_ref(op);
	PTR_ALLOC(struct permute_data_s, data);
	SET_TYPEID(permute_data_s, data);

	int* nperm = *TYPE_ALLOC(int[N]);

	auto opdata_test = CAST_MAYBE(permute_data_s, op->data);
	if (NULL != opdata_test) {

		data->op = operator_ref(opdata_test->op);
		for (int i = 0; i < N; i++)
			nperm[i] = opdata_test->perm[perm[i]];

	} else {

		data->op = operator_ref(op);
		memcpy(nperm, perm, sizeof(int[N]));
	}
	data->perm = nperm;

	return operator_generic_create2(N, io_flags, D, dims, strs, CAST_UP(PTR_PASS(data)), permute_fun, permute_del, operator_permute_get_graph);
}

struct extract_data_s {

	INTERFACE(operator_data_t);

	int a;
	size_t off;
	const struct operator_s* op;

	long* strs;
};

static DEF_TYPEID(extract_data_s);

static void extract_fun(const operator_data_t* _data, unsigned int N, void* args[N])
{
	auto data = CAST_DOWN(extract_data_s, _data);

	assert(N == operator_nr_args(data->op));

	void* ptr[N];

	for (int i = 0; i < (int)N; i++)
		ptr[i] = args[i] + ((data->a == i) ? data->off : 0);

	operator_generic_apply_unchecked(data->op, N, ptr);
}

static void extract_copy_fun(const operator_data_t* _data, unsigned int N, void* args[N])
{
	auto data = CAST_DOWN(extract_data_s, _data);

	assert(N == operator_nr_args(data->op));

	void* ptr[N];

	for (int i = 0; i < (int)N; i++)
		ptr[i] = args[i];

	auto iov = operator_arg_domain(data->op, data->a);

	ptr[data->a] = md_alloc_sameplace(iov->N, iov->dims, iov->size, args[data->a]);

	if (!(data->op->io_flags[data->a]))
		md_copy2(iov->N, iov->dims, iov->strs, ptr[data->a], data->strs, args[data->a] + data->off, iov->size);

	operator_generic_apply_unchecked(data->op, N, ptr);

	if ((data->op->io_flags[data->a]))
		md_copy2(iov->N, iov->dims, data->strs, args[data->a] + data->off, iov->strs, ptr[data->a], iov->size);

	md_free(ptr[data->a]);
}

static void extract_del(const operator_data_t* _data)
{
	auto data = CAST_DOWN(extract_data_s, _data);

	operator_free(data->op);

	xfree(data->strs);

	xfree(data);
}

const struct operator_s* operator_extract_create2(const struct operator_s* op, int a, int Da, const long dimsa[Da], const long strsa[Da], const long pos[Da])
{
	int N = (int)operator_nr_args(op);

	assert(a < N);

	unsigned int D[N];
	const long* dims[N];
	const long* strs[N];

	for (int i = 0; i < N; i++) {

		const struct iovec_s* io = operator_arg_domain(op, i);

		D[i] = io->N;
		dims[i] = io->dims;
		strs[i] = io->strs;
	}

	assert(Da == (int)D[a]);

	auto ioa = operator_arg_domain(op, a);
	bool trivial_strides = iovec_check(ioa, ioa->N, ioa->dims, MD_STRIDES(ioa->N, ioa->dims, ioa->size));
	bool copy_needed = false;

	for (int i = 0; i < Da; i++) {

		assert((0 <= pos[i]) && (pos[i] < dimsa[i]));
		assert(dims[a][i] + pos[i] <= dimsa[i]);
		copy_needed = copy_needed || !((0 == strs[a][i]) || (strs[a][i] == strsa[i]));
	}

	assert(trivial_strides || !copy_needed);

	dims[a] = dimsa;
	strs[a] = strsa;

	PTR_ALLOC(struct extract_data_s, data);
	SET_TYPEID(extract_data_s, data);

	data->op = operator_ref(op);
	data->a = a;
	data->off = md_calc_offset(Da, strsa, pos);

	PTR_ALLOC(long[Da], nstrs);
	md_copy_strides(Da, *nstrs, strsa);
	data->strs = *PTR_PASS(nstrs);

	return operator_generic_create2(N, op->io_flags, D, dims, strs, CAST_UP(PTR_PASS(data)), copy_needed ? extract_copy_fun : extract_fun, extract_del, NULL);
}

const struct operator_s* operator_extract_create(const struct operator_s* op, int a, int Da, const long dimsa[Da], const long pos[Da])
{
	return operator_extract_create2(op, a, Da, dimsa, MD_STRIDES(Da, dimsa, operator_arg_domain(op, a)->size), pos);
}

static bool stack_compatible(unsigned int D, const struct iovec_s* a, const struct iovec_s* b)
{
	if (a->N != b->N)
		return false;

	unsigned int N = a->N;

	for (unsigned int i = 0; i < N; i++)
		if ((D != i) && ((a->dims[i] != b->dims[i] || (a->strs[i] != b->strs[i]))))
			return false;

	for (unsigned int i = D + 1; i < N; i++)
		if (((a->dims[i] != 1) && (a->strs[i] != 0)) || ((b->dims[i] != 1) && (b->strs[i] != 0)))
			return false;

	if ((1 != a->dims[D]) && (1 != b->dims[D]))
		if (a->strs[D] != b->strs[D])
			return false;

	long dims[N];
	md_select_dims(N, ~MD_BIT(D), dims, a->dims);

	long S = md_calc_size(N, dims) * a->size;

	if ((1 != a->dims[D]) && (S != a->strs[D]))
		return false;

	return true;
}

static bool stack_compatible_copy(unsigned int D, const struct iovec_s* a, const struct iovec_s* b)
{
	if (a->N != b->N)
		return false;

	unsigned int N = a->N;

	if (!iovec_check(a, a->N, a->dims, MD_STRIDES(a->N, a->dims, a->size)))
		return false;
	if (!iovec_check(b, b->N, b->dims, MD_STRIDES(b->N, b->dims, b->size)))
		return false;

	for (unsigned int i = 0; i < N; i++)
		if ((D != i) && (a->dims[i] != b->dims[i]))
			return false;

	return true;
}

static void stack_dims(unsigned int N, long dims[N], long strs[N], unsigned int D, const struct iovec_s* a, const struct iovec_s* b)
{
	md_copy_dims(N, dims, a->dims);
	md_copy_strides(N, strs, a->strs);

	long dimsa[N];
	md_select_dims(N, ~MD_BIT(D), dimsa, a->dims);

	strs[D] = md_calc_size(N, dimsa) * a->size;
	dims[D] = a->dims[D] + b->dims[D];
}

static void stack_dims_trivial(unsigned int N, long dims[N], long strs[N], unsigned int D, const struct iovec_s* a, const struct iovec_s* b)
{
	md_copy_dims(N, dims, a->dims);
	dims[D] = a->dims[D] + b->dims[D];
	md_calc_strides(N, strs, dims, a->size);
}

/**
 * Stacks two operators over selected arguments, the other arguments are duplex
 *
 * @param M nr of arguments to stack over
 * @param arg_list index of arguments to stack
 * @param dim_list stack dimension for respective argument
 * @param a first operator to stack
 * @param b second operator to stack
 **/
const struct operator_s* operator_stack2(int M, const int arg_list[M], const int dim_list[M], const struct operator_s* a, const struct operator_s* b)
{
	a = operator_ref(a);
	b = operator_ref(b);

	for (int m = 0; m < M; m++) {

		int arg = arg_list[m];
		int dim = dim_list[m];

		auto ia = operator_arg_domain(a, arg);
		auto ib = operator_arg_domain(b, arg);

		assert(stack_compatible(dim, ia, ib) || stack_compatible_copy(dim, ia, ib));

		int D = ia->N;

		long dims[D];
		long strs[D];

		if (stack_compatible(dim, ia, ib))
			stack_dims(D, dims, strs, dim, ia, ib);
		else
			stack_dims_trivial(D, dims, strs, dim, ia, ib);

		long pos[D];

		for (int i = 0; i < D; i++)
			pos[i] = 0;

		int X = ia->dims[dim];

		auto aa = operator_extract_create2(a, arg, D, dims, strs, (pos[dim] = 0, pos));
		auto bb = operator_extract_create2(b, arg, D, dims, strs, (pos[dim] = X, pos));

		operator_free(a);
		operator_free(b);

		a = aa;
		b = bb;
	}

	auto c = operator_combi_create(2, MAKE_ARRAY(a, b));

	operator_free(a);
	operator_free(b);

	int N = operator_nr_args(a);

	for (int i = N - 1; i >= 0; i--) {

		auto d = operator_dup_create(c, i, N + i);
		operator_free(c);
		c = d;
	}

	return c;
}

/**
 * Create a new operator that stacks a and b along dimension D
 */
const struct operator_s* operator_stack(unsigned int D, unsigned int E, const struct operator_s* a, const struct operator_s* b)
{
	return operator_stack2(2, (int[2]){ 0, 1 }, (int[2]){ D, E }, a, b);
}

bool operator_zero_or_null_p(const struct operator_s* op)
{
	auto opd = operator_get_data(op);

	if (   (NULL != CAST_MAYBE(zero_s, opd))
	    || (NULL != CAST_MAYBE(null_s, opd)))
		return true;

	auto p = CAST_MAYBE(permute_data_s, opd);

	if (NULL != p)
		return operator_zero_or_null_p(p->op);

	// FIXME: unwrap other types...

	auto c = CAST_MAYBE(operator_combi_s, opd);

	if (NULL != c) {

		for (int i = 0; i < c->N; i++)
			if (!operator_zero_or_null_p(c->x[i]))
				return false;

		return true;
	}

	return false;
}

struct operator_sum_s {

	INTERFACE(operator_data_t);

	int II;

	const struct iovec_s* iov;
};

static DEF_TYPEID(operator_sum_s);

static void sum_apply(const operator_data_t* _data, unsigned int N, void* args[N])
{
	auto d = CAST_DOWN(operator_sum_s, _data);

	assert(1 + d->II == (int)N);
	assert(3 <= N);

	void* dst = args[0];
	void* src1 = args[1];
	void* src2 = args[2];

	md_zadd2(d->iov->N, d->iov->dims, d->iov->strs, dst, d->iov->strs, src1, d->iov->strs, src2);

	for (int i = 2; i < d->II; i++)
		md_zadd2(d->iov->N, d->iov->dims, d->iov->strs, dst, d->iov->strs, dst, d->iov->strs, args[1 + i]);
}

static void sum_free(const operator_data_t* _data)
{
	auto data = CAST_DOWN(operator_sum_s, _data);

	iovec_free(data->iov);

	xfree(data);
}

const struct operator_s* operator_zadd_create(int II, int N, const long dims[N])
{
	PTR_ALLOC(struct operator_sum_s, c);
	SET_TYPEID(operator_sum_s, c);

	c->iov = iovec_create(N, dims, CFL_SIZE);
	c->II = II;
	assert(2 <= II);

	bool io_flags[1 + II];
	unsigned int D [1 + II];
	const long* dims_op[1 + II];
	const long* strs_op[1 + II];

	io_flags[0] = true;
	D[0] = N;
	dims_op[0] = c->iov->dims;
	strs_op[0] = c->iov->strs;

	for (int i = 0; i < II; i++) {

		io_flags[i + 1] = false;
		D[i + 1] = N;
		dims_op[i + 1] = c->iov->dims;
		strs_op[i + 1] = c->iov->strs;
	}

	return operator_generic_create2(1 + II, io_flags, D, dims_op, strs_op, CAST_UP(PTR_PASS(c)), sum_apply, sum_free, NULL);
}

bool operator_is_zadd(const struct operator_s* op)
{
	return (NULL != CAST_MAYBE(operator_sum_s, op->data));
}

/**
 * For simple operators with one in and one output, we provide "flat containers".
 * These operators can be optimized (simultaneous application) easily.
 * There are two types of containers, i.e. chains and sums.
 * */

struct operator_plus_s {

	INTERFACE(operator_data_t);

	const struct operator_s* a;
	const struct operator_s* b;
};

static DEF_TYPEID(operator_plus_s);

static void plus_apply(const operator_data_t* _data, unsigned int N, void* args[N])
{
	auto data = CAST_DOWN(operator_plus_s, _data);

	assert(2 == N);

	void* src = args[1];
	void* dst = args[0];

	auto iov = operator_codomain(data->b);
	complex float* tmp = md_alloc_sameplace(iov->N, iov->dims, iov->size, src);

	operator_apply_joined_unchecked(2, MAKE_ARRAY(data->a, data->b), MAKE_ARRAY((complex float*)args[0], tmp), args[1]);

	md_zadd2(iov->N, iov->dims, iov->strs, dst,iov->strs, dst, iov->strs, tmp);
	md_free(tmp);
}

static void plus_free(const operator_data_t* _data)
{
	auto data = CAST_DOWN(operator_plus_s, _data);

	operator_free(data->a);
	operator_free(data->b);

	xfree(data);
}

static const struct graph_s* operator_plus_get_graph(const struct operator_s* op)
{
	const auto d = CAST_DOWN(operator_plus_s, op->data);

	auto graph_a = operator_get_graph(d->a);
	auto graph_b = operator_get_graph(d->b);

	auto iov = operator_codomain(d->a);
	auto op_sum = operator_zadd_create(2, iov->N, iov->dims);
	auto graph_sum = operator_get_graph(op_sum);
	operator_free(op_sum);

	auto graph_combi = operator_graph_combine_F(3, (const struct graph_s*[3]){graph_sum, graph_a, graph_b});

	graph_combi = operator_graph_link_F(graph_combi, 5, 2);
	graph_combi = operator_graph_link_F(graph_combi, 2, 1);
	graph_combi = operator_graph_dup_F(graph_combi, 1, 2);

	return graph_combi;
}

/**
 * Create a new operator that adds the output of two
 */
const struct operator_s* operator_plus_create(const struct operator_s* a, const struct operator_s* b)
{
	//check compatibility
	assert((2 == a->N) && (2 == b->N));
	assert(a->io_flags[0]);
	assert(!a->io_flags[1]);
	assert(b->io_flags[0]);
	assert(!b->io_flags[1]);

	auto doma = operator_domain(a);
	auto domb = operator_domain(b);

	assert(iovec_check(doma, domb->N, domb->dims, domb->strs));
	assert(doma->size == domb->size);

	auto codoma = operator_codomain(a);
	auto codomb = operator_codomain(b);

	assert(iovec_check(codoma, codomb->N, codomb->dims, codomb->strs));
	assert(codoma->size == codomb->size);
	//endcheck compatibility

	PTR_ALLOC(struct operator_plus_s, c);
	SET_TYPEID(operator_plus_s, c);

	c->a = operator_ref(a);
	c->b = operator_ref(b);

	bool io_flags[2] = { true, false };
	unsigned int D[] = { codoma->N, doma->N };
	const long* dims[] = { codoma->dims, doma->dims };
	const long* strs[] = { codoma->strs, doma->strs };

	return operator_generic_create2(2, io_flags, D, dims, strs, CAST_UP(PTR_PASS(c)), plus_apply, plus_free, operator_plus_get_graph);
}

static const struct operator_plus_s* get_plus_data(const struct operator_s* plus_op)
{
	return CAST_MAYBE(operator_plus_s, operator_get_data(plus_op));
}

struct operator_chain_s {

	INTERFACE(operator_data_t);

	unsigned int N;
	const struct operator_s** x;
};

static DEF_TYPEID(operator_chain_s);

static void chain_apply(const operator_data_t* _data, unsigned int N, void* args[N])
{
	auto data = CAST_DOWN(operator_chain_s, _data);

	assert(2 == N);

	complex float* src = args[1];

	for(unsigned int i = 0; i < data->N; i++) {

		auto iov = operator_codomain(data->x[i]);
		complex float* dst;

		if (i == data->N - 1)
			dst = args[0];
		else
			dst = md_alloc_sameplace(iov->N, iov->dims, iov->size, src);

		operator_apply_unchecked(data->x[i], dst, src);

		if (0 != i)
			md_free(src);

		src = dst;
	}
}

static void chain_free(const operator_data_t* _data)
{
	auto data = CAST_DOWN(operator_chain_s, _data);

	for (unsigned int i = 0; i < data->N; i++)
		operator_free(data->x[i]);

	xfree(data->x);
	xfree(data);
}

static const struct graph_s* operator_chain_get_graph(const struct operator_s* op)
{
	const auto d = CAST_DOWN(operator_chain_s, op->data);
	const struct graph_s* tmp_graphs[d->N];
	for (unsigned int i = 0; i < d->N; i++)
		tmp_graphs[i] = operator_get_graph(d->x[i]);
	return operator_graph_chain_F(d->N, tmp_graphs);
}

/**
 * Create a new operator that chaines several others
 */
const struct operator_s* operator_chainN(unsigned int N, const struct operator_s* x[N])
{
	debug_printf(DP_DEBUG4, "operator chainN N=%d:\n", N);
	for (unsigned int i = 0; i < N; i++) {

		assert(2 == x[i]->N);
		assert(x[i]->io_flags[0]);
		assert(!x[i]->io_flags[1]);

		if ((signed)i < (signed)N - 1) {

			auto a = x[i];
			auto b = x[i + 1];

			debug_printf(DP_DEBUG4, "\t[%d] in [%d]:\n\t", i, i + 1, N);
			debug_print_dims(DP_DEBUG4, a->domain[0]->N, a->domain[0]->dims);
			debug_printf(DP_DEBUG4, "\t");
			debug_print_dims(DP_DEBUG4, b->domain[1]->N, b->domain[1]->dims);

			assert(a->domain[0]->N == b->domain[1]->N);
			assert(md_calc_size(a->domain[0]->N, a->domain[0]->dims) == md_calc_size(b->domain[1]->N, b->domain[1]->dims));
			assert((int)a->domain[0]->N == md_calc_blockdim(a->domain[0]->N, a->domain[0]->dims, a->domain[0]->strs, a->domain[0]->size));
			assert((int)b->domain[1]->N == md_calc_blockdim(b->domain[1]->N, b->domain[1]->dims, b->domain[1]->strs, b->domain[1]->size));
		}
	}

	PTR_ALLOC(struct operator_chain_s, c);
	SET_TYPEID(operator_chain_s, c);

	PTR_ALLOC(const struct operator_s*[N], xp);

	for (unsigned int i = 0; i < N; i++)
		(*xp)[i] = operator_ref(x[i]);

	c->x = *PTR_PASS(xp);
	c->N = N;

	return operator_generic_create2(2, (bool[2]){true, false}, (unsigned int[2]){ operator_codomain(x[N - 1])->N, operator_domain(x[0])->N},
						(const long*[2]){ operator_codomain(x[N - 1])->dims, operator_domain(x[0])->dims},
						(const long*[2]){ operator_codomain(x[N - 1])->strs, operator_domain(x[0])->strs},
						CAST_UP(PTR_PASS(c)), chain_apply, chain_free, operator_chain_get_graph);
}

static const struct operator_chain_s* get_chain_data(const struct operator_s* chain_op)
{
	return CAST_MAYBE(operator_chain_s, operator_get_data(chain_op));
}

/**
 * Create a new operator that first applies a, then applies b:
 * c(x) = b(a(x))
 */
const struct operator_s* operator_chain(const struct operator_s* a, const struct operator_s* b)
{
#if 1
	if (NULL != get_plus_data(b)) {

		auto bd = get_plus_data(b);
		auto tmpa = operator_chain(a, bd->a);
		auto tmpb = operator_chain(a, bd->b);

		auto result = operator_plus_create(tmpa, tmpb);

		operator_free(tmpa);
		operator_free(tmpb);

		return result;
	}
#endif

	//Get array of operators in a
	unsigned int Na = 1;
	const struct operator_s** ops_a;

	if (NULL != get_chain_data(a)) {

		auto ad = get_chain_data(a);

		Na = ad->N;
		ops_a = ad->x;

	} else {

		ops_a = &a;
	}

	//Get array of operators in b
	unsigned int Nb = 1;
	const struct operator_s** ops_b;

	if (NULL != get_chain_data(b)) {

		auto bd = get_chain_data(b);

		Nb = bd->N;
		ops_b = bd->x;

	} else {

		ops_b = &b;
	}

	unsigned int N = Na + Nb;
	const struct operator_s* ops[N];

	for (unsigned int i = 0; i < Na; i++)
		ops[i] = ops_a[i];

	for (unsigned int i = 0; i < Nb; i++)
		ops[i + Na] = ops_b[i];

	return operator_chainN(N, ops);
}

//get list of all operators applied in one operator
list_t operator_get_list(const struct operator_s* op) {

	auto data_combi = CAST_MAYBE(operator_combi_s, op->data);
	auto data_link = CAST_MAYBE(operator_link_s, op->data);
	auto data_dup = CAST_MAYBE(operator_dup_s, op->data);
	auto data_reshape = CAST_MAYBE(op_reshape_s, op->data);
	auto data_chain = CAST_MAYBE(operator_chain_s, op->data);
	auto data_perm = CAST_MAYBE(permute_data_s, op->data);
	auto data_plus = CAST_MAYBE(operator_plus_s, op->data);
	auto data_copy = CAST_MAYBE(copy_data_s, op->data);
	auto data_attach = CAST_MAYBE(attach_data_s, op->data);

	if (NULL != data_combi) {

		list_t result = list_create();
		for (int i = 0; i < data_combi->N; i++)
			list_merge(result, operator_get_list(data_combi->x[i]), true);
		return result;
	}

	if (NULL != data_chain) {

		list_t result = list_create();
		for (unsigned int i = 0; i < data_chain->N; i++)
			list_merge(result, operator_get_list(data_chain->x[i]), true);
		return result;
	}

	if (NULL != data_link) {

		return operator_get_list(data_link->x);
	}

	if (NULL != data_dup) {

		return operator_get_list(data_dup->x);
	}

	if (NULL != data_reshape) {

		return operator_get_list(data_reshape->x);
	}

	if (NULL != data_perm) {

		return operator_get_list(data_perm->op);
	}

	if (NULL != data_perm) {

		return operator_get_list(data_perm->op);
	}

	if (NULL != data_plus) {

		list_t result = operator_get_list(data_plus->a);
		list_merge(result, operator_get_list(data_plus->b), true);
		return result;
	}

	if (NULL != data_copy) {

		return operator_get_list(data_copy->op);
	}

	if (NULL != data_attach) {

		return operator_get_list(data_attach->op);
	}

	list_t result = list_create();
	list_append(result, (void*)op);

	return result;
}

const struct graph_s* operator_get_graph(const struct operator_s* op)
{
	if (NULL != op->get_graph)
		return op->get_graph(op);

	return create_graph_operator(op, op->data->TYPEID->name);
}

const struct operator_s* graph_optimize_operator_F(const struct operator_s* op)
{

	int N = operator_nr_out_args(op);

	auto tmp = operator_ref(op);

	bool sorted = true;
	for (int i = 0; i < N; i++)
		sorted = sorted && op->io_flags[i];

	for (int i = 0; sorted && i < N; i++) {

		auto iov = tmp->domain[N-1];
		auto id = operator_identity_create(iov->N, iov->dims);
		auto ttmp = operator_combi_create(2, (const struct operator_s*[2]){id, tmp});
		operator_free(tmp);
		operator_free(id);
		tmp = operator_link_create(ttmp, N + 1, 1);
		operator_free(ttmp);
	}

	auto graph = operator_get_graph(tmp);
	operator_free(tmp);
	operator_free(op);

	return graph_to_operator_F(graph);
}

bool operator_identify(const struct operator_s* a, const struct operator_s* b)
{
	if (a == b)
		return true;
	if (a->data->TYPEID != b->data->TYPEID)
		return false;

	if (NULL != CAST_MAYBE(operator_sum_s, a->data)) {

		auto iova = CAST_DOWN(operator_sum_s, a->data)->iov;
		auto iovb = CAST_DOWN(operator_sum_s, b->data)->iov;

		return iovec_check(iova, iovb->N, iovb->dims, iovb->strs);
	}

	return false;
}

void operator_apply_joined_unchecked(unsigned int N, const struct operator_s* op[N], complex float* dst[N], const complex float* src)
{
	auto combi = operator_combi_create(N, op);

	int perm[2 * N];
	for (unsigned int i = 0; i < N; i++) {

		perm[i] = 2 * i;
		perm[i + N] = 2 * i + 1;
	}

	auto dup = operator_permute(combi, 2 * N, perm);
	operator_free(combi);

	for (unsigned int i = 0; i < N - 1; i++) {

		auto tmp = operator_dup_create(dup, N, N + 1);
		operator_free(dup);
		dup = tmp;
	}

	void* args[N + 1];
	for (unsigned int i = 0; i < N; i++)
		args[i] = dst[i];
	args[N] = (void*)src;

	auto op_optimized = graph_optimize_operator_F(dup);

	operator_generic_apply_unchecked(op_optimized, N + 1, args);

	operator_free(op_optimized);

}


text:
<?php

namespace HeavenProject\GitBranchPanel;

class GitBranch
{
    /** @var string */
    private $entryPath;

    /** @var string */
    private $targetDir;

    /**
     * @param string $entryPath
     * @param string $targetDir
     */
    public function __construct($entryPath, $targetDir)
    {
        $this->entryPath = $entryPath;
        $this->targetDir = $targetDir;
    }

    /**
     * @return string
     */
    public function getBranchName()
    {
        $dir  = $this->findGitDirectory();
        $head = $dir . '/' . $this->targetDir . '/HEAD';

        if (is_dir($dir) && is_readable($head)) {
            $branch = file_get_contents($head);
            if (strpos($branch, 'ref:') === 0) {
                $parts = explode('/', $branch);
                $res   = array_slice($parts, 2);

                return implode('/', $res);
            } else {
                return substr($branch, 0, 7);
            }
        }

        return 'not versioned';
    }

    /**
     * @return string
     */
    private function findGitDirectory()
    {
        $dir = realpath(dirname($this->entryPath));

        while ($dir !== false && !is_dir($dir . '/' . $this->targetDir)) {
            $currentDir = $dir;
            $dir        = realpath($dir . '/..');

            if ($this->inRoot($dir, $currentDir)) {
                break;
            }
        }

        return $dir;
    }

    /**
     * @param  string $checkedDir
     * @param  string $currentDir
     * @return bool
     */
    private function inRoot($checkedDir, $currentDir)
    {
        return $checkedDir === $currentDir;
    }
}

redpajama_set_name: RedPajamaGithub


text:
import BaseMixin from '../_mixin/baseMixin'
import Bs3Row from '/components/bootstrap3/row'

export default {
    template: __inline('main.html'),
    mixins: [BaseMixin],
    components: {
        Bs3Row
    }
};


text:
layout: post
title: How to send WhatsApp Messages in Java
subtitle: Using the WhatsMate WA Gateway REST API
published: true
last_modified_at: 2022-05-03T00:00:00+08:00
---

This article shows you how to send a WhatsApp message in `Java`.

Before the recipient can receive your WhatsApp message, she will need to register with the WhatsMate WA Gateway. Instructions are available on the [official site](https://www.whatsmate.net/whatsapp-gateway-api.html). *Unregistered users will never receive messages from the Gateway.*

To send a WhatsApp message in `Java`, do this:

1. Copy the following source code to a Java file named `WhatsappSender.java`.
2. Customize the TODO lines:
   * Specify your gateway instance ID on line 9.
   * Specify your client ID and secret on lines 10 and 11.
   * Specify your target recipient on line 18. Remember to include the country code.
   * Specify your message on line 19.
3. Compile the Java file:  `javac WhatsappSender.java`
4. Execute the class to send your message: `java WhatsappSender`

You will need a trial account to call the above API. Go [sign up](https://www.whatsmate.net/whatsapp-gateway-api.html) now.


text:
package validationUtils

import (
	"fmt"

	. "github.com/francoishill/goangi2/utils/errorUtils"
)

func CheckFloat32InRange(intToCheck, min, max float32, errorIfOutOfRange string) {
	if intToCheck < min || intToCheck > max {
		PanicValidationError(errorIfOutOfRange + fmt.Sprintf(" (range is %d-%d)", min, max))
	}
}

func CheckFloat32Is_MinimumInclusive(intToCheck, minInclusive float32, errorIfNotIsAtLeast string) {
	if intToCheck < minInclusive {
		PanicValidationError(errorIfNotIsAtLeast + fmt.Sprintf(" (minimumInclusive %d)", minInclusive))
	}
}

func CheckFloat32Is_MinimumExclusive(intToCheck, min float32, errorIfNotIsAtLeast string) {
	if intToCheck <= min {
		PanicValidationError(errorIfNotIsAtLeast + fmt.Sprintf(" (minimumExclusive %d)", min))
	}
}


text:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_marginBottom="15dp"
        android:layout_weight="10" >

        <AutoCompleteTextView
            android:id="@+id/roomPicker"
            android:layout_width="match_parent"
            android:layout_height="fill_parent"
            android:ems="10"
            android:hint="@string/roomPickerHint" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="20"
        android:orientation="horizontal"
        android:weightSum="10" >

        <ToggleButton
            android:id="@+id/validationToggler"
            android:layout_width="0dp"
            android:layout_height="fill_parent"
            android:layout_weight="3"
            android:textOff="@string/validationTogglerOff"
            android:textOn="@string/validationTogglerOn" />

        <Button
            android:id="@+id/submitValidationButton"
            android:layout_width="0dp"
            android:layout_height="fill_parent"
            android:layout_weight="7"
            android:enabled="false"
            android:text="@string/submitValidationForRoom_" />

    </LinearLayout>

    <ScrollView
        android:id="@+id/scrollViewForValidationSummary"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="40" >

        <TextView
            android:id="@+id/validationSummary"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </ScrollView>

    <ScrollView
        android:id="@+id/logScrollViewInValidation"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="40" >

        <TextView
            android:id="@+id/logTextViewInValidation"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />
    </ScrollView>

</LinearLayout>


text:
module SimpleHttpServer

if VERSION < v"0.4.0-dev"
    using Docile
    eval(:(@docstrings(manual = ["../README.md"])))
end

using SimpleHttpCommon
using Compat
using Nettle
using Codecs
using WebSockets
using GnuTLS
using Match
using JSON
import WebSockets: WebSocket, close
import Base: listen, UVError, write
import DataStructures:OrderedDict

const C = SimpleHttpCommon

export HTPHandler,
    Server,
    HTTPServer,
    handle,
    http_handle,
    Request,
    Response,
    headers,
    run,
    listen,
    Iterable,
    readbytes,
    readline,
    readuntil,
    BytesReaderIterator,
    BytesFileIterator,
    LimitedBytesFileIterator,
    FileResponse,
    mh,
    mh_push!

hc_event = SimpleHttpCommon.event

typealias NothingOrUVServer Union(Nothing, Base.UVServer)

type TCPHandler
    handle::Function
    sock::NothingOrUVServer
    events::Dict{String, Function}

    TCPHandler(handle::Function, sock::NothingOrUVServer, events::Dict{String, Function}) = new(handle, sock, events)
    TCPHandler(handle::Function, sock::NothingOrUVServer) = TCPHandler(handle, sock, defaultevents)
    TCPHandler(handle::Function) = TCPHandler(handle, nothing)
end

type Server
    handler::TCPHandler
    error_count::BigInt
    last_client_id::BigInt
    options::Associative{Any, Any}

    Server(handler::TCPHandler, args...) = new(handler, BigInt(0), BigInt(0), Dict{Any,Any}(args))
end

function increase_error(s::Server)
    s.error_count += 1
    return s.error_count
end

function increase_client_id(s::Server)
    s.last_client_id += 1
    return s.last_client_id
end

typealias ClientAddr Union(Nothing, IPv4, IPv6)
typealias ClientHostName Union(Nothing, String)

type Client
    id::BigInt
    server::Server
    sock
    finished::Bool
    addr::ClientAddr
    hostname::ClientHostName

    Client(s::Server, sc, f::Bool) = new(increase_client_id(s), s, sc, f, nothing, nothing)
    Client(s::Server, sc) = Client(s, sc, true)
end

type Error
    id::BigInt
    req::Request
    res
    error
    traceback
end

function print_error(io::IO, e::Error)
    println(io, "[REQUEST_EXCEPTION $(e.id)] BEGIN")
    println(io, "Request error: $(typeof(e.error))")
    println(io, "Request msg: $(e.error)")
    println(io, "Request OPEN: $(isopen(e.req.sock))")
    println(io, "Request: $(e.req)")
    println(io, "")
    showerror(io, e.error, e.traceback)
    println(io, "")
    println(io, "[REQUEST_EXCEPTION $(e.id)] END")
end

function print_respose_iter_error(io::IO, e::Error)
    println(io, "[RESPONSE_ITER_DATA_EXCEPTION $(e.id) BEGIN")
    println(io, "Response: $(e.res)")
    println(io, "")
    showerror(io, e.error, e.traceback)
    println(io, "")
    println(io, "[RESPONSE_ITER_DATA_EXCEPTION $(e.id)] END")
end

function read_ip(sock)
  buffer = Array(Uint8,32)
  bufflen::Int64 = 32

  ccall(:uv_tcp_getpeername,Int64,(Ptr{Void},Ptr{Uint8},Ptr{Int64}), sock.handle,buffer,&bufflen)

  b = buffer[5:8]
  ip = IPv4(b...)
  ip
end

defaultevents = Dict{String, Function}()
defaultevents["error"]  = ( client, err ) -> println( err )
defaultevents["listen"] = ( saddr ) -> println("Listening on $saddr...")
defaultevents["connect"] = ( client ) -> begin
  ip = read_ip(client.sock)
  println("Client connect from: $ip")
  client.addr = ip
end

defaultevents["request_sock_error"] = ( error ) -> begin
    print_error(STDERR, "Sock error: $(error.error)")
end

defaultevents["request_error"] = ( error ) -> begin
    print_error(STDERR, error)
end

defaultevents["post_request_init"] = ( req ) -> begin
    req.events["post_header"] = http_post_header
    req.events["error"] = request_error
    req.events["response_iter_data_error"] = response_iter_data_error
end

defaultevents["response_iter_data_error"] = ( error ) -> begin
    print_respose_iter_error(STDERR, error)
end

function response_iter_data_error(error::Error)
    io = IOBuffer()
    print_respose_iter_error(io, error)
    write_chunk(error.req.sock, takebuf_array(io))
end

function request_error(error::Error, set_res::Function)
    io = IOBuffer()
    print_error(io, error)
    set_res(Response(500, takebuf_array(io)))
end

# copy from: https://github.com/JuliaWeb/WebSockets.jl/blob/master/src/WebSockets.jl
# get key out of request header
get_websocket_key(request::Request) = begin
  return request.headers["Sec-WebSocket-Key"]
end

# copy from: https://github.com/JuliaWeb/WebSockets.jl/blob/master/src/WebSockets.jl
# the protocol requires that a special key
# be processed and sent back with the handshake response
# to prove that received the HTTP request
# and that we *really* know what webSockets means.
function generate_websocket_key(key)
  h = HashState(SHA1)
  update!(h, key*"258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
  bytestring(encode(Base64, digest!(h)))
end

# perform the handshake assuming it's a websocket request
websocket_handshake(req, res) = begin
  key = get_websocket_key(req)
  resp_key = generate_websocket_key(key)

  #TODO: use a proper HTTP response type
  res.status = 101
  res.headers["Upgrade"] = "websocket"
  res.headers["Connection"] = "Upgrade"
  res.headers["Sec-WebSocket-Accept"] = resp_key
  res.data = ""
end

function http_post_header(req::Request, res::Response)
    if !isempty(req.query)
        req.q = parse_qsr(req.query)
    end

    # using web sockets
    if get(req.headers, "Connection", nothing) == "Upgrade"
        hupgrade = get(req.headers, "Upgrade", "")
        if hupgrade == "websocket"
            if get(req.env["server"].options, :ws, true)
                req.websocket = WebSockets.WebSocket(0, req.sock)
                websocket_handshake(req, res)
            else
                throw(HTTPParserHeaderException("Websockts not allowed"))
            end
        else
            throw(HTTPParserHeaderException("Invalid Connection HEADER", "Upgrade: $(hupgrade)"))
        end
    end

    ct = get(req.headers, "Content-Type", "")

    if search(ct, "application/x-www-form-urlencoded").start > 0
        req.p = parse_qsr(C.bodys(req))
    elseif search(ct, "application/json").start > 0
        req.p = JSON.parse(C.bodys(req))
    end
end

handle(h::TCPHandler, c::Client) = h.handle(c)

type HTTPParserHeaderException <: Exception
    message::String
    line::Union(Nothing, String)

    HTTPParserHeaderException(m::String, l::Union(Nothing, String)) = new(m, l)
    HTTPParserHeaderException(m::String) = new(m, nothing)
end

function default_http_processor(client::Client, resource_handler::Function)
    req = Request(client.sock)
    req.env["client"] = client
    req.env["server"] = client.server
    event(client.server, "post_request_init", req)
    res = Response()
    res.req = req
    res_arr = [res]
    write_res = true
    uv_error = false

    try
        try
            parse_http_headers(req)
            hc_event(req, "post_header", req, res)

            # see http://tools.ietf.org/html/rfc7230#section-6.3
            if req.protocol != nothing && get(req.headers, "Connection", nothing) != "close"
                if req.protocol.name == "HTTP" && req.protocol.version >= v"1.1"
                    client.finished = false
                end
            end

            hc_event(req, "pre_handler", req)

            req.finished = client.finished
        catch e
            if isa(e, UVError)
                client.finished = true
                write_res = false
                error = Error(increase_error(client.server), req, res, e, catch_backtrace())
                event(client.server, "request_socket_error", error)
                hc_event(req, "socket_error", error, (new_res) -> begin
                                res_arr[1] = new_res
                            end)
                return
            else
                rethrow()
            end
        end

        if req.websocket != nothing
            write_res = false
            write(req.sock, res)
            resource_handler(req)
            WebSockets.close(req.websocket)
        else
            res2 = resource_handler(req)

            if isa(res2, Response)
                res2.req = req
                res_arr[1] = res2
            end
        end
        hc_event(req, "post_handler", res, (new_res) -> begin
                        res_arr[1] = new_res
                     end)
    catch e
        if isa(e, CloseClientException)
            client.finished = true
            write_res = false
        else
            res = res_arr[1]
            res.status = 500

            error = Error(increase_error(client.server), req, res, e, catch_backtrace())
            event(client.server, "request_error", error)
            hc_event(req, "error", error, (new_res) -> begin
                            res_arr[1] = new_res
                        end)
        end
    finally
        if write_res && isopen(req.sock)
            res = res_arr[1]
            write(req.sock, res)
        end
    end
end

function http_handler(resource_handler::Function)
    callback = client::Client -> default_http_processor(client, resource_handler)
    TCPHandler(callback)
end

Server(handler::Function; args...) = Server(TCPHandler(handler), args...)
HTTPServer(resource_handler::Function; args...) = Server(http_handler(resource_handler), args...)

function event(server::Server, event::String, args...)
    haskey(server.handler.events, event) && server.handler.events[event](args...)
end

@doc "Converts a `Response` to an HTTP response string" ->
function write{T<:IO}(io::T, res::Response)
    write(io, join(["HTTP/1.1", res.status, STATUS_CODES[res.status], "\r\n"], " "))

    it = nothing

    if isa(res.data, Iterable) || isa(res.data, Task)
        it = res.data
    elseif isa(res.data, Function)
        it = Iterable(Task(res.data))
    end

    if it != nothing
        res.headers["Transfer-Encoding"] = "chunked"
    elseif !haskey(res.headers, "Content-Length")
        res.headers["Content-Length"] = string(sizeof(res.data))
    end

    for (header, value) in res.headers
        write(io, @sprintf "%s: %s\r\n" header value)
    end

    for (header, value_list) in res.mheaders
        for value in value_list
            write(io, @sprintf "%s: %s\r\n" header value)
        end
    end

    write(io, "\r\n")

    if it == nothing
        write(io, res.data)
    else
        try
            for data in it.data
                write_chunk(io, data)
            end
        catch e
            bt = catch_backtrace()
            req = res.req
            server = req.env["server"]
            error = Error(increase_error(server), req, res, e, bt)
            event(server, "response_iter_data_error", error)
            hc_event(req, "response_iter_data_error", error)
        end

        write(io, @sprintf "%x\r\n" 0)
        write(io, "\r\n")
        write(io, "\r\n")
    end
end

function listen(server::Server, host::Base.IpAddr, port::Integer)
    server.handler.sock = listen(host, port)
    inet = "$host:$port"
    event(server, "listen", inet)
    return server
end

listen(server::Server, port::Integer) = listen(server, IPv4(0), port)

@unix_only function listen(server::Server, path::String)
    bind(server.handler.sock, path) || throw(ArgumentError("could not listen on path $path"))
    Base.uv_error("listen", Base._listen(server.handler.sock))
    event(server, "listen", path)
    return server
end

function run(server::Server; args...)
    params = Dict(args)

    # parse parameters
    port = get(params, :port, 0)
    host = get(params, :host, IPv4(0))
    use_https = haskey(params, :ssl)
    use_sockets = @unix? (haskey(params, :socket) && !haskey(params, :port)) : false

    server = if use_sockets
        listen(server, params[:socket])  # start server on Unix socket
    else
        listen(server, host, port)       # start server on network socket
    end

    if use_https
        println("HTTPS")
        #handle_https_request(server, params[:ssl])
    else
        handle_http_request(server)
    end
end

@doc """ Handle HTTP request from client """ ->
function handle_http_request(server::Server)
    # handle requests, Base.wait_accept blocks until a connection is made
    while true
        sock = accept(server.handler.sock)
        @async process_sock(server, sock)
    end
end

@doc """ Handle HTTPS request from client """ ->
function handle_https_request(server::Server, cert_store::GnuTLS.CertificateStore)
    while true
        sess = GnuTLS.Session(true)
        set_priority_string!(sess)
        set_credentials!(sess, cert_store)
        client = accept(server.handler.sock)
        try
            associate_stream(sess, client)
            handshake!(sess)
        catch e
            println("Error establishing SSL connection: ", e)
            close(client)
            continue
        end
        sock = accept(server.handler.sock)
        @async process_sock(server, sock)
    end
end

function process_sock(server::Server, sock)
    client = Client(server, sock)
    event(server, "connect", client)

    while isopen(sock)
        try
            handle(server.handler, client)
        catch e
            if isa(e,GnuTLS.GnuTLSException) && e.code == -110
                # Because Chrome is buggy on OS X, ignore E_PREMATURE_TERMINATION
            else
                bt = catch_backtrace()
                err_num = increase_error(server)

                print_error = io -> begin
                    println(io, "[CLIENT_EXCEPTION $err_num] Begin")
                    println(io, "Client: $client")
                    println(io, "Error Type: $(typeof(e))")
                    println(io, "")
                    showerror(io, e, bt)
                    println(io, "")
                    println(io, "[CLIENT_EXCEPTION $err_num] End")
                end

                print_error(STDERR)

                client.finished = true
            end
        finally
            if client.finished
                if isopen(sock)
                    close(sock)
                end

                break
            end
        end
    end

    event(server, "close", client)
end

end # module


text:
#ifndef __i386__
#include <asm/mach/time.h>
#endif
#include <linux/android_alarm.h>
#include <linux/device.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/sysdev.h>
#include <linux/wakelock.h>

#define ANDROID_ALARM_PRINT_ERROR (1U << 0)
#define ANDROID_ALARM_PRINT_INIT_STATUS (1U << 1)
#define ANDROID_ALARM_PRINT_TSET (1U << 2)
#define ANDROID_ALARM_PRINT_CALL (1U << 3)
#define ANDROID_ALARM_PRINT_SUSPEND (1U << 4)
#define ANDROID_ALARM_PRINT_INT (1U << 5)
#define ANDROID_ALARM_PRINT_FLOW (1U << 6)

static int debug_mask = ANDROID_ALARM_PRINT_ERROR | \
			ANDROID_ALARM_PRINT_INIT_STATUS;
module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);

#define pr_alarm(debug_level_mask, args...) \
	do { \
		if (debug_mask & ANDROID_ALARM_PRINT_##debug_level_mask) { \
			pr_info(args); \
		} \
	} while (0)

#define ANDROID_ALARM_WAKEUP_MASK ( \
	ANDROID_ALARM_RTC_WAKEUP_MASK | \
	ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK)

/* support old usespace code */
#define ANDROID_ALARM_SET_OLD               _IOW('a', 2, time_t) /* set alarm */
#define ANDROID_ALARM_SET_AND_WAIT_OLD      _IOW('a', 3, time_t)

struct alarm_queue {
	struct rb_root alarms;
	struct rb_node *first;
	struct hrtimer timer;
	ktime_t delta;
	bool stopped;
	ktime_t stopped_time;
};

static struct rtc_device *alarm_rtc_dev;
static DEFINE_SPINLOCK(alarm_slock);
static DEFINE_MUTEX(alarm_setrtc_mutex);
static struct wake_lock alarm_rtc_wake_lock;
static struct platform_device *alarm_platform_dev;
struct alarm_queue alarms[ANDROID_ALARM_TYPE_COUNT];
static bool suspended;

static void update_timer_locked(struct alarm_queue *base, bool head_removed)
{
	struct alarm *alarm;
	bool is_wakeup = base == &alarms[ANDROID_ALARM_RTC_WAKEUP] ||
			base == &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP];

	if (base->stopped) {
		pr_alarm(FLOW, "changed alarm while setting the wall time\n");
		return;
	}

	if (is_wakeup && !suspended && head_removed)
		wake_unlock(&alarm_rtc_wake_lock);

	if (!base->first)
		return;

	alarm = container_of(base->first, struct alarm, node);

	pr_alarm(FLOW, "selected alarm, type %d, func %pF at %lld\n",
		alarm->type, alarm->function, ktime_to_ns(alarm->expires));

	if (is_wakeup && suspended) {
		pr_alarm(FLOW, "changed alarm while suspened\n");
		wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ);
		return;
	}

	hrtimer_try_to_cancel(&base->timer);
	base->timer.node.expires = ktime_add(base->delta, alarm->expires);
	base->timer._softexpires = ktime_add(base->delta, alarm->softexpires);
	hrtimer_start_expires(&base->timer, HRTIMER_MODE_ABS);
}

static void alarm_enqueue_locked(struct alarm *alarm)
{
	struct alarm_queue *base = &alarms[alarm->type];
	struct rb_node **link = &base->alarms.rb_node;
	struct rb_node *parent = NULL;
	struct alarm *entry;
	int leftmost = 1;
	bool was_first = false;

	pr_alarm(FLOW, "added alarm, type %d, func %pF at %lld\n",
		alarm->type, alarm->function, ktime_to_ns(alarm->expires));

	if (base->first == &alarm->node) {
		base->first = rb_next(&alarm->node);
		was_first = true;
	}
	if (!RB_EMPTY_NODE(&alarm->node)) {
		rb_erase(&alarm->node, &base->alarms);
		RB_CLEAR_NODE(&alarm->node);
	}

	while (*link) {
		parent = *link;
		entry = rb_entry(parent, struct alarm, node);
		/*
		* We dont care about collisions. Nodes with
		* the same expiry time stay together.
		*/
		if (alarm->expires.tv64 < entry->expires.tv64) {
			link = &(*link)->rb_left;
		} else {
			link = &(*link)->rb_right;
			leftmost = 0;
		}
	}
	if (leftmost)
		base->first = &alarm->node;
	if (leftmost || was_first)
		update_timer_locked(base, was_first);

	rb_link_node(&alarm->node, parent, link);
	rb_insert_color(&alarm->node, &base->alarms);
}

/**
 * alarm_init - initialize an alarm
 * @alarm:	the alarm to be initialized
 * @type:	the alarm type to be used
 * @function:	alarm callback function
 */
void alarm_init(struct alarm *alarm,
	enum android_alarm_type type, void (*function)(struct alarm *))
{
	RB_CLEAR_NODE(&alarm->node);
	alarm->type = type;
	alarm->function = function;

	pr_alarm(FLOW, "created alarm, type %d, func %pF\n", type, function);
}

/**
 * alarm_start_range - (re)start an alarm
 * @alarm:	the alarm to be added
 * @start:	earliest expiry time
 * @end:	expiry time
 */
void alarm_start_range(struct alarm *alarm, ktime_t start, ktime_t end)
{
	unsigned long flags;

	spin_lock_irqsave(&alarm_slock, flags);
	alarm->softexpires = start;
	alarm->expires = end;
	alarm_enqueue_locked(alarm);
	spin_unlock_irqrestore(&alarm_slock, flags);
}

/**
 * alarm_try_to_cancel - try to deactivate an alarm
 * @alarm:	alarm to stop
 *
 * Returns:
 *  0 when the alarm was not active
 *  1 when the alarm was active
 * -1 when the alarm may currently be excuting the callback function and
 *    cannot be stopped (it may also be inactive)
 */
int alarm_try_to_cancel(struct alarm *alarm)
{
	struct alarm_queue *base = &alarms[alarm->type];
	unsigned long flags;
	bool first = false;
	int ret = 0;

	spin_lock_irqsave(&alarm_slock, flags);
	if (!RB_EMPTY_NODE(&alarm->node)) {
		pr_alarm(FLOW, "canceled alarm, type %d, func %pF at %lld\n",
			alarm->type, alarm->function,
			ktime_to_ns(alarm->expires));
		ret = 1;
		if (base->first == &alarm->node) {
			base->first = rb_next(&alarm->node);
			first = true;
		}
		rb_erase(&alarm->node, &base->alarms);
		RB_CLEAR_NODE(&alarm->node);
		if (first)
			update_timer_locked(base, true);
	} else
		pr_alarm(FLOW, "tried to cancel alarm, type %d, func %pF\n",
			alarm->type, alarm->function);
	spin_unlock_irqrestore(&alarm_slock, flags);
	if (!ret && hrtimer_callback_running(&base->timer))
		ret = -1;
	return ret;
}

/**
 * alarm_cancel - cancel an alarm and wait for the handler to finish.
 * @alarm:	the alarm to be cancelled
 *
 * Returns:
 *  0 when the alarm was not active
 *  1 when the alarm was active
 */
int alarm_cancel(struct alarm *alarm)
{
	for (;;) {
		int ret = alarm_try_to_cancel(alarm);
		if (ret >= 0)
			return ret;
		cpu_relax();
	}
}

/**
 * alarm_set_rtc - set the kernel and rtc walltime
 * @new_time:	timespec value containing the new time
 */
int alarm_set_rtc(struct timespec new_time)
{
	int i;
	int ret;
	unsigned long flags;
	struct rtc_time rtc_new_rtc_time;
	struct timespec tmp_time;

	rtc_time_to_tm(new_time.tv_sec, &rtc_new_rtc_time);

	pr_alarm(TSET, "set rtc %ld %ld - rtc %02d:%02d:%02d %02d/%02d/%04d\n",
		new_time.tv_sec, new_time.tv_nsec,
		rtc_new_rtc_time.tm_hour, rtc_new_rtc_time.tm_min,
		rtc_new_rtc_time.tm_sec, rtc_new_rtc_time.tm_mon + 1,
		rtc_new_rtc_time.tm_mday,
		rtc_new_rtc_time.tm_year + 1900);

	mutex_lock(&alarm_setrtc_mutex);
	spin_lock_irqsave(&alarm_slock, flags);
	wake_lock(&alarm_rtc_wake_lock);
	getnstimeofday(&tmp_time);
	for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) {
		hrtimer_try_to_cancel(&alarms[i].timer);
		alarms[i].stopped = true;
		alarms[i].stopped_time = timespec_to_ktime(tmp_time);
	}
	alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].delta =
		alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta =
		ktime_sub(alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta,
			timespec_to_ktime(timespec_sub(tmp_time, new_time)));
	spin_unlock_irqrestore(&alarm_slock, flags);
	ret = do_settimeofday(&new_time);
	spin_lock_irqsave(&alarm_slock, flags);
	for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) {
		alarms[i].stopped = false;
		update_timer_locked(&alarms[i], false);
	}
	spin_unlock_irqrestore(&alarm_slock, flags);
	if (ret < 0) {
		pr_alarm(ERROR, "alarm_set_rtc: Failed to set time\n");
		goto err;
	}
	if (!alarm_rtc_dev) {
		pr_alarm(ERROR,
			"alarm_set_rtc: no RTC, time will be lost on reboot\n");
		goto err;
	}
	ret = rtc_set_time(alarm_rtc_dev, &rtc_new_rtc_time);
	if (ret < 0)
		pr_alarm(ERROR, "alarm_set_rtc: "
			"Failed to set RTC, time will be lost on reboot\n");
err:
	wake_unlock(&alarm_rtc_wake_lock);
	mutex_unlock(&alarm_setrtc_mutex);
	return ret;
}

/**
 * alarm_get_elapsed_realtime - get the elapsed real time in ktime_t format
 *
 * returns the time in ktime_t format
 */
ktime_t alarm_get_elapsed_realtime(void)
{
	ktime_t now;
	unsigned long flags;
	struct alarm_queue *base = &alarms[ANDROID_ALARM_ELAPSED_REALTIME];

	spin_lock_irqsave(&alarm_slock, flags);
	now = base->stopped ? base->stopped_time : ktime_get_real();
	now = ktime_sub(now, base->delta);
	spin_unlock_irqrestore(&alarm_slock, flags);
	return now;
}

static enum hrtimer_restart alarm_timer_triggered(struct hrtimer *timer)
{
	struct alarm_queue *base;
	struct alarm *alarm;
	unsigned long flags;
	ktime_t now;

	spin_lock_irqsave(&alarm_slock, flags);

	base = container_of(timer, struct alarm_queue, timer);
	now = base->stopped ? base->stopped_time : hrtimer_cb_get_time(timer);
	now = ktime_sub(now, base->delta);

	pr_alarm(INT, "alarm_timer_triggered type %d at %lld\n",
		base - alarms, ktime_to_ns(now));

	while (base->first) {
		alarm = container_of(base->first, struct alarm, node);
		if (alarm->softexpires.tv64 > now.tv64) {
			pr_alarm(FLOW, "don't call alarm, %pF, %lld (s %lld)\n",
				alarm->function, ktime_to_ns(alarm->expires),
				ktime_to_ns(alarm->softexpires));
			break;
		}
		base->first = rb_next(&alarm->node);
		rb_erase(&alarm->node, &base->alarms);
		RB_CLEAR_NODE(&alarm->node);
		pr_alarm(CALL, "call alarm, type %d, func %pF, %lld (s %lld)\n",
			alarm->type, alarm->function,
			ktime_to_ns(alarm->expires),
			ktime_to_ns(alarm->softexpires));
		spin_unlock_irqrestore(&alarm_slock, flags);
		alarm->function(alarm);
		spin_lock_irqsave(&alarm_slock, flags);
	}
	if (!base->first)
		pr_alarm(FLOW, "no more alarms of type %d\n", base - alarms);
	update_timer_locked(base, true);
	spin_unlock_irqrestore(&alarm_slock, flags);
	return HRTIMER_NORESTART;
}

static void alarm_triggered_func(void *p)
{
	struct rtc_device *rtc = alarm_rtc_dev;
	if (!(rtc->irq_data & RTC_AF))
		return;
	pr_alarm(INT, "rtc alarm triggered\n");
	wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ);
}

static int alarm_suspend(struct platform_device *pdev, pm_message_t state)
{
	int                 err = 0;
	unsigned long       flags;
	struct rtc_wkalrm   rtc_alarm;
	struct rtc_time     rtc_current_rtc_time;
	unsigned long       rtc_current_time;
	unsigned long       rtc_alarm_time;
	struct timespec     rtc_delta;
	struct timespec     wall_time;
	struct alarm_queue *wakeup_queue = NULL;
	struct alarm_queue *tmp_queue = NULL;

	pr_alarm(SUSPEND, "alarm_suspend(%p, %d)\n", pdev, state.event);

	spin_lock_irqsave(&alarm_slock, flags);
	suspended = true;
	spin_unlock_irqrestore(&alarm_slock, flags);

	hrtimer_cancel(&alarms[ANDROID_ALARM_RTC_WAKEUP].timer);
	hrtimer_cancel(&alarms[
			ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].timer);

	tmp_queue = &alarms[ANDROID_ALARM_RTC_WAKEUP];
	if (tmp_queue->first)
		wakeup_queue = tmp_queue;
	tmp_queue = &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP];
	if (tmp_queue->first && (!wakeup_queue ||
				hrtimer_get_expires(&tmp_queue->timer).tv64 <
				hrtimer_get_expires(&wakeup_queue->timer).tv64))
		wakeup_queue = tmp_queue;
	if (wakeup_queue) {
		rtc_read_time(alarm_rtc_dev, &rtc_current_rtc_time);
		getnstimeofday(&wall_time);
		rtc_tm_to_time(&rtc_current_rtc_time, &rtc_current_time);
		set_normalized_timespec(&rtc_delta,
					wall_time.tv_sec - rtc_current_time,
					wall_time.tv_nsec);

		rtc_alarm_time = timespec_sub(ktime_to_timespec(
			hrtimer_get_expires(&wakeup_queue->timer)),
			rtc_delta).tv_sec;

		rtc_time_to_tm(rtc_alarm_time, &rtc_alarm.time);
		rtc_alarm.enabled = 1;
		rtc_set_alarm(alarm_rtc_dev, &rtc_alarm);
		rtc_read_time(alarm_rtc_dev, &rtc_current_rtc_time);
		rtc_tm_to_time(&rtc_current_rtc_time, &rtc_current_time);
		pr_alarm(SUSPEND,
			"rtc alarm set at %ld, now %ld, rtc delta %ld.%09ld\n",
			rtc_alarm_time, rtc_current_time,
			rtc_delta.tv_sec, rtc_delta.tv_nsec);
		if (rtc_current_time + 1 >= rtc_alarm_time) {
			pr_alarm(SUSPEND, "alarm about to go off\n");
			memset(&rtc_alarm, 0, sizeof(rtc_alarm));
			rtc_alarm.enabled = 0;
			rtc_set_alarm(alarm_rtc_dev, &rtc_alarm);

			spin_lock_irqsave(&alarm_slock, flags);
			suspended = false;
			wake_lock_timeout(&alarm_rtc_wake_lock, 2 * HZ);
			update_timer_locked(&alarms[ANDROID_ALARM_RTC_WAKEUP],
									false);
			update_timer_locked(&alarms[
				ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP], false);
			err = -EBUSY;
			spin_unlock_irqrestore(&alarm_slock, flags);
		}
	}
	return err;
}

static int alarm_resume(struct platform_device *pdev)
{
	struct rtc_wkalrm alarm;
	unsigned long       flags;

	pr_alarm(SUSPEND, "alarm_resume(%p)\n", pdev);

	memset(&alarm, 0, sizeof(alarm));
	alarm.enabled = 0;
	rtc_set_alarm(alarm_rtc_dev, &alarm);

	spin_lock_irqsave(&alarm_slock, flags);
	suspended = false;
	update_timer_locked(&alarms[ANDROID_ALARM_RTC_WAKEUP], false);
	update_timer_locked(&alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP],
									false);
	spin_unlock_irqrestore(&alarm_slock, flags);

	return 0;
}

static struct rtc_task alarm_rtc_task = {
	.func = alarm_triggered_func
};

static int rtc_alarm_add_device(struct device *dev,
				struct class_interface *class_intf)
{
	int err;
	struct rtc_device *rtc = to_rtc_device(dev);

	mutex_lock(&alarm_setrtc_mutex);

	if (alarm_rtc_dev) {
		err = -EBUSY;
		goto err1;
	}

	alarm_platform_dev =
		platform_device_register_simple("alarm", -1, NULL, 0);
	if (IS_ERR(alarm_platform_dev)) {
		err = PTR_ERR(alarm_platform_dev);
		goto err2;
	}
	err = rtc_irq_register(rtc, &alarm_rtc_task);
	if (err)
		goto err3;
	alarm_rtc_dev = rtc;
	pr_alarm(INIT_STATUS, "using rtc device, %s, for alarms", rtc->name);
	mutex_unlock(&alarm_setrtc_mutex);

	return 0;

err3:
	platform_device_unregister(alarm_platform_dev);
err2:
err1:
	mutex_unlock(&alarm_setrtc_mutex);
	return err;
}

static void rtc_alarm_remove_device(struct device *dev,
				    struct class_interface *class_intf)
{
	if (dev == &alarm_rtc_dev->dev) {
		pr_alarm(INIT_STATUS, "lost rtc device for alarms");
		rtc_irq_unregister(alarm_rtc_dev, &alarm_rtc_task);
		platform_device_unregister(alarm_platform_dev);
		alarm_rtc_dev = NULL;
	}
}

static struct class_interface rtc_alarm_interface = {
	.add_dev = &rtc_alarm_add_device,
	.remove_dev = &rtc_alarm_remove_device,
};

static struct platform_driver alarm_driver = {
	.suspend = alarm_suspend,
	.resume = alarm_resume,
	.driver = {
		.name = "alarm"
	}
};

static int __init alarm_late_init(void)
{
	unsigned long   flags;
	struct timespec tmp_time, system_time;

	/* this needs to run after the rtc is read at boot */
	spin_lock_irqsave(&alarm_slock, flags);
	/* We read the current rtc and system time so we can later calulate
	 * elasped realtime to be (boot_systemtime + rtc - boot_rtc) ==
	 * (rtc - (boot_rtc - boot_systemtime))
	 */
	getnstimeofday(&tmp_time);
	ktime_get_ts(&system_time);
	alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].delta =
		alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta =
			timespec_to_ktime(timespec_sub(tmp_time, system_time));

	spin_unlock_irqrestore(&alarm_slock, flags);
	return 0;
}

static int __init alarm_driver_init(void)
{
	int err;
	int i;

	for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) {
		hrtimer_init(&alarms[i].timer,
				CLOCK_REALTIME, HRTIMER_MODE_ABS);
		alarms[i].timer.function = alarm_timer_triggered;
	}
	hrtimer_init(&alarms[ANDROID_ALARM_SYSTEMTIME].timer,
		     CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
	alarms[ANDROID_ALARM_SYSTEMTIME].timer.function = alarm_timer_triggered;
	err = platform_driver_register(&alarm_driver);
	if (err < 0)
		goto err1;
	wake_lock_init(&alarm_rtc_wake_lock, WAKE_LOCK_SUSPEND, "alarm_rtc");
	rtc_alarm_interface.class = rtc_class;
	err = class_interface_register(&rtc_alarm_interface);
	if (err < 0)
		goto err2;

	return 0;

err2:
	wake_lock_destroy(&alarm_rtc_wake_lock);
	platform_driver_unregister(&alarm_driver);
err1:
	return err;
}

static void  __exit alarm_exit(void)
{
	class_interface_unregister(&rtc_alarm_interface);
	wake_lock_destroy(&alarm_rtc_wake_lock);
	platform_driver_unregister(&alarm_driver);
}

late_initcall(alarm_late_init);
module_init(alarm_driver_init);
module_exit(alarm_exit);


text:
<?php

namespace Cdn\Request\V20141111;

class AddLivePullStreamInfoRequest extends \RpcAcsRequest
{
	function  __construct()
	{
		parent::__construct("Cdn", "2014-11-11", "AddLivePullStreamInfo");
		$this->setMethod("POST");
	}

	private  $sourceUrl;

	private  $appName;

	private  $securityToken;

	private  $domainName;

	private  $endTime;

	private  $startTime;

	private  $ownerId;

	private  $streamName;

	public function getSourceUrl() {
		return $this->sourceUrl;
	}

	public function setSourceUrl($sourceUrl) {
		$this->sourceUrl = $sourceUrl;
		$this->queryParameters["SourceUrl"]=$sourceUrl;
	}

	public function getAppName() {
		return $this->appName;
	}

	public function setAppName($appName) {
		$this->appName = $appName;
		$this->queryParameters["AppName"]=$appName;
	}

	public function getSecurityToken() {
		return $this->securityToken;
	}

	public function setSecurityToken($securityToken) {
		$this->securityToken = $securityToken;
		$this->queryParameters["SecurityToken"]=$securityToken;
	}

	public function getDomainName() {
		return $this->domainName;
	}

	public function setDomainName($domainName) {
		$this->domainName = $domainName;
		$this->queryParameters["DomainName"]=$domainName;
	}

	public function getEndTime() {
		return $this->endTime;
	}

	public function setEndTime($endTime) {
		$this->endTime = $endTime;
		$this->queryParameters["EndTime"]=$endTime;
	}

	public function getStartTime() {
		return $this->startTime;
	}

	public function setStartTime($startTime) {
		$this->startTime = $startTime;
		$this->queryParameters["StartTime"]=$startTime;
	}

	public function getOwnerId() {
		return $this->ownerId;
	}

	public function setOwnerId($ownerId) {
		$this->ownerId = $ownerId;
		$this->queryParameters["OwnerId"]=$ownerId;
	}

	public function getStreamName() {
		return $this->streamName;
	}

	public function setStreamName($streamName) {
		$this->streamName = $streamName;
		$this->queryParameters["StreamName"]=$streamName;
	}

}


text:
export function onIncrement() {
  return {
    type: 'INCREMENT'
  };
}

export function onDecrement() {
  return {
    type: 'DECREMENT'
  };
}


text:
package org.apache.solr.client.solrj.impl;

import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.solr.common.params.SolrParams;

/**
 * The default http client configurer. If the behaviour needs to be customized a
 * new HttpCilentConfigurer can be set by calling
 * {@link HttpClientUtil#setConfigurer(HttpClientConfigurer)}
 */
public class HttpClientConfigurer {

  protected void configure(DefaultHttpClient httpClient, SolrParams config) {

    if (config.get(HttpClientUtil.PROP_MAX_CONNECTIONS) != null) {
      HttpClientUtil.setMaxConnections(httpClient,
          config.getInt(HttpClientUtil.PROP_MAX_CONNECTIONS));
    }

    if (config.get(HttpClientUtil.PROP_MAX_CONNECTIONS_PER_HOST) != null) {
      HttpClientUtil.setMaxConnectionsPerHost(httpClient,
          config.getInt(HttpClientUtil.PROP_MAX_CONNECTIONS_PER_HOST));
    }

    if (config.get(HttpClientUtil.PROP_CONNECTION_TIMEOUT) != null) {
      HttpClientUtil.setConnectionTimeout(httpClient,
          config.getInt(HttpClientUtil.PROP_CONNECTION_TIMEOUT));
    }

    if (config.get(HttpClientUtil.PROP_SO_TIMEOUT) != null) {
      HttpClientUtil.setSoTimeout(httpClient,
          config.getInt(HttpClientUtil.PROP_SO_TIMEOUT));
    }

    if (config.get(HttpClientUtil.PROP_USE_RETRY) != null) {
      HttpClientUtil.setUseRetry(httpClient,
          config.getBool(HttpClientUtil.PROP_USE_RETRY));
    }

    if (config.get(HttpClientUtil.PROP_FOLLOW_REDIRECTS) != null) {
      HttpClientUtil.setFollowRedirects(httpClient,
          config.getBool(HttpClientUtil.PROP_FOLLOW_REDIRECTS));
    }

    final String basicAuthUser = config
        .get(HttpClientUtil.PROP_BASIC_AUTH_USER);
    final String basicAuthPass = config
        .get(HttpClientUtil.PROP_BASIC_AUTH_PASS);
    HttpClientUtil.setBasicAuth(httpClient, basicAuthUser, basicAuthPass);

    if (config.get(HttpClientUtil.PROP_ALLOW_COMPRESSION) != null) {
      HttpClientUtil.setAllowCompression(httpClient,
          config.getBool(HttpClientUtil.PROP_ALLOW_COMPRESSION));
    }

    boolean sslCheckPeerName = toBooleanDefaultIfNull(
        toBooleanObject(System.getProperty(HttpClientUtil.SYS_PROP_CHECK_PEER_NAME)), true);
    if(sslCheckPeerName == false) {
      HttpClientUtil.setHostNameVerifier(httpClient, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
    }
  }

  public static boolean toBooleanDefaultIfNull(Boolean bool, boolean valueIfNull) {
    if (bool == null) {
      return valueIfNull;
    }
    return bool.booleanValue() ? true : false;
  }

  public static Boolean toBooleanObject(String str) {
    if ("true".equalsIgnoreCase(str)) {
      return Boolean.TRUE;
    } else if ("false".equalsIgnoreCase(str)) {
      return Boolean.FALSE;
    }
    // no match
    return null;
  }
}


text:
<?php

class ZendL_Tool_Rpc_System_Provider_Providers implements ZendL_Tool_Rpc_Provider_Interface
{

    public function listAction()
    {
        $providerRegistry = ZendL_Tool_Rpc_Provider_Registry::getInstance();

        foreach ($providerRegistry->getProviderSignatures() as $provider) {
            echo $provider->getName() . PHP_EOL;
        }
    }

}