text:
#include "postgres.h"

#include <math.h>

#include "access/gist.h"
#include "access/stratnum.h"
#include "utils/builtins.h"
#include "utils/geo_decls.h"

static bool gist_box_leaf_consistent(BOX *key, BOX *query,
						 StrategyNumber strategy);
static bool rtree_internal_consistent(BOX *key, BOX *query,
						  StrategyNumber strategy);

/* Minimum accepted ratio of split */
#define LIMIT_RATIO 0.3

/* Convenience macros for NaN-aware comparisons */
#define FLOAT8_EQ(a,b)	(float8_cmp_internal(a, b) == 0)
#define FLOAT8_LT(a,b)	(float8_cmp_internal(a, b) < 0)
#define FLOAT8_LE(a,b)	(float8_cmp_internal(a, b) <= 0)
#define FLOAT8_GT(a,b)	(float8_cmp_internal(a, b) > 0)
#define FLOAT8_GE(a,b)	(float8_cmp_internal(a, b) >= 0)
#define FLOAT8_MAX(a,b)  (FLOAT8_GT(a, b) ? (a) : (b))
#define FLOAT8_MIN(a,b)  (FLOAT8_LT(a, b) ? (a) : (b))

/**************************************************
 * Box ops
 **************************************************/

/*
 * Calculates union of two boxes, a and b. The result is stored in *n.
 */
static void
rt_box_union(BOX *n, const BOX *a, const BOX *b)
{
	n->high.x = FLOAT8_MAX(a->high.x, b->high.x);
	n->high.y = FLOAT8_MAX(a->high.y, b->high.y);
	n->low.x = FLOAT8_MIN(a->low.x, b->low.x);
	n->low.y = FLOAT8_MIN(a->low.y, b->low.y);
}

/*
 * Size of a BOX for penalty-calculation purposes.
 * The result can be +Infinity, but not NaN.
 */
static double
size_box(const BOX *box)
{
	/*
	 * Check for zero-width cases.  Note that we define the size of a zero-
	 * by-infinity box as zero.  It's important to special-case this somehow,
	 * as naively multiplying infinity by zero will produce NaN.
	 *
	 * The less-than cases should not happen, but if they do, say "zero".
	 */
	if (FLOAT8_LE(box->high.x, box->low.x) ||
		FLOAT8_LE(box->high.y, box->low.y))
		return 0.0;

	/*
	 * We treat NaN as larger than +Infinity, so any distance involving a NaN
	 * and a non-NaN is infinite.  Note the previous check eliminated the
	 * possibility that the low fields are NaNs.
	 */
	if (isnan(box->high.x) || isnan(box->high.y))
		return get_float8_infinity();
	return (box->high.x - box->low.x) * (box->high.y - box->low.y);
}

/*
 * Return amount by which the union of the two boxes is larger than
 * the original BOX's area.  The result can be +Infinity, but not NaN.
 */
static double
box_penalty(const BOX *original, const BOX *new)
{
	BOX			unionbox;

	rt_box_union(&unionbox, original, new);
	return size_box(&unionbox) - size_box(original);
}

/*
 * The GiST Consistent method for boxes
 *
 * Should return false if for all data items x below entry,
 * the predicate x op query must be FALSE, where op is the oper
 * corresponding to strategy in the pg_amop table.
 */
Datum
gist_box_consistent(PG_FUNCTION_ARGS)
{
	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
	BOX		   *query = PG_GETARG_BOX_P(1);
	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);

	/* Oid		subtype = PG_GETARG_OID(3); */
	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);

	/* All cases served by this function are exact */
	*recheck = false;

	if (DatumGetBoxP(entry->key) == NULL || query == NULL)
		PG_RETURN_BOOL(FALSE);

	/*
	 * if entry is not leaf, use rtree_internal_consistent, else use
	 * gist_box_leaf_consistent
	 */
	if (GIST_LEAF(entry))
		PG_RETURN_BOOL(gist_box_leaf_consistent(DatumGetBoxP(entry->key),
												query,
												strategy));
	else
		PG_RETURN_BOOL(rtree_internal_consistent(DatumGetBoxP(entry->key),
												 query,
												 strategy));
}

/*
 * Increase BOX b to include addon.
 */
static void
adjustBox(BOX *b, const BOX *addon)
{
	if (FLOAT8_LT(b->high.x, addon->high.x))
		b->high.x = addon->high.x;
	if (FLOAT8_GT(b->low.x, addon->low.x))
		b->low.x = addon->low.x;
	if (FLOAT8_LT(b->high.y, addon->high.y))
		b->high.y = addon->high.y;
	if (FLOAT8_GT(b->low.y, addon->low.y))
		b->low.y = addon->low.y;
}

/*
 * The GiST Union method for boxes
 *
 * returns the minimal bounding box that encloses all the entries in entryvec
 */
Datum
gist_box_union(PG_FUNCTION_ARGS)
{
	GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
	int		   *sizep = (int *) PG_GETARG_POINTER(1);
	int			numranges,
				i;
	BOX		   *cur,
			   *pageunion;

	numranges = entryvec->n;
	pageunion = (BOX *) palloc(sizeof(BOX));
	cur = DatumGetBoxP(entryvec->vector[0].key);
	memcpy((void *) pageunion, (void *) cur, sizeof(BOX));

	for (i = 1; i < numranges; i++)
	{
		cur = DatumGetBoxP(entryvec->vector[i].key);
		adjustBox(pageunion, cur);
	}
	*sizep = sizeof(BOX);

	PG_RETURN_POINTER(pageunion);
}

/*
 * GiST Compress methods for boxes
 *
 * do not do anything.
 */
Datum
gist_box_compress(PG_FUNCTION_ARGS)
{
	PG_RETURN_POINTER(PG_GETARG_POINTER(0));
}

/*
 * GiST DeCompress method for boxes (also used for points, polygons
 * and circles)
 *
 * do not do anything --- we just use the stored box as is.
 */
Datum
gist_box_decompress(PG_FUNCTION_ARGS)
{
	PG_RETURN_POINTER(PG_GETARG_POINTER(0));
}

/*
 * GiST Fetch method for boxes
 * do not do anything --- we just return the stored box as is.
 */
Datum
gist_box_fetch(PG_FUNCTION_ARGS)
{
	PG_RETURN_POINTER(PG_GETARG_POINTER(0));
}

/*
 * The GiST Penalty method for boxes (also used for points)
 *
 * As in the R-tree paper, we use change in area as our penalty metric
 */
Datum
gist_box_penalty(PG_FUNCTION_ARGS)
{
	GISTENTRY  *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
	GISTENTRY  *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
	float	   *result = (float *) PG_GETARG_POINTER(2);
	BOX		   *origbox = DatumGetBoxP(origentry->key);
	BOX		   *newbox = DatumGetBoxP(newentry->key);

	*result = (float) box_penalty(origbox, newbox);
	PG_RETURN_POINTER(result);
}

/*
 * Trivial split: half of entries will be placed on one page
 * and another half - to another
 */
static void
fallbackSplit(GistEntryVector *entryvec, GIST_SPLITVEC *v)
{
	OffsetNumber i,
				maxoff;
	BOX		   *unionL = NULL,
			   *unionR = NULL;
	int			nbytes;

	maxoff = entryvec->n - 1;

	nbytes = (maxoff + 2) * sizeof(OffsetNumber);
	v->spl_left = (OffsetNumber *) palloc(nbytes);
	v->spl_right = (OffsetNumber *) palloc(nbytes);
	v->spl_nleft = v->spl_nright = 0;

	for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
	{
		BOX		   *cur = DatumGetBoxP(entryvec->vector[i].key);

		if (i <= (maxoff - FirstOffsetNumber + 1) / 2)
		{
			v->spl_left[v->spl_nleft] = i;
			if (unionL == NULL)
			{
				unionL = (BOX *) palloc(sizeof(BOX));
				*unionL = *cur;
			}
			else
				adjustBox(unionL, cur);

			v->spl_nleft++;
		}
		else
		{
			v->spl_right[v->spl_nright] = i;
			if (unionR == NULL)
			{
				unionR = (BOX *) palloc(sizeof(BOX));
				*unionR = *cur;
			}
			else
				adjustBox(unionR, cur);

			v->spl_nright++;
		}
	}

	v->spl_ldatum = BoxPGetDatum(unionL);
	v->spl_rdatum = BoxPGetDatum(unionR);
}

/*
 * Represents information about an entry that can be placed to either group
 * without affecting overlap over selected axis ("common entry").
 */
typedef struct
{
	/* Index of entry in the initial array */
	int			index;
	/* Delta between penalties of entry insertion into different groups */
	double		delta;
} CommonEntry;

/*
 * Context for g_box_consider_split. Contains information about currently
 * selected split and some general information.
 */
typedef struct
{
	int			entriesCount;	/* total number of entries being split */
	BOX			boundingBox;	/* minimum bounding box across all entries */

	/* Information about currently selected split follows */

	bool		first;			/* true if no split was selected yet */

	double		leftUpper;		/* upper bound of left interval */
	double		rightLower;		/* lower bound of right interval */

	float4		ratio;
	float4		overlap;
	int			dim;			/* axis of this split */
	double		range;			/* width of general MBR projection to the
								 * selected axis */
} ConsiderSplitContext;

/*
 * Interval represents projection of box to axis.
 */
typedef struct
{
	double		lower,
				upper;
} SplitInterval;

/*
 * Interval comparison function by lower bound of the interval;
 */
static int
interval_cmp_lower(const void *i1, const void *i2)
{
	double		lower1 = ((const SplitInterval *) i1)->lower,
				lower2 = ((const SplitInterval *) i2)->lower;

	return float8_cmp_internal(lower1, lower2);
}

/*
 * Interval comparison function by upper bound of the interval;
 */
static int
interval_cmp_upper(const void *i1, const void *i2)
{
	double		upper1 = ((const SplitInterval *) i1)->upper,
				upper2 = ((const SplitInterval *) i2)->upper;

	return float8_cmp_internal(upper1, upper2);
}

/*
 * Replace negative (or NaN) value with zero.
 */
static inline float
non_negative(float val)
{
	if (val >= 0.0f)
		return val;
	else
		return 0.0f;
}

/*
 * Consider replacement of currently selected split with the better one.
 */
static inline void
g_box_consider_split(ConsiderSplitContext *context, int dimNum,
					 double rightLower, int minLeftCount,
					 double leftUpper, int maxLeftCount)
{
	int			leftCount,
				rightCount;
	float4		ratio,
				overlap;
	double		range;

	/*
	 * Calculate entries distribution ratio assuming most uniform distribution
	 * of common entries.
	 */
	if (minLeftCount >= (context->entriesCount + 1) / 2)
	{
		leftCount = minLeftCount;
	}
	else
	{
		if (maxLeftCount <= context->entriesCount / 2)
			leftCount = maxLeftCount;
		else
			leftCount = context->entriesCount / 2;
	}
	rightCount = context->entriesCount - leftCount;

	/*
	 * Ratio of split - quotient between size of lesser group and total
	 * entries count.
	 */
	ratio = ((float4) Min(leftCount, rightCount)) /
		((float4) context->entriesCount);

	if (ratio > LIMIT_RATIO)
	{
		bool		selectthis = false;

		/*
		 * The ratio is acceptable, so compare current split with previously
		 * selected one. Between splits of one dimension we search for minimal
		 * overlap (allowing negative values) and minimal ration (between same
		 * overlaps. We switch dimension if find less overlap (non-negative)
		 * or less range with same overlap.
		 */
		if (dimNum == 0)
			range = context->boundingBox.high.x - context->boundingBox.low.x;
		else
			range = context->boundingBox.high.y - context->boundingBox.low.y;

		overlap = (leftUpper - rightLower) / range;

		/* If there is no previous selection, select this */
		if (context->first)
			selectthis = true;
		else if (context->dim == dimNum)
		{
			/*
			 * Within the same dimension, choose the new split if it has a
			 * smaller overlap, or same overlap but better ratio.
			 */
			if (overlap < context->overlap ||
				(overlap == context->overlap && ratio > context->ratio))
				selectthis = true;
		}
		else
		{
			/*
			 * Across dimensions, choose the new split if it has a smaller
			 * *non-negative* overlap, or same *non-negative* overlap but
			 * bigger range. This condition differs from the one described in
			 * the article. On the datasets where leaf MBRs don't overlap
			 * themselves, non-overlapping splits (i.e. splits which have zero
			 * *non-negative* overlap) are frequently possible. In this case
			 * splits tends to be along one dimension, because most distant
			 * non-overlapping splits (i.e. having lowest negative overlap)
			 * appears to be in the same dimension as in the previous split.
			 * Therefore MBRs appear to be very prolonged along another
			 * dimension, which leads to bad search performance. Using range
			 * as the second split criteria makes MBRs more quadratic. Using
			 * *non-negative* overlap instead of overlap as the first split
			 * criteria gives to range criteria a chance to matter, because
			 * non-overlapping splits are equivalent in this criteria.
			 */
			if (non_negative(overlap) < non_negative(context->overlap) ||
				(range > context->range &&
				 non_negative(overlap) <= non_negative(context->overlap)))
				selectthis = true;
		}

		if (selectthis)
		{
			/* save information about selected split */
			context->first = false;
			context->ratio = ratio;
			context->range = range;
			context->overlap = overlap;
			context->rightLower = rightLower;
			context->leftUpper = leftUpper;
			context->dim = dimNum;
		}
	}
}

/*
 * Compare common entries by their deltas.
 * (We assume the deltas can't be NaN.)
 */
static int
common_entry_cmp(const void *i1, const void *i2)
{
	double		delta1 = ((const CommonEntry *) i1)->delta,
				delta2 = ((const CommonEntry *) i2)->delta;

	if (delta1 < delta2)
		return -1;
	else if (delta1 > delta2)
		return 1;
	else
		return 0;
}

/*
 * --------------------------------------------------------------------------
 * Double sorting split algorithm. This is used for both boxes and points.
 *
 * The algorithm finds split of boxes by considering splits along each axis.
 * Each entry is first projected as an interval on the X-axis, and different
 * ways to split the intervals into two groups are considered, trying to
 * minimize the overlap of the groups. Then the same is repeated for the
 * Y-axis, and the overall best split is chosen. The quality of a split is
 * determined by overlap along that axis and some other criteria (see
 * g_box_consider_split).
 *
 * After that, all the entries are divided into three groups:
 *
 * 1) Entries which should be placed to the left group
 * 2) Entries which should be placed to the right group
 * 3) "Common entries" which can be placed to any of groups without affecting
 *	  of overlap along selected axis.
 *
 * The common entries are distributed by minimizing penalty.
 *
 * For details see:
 * "A new double sorting-based node splitting algorithm for R-tree", A. Korotkov
 * http://syrcose.ispras.ru/2011/files/SYRCoSE2011_Proceedings.pdf#page=36
 * --------------------------------------------------------------------------
 */
Datum
gist_box_picksplit(PG_FUNCTION_ARGS)
{
	GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
	GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
	OffsetNumber i,
				maxoff;
	ConsiderSplitContext context;
	BOX		   *box,
			   *leftBox,
			   *rightBox;
	int			dim,
				commonEntriesCount;
	SplitInterval *intervalsLower,
			   *intervalsUpper;
	CommonEntry *commonEntries;
	int			nentries;

	memset(&context, 0, sizeof(ConsiderSplitContext));

	maxoff = entryvec->n - 1;
	nentries = context.entriesCount = maxoff - FirstOffsetNumber + 1;

	/* Allocate arrays for intervals along axes */
	intervalsLower = (SplitInterval *) palloc(nentries * sizeof(SplitInterval));
	intervalsUpper = (SplitInterval *) palloc(nentries * sizeof(SplitInterval));

	/*
	 * Calculate the overall minimum bounding box over all the entries.
	 */
	for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
	{
		box = DatumGetBoxP(entryvec->vector[i].key);
		if (i == FirstOffsetNumber)
			context.boundingBox = *box;
		else
			adjustBox(&context.boundingBox, box);
	}

	/*
	 * Iterate over axes for optimal split searching.
	 */
	context.first = true;		/* nothing selected yet */
	for (dim = 0; dim < 2; dim++)
	{
		double		leftUpper,
					rightLower;
		int			i1,
					i2;

		/* Project each entry as an interval on the selected axis. */
		for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
		{
			box = DatumGetBoxP(entryvec->vector[i].key);
			if (dim == 0)
			{
				intervalsLower[i - FirstOffsetNumber].lower = box->low.x;
				intervalsLower[i - FirstOffsetNumber].upper = box->high.x;
			}
			else
			{
				intervalsLower[i - FirstOffsetNumber].lower = box->low.y;
				intervalsLower[i - FirstOffsetNumber].upper = box->high.y;
			}
		}

		/*
		 * Make two arrays of intervals: one sorted by lower bound and another
		 * sorted by upper bound.
		 */
		memcpy(intervalsUpper, intervalsLower,
			   sizeof(SplitInterval) * nentries);
		qsort(intervalsLower, nentries, sizeof(SplitInterval),
			  interval_cmp_lower);
		qsort(intervalsUpper, nentries, sizeof(SplitInterval),
			  interval_cmp_upper);

		/*----
		 * The goal is to form a left and right interval, so that every entry
		 * interval is contained by either left or right interval (or both).
		 *
		 * For example, with the intervals (0,1), (1,3), (2,3), (2,4):
		 *
		 * 0 1 2 3 4
		 * +-+
		 *	 +---+
		 *	   +-+
		 *	   +---+
		 *
		 * The left and right intervals are of the form (0,a) and (b,4).
		 * We first consider splits where b is the lower bound of an entry.
		 * We iterate through all entries, and for each b, calculate the
		 * smallest possible a. Then we consider splits where a is the
		 * upper bound of an entry, and for each a, calculate the greatest
		 * possible b.
		 *
		 * In the above example, the first loop would consider splits:
		 * b=0: (0,1)-(0,4)
		 * b=1: (0,1)-(1,4)
		 * b=2: (0,3)-(2,4)
		 *
		 * And the second loop:
		 * a=1: (0,1)-(1,4)
		 * a=3: (0,3)-(2,4)
		 * a=4: (0,4)-(2,4)
		 */

		/*
		 * Iterate over lower bound of right group, finding smallest possible
		 * upper bound of left group.
		 */
		i1 = 0;
		i2 = 0;
		rightLower = intervalsLower[i1].lower;
		leftUpper = intervalsUpper[i2].lower;
		while (true)
		{
			/*
			 * Find next lower bound of right group.
			 */
			while (i1 < nentries &&
				   FLOAT8_EQ(rightLower, intervalsLower[i1].lower))
			{
				if (FLOAT8_LT(leftUpper, intervalsLower[i1].upper))
					leftUpper = intervalsLower[i1].upper;
				i1++;
			}
			if (i1 >= nentries)
				break;
			rightLower = intervalsLower[i1].lower;

			/*
			 * Find count of intervals which anyway should be placed to the
			 * left group.
			 */
			while (i2 < nentries &&
				   FLOAT8_LE(intervalsUpper[i2].upper, leftUpper))
				i2++;

			/*
			 * Consider found split.
			 */
			g_box_consider_split(&context, dim, rightLower, i1, leftUpper, i2);
		}

		/*
		 * Iterate over upper bound of left group finding greatest possible
		 * lower bound of right group.
		 */
		i1 = nentries - 1;
		i2 = nentries - 1;
		rightLower = intervalsLower[i1].upper;
		leftUpper = intervalsUpper[i2].upper;
		while (true)
		{
			/*
			 * Find next upper bound of left group.
			 */
			while (i2 >= 0 && FLOAT8_EQ(leftUpper, intervalsUpper[i2].upper))
			{
				if (FLOAT8_GT(rightLower, intervalsUpper[i2].lower))
					rightLower = intervalsUpper[i2].lower;
				i2--;
			}
			if (i2 < 0)
				break;
			leftUpper = intervalsUpper[i2].upper;

			/*
			 * Find count of intervals which anyway should be placed to the
			 * right group.
			 */
			while (i1 >= 0 && FLOAT8_GE(intervalsLower[i1].lower, rightLower))
				i1--;

			/*
			 * Consider found split.
			 */
			g_box_consider_split(&context, dim,
								 rightLower, i1 + 1, leftUpper, i2 + 1);
		}
	}

	/*
	 * If we failed to find any acceptable splits, use trivial split.
	 */
	if (context.first)
	{
		fallbackSplit(entryvec, v);
		PG_RETURN_POINTER(v);
	}

	/*
	 * Ok, we have now selected the split across one axis.
	 *
	 * While considering the splits, we already determined that there will be
	 * enough entries in both groups to reach the desired ratio, but we did
	 * not memorize which entries go to which group. So determine that now.
	 */

	/* Allocate vectors for results */
	v->spl_left = (OffsetNumber *) palloc(nentries * sizeof(OffsetNumber));
	v->spl_right = (OffsetNumber *) palloc(nentries * sizeof(OffsetNumber));
	v->spl_nleft = 0;
	v->spl_nright = 0;

	/* Allocate bounding boxes of left and right groups */
	leftBox = palloc0(sizeof(BOX));
	rightBox = palloc0(sizeof(BOX));

	/*
	 * Allocate an array for "common entries" - entries which can be placed to
	 * either group without affecting overlap along selected axis.
	 */
	commonEntriesCount = 0;
	commonEntries = (CommonEntry *) palloc(nentries * sizeof(CommonEntry));

	/* Helper macros to place an entry in the left or right group */
#define PLACE_LEFT(box, off)					\
	do {										\
		if (v->spl_nleft > 0)					\
			adjustBox(leftBox, box);			\
		else									\
			*leftBox = *(box);					\
		v->spl_left[v->spl_nleft++] = off;		\
	} while(0)

#define PLACE_RIGHT(box, off)					\
	do {										\
		if (v->spl_nright > 0)					\
			adjustBox(rightBox, box);			\
		else									\
			*rightBox = *(box);					\
		v->spl_right[v->spl_nright++] = off;	\
	} while(0)

	/*
	 * Distribute entries which can be distributed unambiguously, and collect
	 * common entries.
	 */
	for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
	{
		double		lower,
					upper;

		/*
		 * Get upper and lower bounds along selected axis.
		 */
		box = DatumGetBoxP(entryvec->vector[i].key);
		if (context.dim == 0)
		{
			lower = box->low.x;
			upper = box->high.x;
		}
		else
		{
			lower = box->low.y;
			upper = box->high.y;
		}

		if (FLOAT8_LE(upper, context.leftUpper))
		{
			/* Fits to the left group */
			if (FLOAT8_GE(lower, context.rightLower))
			{
				/* Fits also to the right group, so "common entry" */
				commonEntries[commonEntriesCount++].index = i;
			}
			else
			{
				/* Doesn't fit to the right group, so join to the left group */
				PLACE_LEFT(box, i);
			}
		}
		else
		{
			/*
			 * Each entry should fit on either left or right group. Since this
			 * entry didn't fit on the left group, it better fit in the right
			 * group.
			 */
			Assert(FLOAT8_GE(lower, context.rightLower));

			/* Doesn't fit to the left group, so join to the right group */
			PLACE_RIGHT(box, i);
		}
	}

	/*
	 * Distribute "common entries", if any.
	 */
	if (commonEntriesCount > 0)
	{
		/*
		 * Calculate minimum number of entries that must be placed in both
		 * groups, to reach LIMIT_RATIO.
		 */
		int			m = ceil(LIMIT_RATIO * (double) nentries);

		/*
		 * Calculate delta between penalties of join "common entries" to
		 * different groups.
		 */
		for (i = 0; i < commonEntriesCount; i++)
		{
			box = DatumGetBoxP(entryvec->vector[commonEntries[i].index].key);
			commonEntries[i].delta = Abs(box_penalty(leftBox, box) -
										 box_penalty(rightBox, box));
		}

		/*
		 * Sort "common entries" by calculated deltas in order to distribute
		 * the most ambiguous entries first.
		 */
		qsort(commonEntries, commonEntriesCount, sizeof(CommonEntry), common_entry_cmp);

		/*
		 * Distribute "common entries" between groups.
		 */
		for (i = 0; i < commonEntriesCount; i++)
		{
			box = DatumGetBoxP(entryvec->vector[commonEntries[i].index].key);

			/*
			 * Check if we have to place this entry in either group to achieve
			 * LIMIT_RATIO.
			 */
			if (v->spl_nleft + (commonEntriesCount - i) <= m)
				PLACE_LEFT(box, commonEntries[i].index);
			else if (v->spl_nright + (commonEntriesCount - i) <= m)
				PLACE_RIGHT(box, commonEntries[i].index);
			else
			{
				/* Otherwise select the group by minimal penalty */
				if (box_penalty(leftBox, box) < box_penalty(rightBox, box))
					PLACE_LEFT(box, commonEntries[i].index);
				else
					PLACE_RIGHT(box, commonEntries[i].index);
			}
		}
	}

	v->spl_ldatum = PointerGetDatum(leftBox);
	v->spl_rdatum = PointerGetDatum(rightBox);
	PG_RETURN_POINTER(v);
}

/*
 * Equality method
 *
 * This is used for boxes, points, circles, and polygons, all of which store
 * boxes as GiST index entries.
 *
 * Returns true only when boxes are exactly the same.  We can't use fuzzy
 * comparisons here without breaking index consistency; therefore, this isn't
 * equivalent to box_same().
 */
Datum
gist_box_same(PG_FUNCTION_ARGS)
{
	BOX		   *b1 = PG_GETARG_BOX_P(0);
	BOX		   *b2 = PG_GETARG_BOX_P(1);
	bool	   *result = (bool *) PG_GETARG_POINTER(2);

	if (b1 && b2)
		*result = (FLOAT8_EQ(b1->low.x, b2->low.x) &&
				   FLOAT8_EQ(b1->low.y, b2->low.y) &&
				   FLOAT8_EQ(b1->high.x, b2->high.x) &&
				   FLOAT8_EQ(b1->high.y, b2->high.y));
	else
		*result = (b1 == NULL && b2 == NULL);
	PG_RETURN_POINTER(result);
}

/*
 * Leaf-level consistency for boxes: just apply the query operator
 */
static bool
gist_box_leaf_consistent(BOX *key, BOX *query, StrategyNumber strategy)
{
	bool		retval;

	switch (strategy)
	{
		case RTLeftStrategyNumber:
			retval = DatumGetBool(DirectFunctionCall2(box_left,
													  PointerGetDatum(key),
													PointerGetDatum(query)));
			break;
		case RTOverLeftStrategyNumber:
			retval = DatumGetBool(DirectFunctionCall2(box_overleft,
													  PointerGetDatum(key),
													PointerGetDatum(query)));
			break;
		case RTOverlapStrategyNumber:
			retval = DatumGetBool(DirectFunctionCall2(box_overlap,
													  PointerGetDatum(key),
													PointerGetDatum(query)));
			break;
		case RTOverRightStrategyNumber:
			retval = DatumGetBool(DirectFunctionCall2(box_overright,
													  PointerGetDatum(key),
													PointerGetDatum(query)));
			break;
		case RTRightStrategyNumber:
			retval = DatumGetBool(DirectFunctionCall2(box_right,
													  PointerGetDatum(key),
													PointerGetDatum(query)));
			break;
		case RTSameStrategyNumber:
			retval = DatumGetBool(DirectFunctionCall2(box_same,
													  PointerGetDatum(key),
													PointerGetDatum(query)));
			break;
		case RTContainsStrategyNumber:
		case RTOldContainsStrategyNumber:
			retval = DatumGetBool(DirectFunctionCall2(box_contain,
													  PointerGetDatum(key),
													PointerGetDatum(query)));
			break;
		case RTContainedByStrategyNumber:
		case RTOldContainedByStrategyNumber:
			retval = DatumGetBool(DirectFunctionCall2(box_contained,
													  PointerGetDatum(key),
													PointerGetDatum(query)));
			break;
		case RTOverBelowStrategyNumber:
			retval = DatumGetBool(DirectFunctionCall2(box_overbelow,
													  PointerGetDatum(key),
													PointerGetDatum(query)));
			break;
		case RTBelowStrategyNumber:
			retval = DatumGetBool(DirectFunctionCall2(box_below,
													  PointerGetDatum(key),
													PointerGetDatum(query)));
			break;
		case RTAboveStrategyNumber:
			retval = DatumGetBool(DirectFunctionCall2(box_above,
													  PointerGetDatum(key),
													PointerGetDatum(query)));
			break;
		case RTOverAboveStrategyNumber:
			retval = DatumGetBool(DirectFunctionCall2(box_overabove,
													  PointerGetDatum(key),
													PointerGetDatum(query)));
			break;
		default:
			elog(ERROR, "unrecognized strategy number: %d", strategy);
			retval = false;		/* keep compiler quiet */
			break;
	}
	return retval;
}

/*****************************************
 * Common rtree functions (for boxes, polygons, and circles)
 *****************************************/

/*
 * Internal-page consistency for all these types
 *
 * We can use the same function since all types use bounding boxes as the
 * internal-page representation.
 */
static bool
rtree_internal_consistent(BOX *key, BOX *query, StrategyNumber strategy)
{
	bool		retval;

	switch (strategy)
	{
		case RTLeftStrategyNumber:
			retval = !DatumGetBool(DirectFunctionCall2(box_overright,
													   PointerGetDatum(key),
													PointerGetDatum(query)));
			break;
		case RTOverLeftStrategyNumber:
			retval = !DatumGetBool(DirectFunctionCall2(box_right,
													   PointerGetDatum(key),
													PointerGetDatum(query)));
			break;
		case RTOverlapStrategyNumber:
			retval = DatumGetBool(DirectFunctionCall2(box_overlap,
													  PointerGetDatum(key),
													PointerGetDatum(query)));
			break;
		case RTOverRightStrategyNumber:
			retval = !DatumGetBool(DirectFunctionCall2(box_left,
													   PointerGetDatum(key),
													PointerGetDatum(query)));
			break;
		case RTRightStrategyNumber:
			retval = !DatumGetBool(DirectFunctionCall2(box_overleft,
													   PointerGetDatum(key),
													PointerGetDatum(query)));
			break;
		case RTSameStrategyNumber:
		case RTContainsStrategyNumber:
		case RTOldContainsStrategyNumber:
			retval = DatumGetBool(DirectFunctionCall2(box_contain,
													  PointerGetDatum(key),
													PointerGetDatum(query)));
			break;
		case RTContainedByStrategyNumber:
		case RTOldContainedByStrategyNumber:
			retval = DatumGetBool(DirectFunctionCall2(box_overlap,
													  PointerGetDatum(key),
													PointerGetDatum(query)));
			break;
		case RTOverBelowStrategyNumber:
			retval = !DatumGetBool(DirectFunctionCall2(box_above,
													   PointerGetDatum(key),
													PointerGetDatum(query)));
			break;
		case RTBelowStrategyNumber:
			retval = !DatumGetBool(DirectFunctionCall2(box_overabove,
													   PointerGetDatum(key),
													PointerGetDatum(query)));
			break;
		case RTAboveStrategyNumber:
			retval = !DatumGetBool(DirectFunctionCall2(box_overbelow,
													   PointerGetDatum(key),
													PointerGetDatum(query)));
			break;
		case RTOverAboveStrategyNumber:
			retval = !DatumGetBool(DirectFunctionCall2(box_below,
													   PointerGetDatum(key),
													PointerGetDatum(query)));
			break;
		default:
			elog(ERROR, "unrecognized strategy number: %d", strategy);
			retval = false;		/* keep compiler quiet */
			break;
	}
	return retval;
}

/**************************************************
 * Polygon ops
 **************************************************/

/*
 * GiST compress for polygons: represent a polygon by its bounding box
 */
Datum
gist_poly_compress(PG_FUNCTION_ARGS)
{
	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
	GISTENTRY  *retval;

	if (entry->leafkey)
	{
		POLYGON    *in = DatumGetPolygonP(entry->key);
		BOX		   *r;

		r = (BOX *) palloc(sizeof(BOX));
		memcpy((void *) r, (void *) &(in->boundbox), sizeof(BOX));

		retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
		gistentryinit(*retval, PointerGetDatum(r),
					  entry->rel, entry->page,
					  entry->offset, FALSE);
	}
	else
		retval = entry;
	PG_RETURN_POINTER(retval);
}

/*
 * The GiST Consistent method for polygons
 */
Datum
gist_poly_consistent(PG_FUNCTION_ARGS)
{
	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
	POLYGON    *query = PG_GETARG_POLYGON_P(1);
	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);

	/* Oid		subtype = PG_GETARG_OID(3); */
	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
	bool		result;

	/* All cases served by this function are inexact */
	*recheck = true;

	if (DatumGetBoxP(entry->key) == NULL || query == NULL)
		PG_RETURN_BOOL(FALSE);

	/*
	 * Since the operators require recheck anyway, we can just use
	 * rtree_internal_consistent even at leaf nodes.  (This works in part
	 * because the index entries are bounding boxes not polygons.)
	 */
	result = rtree_internal_consistent(DatumGetBoxP(entry->key),
									   &(query->boundbox), strategy);

	/* Avoid memory leak if supplied poly is toasted */
	PG_FREE_IF_COPY(query, 1);

	PG_RETURN_BOOL(result);
}

/**************************************************
 * Circle ops
 **************************************************/

/*
 * GiST compress for circles: represent a circle by its bounding box
 */
Datum
gist_circle_compress(PG_FUNCTION_ARGS)
{
	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
	GISTENTRY  *retval;

	if (entry->leafkey)
	{
		CIRCLE	   *in = DatumGetCircleP(entry->key);
		BOX		   *r;

		r = (BOX *) palloc(sizeof(BOX));
		r->high.x = in->center.x + in->radius;
		r->low.x = in->center.x - in->radius;
		r->high.y = in->center.y + in->radius;
		r->low.y = in->center.y - in->radius;

		retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
		gistentryinit(*retval, PointerGetDatum(r),
					  entry->rel, entry->page,
					  entry->offset, FALSE);
	}
	else
		retval = entry;
	PG_RETURN_POINTER(retval);
}

/*
 * The GiST Consistent method for circles
 */
Datum
gist_circle_consistent(PG_FUNCTION_ARGS)
{
	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
	CIRCLE	   *query = PG_GETARG_CIRCLE_P(1);
	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);

	/* Oid		subtype = PG_GETARG_OID(3); */
	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
	BOX			bbox;
	bool		result;

	/* All cases served by this function are inexact */
	*recheck = true;

	if (DatumGetBoxP(entry->key) == NULL || query == NULL)
		PG_RETURN_BOOL(FALSE);

	/*
	 * Since the operators require recheck anyway, we can just use
	 * rtree_internal_consistent even at leaf nodes.  (This works in part
	 * because the index entries are bounding boxes not circles.)
	 */
	bbox.high.x = query->center.x + query->radius;
	bbox.low.x = query->center.x - query->radius;
	bbox.high.y = query->center.y + query->radius;
	bbox.low.y = query->center.y - query->radius;

	result = rtree_internal_consistent(DatumGetBoxP(entry->key),
									   &bbox, strategy);

	PG_RETURN_BOOL(result);
}

/**************************************************
 * Point ops
 **************************************************/

Datum
gist_point_compress(PG_FUNCTION_ARGS)
{
	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);

	if (entry->leafkey)			/* Point, actually */
	{
		BOX		   *box = palloc(sizeof(BOX));
		Point	   *point = DatumGetPointP(entry->key);
		GISTENTRY  *retval = palloc(sizeof(GISTENTRY));

		box->high = box->low = *point;

		gistentryinit(*retval, BoxPGetDatum(box),
					  entry->rel, entry->page, entry->offset, FALSE);

		PG_RETURN_POINTER(retval);
	}

	PG_RETURN_POINTER(entry);
}

/*
 * GiST Fetch method for point
 *
 * Get point coordinates from its bounding box coordinates and form new
 * gistentry.
 */
Datum
gist_point_fetch(PG_FUNCTION_ARGS)
{
	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
	BOX		   *in = DatumGetBoxP(entry->key);
	Point	   *r;
	GISTENTRY  *retval;

	retval = palloc(sizeof(GISTENTRY));

	r = (Point *) palloc(sizeof(Point));
	r->x = in->high.x;
	r->y = in->high.y;
	gistentryinit(*retval, PointerGetDatum(r),
				  entry->rel, entry->page,
				  entry->offset, FALSE);

	PG_RETURN_POINTER(retval);
}

#define point_point_distance(p1,p2) \
	DatumGetFloat8(DirectFunctionCall2(point_distance, \
									   PointPGetDatum(p1), PointPGetDatum(p2)))

static double
computeDistance(bool isLeaf, BOX *box, Point *point)
{
	double		result = 0.0;

	if (isLeaf)
	{
		/* simple point to point distance */
		result = point_point_distance(point, &box->low);
	}
	else if (point->x <= box->high.x && point->x >= box->low.x &&
			 point->y <= box->high.y && point->y >= box->low.y)
	{
		/* point inside the box */
		result = 0.0;
	}
	else if (point->x <= box->high.x && point->x >= box->low.x)
	{
		/* point is over or below box */
		Assert(box->low.y <= box->high.y);
		if (point->y > box->high.y)
			result = point->y - box->high.y;
		else if (point->y < box->low.y)
			result = box->low.y - point->y;
		else
			elog(ERROR, "inconsistent point values");
	}
	else if (point->y <= box->high.y && point->y >= box->low.y)
	{
		/* point is to left or right of box */
		Assert(box->low.x <= box->high.x);
		if (point->x > box->high.x)
			result = point->x - box->high.x;
		else if (point->x < box->low.x)
			result = box->low.x - point->x;
		else
			elog(ERROR, "inconsistent point values");
	}
	else
	{
		/* closest point will be a vertex */
		Point		p;
		double		subresult;

		result = point_point_distance(point, &box->low);

		subresult = point_point_distance(point, &box->high);
		if (result > subresult)
			result = subresult;

		p.x = box->low.x;
		p.y = box->high.y;
		subresult = point_point_distance(point, &p);
		if (result > subresult)
			result = subresult;

		p.x = box->high.x;
		p.y = box->low.y;
		subresult = point_point_distance(point, &p);
		if (result > subresult)
			result = subresult;
	}

	return result;
}

static bool
gist_point_consistent_internal(StrategyNumber strategy,
							   bool isLeaf, BOX *key, Point *query)
{
	bool		result = false;

	switch (strategy)
	{
		case RTLeftStrategyNumber:
			result = FPlt(key->low.x, query->x);
			break;
		case RTRightStrategyNumber:
			result = FPgt(key->high.x, query->x);
			break;
		case RTAboveStrategyNumber:
			result = FPgt(key->high.y, query->y);
			break;
		case RTBelowStrategyNumber:
			result = FPlt(key->low.y, query->y);
			break;
		case RTSameStrategyNumber:
			if (isLeaf)
			{
				/* key.high must equal key.low, so we can disregard it */
				result = (FPeq(key->low.x, query->x) &&
						  FPeq(key->low.y, query->y));
			}
			else
			{
				result = (FPle(query->x, key->high.x) &&
						  FPge(query->x, key->low.x) &&
						  FPle(query->y, key->high.y) &&
						  FPge(query->y, key->low.y));
			}
			break;
		default:
			elog(ERROR, "unrecognized strategy number: %d", strategy);
			result = false;		/* keep compiler quiet */
			break;
	}

	return result;
}

#define GeoStrategyNumberOffset		20
#define PointStrategyNumberGroup	0
#define BoxStrategyNumberGroup		1
#define PolygonStrategyNumberGroup	2
#define CircleStrategyNumberGroup	3

Datum
gist_point_consistent(PG_FUNCTION_ARGS)
{
	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
	bool		result;
	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;

	switch (strategyGroup)
	{
		case PointStrategyNumberGroup:
			result = gist_point_consistent_internal(strategy % GeoStrategyNumberOffset,
													GIST_LEAF(entry),
													DatumGetBoxP(entry->key),
													PG_GETARG_POINT_P(1));
			*recheck = false;
			break;
		case BoxStrategyNumberGroup:
			{
				/*
				 * The only operator in this group is point <@ box (on_pb), so
				 * we needn't examine strategy again.
				 *
				 * For historical reasons, on_pb uses exact rather than fuzzy
				 * comparisons.  We could use box_overlap when at an internal
				 * page, but that would lead to possibly visiting child pages
				 * uselessly, because box_overlap uses fuzzy comparisons.
				 * Instead we write a non-fuzzy overlap test.  The same code
				 * will also serve for leaf-page tests, since leaf keys have
				 * high == low.
				 */
				BOX		   *query,
						   *key;

				query = PG_GETARG_BOX_P(1);
				key = DatumGetBoxP(entry->key);

				result = (key->high.x >= query->low.x &&
						  key->low.x <= query->high.x &&
						  key->high.y >= query->low.y &&
						  key->low.y <= query->high.y);
				*recheck = false;
			}
			break;
		case PolygonStrategyNumberGroup:
			{
				POLYGON    *query = PG_GETARG_POLYGON_P(1);

				result = DatumGetBool(DirectFunctionCall5(
														gist_poly_consistent,
													  PointerGetDatum(entry),
													 PolygonPGetDatum(query),
									  Int16GetDatum(RTOverlapStrategyNumber),
											   0, PointerGetDatum(recheck)));

				if (GIST_LEAF(entry) && result)
				{
					/*
					 * We are on leaf page and quick check shows overlapping
					 * of polygon's bounding box and point
					 */
					BOX		   *box = DatumGetBoxP(entry->key);

					Assert(box->high.x == box->low.x
						   && box->high.y == box->low.y);
					result = DatumGetBool(DirectFunctionCall2(
															  poly_contain_pt,
													 PolygonPGetDatum(query),
												PointPGetDatum(&box->high)));
					*recheck = false;
				}
			}
			break;
		case CircleStrategyNumberGroup:
			{
				CIRCLE	   *query = PG_GETARG_CIRCLE_P(1);

				result = DatumGetBool(DirectFunctionCall5(
													  gist_circle_consistent,
													  PointerGetDatum(entry),
													  CirclePGetDatum(query),
									  Int16GetDatum(RTOverlapStrategyNumber),
											   0, PointerGetDatum(recheck)));

				if (GIST_LEAF(entry) && result)
				{
					/*
					 * We are on leaf page and quick check shows overlapping
					 * of polygon's bounding box and point
					 */
					BOX		   *box = DatumGetBoxP(entry->key);

					Assert(box->high.x == box->low.x
						   && box->high.y == box->low.y);
					result = DatumGetBool(DirectFunctionCall2(
														   circle_contain_pt,
													  CirclePGetDatum(query),
												PointPGetDatum(&box->high)));
					*recheck = false;
				}
			}
			break;
		default:
			elog(ERROR, "unrecognized strategy number: %d", strategy);
			result = false;		/* keep compiler quiet */
			break;
	}

	PG_RETURN_BOOL(result);
}

Datum
gist_point_distance(PG_FUNCTION_ARGS)
{
	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
	double		distance;
	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;

	switch (strategyGroup)
	{
		case PointStrategyNumberGroup:
			distance = computeDistance(GIST_LEAF(entry),
									   DatumGetBoxP(entry->key),
									   PG_GETARG_POINT_P(1));
			break;
		default:
			elog(ERROR, "unrecognized strategy number: %d", strategy);
			distance = 0.0;		/* keep compiler quiet */
			break;
	}

	PG_RETURN_FLOAT8(distance);
}

/*
 * The inexact GiST distance method for geometric types that store bounding
 * boxes.
 *
 * Compute lossy distance from point to index entries.  The result is inexact
 * because index entries are bounding boxes, not the exact shapes of the
 * indexed geometric types.  We use distance from point to MBR of index entry.
 * This is a lower bound estimate of distance from point to indexed geometric
 * type.
 */
static double
gist_bbox_distance(GISTENTRY *entry, Datum query,
				   StrategyNumber strategy, bool *recheck)
{
	double		distance;
	StrategyNumber strategyGroup = strategy / GeoStrategyNumberOffset;

	/* Bounding box distance is always inexact. */
	*recheck = true;

	switch (strategyGroup)
	{
		case PointStrategyNumberGroup:
			distance = computeDistance(false,
									   DatumGetBoxP(entry->key),
									   DatumGetPointP(query));
			break;
		default:
			elog(ERROR, "unrecognized strategy number: %d", strategy);
			distance = 0.0;		/* keep compiler quiet */
	}

	return distance;
}

Datum
gist_circle_distance(PG_FUNCTION_ARGS)
{
	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
	Datum		query = PG_GETARG_DATUM(1);
	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);

	/* Oid subtype = PG_GETARG_OID(3); */
	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
	double		distance;

	distance = gist_bbox_distance(entry, query, strategy, recheck);

	PG_RETURN_FLOAT8(distance);
}

Datum
gist_poly_distance(PG_FUNCTION_ARGS)
{
	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
	Datum		query = PG_GETARG_DATUM(1);
	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);

	/* Oid subtype = PG_GETARG_OID(3); */
	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
	double		distance;

	distance = gist_bbox_distance(entry, query, strategy, recheck);

	PG_RETURN_FLOAT8(distance);
}


text:
<?xml version="1.0" encoding="utf-8"?>

<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:keyWidth="10%p"
    >

    <Row android:keyWidth="8.33%p">
    <!-- йцукенгшщзхъ -->
        <Key android:codes="1081" android:keyLabel="" android:popupCharacters="1" android:keyEdgeFlags="left"/>
        <Key android:codes="1094" android:keyLabel="" android:popupCharacters="2"/>
        <Key android:codes="1091" android:keyLabel="" android:popupCharacters="3"/>
        <Key android:codes="1082" android:keyLabel="" android:popupCharacters="4"/>
        <Key android:codes="1077" android:keyLabel="" android:popupCharacters="ё5"/>
        <Key android:codes="1085" android:keyLabel="" android:popupCharacters="6"/>
        <Key android:codes="1075" android:keyLabel="" android:popupCharacters="7"/>
        <Key android:codes="1096" android:keyLabel="" android:popupCharacters="8"/>
        <Key android:codes="1097" android:keyLabel="" android:popupCharacters="9"/>
        <Key android:codes="1079" android:keyLabel="" android:popupCharacters="0"/>
        <Key android:codes="1093" android:keyLabel="" android:popupCharacters=""/>
        <Key android:codes="1098" android:keyLabel="" android:popupCharacters="" android:keyEdgeFlags="right"/>
    </Row>

    <Row android:keyWidth="9.09%p">
    <!-- фывапролджэ -->
        <Key android:codes="1092" android:keyLabel="" android:keyEdgeFlags="left"/>
        <Key android:codes="1099" android:keyLabel=""/>
        <Key android:codes="1074" android:keyLabel=""/>
        <Key android:codes="1072" android:keyLabel=""/>
        <Key android:codes="1087" android:keyLabel=""/>
        <Key android:codes="1088" android:keyLabel=""/>
        <Key android:codes="1086" android:keyLabel=""/>
        <Key android:codes="1083" android:keyLabel=""/>
        <Key android:codes="1076" android:keyLabel=""/>
        <Key android:codes="1078" android:keyLabel=""/>
        <Key android:codes="1101" android:keyLabel="" android:keyEdgeFlags="right"/>
    </Row>

    <Row android:keyWidth="9.09%p">
    <!-- ячсмитьбю -->
        <Key android:codes="-1" android:isModifier="true" android:isSticky="true" android:keyEdgeFlags="left"/>
        <Key android:codes="1103" android:keyLabel=""/>
        <Key android:codes="1095" android:keyLabel=""/>
        <Key android:codes="1089" android:keyLabel=""/>
        <Key android:codes="1084" android:keyLabel=""/>
        <Key android:codes="1080" android:keyLabel=""/>
        <Key android:codes="1090" android:keyLabel=""/>
        <Key android:codes="1100" android:keyLabel=""/>
        <Key android:codes="1073" android:keyLabel=""/>
        <Key android:codes="1102" android:keyLabel=""/>
        <Key android:codes="-5" android:keyEdgeFlags="right" android:isRepeatable="true"/>
    </Row>
</Keyboard>

redpajama_set_name: RedPajamaGithub


text:
/*
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
/*
 * This code was generated by https://github.com/googleapis/google-api-java-client-services/
 * Modify at your own risk.
 */

package com.google.api.services.drivelabels.v2.model;

/**
 * A Label defines a taxonomy which may be applied to a Drive items in order to organize and search
 * across Items. Labels may be simple strings, or may contain Fields that describe additional
 * metadata which can be further used to organize and search Drive items.
 *
 *
 This is the Java data model class that specifies how to parse/serialize into the JSON that is
 * transmitted over HTTP when working with the Drive Labels API. For a detailed explanation see:
 * https://developers.google.com/api-client-library/java/google-http-java-client/json
 *

 *
 * @author Google, Inc.
 */
@SuppressWarnings("javadoc")
public final class GoogleAppsDriveLabelsV2Label extends com.google.api.client.json.GenericJson {

  /**
   * Output only. The capabilities related to this label on applied metadata.
   * The value may be {@code null}.
   */
  @com.google.api.client.util.Key
  private GoogleAppsDriveLabelsV2LabelAppliedCapabilities appliedCapabilities;

  /**
   * Output only. Behavior of this Label when its applied to Drive items.
   * The value may be {@code null}.
   */
  @com.google.api.client.util.Key
  private GoogleAppsDriveLabelsV2LabelAppliedLabelPolicy appliedLabelPolicy;

  /**
   * Output only. The time this label was created.
   * The value may be {@code null}.
   */
  @com.google.api.client.util.Key
  private String createTime;

  /**
   * Output only. The user who created this label.
   * The value may be {@code null}.
   */
  @com.google.api.client.util.Key
  private GoogleAppsDriveLabelsV2UserInfo creator;

  /**
   * Output only. The time this label was disabled. This value has no meaning when the label is not
   * disabled.
   * The value may be {@code null}.
   */
  @com.google.api.client.util.Key
  private String disableTime;

  /**
   * Output only. The user who disabled this label. This value has no meaning when the label is not
   * disabled.
   * The value may be {@code null}.
   */
  @com.google.api.client.util.Key
  private GoogleAppsDriveLabelsV2UserInfo disabler;

  /**
   * Output only. UI Display hints for rendering the Label.
   * The value may be {@code null}.
   */
  @com.google.api.client.util.Key
  private GoogleAppsDriveLabelsV2LabelDisplayHints displayHints;

  /**
   * List of Fields in descending priority order.
   * The value may be {@code null}.
   */
  @com.google.api.client.util.Key
  private java.util.List<GoogleAppsDriveLabelsV2Field> fields;

  static {
    // hack to force ProGuard to consider GoogleAppsDriveLabelsV2Field used, since otherwise it would be stripped out
    // see https://github.com/google/google-api-java-client/issues/543
    com.google.api.client.util.Data.nullOf(GoogleAppsDriveLabelsV2Field.class);
  }

  /**
   * Output only. Globally unique identifier of this Label. ID makes up part of the Label `name`,
   * but unlike `name`, ID is consistent between revisions. Matches the regex: `([a-zA-Z0-9])+`
   * The value may be {@code null}.
   */
  @com.google.api.client.util.Key
  private java.lang.String id;

  /**
   * Required. The type of this label.
   * The value may be {@code null}.
   */
  @com.google.api.client.util.Key
  private java.lang.String labelType;

  /**
   * Custom URL to present to users to allow them to learn more about this label and how it should
   * be used.
   * The value may be {@code null}.
   */
  @com.google.api.client.util.Key
  private java.lang.String learnMoreUri;

  /**
   * Output only. The lifecycle state of the label including whether it's published, deprecated, and
   * has draft changes.
   * The value may be {@code null}.
   */
  @com.google.api.client.util.Key
  private GoogleAppsDriveLabelsV2Lifecycle lifecycle;

  /**
   * Output only. The LockStatus of this label.
   * The value may be {@code null}.
   */
  @com.google.api.client.util.Key
  private GoogleAppsDriveLabelsV2LockStatus lockStatus;

  /**
   * Output only. Resource name of the Label. Will be in the form of either: `labels/{id}` or
   * `labels/{id}@{revision_id}` depending on the request. See `id` and `revision_id` below.
   * The value may be {@code null}.
   */
  @com.google.api.client.util.Key
  private java.lang.String name;

  /**
   * Required. The basic properties of the Label.
   * The value may be {@code null}.
   */
  @com.google.api.client.util.Key
  private GoogleAppsDriveLabelsV2LabelProperties properties;

  /**
   * Output only. The time this label was published. This value has no meaning when the label is not
   * published.
   * The value may be {@code null}.
   */
  @com.google.api.client.util.Key
  private String publishTime;

  /**
   * Output only. The user who published this label. This value has no meaning when the label is not
   * published.
   * The value may be {@code null}.
   */
  @com.google.api.client.util.Key
  private GoogleAppsDriveLabelsV2UserInfo publisher;

  /**
   * Output only. The time this label revision was created.
   * The value may be {@code null}.
   */
  @com.google.api.client.util.Key
  private String revisionCreateTime;

  /**
   * Output only. The user who created this label revision.
   * The value may be {@code null}.
   */
  @com.google.api.client.util.Key
  private GoogleAppsDriveLabelsV2UserInfo revisionCreator;

  /**
   * Output only. Revision ID of the Label. Revision ID may be part of the Label `name` depending on
   * the request issued. A new revision is created whenever revisioned properties of a Label are
   * changed. Matches the regex: `([a-zA-Z0-9])+`
   * The value may be {@code null}.
   */
  @com.google.api.client.util.Key
  private java.lang.String revisionId;

  /**
   * Output only. The capabilities the user has on this Label.
   * The value may be {@code null}.
   */
  @com.google.api.client.util.Key
  private GoogleAppsDriveLabelsV2LabelSchemaCapabilities schemaCapabilities;

  /**
   * Output only. The capabilities related to this label on applied metadata.
   * @return value or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2LabelAppliedCapabilities getAppliedCapabilities() {
    return appliedCapabilities;
  }

  /**
   * Output only. The capabilities related to this label on applied metadata.
   * @param appliedCapabilities appliedCapabilities or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2Label setAppliedCapabilities(GoogleAppsDriveLabelsV2LabelAppliedCapabilities appliedCapabilities) {
    this.appliedCapabilities = appliedCapabilities;
    return this;
  }

  /**
   * Output only. Behavior of this Label when its applied to Drive items.
   * @return value or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2LabelAppliedLabelPolicy getAppliedLabelPolicy() {
    return appliedLabelPolicy;
  }

  /**
   * Output only. Behavior of this Label when its applied to Drive items.
   * @param appliedLabelPolicy appliedLabelPolicy or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2Label setAppliedLabelPolicy(GoogleAppsDriveLabelsV2LabelAppliedLabelPolicy appliedLabelPolicy) {
    this.appliedLabelPolicy = appliedLabelPolicy;
    return this;
  }

  /**
   * Output only. The time this label was created.
   * @return value or {@code null} for none
   */
  public String getCreateTime() {
    return createTime;
  }

  /**
   * Output only. The time this label was created.
   * @param createTime createTime or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2Label setCreateTime(String createTime) {
    this.createTime = createTime;
    return this;
  }

  /**
   * Output only. The user who created this label.
   * @return value or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2UserInfo getCreator() {
    return creator;
  }

  /**
   * Output only. The user who created this label.
   * @param creator creator or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2Label setCreator(GoogleAppsDriveLabelsV2UserInfo creator) {
    this.creator = creator;
    return this;
  }

  /**
   * Output only. The time this label was disabled. This value has no meaning when the label is not
   * disabled.
   * @return value or {@code null} for none
   */
  public String getDisableTime() {
    return disableTime;
  }

  /**
   * Output only. The time this label was disabled. This value has no meaning when the label is not
   * disabled.
   * @param disableTime disableTime or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2Label setDisableTime(String disableTime) {
    this.disableTime = disableTime;
    return this;
  }

  /**
   * Output only. The user who disabled this label. This value has no meaning when the label is not
   * disabled.
   * @return value or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2UserInfo getDisabler() {
    return disabler;
  }

  /**
   * Output only. The user who disabled this label. This value has no meaning when the label is not
   * disabled.
   * @param disabler disabler or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2Label setDisabler(GoogleAppsDriveLabelsV2UserInfo disabler) {
    this.disabler = disabler;
    return this;
  }

  /**
   * Output only. UI Display hints for rendering the Label.
   * @return value or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2LabelDisplayHints getDisplayHints() {
    return displayHints;
  }

  /**
   * Output only. UI Display hints for rendering the Label.
   * @param displayHints displayHints or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2Label setDisplayHints(GoogleAppsDriveLabelsV2LabelDisplayHints displayHints) {
    this.displayHints = displayHints;
    return this;
  }

  /**
   * List of Fields in descending priority order.
   * @return value or {@code null} for none
   */
  public java.util.List<GoogleAppsDriveLabelsV2Field> getFields() {
    return fields;
  }

  /**
   * List of Fields in descending priority order.
   * @param fields fields or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2Label setFields(java.util.List<GoogleAppsDriveLabelsV2Field> fields) {
    this.fields = fields;
    return this;
  }

  /**
   * Output only. Globally unique identifier of this Label. ID makes up part of the Label `name`,
   * but unlike `name`, ID is consistent between revisions. Matches the regex: `([a-zA-Z0-9])+`
   * @return value or {@code null} for none
   */
  public java.lang.String getId() {
    return id;
  }

  /**
   * Output only. Globally unique identifier of this Label. ID makes up part of the Label `name`,
   * but unlike `name`, ID is consistent between revisions. Matches the regex: `([a-zA-Z0-9])+`
   * @param id id or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2Label setId(java.lang.String id) {
    this.id = id;
    return this;
  }

  /**
   * Required. The type of this label.
   * @return value or {@code null} for none
   */
  public java.lang.String getLabelType() {
    return labelType;
  }

  /**
   * Required. The type of this label.
   * @param labelType labelType or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2Label setLabelType(java.lang.String labelType) {
    this.labelType = labelType;
    return this;
  }

  /**
   * Custom URL to present to users to allow them to learn more about this label and how it should
   * be used.
   * @return value or {@code null} for none
   */
  public java.lang.String getLearnMoreUri() {
    return learnMoreUri;
  }

  /**
   * Custom URL to present to users to allow them to learn more about this label and how it should
   * be used.
   * @param learnMoreUri learnMoreUri or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2Label setLearnMoreUri(java.lang.String learnMoreUri) {
    this.learnMoreUri = learnMoreUri;
    return this;
  }

  /**
   * Output only. The lifecycle state of the label including whether it's published, deprecated, and
   * has draft changes.
   * @return value or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2Lifecycle getLifecycle() {
    return lifecycle;
  }

  /**
   * Output only. The lifecycle state of the label including whether it's published, deprecated, and
   * has draft changes.
   * @param lifecycle lifecycle or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2Label setLifecycle(GoogleAppsDriveLabelsV2Lifecycle lifecycle) {
    this.lifecycle = lifecycle;
    return this;
  }

  /**
   * Output only. The LockStatus of this label.
   * @return value or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2LockStatus getLockStatus() {
    return lockStatus;
  }

  /**
   * Output only. The LockStatus of this label.
   * @param lockStatus lockStatus or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2Label setLockStatus(GoogleAppsDriveLabelsV2LockStatus lockStatus) {
    this.lockStatus = lockStatus;
    return this;
  }

  /**
   * Output only. Resource name of the Label. Will be in the form of either: `labels/{id}` or
   * `labels/{id}@{revision_id}` depending on the request. See `id` and `revision_id` below.
   * @return value or {@code null} for none
   */
  public java.lang.String getName() {
    return name;
  }

  /**
   * Output only. Resource name of the Label. Will be in the form of either: `labels/{id}` or
   * `labels/{id}@{revision_id}` depending on the request. See `id` and `revision_id` below.
   * @param name name or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2Label setName(java.lang.String name) {
    this.name = name;
    return this;
  }

  /**
   * Required. The basic properties of the Label.
   * @return value or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2LabelProperties getProperties() {
    return properties;
  }

  /**
   * Required. The basic properties of the Label.
   * @param properties properties or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2Label setProperties(GoogleAppsDriveLabelsV2LabelProperties properties) {
    this.properties = properties;
    return this;
  }

  /**
   * Output only. The time this label was published. This value has no meaning when the label is not
   * published.
   * @return value or {@code null} for none
   */
  public String getPublishTime() {
    return publishTime;
  }

  /**
   * Output only. The time this label was published. This value has no meaning when the label is not
   * published.
   * @param publishTime publishTime or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2Label setPublishTime(String publishTime) {
    this.publishTime = publishTime;
    return this;
  }

  /**
   * Output only. The user who published this label. This value has no meaning when the label is not
   * published.
   * @return value or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2UserInfo getPublisher() {
    return publisher;
  }

  /**
   * Output only. The user who published this label. This value has no meaning when the label is not
   * published.
   * @param publisher publisher or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2Label setPublisher(GoogleAppsDriveLabelsV2UserInfo publisher) {
    this.publisher = publisher;
    return this;
  }

  /**
   * Output only. The time this label revision was created.
   * @return value or {@code null} for none
   */
  public String getRevisionCreateTime() {
    return revisionCreateTime;
  }

  /**
   * Output only. The time this label revision was created.
   * @param revisionCreateTime revisionCreateTime or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2Label setRevisionCreateTime(String revisionCreateTime) {
    this.revisionCreateTime = revisionCreateTime;
    return this;
  }

  /**
   * Output only. The user who created this label revision.
   * @return value or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2UserInfo getRevisionCreator() {
    return revisionCreator;
  }

  /**
   * Output only. The user who created this label revision.
   * @param revisionCreator revisionCreator or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2Label setRevisionCreator(GoogleAppsDriveLabelsV2UserInfo revisionCreator) {
    this.revisionCreator = revisionCreator;
    return this;
  }

  /**
   * Output only. Revision ID of the Label. Revision ID may be part of the Label `name` depending on
   * the request issued. A new revision is created whenever revisioned properties of a Label are
   * changed. Matches the regex: `([a-zA-Z0-9])+`
   * @return value or {@code null} for none
   */
  public java.lang.String getRevisionId() {
    return revisionId;
  }

  /**
   * Output only. Revision ID of the Label. Revision ID may be part of the Label `name` depending on
   * the request issued. A new revision is created whenever revisioned properties of a Label are
   * changed. Matches the regex: `([a-zA-Z0-9])+`
   * @param revisionId revisionId or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2Label setRevisionId(java.lang.String revisionId) {
    this.revisionId = revisionId;
    return this;
  }

  /**
   * Output only. The capabilities the user has on this Label.
   * @return value or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2LabelSchemaCapabilities getSchemaCapabilities() {
    return schemaCapabilities;
  }

  /**
   * Output only. The capabilities the user has on this Label.
   * @param schemaCapabilities schemaCapabilities or {@code null} for none
   */
  public GoogleAppsDriveLabelsV2Label setSchemaCapabilities(GoogleAppsDriveLabelsV2LabelSchemaCapabilities schemaCapabilities) {
    this.schemaCapabilities = schemaCapabilities;
    return this;
  }

  @Override
  public GoogleAppsDriveLabelsV2Label set(String fieldName, Object value) {
    return (GoogleAppsDriveLabelsV2Label) super.set(fieldName, value);
  }

  @Override
  public GoogleAppsDriveLabelsV2Label clone() {
    return (GoogleAppsDriveLabelsV2Label) super.clone();
  }

}


text:
import os

from measurements import smoothness_controller
from measurements import timeline_controller
from telemetry.core.platform import tracing_category_filter
from telemetry.core.platform import tracing_options
from telemetry.page import page_test
from telemetry.page.actions import action_runner
from telemetry.timeline.model import TimelineModel
from telemetry.util import statistics
from telemetry.value import list_of_scalar_values
from telemetry.value import scalar
from telemetry.value import trace

_CR_RENDERER_MAIN = 'CrRendererMain'
_RUN_SMOOTH_ACTIONS = 'RunSmoothAllActions'
_NAMES_TO_DUMP = ['oilpan_precise_mark',
                  'oilpan_precise_lazy_sweep',
                  'oilpan_precise_complete_sweep',
                  'oilpan_conservative_mark',
                  'oilpan_conservative_lazy_sweep',
                  'oilpan_conservative_complete_sweep',
                  'oilpan_coalesce']

def _AddTracingResults(events, results):
  # Prepare
  values = {}
  for name in _NAMES_TO_DUMP:
    values[name] = []

  # Parse in time line
  gc_type = None
  forced = False
  mark_time = 0
  lazy_sweep_time = 0
  complete_sweep_time = 0
  for event in events:
    duration = event.thread_duration or event.duration
    if event.name == 'ThreadHeap::coalesce':
      values['oilpan_coalesce'].append(duration)
      continue
    if event.name == 'Heap::collectGarbage':
      if not gc_type is None and not forced:
        values['oilpan_%s_mark' % gc_type].append(mark_time)
        values['oilpan_%s_lazy_sweep' % gc_type].append(lazy_sweep_time)
        values['oilpan_%s_complete_sweep' % gc_type].append(complete_sweep_time)

      gc_type = 'precise' if event.args['precise'] else 'conservative'
      forced = event.args['forced']
      mark_time = duration
      lazy_sweep_time = 0
      complete_sweep_time = 0
      continue
    if event.name == 'ThreadHeap::lazySweepPages':
      lazy_sweep_time += duration
      continue
    if event.name == 'ThreadState::completeSweep':
      complete_sweep_time += duration
      continue

  if not gc_type is None and not forced:
    values['oilpan_%s_mark' % gc_type].append(mark_time)
    values['oilpan_%s_lazy_sweep' % gc_type].append(lazy_sweep_time)
    values['oilpan_%s_complete_sweep' % gc_type].append(complete_sweep_time)

  # Dump
  page = results.current_page
  unit = 'ms'
  for name in _NAMES_TO_DUMP:
    if values[name]:
      results.AddValue(list_of_scalar_values.ListOfScalarValues(
          page, name, unit, values[name]))
      results.AddValue(scalar.ScalarValue(
          page, name + '_max', unit, max(values[name])))
    results.AddValue(scalar.ScalarValue(
        page, name + '_total', unit, sum(values[name])))

  # Summarize marking time
  total_mark_time = 0
  for gc_type in ['precise', 'conservative']:
    total_mark_time += sum(values['oilpan_%s_mark' % gc_type])
  results.AddValue(
      scalar.ScalarValue(page, 'oilpan_mark', unit, total_mark_time))

  # Summarize sweeping time
  total_sweep_time = 0
  for do_type in ['lazy_sweep', 'complete_sweep']:
    sweep_time = 0
    for gc_type in ['precise', 'conservative']:
      sweep_time += sum(values['oilpan_%s_%s' % (gc_type, do_type)])
    key = 'oilpan_%s' % do_type
    results.AddValue(scalar.ScalarValue(page, key, unit, sweep_time))
    total_sweep_time += sweep_time
  results.AddValue(
      scalar.ScalarValue(page, 'oilpan_sweep', unit, total_sweep_time))

  gc_time = 0
  for key in values:
    gc_time += sum(values[key])
  results.AddValue(scalar.ScalarValue(page, 'oilpan_gc', unit, gc_time))

class _OilpanGCTimesBase(page_test.PageTest):
  def __init__(self):
    super(_OilpanGCTimesBase, self).__init__()
    self._timeline_model = None

  def WillNavigateToPage(self, page, tab):
    # FIXME: Remove webkit.console when blink.console lands in chromium and
    # the ref builds are updated. crbug.com/386847
    categories = ['webkit.console', 'blink.console', 'blink_gc']
    category_filter = tracing_category_filter.TracingCategoryFilter()
    for c in categories:
      category_filter.AddIncludedCategory(c)
    options = tracing_options.TracingOptions()
    options.enable_chrome_trace = True
    tab.browser.platform.tracing_controller.Start(options, category_filter,
                                                  timeout=1000)

  def DidRunActions(self, page, tab):
    timeline_data = tab.browser.platform.tracing_controller.Stop()
    self._timeline_model = TimelineModel(timeline_data)

  def ValidateAndMeasurePage(self, page, tab, results):
    threads = self._timeline_model.GetAllThreads()
    for thread in threads:
      if thread.name == _CR_RENDERER_MAIN:
        _AddTracingResults(thread.all_slices, results)

  def CleanUpAfterPage(self, page, tab):
    if tab.browser.platform.tracing_controller.is_tracing_running:
      tab.browser.platform.tracing_controller.Stop()

class OilpanGCTimesForSmoothness(_OilpanGCTimesBase):
  def __init__(self):
    super(OilpanGCTimesForSmoothness, self).__init__()
    self._interaction = None

  def WillRunActions(self, page, tab):
    runner = action_runner.ActionRunner(tab)
    self._interaction = runner.BeginInteraction(_RUN_SMOOTH_ACTIONS,
                                                is_smooth=True)

  def DidRunActions(self, page, tab):
    self._interaction.End()
    super(OilpanGCTimesForSmoothness, self).DidRunActions(page, tab)

class OilpanGCTimesForBlinkPerf(_OilpanGCTimesBase):
  def __init__(self):
    super(OilpanGCTimesForBlinkPerf, self).__init__()
    with open(os.path.join(os.path.dirname(__file__), '..', 'benchmarks',
                           'blink_perf.js'), 'r') as f:
      self._blink_perf_js = f.read()

  def WillNavigateToPage(self, page, tab):
    page.script_to_evaluate_on_commit = self._blink_perf_js
    super(OilpanGCTimesForBlinkPerf, self).WillNavigateToPage(page, tab)

  def DidRunActions(self, page, tab):
    tab.WaitForJavaScriptExpression('testRunner.isDone', 600)
    super(OilpanGCTimesForBlinkPerf, self).DidRunActions(page, tab)

class OilpanGCTimesForInternals(_OilpanGCTimesBase):
  def __init__(self):
    super(OilpanGCTimesForInternals, self).__init__()

  @classmethod
  def CustomizeBrowserOptions(cls, options):
    # 'expose-internals-for-testing' can be enabled on content shell.
    assert 'content-shell' in options.browser_type
    options.AppendExtraBrowserArgs(['--expose-internals-for-testing',
                                    '--js-flags=--expose-gc'])


text:
#ifndef _PRIVATE_BIONIC_GLOBALS_H
#define _PRIVATE_BIONIC_GLOBALS_H

#include <stdatomic.h>
#include <sys/cdefs.h>
#include <link.h>
#include <pthread.h>

#include "private/bionic_allocator.h"
#include "private/bionic_elf_tls.h"
#include "private/bionic_fdsan.h"
#include "private/bionic_malloc_dispatch.h"
#include "private/bionic_vdso.h"
#include "private/WriteProtected.h"

#include <platform/bionic/malloc.h>

struct libc_globals {
  vdso_entry vdso[VDSO_END];
  long setjmp_cookie;
  uintptr_t heap_pointer_tag;

  // In order to allow a complete switch between dispatch tables without
  // the need for copying each function by function in the structure,
  // use a single atomic pointer to switch.
  // The current_dispatch_table pointer can only ever be set to a complete
  // table. Any dispatch table that is pointed to by current_dispatch_table
  // cannot be modified after that. If the pointer changes in the future,
  // the old pointer must always stay valid.
  // The malloc_dispatch_table is modified by malloc debug, malloc hooks,
  // and heaprofd. Only one of these modes can be active at any given time.
  _Atomic(const MallocDispatch*) current_dispatch_table;
  // This pointer is only used by the allocation limit code when both a
  // limit is enabled and some other hook is enabled at the same time.
  _Atomic(const MallocDispatch*) default_dispatch_table;
  MallocDispatch malloc_dispatch_table;
};

__LIBC_HIDDEN__ extern WriteProtected<libc_globals> __libc_globals;

struct abort_msg_t;
namespace gwp_asan {
struct AllocatorState;
struct AllocationMetadata;
};  // namespace gwp_asan

// Globals shared between the dynamic linker and libc.so.
struct libc_shared_globals {
  // Construct the shared globals using a constexpr constructor to ensure that
  // the object doesn't need dynamic initialization. The object is accessed
  // before the dynamic linker has relocated itself.
  constexpr libc_shared_globals() {}

  FdTable fd_table;

  // When the linker is invoked on a binary (e.g. `linker64 /system/bin/date`),
  // record the number of arguments passed to the linker itself rather than to
  // the program it's loading. Typically 0, sometimes 1.
  int initial_linker_arg_count = 0;

  ElfW(auxv_t)* auxv = nullptr;

  pthread_mutex_t abort_msg_lock = PTHREAD_MUTEX_INITIALIZER;
  abort_msg_t* abort_msg = nullptr;

  StaticTlsLayout static_tls_layout;
  TlsModules tls_modules;
  BionicAllocator tls_allocator;

  // Values passed from libc.so to the loader.
  void (*load_hook)(ElfW(Addr) base, const ElfW(Phdr)* phdr, ElfW(Half) phnum) = nullptr;
  void (*unload_hook)(ElfW(Addr) base, const ElfW(Phdr)* phdr, ElfW(Half) phnum) = nullptr;
  void (*set_target_sdk_version_hook)(int target) = nullptr;

  // Values passed from the linker to libc.so.
  const char* init_progname = nullptr;
  char** init_environ = nullptr;

  const gwp_asan::AllocatorState* gwp_asan_state = nullptr;
  const gwp_asan::AllocationMetadata* gwp_asan_metadata = nullptr;

  const char* scudo_stack_depot = nullptr;
  const char* scudo_region_info = nullptr;
  const char* scudo_ring_buffer = nullptr;

  HeapTaggingLevel initial_heap_tagging_level = M_HEAP_TAGGING_LEVEL_NONE;
};

__LIBC_HIDDEN__ libc_shared_globals* __libc_shared_globals();
__LIBC_HIDDEN__ void __libc_init_fdsan();
__LIBC_HIDDEN__ void __libc_init_fdtrack();
__LIBC_HIDDEN__ void __libc_init_profiling_handlers();

__LIBC_HIDDEN__ void __libc_init_malloc(libc_globals* globals);
__LIBC_HIDDEN__ void __libc_init_setjmp_cookie(libc_globals* globals);
__LIBC_HIDDEN__ void __libc_init_vdso(libc_globals* globals);

#if defined(__i386__)
__LIBC_HIDDEN__ extern void* __libc_sysinfo;
extern "C" __LIBC_HIDDEN__ void __libc_int0x80();
__LIBC_HIDDEN__ void __libc_init_sysinfo();
#endif

#endif


text:
\begin {figure}[hbtp]
\centering
\includegraphics[width=\textwidth]{output/R4_R3_1000_ALL_FEATURES/plot_R4_R3_1000_bestmodels.eps}
\caption{Completion time vs ncores for: R4 $\rightarrow$ R3 with datasize 1000GB}
\label{fig:coreonly_linear_R4_R3_1000}
\end {figure}


text:
package org.apache.hadoop.hbase.regionserver;

import org.apache.hadoop.hbase.classification.InterfaceAudience;
import org.apache.hadoop.hbase.util.ClassSize;

/**
 * CSLMImmutableSegment is an abstract class that extends the API supported by a {@link Segment},
 * and {@link ImmutableSegment}. This immutable segment is working with CellSet with
 * ConcurrentSkipListMap (CSLM) delegatee.
 */
@InterfaceAudience.Private
public class CSLMImmutableSegment extends ImmutableSegment {
  public static final long DEEP_OVERHEAD_CSLM =
      ImmutableSegment.DEEP_OVERHEAD + ClassSize.CONCURRENT_SKIPLISTMAP;

  /**------------------------------------------------------------------------
   * Copy C-tor to be used when new CSLMImmutableSegment is being built from a Mutable one.
   * This C-tor should be used when active MutableSegment is pushed into the compaction
   * pipeline and becomes an ImmutableSegment.
   */
  protected CSLMImmutableSegment(Segment segment) {
    super(segment);
    // update the segment metadata heap size
    incSize(0, -MutableSegment.DEEP_OVERHEAD + DEEP_OVERHEAD_CSLM);
  }

  @Override
  protected long indexEntrySize() {
    return ClassSize.CONCURRENT_SKIPLISTMAP_ENTRY;
  }

  @Override protected boolean canBeFlattened() {
    return true;
  }
}


text:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.Remoting.Messaging;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Orleans;
using Orleans.Runtime;
using Orleans.Serialization;
using TestExtensions;
using Xunit;
using Tester;

namespace UnitTests.General
{
    [Collection(TestEnvironmentFixture.DefaultCollection)]
    public class RequestContextTests_Local : IDisposable
    {
        private readonly Dictionary<string, object> headers = new Dictionary<string, object>();

        private static bool oldPropagateActivityId;

        private static readonly SafeRandom random = new SafeRandom();
        private readonly TestEnvironmentFixture fixture;

        public RequestContextTests_Local(TestEnvironmentFixture fixture)
        {
            this.fixture = fixture;
            oldPropagateActivityId = RequestContext.PropagateActivityId;
            RequestContext.PropagateActivityId = true;
            RequestContextTestUtils.SetActivityId(Guid.Empty);
            RequestContext.Clear();
            headers.Clear();
            this.fixture.RuntimeClient.ClientInvokeCallback = null;
        }

        public void Dispose()
        {
            TestCleanup();
        }

        private void TestCleanup()
        {
            RequestContextTestUtils.ClearActivityId();
            RequestContext.Clear();
            headers.Clear();
            this.fixture.RuntimeClient.ClientInvokeCallback = null;
        }

        [Fact, TestCategory("Functional"), TestCategory("RequestContext")]
        public async Task RequestContext_MultiThreads_ExportToMessage()
        {
            const int NumLoops = 50;
            string id = "key" + random.Next();

            Message msg = new Message();
            Task[] promises = new Task[NumLoops];
            ManualResetEventSlim flag = new ManualResetEventSlim(false);
            for (int i = 0; i < NumLoops; i++)
            {
                string key = id + "-" + i;
                RequestContext.Set(key, i);
                promises[i] = Task.Run(() =>
                {
                    flag.Wait();
                    msg.RequestContextData = RequestContextExtensions.Export(this.fixture.SerializationManager);
                });
                flag.Set();
                Thread.Sleep(1);
                RequestContext.Remove(key);
            }
            await Task.WhenAll(promises);
        }

        [Fact, TestCategory("Functional"), TestCategory("RequestContext")]
        public void RequestContext_ActivityId_ExportToMessage()
        {
            Guid activityId = Guid.NewGuid();
            Guid activityId2 = Guid.NewGuid();
            Guid nullActivityId = Guid.Empty;

            Message msg = new Message();
            msg.RequestContextData = RequestContextExtensions.Export(this.fixture.SerializationManager);
            if (msg.RequestContextData != null) foreach (var kvp in msg.RequestContextData)
                {
                    headers.Add(kvp.Key, kvp.Value);
                };
            Assert.False(headers.ContainsKey(RequestContext.E2_E_TRACING_ACTIVITY_ID_HEADER), "ActivityId should not be be present " + headers.ToStrings(separator: ","));
            TestCleanup();

            RequestContextTestUtils.SetActivityId(activityId);
            msg = new Message();
            msg.RequestContextData = RequestContextExtensions.Export(this.fixture.SerializationManager);
            if (msg.RequestContextData != null) foreach (var kvp in msg.RequestContextData)
                {
                    headers.Add(kvp.Key, kvp.Value);
                };
            Assert.True(headers.ContainsKey(RequestContext.E2_E_TRACING_ACTIVITY_ID_HEADER), "ActivityId #1 should be present " + headers.ToStrings(separator: ","));
            object result = headers[RequestContext.E2_E_TRACING_ACTIVITY_ID_HEADER];
            Assert.NotNull(result);// ActivityId #1 should not be null
            Assert.Equal(activityId, result);  // "E2E ActivityId #1 not propagated correctly"
            Assert.Equal(activityId, RequestContextTestUtils.GetActivityId());  // "Original E2E ActivityId #1 should not have changed"
            TestCleanup();

            RequestContextTestUtils.SetActivityId(nullActivityId);
            msg = new Message();
            msg.RequestContextData = RequestContextExtensions.Export(this.fixture.SerializationManager);
            if (msg.RequestContextData != null) foreach (var kvp in msg.RequestContextData)
                {
                    headers.Add(kvp.Key, kvp.Value);
                };
            Assert.False(headers.ContainsKey(RequestContext.E2_E_TRACING_ACTIVITY_ID_HEADER), "Null ActivityId should not be present " + headers.ToStrings(separator: ","));
            TestCleanup();

            RequestContextTestUtils.SetActivityId(activityId2);
            msg = new Message();
            msg.RequestContextData = RequestContextExtensions.Export(this.fixture.SerializationManager);
            foreach (var kvp in msg.RequestContextData)
            {
                headers.Add(kvp.Key, kvp.Value);
            };
            Assert.True(headers.ContainsKey(RequestContext.E2_E_TRACING_ACTIVITY_ID_HEADER), "ActivityId #2 should be present " + headers.ToStrings(separator: ","));
            result = headers[RequestContext.E2_E_TRACING_ACTIVITY_ID_HEADER];
            Assert.NotNull(result); // ActivityId #2 should not be null
            Assert.Equal(activityId2, result);  // "E2E ActivityId #2 not propagated correctly"

            Assert.Equal(activityId2, RequestContextTestUtils.GetActivityId());  // "Original E2E ActivityId #2 should not have changed"
            TestCleanup();
        }

        [Fact, TestCategory("Functional"), TestCategory("RequestContext")]
        public void RequestContext_ActivityId_ExportImport()
        {
            Guid activityId = Guid.NewGuid();
            Guid activityId2 = Guid.NewGuid();
            Guid nullActivityId = Guid.Empty;

            Message msg = new Message();
            msg.RequestContextData = RequestContextExtensions.Export(this.fixture.SerializationManager);
            RequestContext.Clear();
            RequestContextExtensions.Import(msg.RequestContextData);
            var actId = RequestContext.Get(RequestContext.E2_E_TRACING_ACTIVITY_ID_HEADER);
            Assert.Null(actId);
            TestCleanup();

            RequestContextTestUtils.SetActivityId(activityId);
            msg = new Message();
            msg.RequestContextData = RequestContextExtensions.Export(this.fixture.SerializationManager);
            RequestContext.Clear();
            RequestContextExtensions.Import(msg.RequestContextData);
            actId = RequestContext.Get(RequestContext.E2_E_TRACING_ACTIVITY_ID_HEADER);
            if (msg.RequestContextData != null) foreach (var kvp in msg.RequestContextData)
                {
                    headers.Add(kvp.Key, kvp.Value);
                };
            Assert.NotNull(actId); // "ActivityId #1 should be present " + headers.ToStrings(separator: ",")
            object result = headers[RequestContext.E2_E_TRACING_ACTIVITY_ID_HEADER];
            Assert.NotNull(result);// "ActivityId #1 should not be null"
            Assert.Equal(activityId, result);  // "E2E ActivityId #1 not propagated correctly"
            Assert.Equal(activityId, RequestContextTestUtils.GetActivityId());  // "Original E2E ActivityId #1 should not have changed"
            TestCleanup();

            RequestContextTestUtils.SetActivityId(nullActivityId);
            msg = new Message();
            msg.RequestContextData = RequestContextExtensions.Export(this.fixture.SerializationManager);
            RequestContext.Clear();
            RequestContextExtensions.Import(msg.RequestContextData);
            actId = RequestContext.Get(RequestContext.E2_E_TRACING_ACTIVITY_ID_HEADER);
            Assert.Null(actId);
            TestCleanup();

            RequestContextTestUtils.SetActivityId(activityId2);
            msg = new Message();
            msg.RequestContextData = RequestContextExtensions.Export(this.fixture.SerializationManager);
            RequestContext.Clear();
            RequestContextExtensions.Import(msg.RequestContextData);
            actId = RequestContext.Get(RequestContext.E2_E_TRACING_ACTIVITY_ID_HEADER);
            if (msg.RequestContextData != null) foreach (var kvp in msg.RequestContextData)
                {
                    headers.Add(kvp.Key, kvp.Value);
                };
            Assert.NotNull(actId); // "ActivityId #2 should be present " + headers.ToStrings(separator: ",")
            result = headers[RequestContext.E2_E_TRACING_ACTIVITY_ID_HEADER];
            Assert.NotNull(result); // "ActivityId #2 should not be null"
            Assert.Equal(activityId2, result);// "E2E ActivityId #2 not propagated correctly

            Assert.Equal(activityId2, RequestContextTestUtils.GetActivityId()); // "Original E2E ActivityId #2 should not have changed"
            TestCleanup();
        }

        [Fact, TestCategory("Functional"), TestCategory("RequestContext")]
        public async Task LCC_Basic()
        {
            string name1 = "Name" + random.Next();
            string data1 = "Main";
            const int NumLoops = 1000;

            CallContext.LogicalSetData(name1, data1);

            Assert.Equal(data1, CallContext.LogicalGetData(name1));

            Task t = Task.Run(() =>
            {
                Assert.Equal(data1, CallContext.LogicalGetData(name1));
            });
            await t;

            Task[] promises = new Task[NumLoops];
            for (int i = 0; i < NumLoops; i++)
            {
                string str = i.ToString(CultureInfo.InvariantCulture);
                promises[i] = Task.Run(async () =>
                {
                    CallContext.LogicalSetData(name1, str);

                    await Task.Delay(10);

                    Assert.Equal(str, CallContext.LogicalGetData(name1));  // "LCC.GetData-Task.Run-"+str
                });
            }
            await Task.WhenAll(promises);
        }
        [Fact, TestCategory("Functional"), TestCategory("RequestContext")]
        public async Task LCC_Dictionary()
        {
            string name1 = "Name" + random.Next();
            string data1 = "Main";
            const int NumLoops = 1000;

            var dict = new Dictionary<string, string>();
            dict[name1] = data1;
            CallContext.LogicalSetData(name1, dict);

            var result1 = (Dictionary<string, string>)CallContext.LogicalGetData(name1);
            Assert.Equal(data1, result1[name1]);  // "LCC.GetData-Main"

            Task t = Task.Run(() =>
            {
                var result2 = (Dictionary<string, string>)CallContext.LogicalGetData(name1);
                Assert.Equal(data1, result2[name1]);  // "LCC.GetData-Task.Run"
                Assert.Same(dict, result2);  // "Same object LCC.GetData-Task.Run"
            });
            await t;

            Task[] promises = new Task[NumLoops];
            for (int i = 0; i < NumLoops; i++)
            {
                string str = i.ToString(CultureInfo.InvariantCulture);
                promises[i] = Task.Run(async () =>
                {
                    var dict2 = (Dictionary<string, string>)CallContext.LogicalGetData(name1);
                    Assert.Equal(data1, dict2[name1]);  // "LCC.GetData-Task.Run-Get-" + str
                    Assert.Same(dict, dict2);  // "Same object LCC.GetData-Task.Run-Get" + str

                    var dict3 = new Dictionary<string, string>();
                    dict3[name1] = str;
                    CallContext.LogicalSetData(name1, dict3);

                    await Task.Delay(10);

                    var result3 = (Dictionary<string, string>)CallContext.LogicalGetData(name1);
                    Assert.Equal(str, result3[name1]);  // "LCC.GetData-Task.Run-Set-" + str
                    Assert.Same(dict3, result3);  // "Same object LCC.GetData-Task.Run-Set-" + str
                    Assert.NotSame(dict2, result3);  // "Different object LCC.GetData-Task.Run-Set-" + str
                });
            }
            await Task.WhenAll(promises);
        }

        [Fact, TestCategory("Functional"), TestCategory("RequestContext")]
        public async Task LCC_CrossThread()
        {
            const int NumLoops = 1000;

            string name1 = "Name" + random.Next();
            string data1 = "Main";

            CallContext.LogicalSetData(name1, data1);
            Assert.Equal(data1, CallContext.LogicalGetData(name1));  // "LCC.GetData-Main"

            Task[] promises = new Task[NumLoops];
            for (int i = 0; i < NumLoops; i++)
            {
                string str = i.ToString(CultureInfo.InvariantCulture);
                promises[i] = Task.Run(async () =>
                {
                    await Task.Delay(5);
                    Assert.Equal(data1, CallContext.LogicalGetData(name1));  // "LCC.GetData-Main"
                    await Task.Delay(5);
                    CallContext.LogicalSetData(name1, str);
                    Assert.Equal(str, CallContext.LogicalGetData(name1));  // "LCC.GetData-Task.Run-1-" + str
                    await Task.Delay(5);
                    Assert.Equal(str, CallContext.LogicalGetData(name1));  // "LCC.GetData-Task.Run-1-" + str
                    await Task.Delay(5);
                    Assert.Equal(str, CallContext.LogicalGetData(name1));  // "LCC.GetData-Task.Run-2-" + str
                });
            }
            await Task.WhenAll(promises);
            Assert.Equal(data1, CallContext.LogicalGetData(name1));  // "LCC.GetData-Main-Final"
        }

        [Fact, TestCategory("Functional"), TestCategory("RequestContext")]
        public async Task LCC_CrossThread_Dictionary()
        {
            const int NumLoops = 1000;

            string name1 = "Name" + random.Next();
            string data1 = "Main";

            var dict = new Dictionary<string, string>();
            dict[name1] = data1;
            CallContext.LogicalSetData(name1, dict);

            var result0 = (Dictionary<string, string>)CallContext.LogicalGetData(name1);
            Assert.Equal(data1, result0[name1]);  // "LCC.GetData-Main"

            Task[] promises = new Task[NumLoops];
            for (int i = 0; i < NumLoops; i++)
            {
                string str = i.ToString(CultureInfo.InvariantCulture);
                promises[i] = Task.Run(async () =>
                {
                    var result1 = (Dictionary<string, string>)CallContext.LogicalGetData(name1);
                    Assert.Same(dict, result1);  // "Same object LCC.GetData-Task.Run-Get" + str
                    Assert.Equal(data1, result1[name1]);  // "LCC.GetData-Task.Run-Get-" + str

                    await Task.Delay(5);

                    var dict2 = (Dictionary<string, string>)CallContext.LogicalGetData(name1);
                    Assert.Same(dict, dict2);  // "Same object LCC.GetData-Task.Run-Get" + str
                    Assert.Equal(data1, dict2[name1]);  // "LCC.GetData-Task.Run-Get-" + str

                    // Set New Dictionary
                    var dict3 = new Dictionary<string, string>();
                    dict3[name1] = str;
                    CallContext.LogicalSetData(name1, dict3);

                    var result3 = (Dictionary<string, string>)CallContext.LogicalGetData(name1);
                    Assert.Same(dict3, result3);  // "Same object LCC.GetData-Task.Run-Set-1-" + str
                    Assert.Equal(str, result3[name1]);  // "LCC.GetData-Task.Run-Set-" + str

                    await Task.Delay(5);

                    result3 = (Dictionary<string, string>)CallContext.LogicalGetData(name1);
                    Assert.Same(dict3, result3);  // "Same object LCC.GetData-Task.Run-Set-1-" + str
                    Assert.Equal(str, result3[name1]);  // "LCC.GetData-Task.Run-Set-" + str

                    await Task.Delay(5);
                    result3 = (Dictionary<string, string>)CallContext.LogicalGetData(name1);
                    Assert.Same(dict3, result3);  // "Same object LCC.GetData-Task.Run-Set-2-" + str
                    Assert.Equal(str, result3[name1]);  // "LCC.GetData-Task.Run-Set-" + str
                });
            }
            await Task.WhenAll(promises);
            result0 = (Dictionary<string, string>)CallContext.LogicalGetData(name1);
            Assert.Same(dict, result0);  // "Same object LCC.GetData-Task.Run-Get"
            Assert.Equal(data1, result0[name1]);  // "LCC.GetData-Main-Final"
        }

        [Fact, TestCategory("Functional"), TestCategory("RequestContext")]
        public async Task RequestContext_CrossThread()
        {
            const int NumLoops = 1000;

            string name1 = "Name" + random.Next();
            string data1 = "Main";

            RequestContext.Set(name1, data1);
            Assert.Equal(data1, RequestContext.Get(name1));  // "RC.GetData-Main"

            Task[] promises = new Task[NumLoops];
            for (int i = 0; i < NumLoops; i++)
            {
                string str = i.ToString(CultureInfo.InvariantCulture);
                promises[i] = Task.Run(async () =>
                {
                    await Task.Delay(5);
                    Assert.Equal(data1, RequestContext.Get(name1));  // "RC.GetData-Task.Run-0"
                    await Task.Delay(5);
                    // Set New value
                    RequestContext.Set(name1, str);
                    Assert.Equal(str, RequestContext.Get(name1));  // "RC.GetData-Task.Run-1-" + str
                    await Task.Delay(5);
                    Assert.Equal(str, RequestContext.Get(name1));  // "RC.GetData-Task.Run-2-" + str
                    await Task.Delay(5);
                    Assert.Equal(str, RequestContext.Get(name1));  // "RC.GetData-Task.Run-3-" + str
                });
            }
            await Task.WhenAll(promises);
            Assert.Equal(data1, RequestContext.Get(name1));  // "RC.GetData-Main-Final"
        }

    }

}


text:
// @(#)root/eve:$Id$
// Author: Matevz Tadel 2007

#ifndef AliEveV0ListEditor_H
#define AliEveV0ListEditor_H

#include "TGedFrame.h"

class TGButton;
class TGCheckButton;
class TGNumberEntry;
class TGColorSelect;
class TEveGDoubleValuator;
class TGComboBox;

class AliEveV0List;

//______________________________________________________________________________
// Short description of AliEveV0ListEditor
//

class AliEveV0ListEditor : public TGedFrame
{
public:
  AliEveV0ListEditor(const TGWindow* p=0, Int_t width=170, Int_t height=30,
                     UInt_t options=kChildFrame, Pixel_t back=GetDefaultFrameBackground());
  virtual ~AliEveV0ListEditor() {}

  virtual void SetModel(TObject* obj);

  // Declare callback/slot methods
  void DoMinMaxRCut();
  void DoMinMaxDaughterDCA();
  void DoMinMaxPt();
  void DoSelectNegPid(Int_t rNegPid);
  void DoCheckNegPid();
  void DoSelectNegProb();
  void DoSelectPosPid(Int_t rPosPid);
  void DoCheckPosPid();
  void DoSelectPosProb();
  void DoMinMaxInvariantMass();

protected:
  AliEveV0List            *fM; // Model object.

  // Declare widgets
  // TGSomeWidget*   fXYZZ;
  TEveGDoubleValuator* fMinMaxRCut;
  TEveGDoubleValuator* fMinMaxDaughterDCA;
  TEveGDoubleValuator* fMinMaxPt;
  TGComboBox*          fNegativeSpecies;
  TGComboBox*          fPositiveSpecies;
  TGCheckButton*       fNegativeCheckMaxPidProbability;
  TGCheckButton*       fPositiveCheckMaxPidProbability;
  TGNumberEntry*       fNegativeLevelPidProbability;
  TGNumberEntry*       fPositiveLevelPidProbability;
  TEveGDoubleValuator* fMinMaxInvariantMass;

private:
  AliEveV0ListEditor(const AliEveV0ListEditor&);            // Not implemented
  AliEveV0ListEditor& operator=(const AliEveV0ListEditor&); // Not implemented

  ClassDef(AliEveV0ListEditor, 0); // GUI editor for AliEveV0List.
};

#endif