#include <bits/stdc++.h>
using namespace std;
// ===================================================================
// This file contains a collection of 2D Segment Tree algorithms.
// Each function/class is ready to be used as a "black box".
// Read the comments above each one to understand:
// - What it solves
// - What input it expects
// - What it returns
// - Time complexity
// - Important constraints / assumptions
// - Any extra notes
// ===================================================================
// ===================================================================
// 1) STATIC 2D SEGMENT TREE FOR SUM
// (Point Update, Rectangle Sum Query)
// ===================================================================
// -------------------------------------------------------------------
// CLASS: SegTree2DSum
// -------------------------------------------------------------------
// WHAT IT DOES:
// Builds a 2D segment tree over a grid of integers (N rows x M columns).
// It supports:
// - Point update: add a value (delta) to a single cell.
// - Rectangle sum: compute the sum of all cells inside a given
// rectangle [x1..x2] × [y1..y2].
//
// INPUT:
// - The grid is given as a 2D vector (N x M) in the `build` function.
// - Coordinates are 0‑based (row and column indices start from 0).
//
// OUTPUT:
// - `querySum` returns an integer – the sum of the rectangle.
// - `updatePoint` does not return anything; it modifies the tree.
//
// TIME COMPLEXITY:
// - Build: O(N * M) (actually O(4*N * 4*M) but practically O(N*M)).
// - Update: O(log N * log M).
// - Query: O(log N * log M).
//
// MEMORY:
// - O(N * M) (stored as a 2D array of size 4*N × 4*M).
//
// CONSTRAINTS / ASSUMPTIONS:
// - N and M must be known at construction time.
// - The grid values are integers (int).
// - The grid size (N × M) should be reasonable (e.g., N, M <= 1000)
// because memory grows quadratically.
// - Updates add a delta; they do not set a value (use negative delta
// to subtract).
//
// NOTES:
// - This implementation uses 0‑based indices everywhere.
// - It is a "static" tree because the grid size is fixed after build.
// - The class allocates a full 4*N × 4*M array, so it may be heavy
// for large grids.
// - If you need to handle sparse data or very large coordinates,
// see the Fenwick2D class below (coordinate compression).
// -------------------------------------------------------------------
class SegTree2DSum {
int n, m;
vector< vector< int >> tree; // tree[4*n][4*m]
// Build the column segment tree for a single row (leaf row node).
void buildColTree( int rowNode, int colNode, int l, int r, const vector< int > & row) {
if ( l == r) {
tree[ rowNode] [ colNode] = row[ l] ;
return ;
}
int mid = ( l + r) / 2 ;
buildColTree( rowNode, colNode* 2 , l, mid, row) ;
buildColTree( rowNode, colNode* 2 + 1 , mid+ 1 , r, row) ;
tree[ rowNode] [ colNode] = tree[ rowNode] [ colNode* 2 ] + tree[ rowNode] [ colNode* 2 + 1 ] ;
}
// Merge the column trees of two child row nodes into the parent row node.
void mergeColTrees( int rowNode, int colNode, int l, int r) {
if ( l == r) {
tree[ rowNode] [ colNode] = tree[ rowNode* 2 ] [ colNode] + tree[ rowNode* 2 + 1 ] [ colNode] ;
return ;
}
int mid = ( l + r) / 2 ;
mergeColTrees( rowNode, colNode* 2 , l, mid) ;
mergeColTrees( rowNode, colNode* 2 + 1 , mid+ 1 , r) ;
tree[ rowNode] [ colNode] = tree[ rowNode* 2 ] [ colNode] + tree[ rowNode* 2 + 1 ] [ colNode] ;
}
// Build the row segment tree recursively.
void buildRow( int node, int l, int r, const vector< vector< int >> & grid) {
if ( l == r) {
// Leaf row: build its column tree from the grid row.
buildColTree( node, 1 , 0 , m- 1 , grid[ l] ) ;
return ;
}
int mid = ( l + r) / 2 ;
buildRow( node* 2 , l, mid, grid) ;
buildRow( node* 2 + 1 , mid+ 1 , r, grid) ;
// Merge the column trees of the two children.
mergeColTrees( node, 1 , 0 , m- 1 ) ;
}
// Update a single column in a leaf row node.
void updateCol( int rowNode, int colNode, int l, int r, int y, int delta) {
if ( l == r) {
tree[ rowNode] [ colNode] + = delta;
return ;
}
int mid = ( l + r) / 2 ;
if ( y <= mid) updateCol( rowNode, colNode* 2 , l, mid, y, delta) ;
else updateCol( rowNode, colNode* 2 + 1 , mid+ 1 , r, y, delta) ;
tree[ rowNode] [ colNode] = tree[ rowNode] [ colNode* 2 ] + tree[ rowNode] [ colNode* 2 + 1 ] ;
}
// After updating one child row, recompute the current row node's
// column tree for the affected column.
void updateColMerge( int rowNode, int colNode, int l, int r, int y, int delta) {
if ( l == r) {
tree[ rowNode] [ colNode] = tree[ rowNode* 2 ] [ colNode] + tree[ rowNode* 2 + 1 ] [ colNode] ;
return ;
}
int mid = ( l + r) / 2 ;
if ( y <= mid) updateColMerge( rowNode, colNode* 2 , l, mid, y, delta) ;
else updateColMerge( rowNode, colNode* 2 + 1 , mid+ 1 , r, y, delta) ;
tree[ rowNode] [ colNode] = tree[ rowNode* 2 ] [ colNode] + tree[ rowNode* 2 + 1 ] [ colNode] ;
}
// Update a cell (x,y) by adding delta, traversing the row tree.
void updateRow( int node, int l, int r, int x, int y, int delta) {
if ( l == r) {
updateCol( node, 1 , 0 , m- 1 , y, delta) ;
return ;
}
int mid = ( l + r) / 2 ;
if ( x <= mid) updateRow( node* 2 , l, mid, x, y, delta) ;
else updateRow( node* 2 + 1 , mid+ 1 , r, x, y, delta) ;
// After child is updated, update the current node's column tree.
updateColMerge( node, 1 , 0 , m- 1 , y, delta) ;
}
// Query the column tree of a given row node for a range of columns.
int queryCol( int rowNode, int colNode, int l, int r, int y1, int y2) {
if ( y1 <= l && r <= y2) {
return tree[ rowNode] [ colNode] ;
}
int mid = ( l + r) / 2 ;
int res = 0 ;
if ( y1 <= mid) res + = queryCol( rowNode, colNode* 2 , l, mid, y1, y2) ;
if ( y2 > mid) res + = queryCol( rowNode, colNode* 2 + 1 , mid+ 1 , r, y1, y2) ;
return res;
}
// Query the row tree for a rectangle [x1..x2] × [y1..y2].
int queryRow( int node, int l, int r, int x1, int x2, int y1, int y2) {
if ( x1 <= l && r <= x2) {
return queryCol( node, 1 , 0 , m- 1 , y1, y2) ;
}
int mid = ( l + r) / 2 ;
int res = 0 ;
if ( x1 <= mid) res + = queryRow( node* 2 , l, mid, x1, x2, y1, y2) ;
if ( x2 > mid) res + = queryRow( node* 2 + 1 , mid+ 1 , r, x1, x2, y1, y2) ;
return res;
}
public :
// Constructor: prepares the tree with given dimensions.
// Input: number of rows (n) and columns (m).
SegTree2DSum( int n, int m) : n( n) , m( m) {
tree.assign ( 4 * n, vector< int > ( 4 * m, 0 ) ) ;
}
// Build the 2D segment tree from the grid.
// Input: a 2D vector grid of size n x m (must match the constructor dimensions).
// Time: O(n*m).
void build( const vector< vector< int >> & grid) {
buildRow( 1 , 0 , n- 1 , grid) ;
}
// Point update: add 'delta' to cell (x,y).
// Input: x (row), y (column), delta (value to add, can be negative).
// Time: O(log n * log m).
void updatePoint( int x, int y, int delta) {
updateRow( 1 , 0 , n- 1 , x, y, delta) ;
}
// Rectangle sum query: sum of cells in [x1..x2] × [y1..y2].
// Input: x1, y1, x2, y2 (all 0‑based indices, inclusive).
// Returns: the sum as an integer.
// Time: O(log n * log m).
int querySum( int x1, int y1, int x2, int y2) {
return queryRow( 1 , 0 , n- 1 , x1, x2, y1, y2) ;
}
} ;
// ===================================================================
// 2) STATIC 2D SEGMENT TREE FOR MIN / MAX
// (Point Update, Rectangle Query)
// ===================================================================
// -------------------------------------------------------------------
// CLASS: SegTree2DMinMax
// -------------------------------------------------------------------
// WHAT IT DOES:
// Same structure as the sum version, but instead of summing,
// it combines values using a custom merge function (e.g., min or max).
// It supports point updates (set a cell to a value) and rectangle
// queries (get the min or max over a rectangle).
//
// INPUT:
// - Template parameter T: the data type (e.g., int, long long).
// - Template parameter mergeFunc: a function pointer T (*)(T,T) that
// combines two values (e.g., minFunc or maxFunc).
// - The constructor also takes an 'identity' value – the neutral element
// for the merge operation (e.g., INF for min, -INF for max).
// - The grid is given as a 2D vector of T.
// - Coordinates are 0‑based.
//
// OUTPUT:
// - `query` returns a value of type T – the result of the merge over
// the rectangle (min or max).
// - `updatePoint` sets a cell to a new value (not an addition).
//
// TIME COMPLEXITY:
// - Build: O(N * M).
// - Update: O(log N * log M).
// - Query: O(log N * log M).
//
// MEMORY:
// - O(N * M).
//
// CONSTRAINTS / ASSUMPTIONS:
// - N and M must be known at construction.
// - The grid values and the identity must be of type T.
// - The merge function must be associative (like min, max).
// - Use INT_MAX / INT_MIN for int, or LLONG_MAX / LLONG_MIN for long long.
// - Point update sets the cell to the given value (overwrites).
//
// NOTES:
// - The class is generic, so you need to instantiate it with a merge
// function. Two helper functions (minFunc, maxFunc) are provided below.
// - Example usage: SegTree2DMinMax<int, minFunc> segMin(n, m, INT_MAX);
// - Because it's a static tree, it allocates full memory; use only for
// moderate grid sizes.
// -------------------------------------------------------------------
template < typename T, T ( * mergeFunc) ( T, T) >
class SegTree2DMinMax {
int n, m;
vector< vector< T>> tree;
T identity;
// Build column tree for a single row.
void buildColTree( int rowNode, int colNode, int l, int r, const vector< T> & row) {
if ( l == r) {
tree[ rowNode] [ colNode] = row[ l] ;
return ;
}
int mid = ( l + r) / 2 ;
buildColTree( rowNode, colNode* 2 , l, mid, row) ;
buildColTree( rowNode, colNode* 2 + 1 , mid+ 1 , r, row) ;
tree[ rowNode] [ colNode] = mergeFunc( tree[ rowNode] [ colNode* 2 ] , tree[ rowNode] [ colNode* 2 + 1 ] ) ;
}
// Merge two child row nodes' column trees into the parent.
void mergeColTrees( int rowNode, int colNode, int l, int r) {
if ( l == r) {
tree[ rowNode] [ colNode] = mergeFunc( tree[ rowNode* 2 ] [ colNode] , tree[ rowNode* 2 + 1 ] [ colNode] ) ;
return ;
}
int mid = ( l + r) / 2 ;
mergeColTrees( rowNode, colNode* 2 , l, mid) ;
mergeColTrees( rowNode, colNode* 2 + 1 , mid+ 1 , r) ;
tree[ rowNode] [ colNode] = mergeFunc( tree[ rowNode* 2 ] [ colNode] , tree[ rowNode* 2 + 1 ] [ colNode] ) ;
}
void buildRow( int node, int l, int r, const vector< vector< T>> & grid) {
if ( l == r) {
buildColTree( node, 1 , 0 , m- 1 , grid[ l] ) ;
return ;
}
int mid = ( l + r) / 2 ;
buildRow( node* 2 , l, mid, grid) ;
buildRow( node* 2 + 1 , mid+ 1 , r, grid) ;
mergeColTrees( node, 1 , 0 , m- 1 ) ;
}
void updateCol( int rowNode, int colNode, int l, int r, int y, T val) {
if ( l == r) {
tree[ rowNode] [ colNode] = val;
return ;
}
int mid = ( l + r) / 2 ;
if ( y <= mid) updateCol( rowNode, colNode* 2 , l, mid, y, val) ;
else updateCol( rowNode, colNode* 2 + 1 , mid+ 1 , r, y, val) ;
tree[ rowNode] [ colNode] = mergeFunc( tree[ rowNode] [ colNode* 2 ] , tree[ rowNode] [ colNode* 2 + 1 ] ) ;
}
// Recompute current row node's column tree after a child row update.
void updateColMerge( int rowNode, int colNode, int l, int r, int y, T val) {
if ( l == r) {
tree[ rowNode] [ colNode] = mergeFunc( tree[ rowNode* 2 ] [ colNode] , tree[ rowNode* 2 + 1 ] [ colNode] ) ;
return ;
}
int mid = ( l + r) / 2 ;
if ( y <= mid) updateColMerge( rowNode, colNode* 2 , l, mid, y, val) ;
else updateColMerge( rowNode, colNode* 2 + 1 , mid+ 1 , r, y, val) ;
tree[ rowNode] [ colNode] = mergeFunc( tree[ rowNode* 2 ] [ colNode] , tree[ rowNode* 2 + 1 ] [ colNode] ) ;
}
void updateRow( int node, int l, int r, int x, int y, T val) {
if ( l == r) {
updateCol( node, 1 , 0 , m- 1 , y, val) ;
return ;
}
int mid = ( l + r) / 2 ;
if ( x <= mid) updateRow( node* 2 , l, mid, x, y, val) ;
else updateRow( node* 2 + 1 , mid+ 1 , r, x, y, val) ;
updateColMerge( node, 1 , 0 , m- 1 , y, val) ;
}
T queryCol( int rowNode, int colNode, int l, int r, int y1, int y2) {
if ( y1 <= l && r <= y2) {
return tree[ rowNode] [ colNode] ;
}
int mid = ( l + r) / 2 ;
T res = identity;
if ( y1 <= mid) res = mergeFunc( res, queryCol( rowNode, colNode* 2 , l, mid, y1, y2) ) ;
if ( y2 > mid) res = mergeFunc( res, queryCol( rowNode, colNode* 2 + 1 , mid+ 1 , r, y1, y2) ) ;
return res;
}
T queryRow( int node, int l, int r, int x1, int x2, int y1, int y2) {
if ( x1 <= l && r <= x2) {
return queryCol( node, 1 , 0 , m- 1 , y1, y2) ;
}
int mid = ( l + r) / 2 ;
T res = identity;
if ( x1 <= mid) res = mergeFunc( res, queryRow( node* 2 , l, mid, x1, x2, y1, y2) ) ;
if ( x2 > mid) res = mergeFunc( res, queryRow( node* 2 + 1 , mid+ 1 , r, x1, x2, y1, y2) ) ;
return res;
}
public :
// Constructor: pass grid dimensions and the identity value for the merge.
// Input: n (rows), m (columns), identity (e.g., INF for min, -INF for max).
SegTree2DMinMax( int n, int m, T identity) : n( n) , m( m) , identity( identity) {
tree.assign ( 4 * n, vector< T> ( 4 * m, identity) ) ;
}
// Build the tree from the grid.
// Input: 2D vector grid of size n x m.
// Time: O(n*m).
void build( const vector< vector< T>> & grid) {
buildRow( 1 , 0 , n- 1 , grid) ;
}
// Point update: set cell (x,y) to value 'val' (overwrites previous value).
// Input: x, y, val.
// Time: O(log n * log m).
void updatePoint( int x, int y, T val) {
updateRow( 1 , 0 , n- 1 , x, y, val) ;
}
// Rectangle query: returns the merge result over [x1..x2] × [y1..y2].
// Input: x1, y1, x2, y2 (inclusive, 0‑based).
// Returns: the min or max (depending on mergeFunc) as type T.
// Time: O(log n * log m).
T query( int x1, int y1, int x2, int y2) {
return queryRow( 1 , 0 , n- 1 , x1, x2, y1, y2) ;
}
} ;
// -------------------------------------------------------------------
// Helper merge functions for min and max (to use with SegTree2DMinMax)
// -------------------------------------------------------------------
// minFunc: returns the smaller of two values.
// maxFunc: returns the larger of two values.
// These are simple functions that you can pass as template arguments.
int minFunc( int a, int b) { return min( a, b) ; }
int maxFunc( int a, int b) { return max( a, b) ; }
// ===================================================================
// 3) 2D FENWICK TREE WITH COORDINATE COMPRESSION (SPARSE POINTS)
// (Point Update, Prefix Sum, Rectangle Sum)
// ===================================================================
// -------------------------------------------------------------------
// CLASS: Fenwick2D
// -------------------------------------------------------------------
// WHAT IT DOES:
// This is a 2D Fenwick tree (also called Binary Indexed Tree) that
// works with sparse points. It is useful when the grid is huge
// (coordinates up to 1e9) but the number of points that will ever
// be updated is relatively small (K points).
// It supports:
// - Point update: add a value (delta) to a point (x, y).
// - Prefix sum: sum of all points with X <= x and Y <= y.
// - Rectangle sum: sum over a rectangle using inclusion‑exclusion
// from prefix sums.
//
// INPUT:
// - Constructor: a list of all points (x, y) that will ever be updated.
// This is used to compress the coordinates.
// - Updates and queries use the same coordinate values (they must be
// among those initially provided, otherwise the update will fail
// or produce wrong results).
// - Coordinates can be negative or large; they are stored as ints.
//
// OUTPUT:
// - `add` modifies the internal structure (no return).
// - `prefixSum(x, y)` returns the sum of points with X <= x and Y <= y.
// - `rectangleSum(x1, y1, x2, y2)` returns the sum in that rectangle.
//
// TIME COMPLEXITY:
// - Build (constructor): O(K log K) roughly, where K is the number of
// unique points (or the number of points provided).
// - Update: O(log K) in both dimensions.
// - Prefix sum: O(log K) in both dimensions.
//
// MEMORY:
// - O(K log K) in the worst case, because each point is inserted into
// O(log K) Fenwick nodes. In practice, it is manageable for K up to
// a few hundred thousand.
//
// CONSTRAINTS / ASSUMPTIONS:
// - All points that will be updated must be passed to the constructor
// beforehand. If you try to update a point that was not in the list,
// the internal `ys` vector for that x will not contain that y, and
// the update will access out‑of‑bounds (or silently fail).
// - Coordinates are integer values.
// - The class uses 1‑based indexing internally for the Fenwick tree,
// but the public interface uses the original coordinates (0‑based or
// any integer).
// - Rectangle queries use the standard inclusion‑exclusion formula
// with prefix sums.
//
// NOTES:
// - "Fenwick tree" is a data structure that efficiently supports
// prefix sums and point updates. It is also called a Binary Indexed
// Tree (BIT).
// - "Coordinate compression" means we map large coordinate values to
// small indices (1..K) so that we can store arrays of manageable size.
// - This implementation is offline: it needs all update points in
// advance. If you have dynamic additions of new points, you need a
// different approach (e.g., a dynamic 2D segment tree).
// - The `prefixSum` method returns the sum for all points with X <= x
// and Y <= y. If x or y is smaller than all provided coordinates,
// it returns 0.
// -------------------------------------------------------------------
class Fenwick2D {
int n; // number of compressed x coordinates
vector< vector< int >> ys; // compressed y coordinates per x node
vector< vector< int >> bit; // BIT values (2D)
vector< int > xs; // all unique x coordinates
public :
// Constructor: takes a list of all points that will ever be updated.
// Input: vector of pairs (x, y). Duplicates are allowed (they are handled).
// Time: O(K log K) where K is the number of points.
Fenwick2D( const vector< pair< int ,int >> & points) {
// Collect all unique x coordinates.
vector< int > allX;
for ( auto & p : points) allX.push_back ( p.first ) ;
sort( allX.begin ( ) , allX.end ( ) ) ;
allX.erase ( unique( allX.begin ( ) , allX.end ( ) ) , allX.end ( ) ) ;
xs = allX;
n = xs.size ( ) ;
ys.resize ( n+ 1 ) ;
// For each point, add its y to all Fenwick nodes that cover its x.
for ( auto & p : points) {
int x = p.first ;
int idx = lower_bound( xs.begin ( ) , xs.end ( ) , x) - xs.begin ( ) + 1 ; // 1-indexed
for ( int i = idx; i <= n; i + = i & - i) {
ys[ i] .push_back ( p.second ) ;
}
}
// Compress each y list and allocate the BIT array.
bit.resize ( n+ 1 ) ;
for ( int i = 1 ; i <= n; i++ ) {
sort( ys[ i] .begin ( ) , ys[ i] .end ( ) ) ;
ys[ i] .erase ( unique( ys[ i] .begin ( ) , ys[ i] .end ( ) ) , ys[ i] .end ( ) ) ;
bit[ i] .assign ( ys[ i] .size ( ) + 1 , 0 ) ;
}
}
// Point update: add 'delta' to point (x, y).
// Input: x, y (coordinates), delta (value to add).
// Time: O(log K) where K is the number of points.
// IMPORTANT: (x,y) must have been included in the constructor's point list.
void add( int x, int y, int delta) {
int xi = lower_bound( xs.begin ( ) , xs.end ( ) , x) - xs.begin ( ) + 1 ;
for ( int i = xi; i <= n; i + = i & - i) {
int yi = lower_bound( ys[ i] .begin ( ) , ys[ i] .end ( ) , y) - ys[ i] .begin ( ) + 1 ;
for ( int j = yi; j < ( int ) bit[ i] .size ( ) ; j + = j & - j) {
bit[ i] [ j] + = delta;
}
}
}
// Prefix sum: sum of all points with X <= x and Y <= y.
// Input: x, y (coordinates).
// Returns: integer sum.
// Time: O(log K).
int prefixSum( int x, int y) {
int xi = upper_bound( xs.begin ( ) , xs.end ( ) , x) - xs.begin ( ) ; // number of xs <= x
int res = 0 ;
for ( int i = xi; i > 0 ; i - = i & - i) {
int yi = upper_bound( ys[ i] .begin ( ) , ys[ i] .end ( ) , y) - ys[ i] .begin ( ) ;
for ( int j = yi; j > 0 ; j - = j & - j) {
res + = bit[ i] [ j] ;
}
}
return res;
}
// Rectangle sum: sum of points inside [x1..x2] × [y1..y2].
// Input: x1, y1, x2, y2 (inclusive, any order).
// Returns: integer sum.
// Time: O(log K) (four prefixSum calls).
int rectangleSum( int x1, int y1, int x2, int y2) {
return prefixSum( x2, y2) - prefixSum( x1- 1 , y2) - prefixSum( x2, y1- 1 ) + prefixSum( x1- 1 , y1- 1 ) ;
}
} ;
// ===================================================================
// 4) 2D SEGMENT TREE WITH LAZY PROPAGATION (RANGE UPDATES)
// (Concept only – not implemented)
// ===================================================================
// This section is kept as a placeholder. Lazy propagation in 2D is
// advanced and rarely needed. For most problems, a 2D BIT or offline
// sweepline is sufficient. No implementation is provided here.
// ===================================================================
// ===================================================================
// 5) COMMON TRICKS & PATTERNS FOR ECPC/ACPC
// ===================================================================
// The following notes are for your reference:
//
// 5.1) Offline queries with sweepline:
// For static 2D points, you can answer rectangle sum queries by
// sorting points by x, queries by x2, and using a 1D BIT on y.
// This avoids 2D segment trees entirely.
//
// 5.2) Dynamic 2D Segment Tree using pointers:
// When the grid is huge and updates/queries are few, you can
// create nodes on demand. This is not implemented here because
// it is complex; the Fenwick2D class is usually enough for sparse data.
//
// 5.3) Using 2D Segment Tree for range maximum with point updates:
// The SegTree2DMinMax class above does exactly that.
//
// 5.4) Combining with Binary Search on answer:
// If you need to find the smallest rectangle containing a certain
// number of points, you can binary search the size and use a
// 2D segment tree to count points in a rectangle.
//
// 5.5) Negative coordinates or large ranges:
// Always use coordinate compression (Fenwick2D) for such cases.
// ===================================================================
// ===================================================================
// 6) SPARSE 2D SEGMENT TREE (DYNAMIC ALLOCATION) – NOT IMPLEMENTED
// ===================================================================
// A fully dynamic 2D segment tree would allocate nodes only when
// needed. Because of its complexity, we recommend using Fenwick2D
// with coordinate compression instead.
// ===================================================================
// ===================================================================
// 7) EXAMPLE USAGE
// ===================================================================
// The main() function below demonstrates how to use the three main
// classes. Read the comments inside to see each step.
// ===================================================================
int main( ) {
ios:: sync_with_stdio ( false ) ;
cin .tie ( nullptr) ;
// ---------- Example 1: Sum 2D Segment Tree ----------
vector< vector< int >> grid = {
{ 1 , 2 , 3 } ,
{ 4 , 5 , 6 } ,
{ 7 , 8 , 9 }
} ;
int n = 3 , m = 3 ;
SegTree2DSum seg( n, m) ;
seg.build ( grid) ;
cout << "Sum of entire grid: " << seg.querySum ( 0 ,0 ,2 ,2 ) << '\n ' ; // 45
cout << "Sum of subrectangle (1,1)-(2,2): " << seg.querySum ( 1 ,1 ,2 ,2 ) << '\n ' ; // 5+6+8+9=28
seg.updatePoint ( 1 ,1 , 10 ) ; // add 10 to cell (1,1) which was 5 -> now 15
cout << "After update, sum of subrectangle (1,1)-(2,2): " << seg.querySum ( 1 ,1 ,2 ,2 ) << '\n ' ; // 15+6+8+9=38
// ---------- Example 2: Min 2D Segment Tree ----------
SegTree2DMinMax< int , minFunc> segMin( n, m, INT_MAX ) ;
segMin.build ( grid) ;
cout << "Min in entire grid: " << segMin.query ( 0 ,0 ,2 ,2 ) << '\n ' ; // 1
segMin.updatePoint ( 0 ,0 , 0 ) ; // set (0,0) to 0
cout << "Min after update: " << segMin.query ( 0 ,0 ,2 ,2 ) << '\n ' ; // 0
// ---------- Example 3: 2D Fenwick with coordinate compression ----------
vector< pair< int ,int >> points = { { 1 ,1 } , { 2 ,3 } , { 5 ,7 } } ;
Fenwick2D fw( points) ;
fw.add ( 1 ,1 , 5 ) ;
fw.add ( 2 ,3 , 10 ) ;
cout << "Prefix sum up to (2,3): " << fw.prefixSum ( 2 ,3 ) << '\n ' ; // 15
cout << "Prefix sum up to (5,7): " << fw.prefixSum ( 5 ,7 ) << '\n ' ; // 15
fw.add ( 5 ,7 , 3 ) ;
cout << "After add: " << fw.prefixSum ( 5 ,7 ) << '\n ' ; // 18
return 0 ;
}
// ===================================================================
// ADDITIONAL NOTES FOR ECPC/ACPC COMPETITORS:
// - 2D Segment Trees are memory heavy; use them only when N and M are
// small (<= 1000) or when coordinates are compressed.
// - For dynamic updates and large coordinates, prefer Fenwick2D with
// compression (offline).
// - For offline static queries, a sweepline + 1D BIT is often simpler
// and faster.
// - When implementing your own 2D segment tree, watch out for recursion
// depth and memory consumption.
// - Always test edge cases: N=1, M=1, empty rectangles, negative
// coordinates (Fenwick2D handles them if you provide them).
// ===================================================================
I2luY2x1ZGUgPGJpdHMvc3RkYysrLmg+CnVzaW5nIG5hbWVzcGFjZSBzdGQ7CgovLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09Ci8vIFRoaXMgZmlsZSBjb250YWlucyBhIGNvbGxlY3Rpb24gb2YgMkQgU2VnbWVudCBUcmVlIGFsZ29yaXRobXMuCi8vIEVhY2ggZnVuY3Rpb24vY2xhc3MgaXMgcmVhZHkgdG8gYmUgdXNlZCBhcyBhICJibGFjayBib3giLgovLyBSZWFkIHRoZSBjb21tZW50cyBhYm92ZSBlYWNoIG9uZSB0byB1bmRlcnN0YW5kOgovLyAgIC0gV2hhdCBpdCBzb2x2ZXMKLy8gICAtIFdoYXQgaW5wdXQgaXQgZXhwZWN0cwovLyAgIC0gV2hhdCBpdCByZXR1cm5zCi8vICAgLSBUaW1lIGNvbXBsZXhpdHkKLy8gICAtIEltcG9ydGFudCBjb25zdHJhaW50cyAvIGFzc3VtcHRpb25zCi8vICAgLSBBbnkgZXh0cmEgbm90ZXMKLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQoKLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQovLyAxKSBTVEFUSUMgMkQgU0VHTUVOVCBUUkVFIEZPUiBTVU0KLy8gICAgKFBvaW50IFVwZGF0ZSwgUmVjdGFuZ2xlIFN1bSBRdWVyeSkKLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQoKLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQovLyBDTEFTUzogU2VnVHJlZTJEU3VtCi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KLy8gV0hBVCBJVCBET0VTOgovLyAgIEJ1aWxkcyBhIDJEIHNlZ21lbnQgdHJlZSBvdmVyIGEgZ3JpZCBvZiBpbnRlZ2VycyAoTiByb3dzIHggTSBjb2x1bW5zKS4KLy8gICBJdCBzdXBwb3J0czoKLy8gICAgIC0gUG9pbnQgdXBkYXRlOiBhZGQgYSB2YWx1ZSAoZGVsdGEpIHRvIGEgc2luZ2xlIGNlbGwuCi8vICAgICAtIFJlY3RhbmdsZSBzdW06IGNvbXB1dGUgdGhlIHN1bSBvZiBhbGwgY2VsbHMgaW5zaWRlIGEgZ2l2ZW4KLy8gICAgICAgcmVjdGFuZ2xlIFt4MS4ueDJdIMOXIFt5MS4ueTJdLgovLwovLyBJTlBVVDoKLy8gICAtIFRoZSBncmlkIGlzIGdpdmVuIGFzIGEgMkQgdmVjdG9yIChOIHggTSkgaW4gdGhlIGBidWlsZGAgZnVuY3Rpb24uCi8vICAgLSBDb29yZGluYXRlcyBhcmUgMOKAkWJhc2VkIChyb3cgYW5kIGNvbHVtbiBpbmRpY2VzIHN0YXJ0IGZyb20gMCkuCi8vCi8vIE9VVFBVVDoKLy8gICAtIGBxdWVyeVN1bWAgcmV0dXJucyBhbiBpbnRlZ2VyIOKAkyB0aGUgc3VtIG9mIHRoZSByZWN0YW5nbGUuCi8vICAgLSBgdXBkYXRlUG9pbnRgIGRvZXMgbm90IHJldHVybiBhbnl0aGluZzsgaXQgbW9kaWZpZXMgdGhlIHRyZWUuCi8vCi8vIFRJTUUgQ09NUExFWElUWToKLy8gICAtIEJ1aWxkOiBPKE4gKiBNKSAgKGFjdHVhbGx5IE8oNCpOICogNCpNKSBidXQgcHJhY3RpY2FsbHkgTyhOKk0pKS4KLy8gICAtIFVwZGF0ZTogTyhsb2cgTiAqIGxvZyBNKS4KLy8gICAtIFF1ZXJ5OiAgTyhsb2cgTiAqIGxvZyBNKS4KLy8KLy8gTUVNT1JZOgovLyAgIC0gTyhOICogTSkgIChzdG9yZWQgYXMgYSAyRCBhcnJheSBvZiBzaXplIDQqTiDDlyA0Kk0pLgovLwovLyBDT05TVFJBSU5UUyAvIEFTU1VNUFRJT05TOgovLyAgIC0gTiBhbmQgTSBtdXN0IGJlIGtub3duIGF0IGNvbnN0cnVjdGlvbiB0aW1lLgovLyAgIC0gVGhlIGdyaWQgdmFsdWVzIGFyZSBpbnRlZ2VycyAoaW50KS4KLy8gICAtIFRoZSBncmlkIHNpemUgKE4gw5cgTSkgc2hvdWxkIGJlIHJlYXNvbmFibGUgKGUuZy4sIE4sIE0gPD0gMTAwMCkKLy8gICAgIGJlY2F1c2UgbWVtb3J5IGdyb3dzIHF1YWRyYXRpY2FsbHkuCi8vICAgLSBVcGRhdGVzIGFkZCBhIGRlbHRhOyB0aGV5IGRvIG5vdCBzZXQgYSB2YWx1ZSAodXNlIG5lZ2F0aXZlIGRlbHRhCi8vICAgICB0byBzdWJ0cmFjdCkuCi8vCi8vIE5PVEVTOgovLyAgIC0gVGhpcyBpbXBsZW1lbnRhdGlvbiB1c2VzIDDigJFiYXNlZCBpbmRpY2VzIGV2ZXJ5d2hlcmUuCi8vICAgLSBJdCBpcyBhICJzdGF0aWMiIHRyZWUgYmVjYXVzZSB0aGUgZ3JpZCBzaXplIGlzIGZpeGVkIGFmdGVyIGJ1aWxkLgovLyAgIC0gVGhlIGNsYXNzIGFsbG9jYXRlcyBhIGZ1bGwgNCpOIMOXIDQqTSBhcnJheSwgc28gaXQgbWF5IGJlIGhlYXZ5Ci8vICAgICBmb3IgbGFyZ2UgZ3JpZHMuCi8vICAgLSBJZiB5b3UgbmVlZCB0byBoYW5kbGUgc3BhcnNlIGRhdGEgb3IgdmVyeSBsYXJnZSBjb29yZGluYXRlcywKLy8gICAgIHNlZSB0aGUgRmVud2ljazJEIGNsYXNzIGJlbG93IChjb29yZGluYXRlIGNvbXByZXNzaW9uKS4KLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKY2xhc3MgU2VnVHJlZTJEU3VtIHsKICAgIGludCBuLCBtOwogICAgdmVjdG9yPHZlY3RvcjxpbnQ+PiB0cmVlOyAgLy8gdHJlZVs0Km5dWzQqbV0KCiAgICAvLyBCdWlsZCB0aGUgY29sdW1uIHNlZ21lbnQgdHJlZSBmb3IgYSBzaW5nbGUgcm93IChsZWFmIHJvdyBub2RlKS4KICAgIHZvaWQgYnVpbGRDb2xUcmVlKGludCByb3dOb2RlLCBpbnQgY29sTm9kZSwgaW50IGwsIGludCByLCBjb25zdCB2ZWN0b3I8aW50PiYgcm93KSB7CiAgICAgICAgaWYgKGwgPT0gcikgewogICAgICAgICAgICB0cmVlW3Jvd05vZGVdW2NvbE5vZGVdID0gcm93W2xdOwogICAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICAgIGludCBtaWQgPSAobCArIHIpIC8gMjsKICAgICAgICBidWlsZENvbFRyZWUocm93Tm9kZSwgY29sTm9kZSoyLCBsLCBtaWQsIHJvdyk7CiAgICAgICAgYnVpbGRDb2xUcmVlKHJvd05vZGUsIGNvbE5vZGUqMisxLCBtaWQrMSwgciwgcm93KTsKICAgICAgICB0cmVlW3Jvd05vZGVdW2NvbE5vZGVdID0gdHJlZVtyb3dOb2RlXVtjb2xOb2RlKjJdICsgdHJlZVtyb3dOb2RlXVtjb2xOb2RlKjIrMV07CiAgICB9CgogICAgLy8gTWVyZ2UgdGhlIGNvbHVtbiB0cmVlcyBvZiB0d28gY2hpbGQgcm93IG5vZGVzIGludG8gdGhlIHBhcmVudCByb3cgbm9kZS4KICAgIHZvaWQgbWVyZ2VDb2xUcmVlcyhpbnQgcm93Tm9kZSwgaW50IGNvbE5vZGUsIGludCBsLCBpbnQgcikgewogICAgICAgIGlmIChsID09IHIpIHsKICAgICAgICAgICAgdHJlZVtyb3dOb2RlXVtjb2xOb2RlXSA9IHRyZWVbcm93Tm9kZSoyXVtjb2xOb2RlXSArIHRyZWVbcm93Tm9kZSoyKzFdW2NvbE5vZGVdOwogICAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICAgIGludCBtaWQgPSAobCArIHIpIC8gMjsKICAgICAgICBtZXJnZUNvbFRyZWVzKHJvd05vZGUsIGNvbE5vZGUqMiwgbCwgbWlkKTsKICAgICAgICBtZXJnZUNvbFRyZWVzKHJvd05vZGUsIGNvbE5vZGUqMisxLCBtaWQrMSwgcik7CiAgICAgICAgdHJlZVtyb3dOb2RlXVtjb2xOb2RlXSA9IHRyZWVbcm93Tm9kZSoyXVtjb2xOb2RlXSArIHRyZWVbcm93Tm9kZSoyKzFdW2NvbE5vZGVdOwogICAgfQoKICAgIC8vIEJ1aWxkIHRoZSByb3cgc2VnbWVudCB0cmVlIHJlY3Vyc2l2ZWx5LgogICAgdm9pZCBidWlsZFJvdyhpbnQgbm9kZSwgaW50IGwsIGludCByLCBjb25zdCB2ZWN0b3I8dmVjdG9yPGludD4+JiBncmlkKSB7CiAgICAgICAgaWYgKGwgPT0gcikgewogICAgICAgICAgICAvLyBMZWFmIHJvdzogYnVpbGQgaXRzIGNvbHVtbiB0cmVlIGZyb20gdGhlIGdyaWQgcm93LgogICAgICAgICAgICBidWlsZENvbFRyZWUobm9kZSwgMSwgMCwgbS0xLCBncmlkW2xdKTsKICAgICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KICAgICAgICBpbnQgbWlkID0gKGwgKyByKSAvIDI7CiAgICAgICAgYnVpbGRSb3cobm9kZSoyLCBsLCBtaWQsIGdyaWQpOwogICAgICAgIGJ1aWxkUm93KG5vZGUqMisxLCBtaWQrMSwgciwgZ3JpZCk7CiAgICAgICAgLy8gTWVyZ2UgdGhlIGNvbHVtbiB0cmVlcyBvZiB0aGUgdHdvIGNoaWxkcmVuLgogICAgICAgIG1lcmdlQ29sVHJlZXMobm9kZSwgMSwgMCwgbS0xKTsKICAgIH0KCiAgICAvLyBVcGRhdGUgYSBzaW5nbGUgY29sdW1uIGluIGEgbGVhZiByb3cgbm9kZS4KICAgIHZvaWQgdXBkYXRlQ29sKGludCByb3dOb2RlLCBpbnQgY29sTm9kZSwgaW50IGwsIGludCByLCBpbnQgeSwgaW50IGRlbHRhKSB7CiAgICAgICAgaWYgKGwgPT0gcikgewogICAgICAgICAgICB0cmVlW3Jvd05vZGVdW2NvbE5vZGVdICs9IGRlbHRhOwogICAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICAgIGludCBtaWQgPSAobCArIHIpIC8gMjsKICAgICAgICBpZiAoeSA8PSBtaWQpIHVwZGF0ZUNvbChyb3dOb2RlLCBjb2xOb2RlKjIsIGwsIG1pZCwgeSwgZGVsdGEpOwogICAgICAgIGVsc2UgdXBkYXRlQ29sKHJvd05vZGUsIGNvbE5vZGUqMisxLCBtaWQrMSwgciwgeSwgZGVsdGEpOwogICAgICAgIHRyZWVbcm93Tm9kZV1bY29sTm9kZV0gPSB0cmVlW3Jvd05vZGVdW2NvbE5vZGUqMl0gKyB0cmVlW3Jvd05vZGVdW2NvbE5vZGUqMisxXTsKICAgIH0KCiAgICAvLyBBZnRlciB1cGRhdGluZyBvbmUgY2hpbGQgcm93LCByZWNvbXB1dGUgdGhlIGN1cnJlbnQgcm93IG5vZGUncwogICAgLy8gY29sdW1uIHRyZWUgZm9yIHRoZSBhZmZlY3RlZCBjb2x1bW4uCiAgICB2b2lkIHVwZGF0ZUNvbE1lcmdlKGludCByb3dOb2RlLCBpbnQgY29sTm9kZSwgaW50IGwsIGludCByLCBpbnQgeSwgaW50IGRlbHRhKSB7CiAgICAgICAgaWYgKGwgPT0gcikgewogICAgICAgICAgICB0cmVlW3Jvd05vZGVdW2NvbE5vZGVdID0gdHJlZVtyb3dOb2RlKjJdW2NvbE5vZGVdICsgdHJlZVtyb3dOb2RlKjIrMV1bY29sTm9kZV07CiAgICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgaW50IG1pZCA9IChsICsgcikgLyAyOwogICAgICAgIGlmICh5IDw9IG1pZCkgdXBkYXRlQ29sTWVyZ2Uocm93Tm9kZSwgY29sTm9kZSoyLCBsLCBtaWQsIHksIGRlbHRhKTsKICAgICAgICBlbHNlIHVwZGF0ZUNvbE1lcmdlKHJvd05vZGUsIGNvbE5vZGUqMisxLCBtaWQrMSwgciwgeSwgZGVsdGEpOwogICAgICAgIHRyZWVbcm93Tm9kZV1bY29sTm9kZV0gPSB0cmVlW3Jvd05vZGUqMl1bY29sTm9kZV0gKyB0cmVlW3Jvd05vZGUqMisxXVtjb2xOb2RlXTsKICAgIH0KCiAgICAvLyBVcGRhdGUgYSBjZWxsICh4LHkpIGJ5IGFkZGluZyBkZWx0YSwgdHJhdmVyc2luZyB0aGUgcm93IHRyZWUuCiAgICB2b2lkIHVwZGF0ZVJvdyhpbnQgbm9kZSwgaW50IGwsIGludCByLCBpbnQgeCwgaW50IHksIGludCBkZWx0YSkgewogICAgICAgIGlmIChsID09IHIpIHsKICAgICAgICAgICAgdXBkYXRlQ29sKG5vZGUsIDEsIDAsIG0tMSwgeSwgZGVsdGEpOwogICAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICAgIGludCBtaWQgPSAobCArIHIpIC8gMjsKICAgICAgICBpZiAoeCA8PSBtaWQpIHVwZGF0ZVJvdyhub2RlKjIsIGwsIG1pZCwgeCwgeSwgZGVsdGEpOwogICAgICAgIGVsc2UgdXBkYXRlUm93KG5vZGUqMisxLCBtaWQrMSwgciwgeCwgeSwgZGVsdGEpOwogICAgICAgIC8vIEFmdGVyIGNoaWxkIGlzIHVwZGF0ZWQsIHVwZGF0ZSB0aGUgY3VycmVudCBub2RlJ3MgY29sdW1uIHRyZWUuCiAgICAgICAgdXBkYXRlQ29sTWVyZ2Uobm9kZSwgMSwgMCwgbS0xLCB5LCBkZWx0YSk7CiAgICB9CgogICAgLy8gUXVlcnkgdGhlIGNvbHVtbiB0cmVlIG9mIGEgZ2l2ZW4gcm93IG5vZGUgZm9yIGEgcmFuZ2Ugb2YgY29sdW1ucy4KICAgIGludCBxdWVyeUNvbChpbnQgcm93Tm9kZSwgaW50IGNvbE5vZGUsIGludCBsLCBpbnQgciwgaW50IHkxLCBpbnQgeTIpIHsKICAgICAgICBpZiAoeTEgPD0gbCAmJiByIDw9IHkyKSB7CiAgICAgICAgICAgIHJldHVybiB0cmVlW3Jvd05vZGVdW2NvbE5vZGVdOwogICAgICAgIH0KICAgICAgICBpbnQgbWlkID0gKGwgKyByKSAvIDI7CiAgICAgICAgaW50IHJlcyA9IDA7CiAgICAgICAgaWYgKHkxIDw9IG1pZCkgcmVzICs9IHF1ZXJ5Q29sKHJvd05vZGUsIGNvbE5vZGUqMiwgbCwgbWlkLCB5MSwgeTIpOwogICAgICAgIGlmICh5MiA+IG1pZCkgcmVzICs9IHF1ZXJ5Q29sKHJvd05vZGUsIGNvbE5vZGUqMisxLCBtaWQrMSwgciwgeTEsIHkyKTsKICAgICAgICByZXR1cm4gcmVzOwogICAgfQoKICAgIC8vIFF1ZXJ5IHRoZSByb3cgdHJlZSBmb3IgYSByZWN0YW5nbGUgW3gxLi54Ml0gw5cgW3kxLi55Ml0uCiAgICBpbnQgcXVlcnlSb3coaW50IG5vZGUsIGludCBsLCBpbnQgciwgaW50IHgxLCBpbnQgeDIsIGludCB5MSwgaW50IHkyKSB7CiAgICAgICAgaWYgKHgxIDw9IGwgJiYgciA8PSB4MikgewogICAgICAgICAgICByZXR1cm4gcXVlcnlDb2wobm9kZSwgMSwgMCwgbS0xLCB5MSwgeTIpOwogICAgICAgIH0KICAgICAgICBpbnQgbWlkID0gKGwgKyByKSAvIDI7CiAgICAgICAgaW50IHJlcyA9IDA7CiAgICAgICAgaWYgKHgxIDw9IG1pZCkgcmVzICs9IHF1ZXJ5Um93KG5vZGUqMiwgbCwgbWlkLCB4MSwgeDIsIHkxLCB5Mik7CiAgICAgICAgaWYgKHgyID4gbWlkKSByZXMgKz0gcXVlcnlSb3cobm9kZSoyKzEsIG1pZCsxLCByLCB4MSwgeDIsIHkxLCB5Mik7CiAgICAgICAgcmV0dXJuIHJlczsKICAgIH0KCnB1YmxpYzoKICAgIC8vIENvbnN0cnVjdG9yOiBwcmVwYXJlcyB0aGUgdHJlZSB3aXRoIGdpdmVuIGRpbWVuc2lvbnMuCiAgICAvLyBJbnB1dDogbnVtYmVyIG9mIHJvd3MgKG4pIGFuZCBjb2x1bW5zIChtKS4KICAgIFNlZ1RyZWUyRFN1bShpbnQgbiwgaW50IG0pIDogbihuKSwgbShtKSB7CiAgICAgICAgdHJlZS5hc3NpZ24oNCpuLCB2ZWN0b3I8aW50Pig0Km0sIDApKTsKICAgIH0KCiAgICAvLyBCdWlsZCB0aGUgMkQgc2VnbWVudCB0cmVlIGZyb20gdGhlIGdyaWQuCiAgICAvLyBJbnB1dDogYSAyRCB2ZWN0b3IgZ3JpZCBvZiBzaXplIG4geCBtIChtdXN0IG1hdGNoIHRoZSBjb25zdHJ1Y3RvciBkaW1lbnNpb25zKS4KICAgIC8vIFRpbWU6IE8obiptKS4KICAgIHZvaWQgYnVpbGQoY29uc3QgdmVjdG9yPHZlY3RvcjxpbnQ+PiYgZ3JpZCkgewogICAgICAgIGJ1aWxkUm93KDEsIDAsIG4tMSwgZ3JpZCk7CiAgICB9CgogICAgLy8gUG9pbnQgdXBkYXRlOiBhZGQgJ2RlbHRhJyB0byBjZWxsICh4LHkpLgogICAgLy8gSW5wdXQ6IHggKHJvdyksIHkgKGNvbHVtbiksIGRlbHRhICh2YWx1ZSB0byBhZGQsIGNhbiBiZSBuZWdhdGl2ZSkuCiAgICAvLyBUaW1lOiBPKGxvZyBuICogbG9nIG0pLgogICAgdm9pZCB1cGRhdGVQb2ludChpbnQgeCwgaW50IHksIGludCBkZWx0YSkgewogICAgICAgIHVwZGF0ZVJvdygxLCAwLCBuLTEsIHgsIHksIGRlbHRhKTsKICAgIH0KCiAgICAvLyBSZWN0YW5nbGUgc3VtIHF1ZXJ5OiBzdW0gb2YgY2VsbHMgaW4gW3gxLi54Ml0gw5cgW3kxLi55Ml0uCiAgICAvLyBJbnB1dDogeDEsIHkxLCB4MiwgeTIgKGFsbCAw4oCRYmFzZWQgaW5kaWNlcywgaW5jbHVzaXZlKS4KICAgIC8vIFJldHVybnM6IHRoZSBzdW0gYXMgYW4gaW50ZWdlci4KICAgIC8vIFRpbWU6IE8obG9nIG4gKiBsb2cgbSkuCiAgICBpbnQgcXVlcnlTdW0oaW50IHgxLCBpbnQgeTEsIGludCB4MiwgaW50IHkyKSB7CiAgICAgICAgcmV0dXJuIHF1ZXJ5Um93KDEsIDAsIG4tMSwgeDEsIHgyLCB5MSwgeTIpOwogICAgfQp9OwoKLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQovLyAyKSBTVEFUSUMgMkQgU0VHTUVOVCBUUkVFIEZPUiBNSU4gLyBNQVgKLy8gICAgKFBvaW50IFVwZGF0ZSwgUmVjdGFuZ2xlIFF1ZXJ5KQovLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09CgovLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCi8vIENMQVNTOiBTZWdUcmVlMkRNaW5NYXgKLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQovLyBXSEFUIElUIERPRVM6Ci8vICAgU2FtZSBzdHJ1Y3R1cmUgYXMgdGhlIHN1bSB2ZXJzaW9uLCBidXQgaW5zdGVhZCBvZiBzdW1taW5nLAovLyAgIGl0IGNvbWJpbmVzIHZhbHVlcyB1c2luZyBhIGN1c3RvbSBtZXJnZSBmdW5jdGlvbiAoZS5nLiwgbWluIG9yIG1heCkuCi8vICAgSXQgc3VwcG9ydHMgcG9pbnQgdXBkYXRlcyAoc2V0IGEgY2VsbCB0byBhIHZhbHVlKSBhbmQgcmVjdGFuZ2xlCi8vICAgcXVlcmllcyAoZ2V0IHRoZSBtaW4gb3IgbWF4IG92ZXIgYSByZWN0YW5nbGUpLgovLwovLyBJTlBVVDoKLy8gICAtIFRlbXBsYXRlIHBhcmFtZXRlciBUOiB0aGUgZGF0YSB0eXBlIChlLmcuLCBpbnQsIGxvbmcgbG9uZykuCi8vICAgLSBUZW1wbGF0ZSBwYXJhbWV0ZXIgbWVyZ2VGdW5jOiBhIGZ1bmN0aW9uIHBvaW50ZXIgVCAoKikoVCxUKSB0aGF0Ci8vICAgICBjb21iaW5lcyB0d28gdmFsdWVzIChlLmcuLCBtaW5GdW5jIG9yIG1heEZ1bmMpLgovLyAgIC0gVGhlIGNvbnN0cnVjdG9yIGFsc28gdGFrZXMgYW4gJ2lkZW50aXR5JyB2YWx1ZSDigJMgdGhlIG5ldXRyYWwgZWxlbWVudAovLyAgICAgZm9yIHRoZSBtZXJnZSBvcGVyYXRpb24gKGUuZy4sIElORiBmb3IgbWluLCAtSU5GIGZvciBtYXgpLgovLyAgIC0gVGhlIGdyaWQgaXMgZ2l2ZW4gYXMgYSAyRCB2ZWN0b3Igb2YgVC4KLy8gICAtIENvb3JkaW5hdGVzIGFyZSAw4oCRYmFzZWQuCi8vCi8vIE9VVFBVVDoKLy8gICAtIGBxdWVyeWAgcmV0dXJucyBhIHZhbHVlIG9mIHR5cGUgVCDigJMgdGhlIHJlc3VsdCBvZiB0aGUgbWVyZ2Ugb3ZlcgovLyAgICAgdGhlIHJlY3RhbmdsZSAobWluIG9yIG1heCkuCi8vICAgLSBgdXBkYXRlUG9pbnRgIHNldHMgYSBjZWxsIHRvIGEgbmV3IHZhbHVlIChub3QgYW4gYWRkaXRpb24pLgovLwovLyBUSU1FIENPTVBMRVhJVFk6Ci8vICAgLSBCdWlsZDogTyhOICogTSkuCi8vICAgLSBVcGRhdGU6IE8obG9nIE4gKiBsb2cgTSkuCi8vICAgLSBRdWVyeTogIE8obG9nIE4gKiBsb2cgTSkuCi8vCi8vIE1FTU9SWToKLy8gICAtIE8oTiAqIE0pLgovLwovLyBDT05TVFJBSU5UUyAvIEFTU1VNUFRJT05TOgovLyAgIC0gTiBhbmQgTSBtdXN0IGJlIGtub3duIGF0IGNvbnN0cnVjdGlvbi4KLy8gICAtIFRoZSBncmlkIHZhbHVlcyBhbmQgdGhlIGlkZW50aXR5IG11c3QgYmUgb2YgdHlwZSBULgovLyAgIC0gVGhlIG1lcmdlIGZ1bmN0aW9uIG11c3QgYmUgYXNzb2NpYXRpdmUgKGxpa2UgbWluLCBtYXgpLgovLyAgIC0gVXNlIElOVF9NQVggLyBJTlRfTUlOIGZvciBpbnQsIG9yIExMT05HX01BWCAvIExMT05HX01JTiBmb3IgbG9uZyBsb25nLgovLyAgIC0gUG9pbnQgdXBkYXRlIHNldHMgdGhlIGNlbGwgdG8gdGhlIGdpdmVuIHZhbHVlIChvdmVyd3JpdGVzKS4KLy8KLy8gTk9URVM6Ci8vICAgLSBUaGUgY2xhc3MgaXMgZ2VuZXJpYywgc28geW91IG5lZWQgdG8gaW5zdGFudGlhdGUgaXQgd2l0aCBhIG1lcmdlCi8vICAgICBmdW5jdGlvbi4gVHdvIGhlbHBlciBmdW5jdGlvbnMgKG1pbkZ1bmMsIG1heEZ1bmMpIGFyZSBwcm92aWRlZCBiZWxvdy4KLy8gICAtIEV4YW1wbGUgdXNhZ2U6IFNlZ1RyZWUyRE1pbk1heDxpbnQsIG1pbkZ1bmM+IHNlZ01pbihuLCBtLCBJTlRfTUFYKTsKLy8gICAtIEJlY2F1c2UgaXQncyBhIHN0YXRpYyB0cmVlLCBpdCBhbGxvY2F0ZXMgZnVsbCBtZW1vcnk7IHVzZSBvbmx5IGZvcgovLyAgICAgbW9kZXJhdGUgZ3JpZCBzaXplcy4KLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQoKdGVtcGxhdGU8dHlwZW5hbWUgVCwgVCAoKm1lcmdlRnVuYykoVCwgVCk+CmNsYXNzIFNlZ1RyZWUyRE1pbk1heCB7CiAgICBpbnQgbiwgbTsKICAgIHZlY3Rvcjx2ZWN0b3I8VD4+IHRyZWU7CiAgICBUIGlkZW50aXR5OwoKICAgIC8vIEJ1aWxkIGNvbHVtbiB0cmVlIGZvciBhIHNpbmdsZSByb3cuCiAgICB2b2lkIGJ1aWxkQ29sVHJlZShpbnQgcm93Tm9kZSwgaW50IGNvbE5vZGUsIGludCBsLCBpbnQgciwgY29uc3QgdmVjdG9yPFQ+JiByb3cpIHsKICAgICAgICBpZiAobCA9PSByKSB7CiAgICAgICAgICAgIHRyZWVbcm93Tm9kZV1bY29sTm9kZV0gPSByb3dbbF07CiAgICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgaW50IG1pZCA9IChsICsgcikgLyAyOwogICAgICAgIGJ1aWxkQ29sVHJlZShyb3dOb2RlLCBjb2xOb2RlKjIsIGwsIG1pZCwgcm93KTsKICAgICAgICBidWlsZENvbFRyZWUocm93Tm9kZSwgY29sTm9kZSoyKzEsIG1pZCsxLCByLCByb3cpOwogICAgICAgIHRyZWVbcm93Tm9kZV1bY29sTm9kZV0gPSBtZXJnZUZ1bmModHJlZVtyb3dOb2RlXVtjb2xOb2RlKjJdLCB0cmVlW3Jvd05vZGVdW2NvbE5vZGUqMisxXSk7CiAgICB9CgogICAgLy8gTWVyZ2UgdHdvIGNoaWxkIHJvdyBub2RlcycgY29sdW1uIHRyZWVzIGludG8gdGhlIHBhcmVudC4KICAgIHZvaWQgbWVyZ2VDb2xUcmVlcyhpbnQgcm93Tm9kZSwgaW50IGNvbE5vZGUsIGludCBsLCBpbnQgcikgewogICAgICAgIGlmIChsID09IHIpIHsKICAgICAgICAgICAgdHJlZVtyb3dOb2RlXVtjb2xOb2RlXSA9IG1lcmdlRnVuYyh0cmVlW3Jvd05vZGUqMl1bY29sTm9kZV0sIHRyZWVbcm93Tm9kZSoyKzFdW2NvbE5vZGVdKTsKICAgICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KICAgICAgICBpbnQgbWlkID0gKGwgKyByKSAvIDI7CiAgICAgICAgbWVyZ2VDb2xUcmVlcyhyb3dOb2RlLCBjb2xOb2RlKjIsIGwsIG1pZCk7CiAgICAgICAgbWVyZ2VDb2xUcmVlcyhyb3dOb2RlLCBjb2xOb2RlKjIrMSwgbWlkKzEsIHIpOwogICAgICAgIHRyZWVbcm93Tm9kZV1bY29sTm9kZV0gPSBtZXJnZUZ1bmModHJlZVtyb3dOb2RlKjJdW2NvbE5vZGVdLCB0cmVlW3Jvd05vZGUqMisxXVtjb2xOb2RlXSk7CiAgICB9CgogICAgdm9pZCBidWlsZFJvdyhpbnQgbm9kZSwgaW50IGwsIGludCByLCBjb25zdCB2ZWN0b3I8dmVjdG9yPFQ+PiYgZ3JpZCkgewogICAgICAgIGlmIChsID09IHIpIHsKICAgICAgICAgICAgYnVpbGRDb2xUcmVlKG5vZGUsIDEsIDAsIG0tMSwgZ3JpZFtsXSk7CiAgICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgaW50IG1pZCA9IChsICsgcikgLyAyOwogICAgICAgIGJ1aWxkUm93KG5vZGUqMiwgbCwgbWlkLCBncmlkKTsKICAgICAgICBidWlsZFJvdyhub2RlKjIrMSwgbWlkKzEsIHIsIGdyaWQpOwogICAgICAgIG1lcmdlQ29sVHJlZXMobm9kZSwgMSwgMCwgbS0xKTsKICAgIH0KCiAgICB2b2lkIHVwZGF0ZUNvbChpbnQgcm93Tm9kZSwgaW50IGNvbE5vZGUsIGludCBsLCBpbnQgciwgaW50IHksIFQgdmFsKSB7CiAgICAgICAgaWYgKGwgPT0gcikgewogICAgICAgICAgICB0cmVlW3Jvd05vZGVdW2NvbE5vZGVdID0gdmFsOwogICAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICAgIGludCBtaWQgPSAobCArIHIpIC8gMjsKICAgICAgICBpZiAoeSA8PSBtaWQpIHVwZGF0ZUNvbChyb3dOb2RlLCBjb2xOb2RlKjIsIGwsIG1pZCwgeSwgdmFsKTsKICAgICAgICBlbHNlIHVwZGF0ZUNvbChyb3dOb2RlLCBjb2xOb2RlKjIrMSwgbWlkKzEsIHIsIHksIHZhbCk7CiAgICAgICAgdHJlZVtyb3dOb2RlXVtjb2xOb2RlXSA9IG1lcmdlRnVuYyh0cmVlW3Jvd05vZGVdW2NvbE5vZGUqMl0sIHRyZWVbcm93Tm9kZV1bY29sTm9kZSoyKzFdKTsKICAgIH0KCiAgICAvLyBSZWNvbXB1dGUgY3VycmVudCByb3cgbm9kZSdzIGNvbHVtbiB0cmVlIGFmdGVyIGEgY2hpbGQgcm93IHVwZGF0ZS4KICAgIHZvaWQgdXBkYXRlQ29sTWVyZ2UoaW50IHJvd05vZGUsIGludCBjb2xOb2RlLCBpbnQgbCwgaW50IHIsIGludCB5LCBUIHZhbCkgewogICAgICAgIGlmIChsID09IHIpIHsKICAgICAgICAgICAgdHJlZVtyb3dOb2RlXVtjb2xOb2RlXSA9IG1lcmdlRnVuYyh0cmVlW3Jvd05vZGUqMl1bY29sTm9kZV0sIHRyZWVbcm93Tm9kZSoyKzFdW2NvbE5vZGVdKTsKICAgICAgICAgICAgcmV0dXJuOwogICAgICAgIH0KICAgICAgICBpbnQgbWlkID0gKGwgKyByKSAvIDI7CiAgICAgICAgaWYgKHkgPD0gbWlkKSB1cGRhdGVDb2xNZXJnZShyb3dOb2RlLCBjb2xOb2RlKjIsIGwsIG1pZCwgeSwgdmFsKTsKICAgICAgICBlbHNlIHVwZGF0ZUNvbE1lcmdlKHJvd05vZGUsIGNvbE5vZGUqMisxLCBtaWQrMSwgciwgeSwgdmFsKTsKICAgICAgICB0cmVlW3Jvd05vZGVdW2NvbE5vZGVdID0gbWVyZ2VGdW5jKHRyZWVbcm93Tm9kZSoyXVtjb2xOb2RlXSwgdHJlZVtyb3dOb2RlKjIrMV1bY29sTm9kZV0pOwogICAgfQoKICAgIHZvaWQgdXBkYXRlUm93KGludCBub2RlLCBpbnQgbCwgaW50IHIsIGludCB4LCBpbnQgeSwgVCB2YWwpIHsKICAgICAgICBpZiAobCA9PSByKSB7CiAgICAgICAgICAgIHVwZGF0ZUNvbChub2RlLCAxLCAwLCBtLTEsIHksIHZhbCk7CiAgICAgICAgICAgIHJldHVybjsKICAgICAgICB9CiAgICAgICAgaW50IG1pZCA9IChsICsgcikgLyAyOwogICAgICAgIGlmICh4IDw9IG1pZCkgdXBkYXRlUm93KG5vZGUqMiwgbCwgbWlkLCB4LCB5LCB2YWwpOwogICAgICAgIGVsc2UgdXBkYXRlUm93KG5vZGUqMisxLCBtaWQrMSwgciwgeCwgeSwgdmFsKTsKICAgICAgICB1cGRhdGVDb2xNZXJnZShub2RlLCAxLCAwLCBtLTEsIHksIHZhbCk7CiAgICB9CgogICAgVCBxdWVyeUNvbChpbnQgcm93Tm9kZSwgaW50IGNvbE5vZGUsIGludCBsLCBpbnQgciwgaW50IHkxLCBpbnQgeTIpIHsKICAgICAgICBpZiAoeTEgPD0gbCAmJiByIDw9IHkyKSB7CiAgICAgICAgICAgIHJldHVybiB0cmVlW3Jvd05vZGVdW2NvbE5vZGVdOwogICAgICAgIH0KICAgICAgICBpbnQgbWlkID0gKGwgKyByKSAvIDI7CiAgICAgICAgVCByZXMgPSBpZGVudGl0eTsKICAgICAgICBpZiAoeTEgPD0gbWlkKSByZXMgPSBtZXJnZUZ1bmMocmVzLCBxdWVyeUNvbChyb3dOb2RlLCBjb2xOb2RlKjIsIGwsIG1pZCwgeTEsIHkyKSk7CiAgICAgICAgaWYgKHkyID4gbWlkKSByZXMgPSBtZXJnZUZ1bmMocmVzLCBxdWVyeUNvbChyb3dOb2RlLCBjb2xOb2RlKjIrMSwgbWlkKzEsIHIsIHkxLCB5MikpOwogICAgICAgIHJldHVybiByZXM7CiAgICB9CgogICAgVCBxdWVyeVJvdyhpbnQgbm9kZSwgaW50IGwsIGludCByLCBpbnQgeDEsIGludCB4MiwgaW50IHkxLCBpbnQgeTIpIHsKICAgICAgICBpZiAoeDEgPD0gbCAmJiByIDw9IHgyKSB7CiAgICAgICAgICAgIHJldHVybiBxdWVyeUNvbChub2RlLCAxLCAwLCBtLTEsIHkxLCB5Mik7CiAgICAgICAgfQogICAgICAgIGludCBtaWQgPSAobCArIHIpIC8gMjsKICAgICAgICBUIHJlcyA9IGlkZW50aXR5OwogICAgICAgIGlmICh4MSA8PSBtaWQpIHJlcyA9IG1lcmdlRnVuYyhyZXMsIHF1ZXJ5Um93KG5vZGUqMiwgbCwgbWlkLCB4MSwgeDIsIHkxLCB5MikpOwogICAgICAgIGlmICh4MiA+IG1pZCkgcmVzID0gbWVyZ2VGdW5jKHJlcywgcXVlcnlSb3cobm9kZSoyKzEsIG1pZCsxLCByLCB4MSwgeDIsIHkxLCB5MikpOwogICAgICAgIHJldHVybiByZXM7CiAgICB9CgpwdWJsaWM6CiAgICAvLyBDb25zdHJ1Y3RvcjogcGFzcyBncmlkIGRpbWVuc2lvbnMgYW5kIHRoZSBpZGVudGl0eSB2YWx1ZSBmb3IgdGhlIG1lcmdlLgogICAgLy8gSW5wdXQ6IG4gKHJvd3MpLCBtIChjb2x1bW5zKSwgaWRlbnRpdHkgKGUuZy4sIElORiBmb3IgbWluLCAtSU5GIGZvciBtYXgpLgogICAgU2VnVHJlZTJETWluTWF4KGludCBuLCBpbnQgbSwgVCBpZGVudGl0eSkgOiBuKG4pLCBtKG0pLCBpZGVudGl0eShpZGVudGl0eSkgewogICAgICAgIHRyZWUuYXNzaWduKDQqbiwgdmVjdG9yPFQ+KDQqbSwgaWRlbnRpdHkpKTsKICAgIH0KCiAgICAvLyBCdWlsZCB0aGUgdHJlZSBmcm9tIHRoZSBncmlkLgogICAgLy8gSW5wdXQ6IDJEIHZlY3RvciBncmlkIG9mIHNpemUgbiB4IG0uCiAgICAvLyBUaW1lOiBPKG4qbSkuCiAgICB2b2lkIGJ1aWxkKGNvbnN0IHZlY3Rvcjx2ZWN0b3I8VD4+JiBncmlkKSB7CiAgICAgICAgYnVpbGRSb3coMSwgMCwgbi0xLCBncmlkKTsKICAgIH0KCiAgICAvLyBQb2ludCB1cGRhdGU6IHNldCBjZWxsICh4LHkpIHRvIHZhbHVlICd2YWwnIChvdmVyd3JpdGVzIHByZXZpb3VzIHZhbHVlKS4KICAgIC8vIElucHV0OiB4LCB5LCB2YWwuCiAgICAvLyBUaW1lOiBPKGxvZyBuICogbG9nIG0pLgogICAgdm9pZCB1cGRhdGVQb2ludChpbnQgeCwgaW50IHksIFQgdmFsKSB7CiAgICAgICAgdXBkYXRlUm93KDEsIDAsIG4tMSwgeCwgeSwgdmFsKTsKICAgIH0KCiAgICAvLyBSZWN0YW5nbGUgcXVlcnk6IHJldHVybnMgdGhlIG1lcmdlIHJlc3VsdCBvdmVyIFt4MS4ueDJdIMOXIFt5MS4ueTJdLgogICAgLy8gSW5wdXQ6IHgxLCB5MSwgeDIsIHkyIChpbmNsdXNpdmUsIDDigJFiYXNlZCkuCiAgICAvLyBSZXR1cm5zOiB0aGUgbWluIG9yIG1heCAoZGVwZW5kaW5nIG9uIG1lcmdlRnVuYykgYXMgdHlwZSBULgogICAgLy8gVGltZTogTyhsb2cgbiAqIGxvZyBtKS4KICAgIFQgcXVlcnkoaW50IHgxLCBpbnQgeTEsIGludCB4MiwgaW50IHkyKSB7CiAgICAgICAgcmV0dXJuIHF1ZXJ5Um93KDEsIDAsIG4tMSwgeDEsIHgyLCB5MSwgeTIpOwogICAgfQp9OwoKLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQovLyBIZWxwZXIgbWVyZ2UgZnVuY3Rpb25zIGZvciBtaW4gYW5kIG1heCAodG8gdXNlIHdpdGggU2VnVHJlZTJETWluTWF4KQovLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCi8vIG1pbkZ1bmM6IHJldHVybnMgdGhlIHNtYWxsZXIgb2YgdHdvIHZhbHVlcy4KLy8gbWF4RnVuYzogcmV0dXJucyB0aGUgbGFyZ2VyIG9mIHR3byB2YWx1ZXMuCi8vIFRoZXNlIGFyZSBzaW1wbGUgZnVuY3Rpb25zIHRoYXQgeW91IGNhbiBwYXNzIGFzIHRlbXBsYXRlIGFyZ3VtZW50cy4KaW50IG1pbkZ1bmMoaW50IGEsIGludCBiKSB7IHJldHVybiBtaW4oYSwgYik7IH0KaW50IG1heEZ1bmMoaW50IGEsIGludCBiKSB7IHJldHVybiBtYXgoYSwgYik7IH0KCi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KLy8gMykgMkQgRkVOV0lDSyBUUkVFIFdJVEggQ09PUkRJTkFURSBDT01QUkVTU0lPTiAoU1BBUlNFIFBPSU5UUykKLy8gICAgKFBvaW50IFVwZGF0ZSwgUHJlZml4IFN1bSwgUmVjdGFuZ2xlIFN1bSkKLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQoKLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQovLyBDTEFTUzogRmVud2ljazJECi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KLy8gV0hBVCBJVCBET0VTOgovLyAgIFRoaXMgaXMgYSAyRCBGZW53aWNrIHRyZWUgKGFsc28gY2FsbGVkIEJpbmFyeSBJbmRleGVkIFRyZWUpIHRoYXQKLy8gICB3b3JrcyB3aXRoIHNwYXJzZSBwb2ludHMuIEl0IGlzIHVzZWZ1bCB3aGVuIHRoZSBncmlkIGlzIGh1Z2UKLy8gICAoY29vcmRpbmF0ZXMgdXAgdG8gMWU5KSBidXQgdGhlIG51bWJlciBvZiBwb2ludHMgdGhhdCB3aWxsIGV2ZXIKLy8gICBiZSB1cGRhdGVkIGlzIHJlbGF0aXZlbHkgc21hbGwgKEsgcG9pbnRzKS4KLy8gICBJdCBzdXBwb3J0czoKLy8gICAgIC0gUG9pbnQgdXBkYXRlOiBhZGQgYSB2YWx1ZSAoZGVsdGEpIHRvIGEgcG9pbnQgKHgsIHkpLgovLyAgICAgLSBQcmVmaXggc3VtOiBzdW0gb2YgYWxsIHBvaW50cyB3aXRoIFggPD0geCBhbmQgWSA8PSB5LgovLyAgICAgLSBSZWN0YW5nbGUgc3VtOiBzdW0gb3ZlciBhIHJlY3RhbmdsZSB1c2luZyBpbmNsdXNpb27igJFleGNsdXNpb24KLy8gICAgICAgZnJvbSBwcmVmaXggc3Vtcy4KLy8KLy8gSU5QVVQ6Ci8vICAgLSBDb25zdHJ1Y3RvcjogYSBsaXN0IG9mIGFsbCBwb2ludHMgKHgsIHkpIHRoYXQgd2lsbCBldmVyIGJlIHVwZGF0ZWQuCi8vICAgICBUaGlzIGlzIHVzZWQgdG8gY29tcHJlc3MgdGhlIGNvb3JkaW5hdGVzLgovLyAgIC0gVXBkYXRlcyBhbmQgcXVlcmllcyB1c2UgdGhlIHNhbWUgY29vcmRpbmF0ZSB2YWx1ZXMgKHRoZXkgbXVzdCBiZQovLyAgICAgYW1vbmcgdGhvc2UgaW5pdGlhbGx5IHByb3ZpZGVkLCBvdGhlcndpc2UgdGhlIHVwZGF0ZSB3aWxsIGZhaWwKLy8gICAgIG9yIHByb2R1Y2Ugd3JvbmcgcmVzdWx0cykuCi8vICAgLSBDb29yZGluYXRlcyBjYW4gYmUgbmVnYXRpdmUgb3IgbGFyZ2U7IHRoZXkgYXJlIHN0b3JlZCBhcyBpbnRzLgovLwovLyBPVVRQVVQ6Ci8vICAgLSBgYWRkYCBtb2RpZmllcyB0aGUgaW50ZXJuYWwgc3RydWN0dXJlIChubyByZXR1cm4pLgovLyAgIC0gYHByZWZpeFN1bSh4LCB5KWAgcmV0dXJucyB0aGUgc3VtIG9mIHBvaW50cyB3aXRoIFggPD0geCBhbmQgWSA8PSB5LgovLyAgIC0gYHJlY3RhbmdsZVN1bSh4MSwgeTEsIHgyLCB5MilgIHJldHVybnMgdGhlIHN1bSBpbiB0aGF0IHJlY3RhbmdsZS4KLy8KLy8gVElNRSBDT01QTEVYSVRZOgovLyAgIC0gQnVpbGQgKGNvbnN0cnVjdG9yKTogTyhLIGxvZyBLKSByb3VnaGx5LCB3aGVyZSBLIGlzIHRoZSBudW1iZXIgb2YKLy8gICAgIHVuaXF1ZSBwb2ludHMgKG9yIHRoZSBudW1iZXIgb2YgcG9pbnRzIHByb3ZpZGVkKS4KLy8gICAtIFVwZGF0ZTogTyhsb2cgSykgaW4gYm90aCBkaW1lbnNpb25zLgovLyAgIC0gUHJlZml4IHN1bTogTyhsb2cgSykgaW4gYm90aCBkaW1lbnNpb25zLgovLwovLyBNRU1PUlk6Ci8vICAgLSBPKEsgbG9nIEspIGluIHRoZSB3b3JzdCBjYXNlLCBiZWNhdXNlIGVhY2ggcG9pbnQgaXMgaW5zZXJ0ZWQgaW50bwovLyAgICAgTyhsb2cgSykgRmVud2ljayBub2Rlcy4gSW4gcHJhY3RpY2UsIGl0IGlzIG1hbmFnZWFibGUgZm9yIEsgdXAgdG8KLy8gICAgIGEgZmV3IGh1bmRyZWQgdGhvdXNhbmQuCi8vCi8vIENPTlNUUkFJTlRTIC8gQVNTVU1QVElPTlM6Ci8vICAgLSBBbGwgcG9pbnRzIHRoYXQgd2lsbCBiZSB1cGRhdGVkIG11c3QgYmUgcGFzc2VkIHRvIHRoZSBjb25zdHJ1Y3RvcgovLyAgICAgYmVmb3JlaGFuZC4gSWYgeW91IHRyeSB0byB1cGRhdGUgYSBwb2ludCB0aGF0IHdhcyBub3QgaW4gdGhlIGxpc3QsCi8vICAgICB0aGUgaW50ZXJuYWwgYHlzYCB2ZWN0b3IgZm9yIHRoYXQgeCB3aWxsIG5vdCBjb250YWluIHRoYXQgeSwgYW5kCi8vICAgICB0aGUgdXBkYXRlIHdpbGwgYWNjZXNzIG91dOKAkW9m4oCRYm91bmRzIChvciBzaWxlbnRseSBmYWlsKS4KLy8gICAtIENvb3JkaW5hdGVzIGFyZSBpbnRlZ2VyIHZhbHVlcy4KLy8gICAtIFRoZSBjbGFzcyB1c2VzIDHigJFiYXNlZCBpbmRleGluZyBpbnRlcm5hbGx5IGZvciB0aGUgRmVud2ljayB0cmVlLAovLyAgICAgYnV0IHRoZSBwdWJsaWMgaW50ZXJmYWNlIHVzZXMgdGhlIG9yaWdpbmFsIGNvb3JkaW5hdGVzICgw4oCRYmFzZWQgb3IKLy8gICAgIGFueSBpbnRlZ2VyKS4KLy8gICAtIFJlY3RhbmdsZSBxdWVyaWVzIHVzZSB0aGUgc3RhbmRhcmQgaW5jbHVzaW9u4oCRZXhjbHVzaW9uIGZvcm11bGEKLy8gICAgIHdpdGggcHJlZml4IHN1bXMuCi8vCi8vIE5PVEVTOgovLyAgIC0gIkZlbndpY2sgdHJlZSIgaXMgYSBkYXRhIHN0cnVjdHVyZSB0aGF0IGVmZmljaWVudGx5IHN1cHBvcnRzCi8vICAgICBwcmVmaXggc3VtcyBhbmQgcG9pbnQgdXBkYXRlcy4gSXQgaXMgYWxzbyBjYWxsZWQgYSBCaW5hcnkgSW5kZXhlZAovLyAgICAgVHJlZSAoQklUKS4KLy8gICAtICJDb29yZGluYXRlIGNvbXByZXNzaW9uIiBtZWFucyB3ZSBtYXAgbGFyZ2UgY29vcmRpbmF0ZSB2YWx1ZXMgdG8KLy8gICAgIHNtYWxsIGluZGljZXMgKDEuLkspIHNvIHRoYXQgd2UgY2FuIHN0b3JlIGFycmF5cyBvZiBtYW5hZ2VhYmxlIHNpemUuCi8vICAgLSBUaGlzIGltcGxlbWVudGF0aW9uIGlzIG9mZmxpbmU6IGl0IG5lZWRzIGFsbCB1cGRhdGUgcG9pbnRzIGluCi8vICAgICBhZHZhbmNlLiBJZiB5b3UgaGF2ZSBkeW5hbWljIGFkZGl0aW9ucyBvZiBuZXcgcG9pbnRzLCB5b3UgbmVlZCBhCi8vICAgICBkaWZmZXJlbnQgYXBwcm9hY2ggKGUuZy4sIGEgZHluYW1pYyAyRCBzZWdtZW50IHRyZWUpLgovLyAgIC0gVGhlIGBwcmVmaXhTdW1gIG1ldGhvZCByZXR1cm5zIHRoZSBzdW0gZm9yIGFsbCBwb2ludHMgd2l0aCBYIDw9IHgKLy8gICAgIGFuZCBZIDw9IHkuIElmIHggb3IgeSBpcyBzbWFsbGVyIHRoYW4gYWxsIHByb3ZpZGVkIGNvb3JkaW5hdGVzLAovLyAgICAgaXQgcmV0dXJucyAwLgovLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCgpjbGFzcyBGZW53aWNrMkQgewogICAgaW50IG47IC8vIG51bWJlciBvZiBjb21wcmVzc2VkIHggY29vcmRpbmF0ZXMKICAgIHZlY3Rvcjx2ZWN0b3I8aW50Pj4geXM7IC8vIGNvbXByZXNzZWQgeSBjb29yZGluYXRlcyBwZXIgeCBub2RlCiAgICB2ZWN0b3I8dmVjdG9yPGludD4+IGJpdDsgLy8gQklUIHZhbHVlcyAoMkQpCiAgICB2ZWN0b3I8aW50PiB4czsgLy8gYWxsIHVuaXF1ZSB4IGNvb3JkaW5hdGVzCgpwdWJsaWM6CiAgICAvLyBDb25zdHJ1Y3RvcjogdGFrZXMgYSBsaXN0IG9mIGFsbCBwb2ludHMgdGhhdCB3aWxsIGV2ZXIgYmUgdXBkYXRlZC4KICAgIC8vIElucHV0OiB2ZWN0b3Igb2YgcGFpcnMgKHgsIHkpLiBEdXBsaWNhdGVzIGFyZSBhbGxvd2VkICh0aGV5IGFyZSBoYW5kbGVkKS4KICAgIC8vIFRpbWU6IE8oSyBsb2cgSykgd2hlcmUgSyBpcyB0aGUgbnVtYmVyIG9mIHBvaW50cy4KICAgIEZlbndpY2syRChjb25zdCB2ZWN0b3I8cGFpcjxpbnQsaW50Pj4mIHBvaW50cykgewogICAgICAgIC8vIENvbGxlY3QgYWxsIHVuaXF1ZSB4IGNvb3JkaW5hdGVzLgogICAgICAgIHZlY3RvcjxpbnQ+IGFsbFg7CiAgICAgICAgZm9yIChhdXRvICZwIDogcG9pbnRzKSBhbGxYLnB1c2hfYmFjayhwLmZpcnN0KTsKICAgICAgICBzb3J0KGFsbFguYmVnaW4oKSwgYWxsWC5lbmQoKSk7CiAgICAgICAgYWxsWC5lcmFzZSh1bmlxdWUoYWxsWC5iZWdpbigpLCBhbGxYLmVuZCgpKSwgYWxsWC5lbmQoKSk7CiAgICAgICAgeHMgPSBhbGxYOwogICAgICAgIG4gPSB4cy5zaXplKCk7CiAgICAgICAgeXMucmVzaXplKG4rMSk7CiAgICAgICAgLy8gRm9yIGVhY2ggcG9pbnQsIGFkZCBpdHMgeSB0byBhbGwgRmVud2ljayBub2RlcyB0aGF0IGNvdmVyIGl0cyB4LgogICAgICAgIGZvciAoYXV0byAmcCA6IHBvaW50cykgewogICAgICAgICAgICBpbnQgeCA9IHAuZmlyc3Q7CiAgICAgICAgICAgIGludCBpZHggPSBsb3dlcl9ib3VuZCh4cy5iZWdpbigpLCB4cy5lbmQoKSwgeCkgLSB4cy5iZWdpbigpICsgMTsgLy8gMS1pbmRleGVkCiAgICAgICAgICAgIGZvciAoaW50IGkgPSBpZHg7IGkgPD0gbjsgaSArPSBpICYgLWkpIHsKICAgICAgICAgICAgICAgIHlzW2ldLnB1c2hfYmFjayhwLnNlY29uZCk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgLy8gQ29tcHJlc3MgZWFjaCB5IGxpc3QgYW5kIGFsbG9jYXRlIHRoZSBCSVQgYXJyYXkuCiAgICAgICAgYml0LnJlc2l6ZShuKzEpOwogICAgICAgIGZvciAoaW50IGkgPSAxOyBpIDw9IG47IGkrKykgewogICAgICAgICAgICBzb3J0KHlzW2ldLmJlZ2luKCksIHlzW2ldLmVuZCgpKTsKICAgICAgICAgICAgeXNbaV0uZXJhc2UodW5pcXVlKHlzW2ldLmJlZ2luKCksIHlzW2ldLmVuZCgpKSwgeXNbaV0uZW5kKCkpOwogICAgICAgICAgICBiaXRbaV0uYXNzaWduKHlzW2ldLnNpemUoKSsxLCAwKTsKICAgICAgICB9CiAgICB9CgogICAgLy8gUG9pbnQgdXBkYXRlOiBhZGQgJ2RlbHRhJyB0byBwb2ludCAoeCwgeSkuCiAgICAvLyBJbnB1dDogeCwgeSAoY29vcmRpbmF0ZXMpLCBkZWx0YSAodmFsdWUgdG8gYWRkKS4KICAgIC8vIFRpbWU6IE8obG9nIEspIHdoZXJlIEsgaXMgdGhlIG51bWJlciBvZiBwb2ludHMuCiAgICAvLyBJTVBPUlRBTlQ6ICh4LHkpIG11c3QgaGF2ZSBiZWVuIGluY2x1ZGVkIGluIHRoZSBjb25zdHJ1Y3RvcidzIHBvaW50IGxpc3QuCiAgICB2b2lkIGFkZChpbnQgeCwgaW50IHksIGludCBkZWx0YSkgewogICAgICAgIGludCB4aSA9IGxvd2VyX2JvdW5kKHhzLmJlZ2luKCksIHhzLmVuZCgpLCB4KSAtIHhzLmJlZ2luKCkgKyAxOwogICAgICAgIGZvciAoaW50IGkgPSB4aTsgaSA8PSBuOyBpICs9IGkgJiAtaSkgewogICAgICAgICAgICBpbnQgeWkgPSBsb3dlcl9ib3VuZCh5c1tpXS5iZWdpbigpLCB5c1tpXS5lbmQoKSwgeSkgLSB5c1tpXS5iZWdpbigpICsgMTsKICAgICAgICAgICAgZm9yIChpbnQgaiA9IHlpOyBqIDwgKGludCliaXRbaV0uc2l6ZSgpOyBqICs9IGogJiAtaikgewogICAgICAgICAgICAgICAgYml0W2ldW2pdICs9IGRlbHRhOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgfQoKICAgIC8vIFByZWZpeCBzdW06IHN1bSBvZiBhbGwgcG9pbnRzIHdpdGggWCA8PSB4IGFuZCBZIDw9IHkuCiAgICAvLyBJbnB1dDogeCwgeSAoY29vcmRpbmF0ZXMpLgogICAgLy8gUmV0dXJuczogaW50ZWdlciBzdW0uCiAgICAvLyBUaW1lOiBPKGxvZyBLKS4KICAgIGludCBwcmVmaXhTdW0oaW50IHgsIGludCB5KSB7CiAgICAgICAgaW50IHhpID0gdXBwZXJfYm91bmQoeHMuYmVnaW4oKSwgeHMuZW5kKCksIHgpIC0geHMuYmVnaW4oKTsgLy8gbnVtYmVyIG9mIHhzIDw9IHgKICAgICAgICBpbnQgcmVzID0gMDsKICAgICAgICBmb3IgKGludCBpID0geGk7IGkgPiAwOyBpIC09IGkgJiAtaSkgewogICAgICAgICAgICBpbnQgeWkgPSB1cHBlcl9ib3VuZCh5c1tpXS5iZWdpbigpLCB5c1tpXS5lbmQoKSwgeSkgLSB5c1tpXS5iZWdpbigpOwogICAgICAgICAgICBmb3IgKGludCBqID0geWk7IGogPiAwOyBqIC09IGogJiAtaikgewogICAgICAgICAgICAgICAgcmVzICs9IGJpdFtpXVtqXTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICByZXR1cm4gcmVzOwogICAgfQoKICAgIC8vIFJlY3RhbmdsZSBzdW06IHN1bSBvZiBwb2ludHMgaW5zaWRlIFt4MS4ueDJdIMOXIFt5MS4ueTJdLgogICAgLy8gSW5wdXQ6IHgxLCB5MSwgeDIsIHkyIChpbmNsdXNpdmUsIGFueSBvcmRlcikuCiAgICAvLyBSZXR1cm5zOiBpbnRlZ2VyIHN1bS4KICAgIC8vIFRpbWU6IE8obG9nIEspIChmb3VyIHByZWZpeFN1bSBjYWxscykuCiAgICBpbnQgcmVjdGFuZ2xlU3VtKGludCB4MSwgaW50IHkxLCBpbnQgeDIsIGludCB5MikgewogICAgICAgIHJldHVybiBwcmVmaXhTdW0oeDIsIHkyKSAtIHByZWZpeFN1bSh4MS0xLCB5MikgLSBwcmVmaXhTdW0oeDIsIHkxLTEpICsgcHJlZml4U3VtKHgxLTEsIHkxLTEpOwogICAgfQp9OwoKLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQovLyA0KSAyRCBTRUdNRU5UIFRSRUUgV0lUSCBMQVpZIFBST1BBR0FUSU9OIChSQU5HRSBVUERBVEVTKQovLyAgICAoQ29uY2VwdCBvbmx5IOKAkyBub3QgaW1wbGVtZW50ZWQpCi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KLy8gVGhpcyBzZWN0aW9uIGlzIGtlcHQgYXMgYSBwbGFjZWhvbGRlci4gTGF6eSBwcm9wYWdhdGlvbiBpbiAyRCBpcwovLyBhZHZhbmNlZCBhbmQgcmFyZWx5IG5lZWRlZC4gRm9yIG1vc3QgcHJvYmxlbXMsIGEgMkQgQklUIG9yIG9mZmxpbmUKLy8gc3dlZXBsaW5lIGlzIHN1ZmZpY2llbnQuIE5vIGltcGxlbWVudGF0aW9uIGlzIHByb3ZpZGVkIGhlcmUuCi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KLy8gNSkgQ09NTU9OIFRSSUNLUyAmIFBBVFRFUk5TIEZPUiBFQ1BDL0FDUEMKLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQovLyBUaGUgZm9sbG93aW5nIG5vdGVzIGFyZSBmb3IgeW91ciByZWZlcmVuY2U6Ci8vCi8vIDUuMSkgT2ZmbGluZSBxdWVyaWVzIHdpdGggc3dlZXBsaW5lOgovLyAgICAgIEZvciBzdGF0aWMgMkQgcG9pbnRzLCB5b3UgY2FuIGFuc3dlciByZWN0YW5nbGUgc3VtIHF1ZXJpZXMgYnkKLy8gICAgICBzb3J0aW5nIHBvaW50cyBieSB4LCBxdWVyaWVzIGJ5IHgyLCBhbmQgdXNpbmcgYSAxRCBCSVQgb24geS4KLy8gICAgICBUaGlzIGF2b2lkcyAyRCBzZWdtZW50IHRyZWVzIGVudGlyZWx5LgovLwovLyA1LjIpIER5bmFtaWMgMkQgU2VnbWVudCBUcmVlIHVzaW5nIHBvaW50ZXJzOgovLyAgICAgIFdoZW4gdGhlIGdyaWQgaXMgaHVnZSBhbmQgdXBkYXRlcy9xdWVyaWVzIGFyZSBmZXcsIHlvdSBjYW4KLy8gICAgICBjcmVhdGUgbm9kZXMgb24gZGVtYW5kLiBUaGlzIGlzIG5vdCBpbXBsZW1lbnRlZCBoZXJlIGJlY2F1c2UKLy8gICAgICBpdCBpcyBjb21wbGV4OyB0aGUgRmVud2ljazJEIGNsYXNzIGlzIHVzdWFsbHkgZW5vdWdoIGZvciBzcGFyc2UgZGF0YS4KLy8KLy8gNS4zKSBVc2luZyAyRCBTZWdtZW50IFRyZWUgZm9yIHJhbmdlIG1heGltdW0gd2l0aCBwb2ludCB1cGRhdGVzOgovLyAgICAgIFRoZSBTZWdUcmVlMkRNaW5NYXggY2xhc3MgYWJvdmUgZG9lcyBleGFjdGx5IHRoYXQuCi8vCi8vIDUuNCkgQ29tYmluaW5nIHdpdGggQmluYXJ5IFNlYXJjaCBvbiBhbnN3ZXI6Ci8vICAgICAgSWYgeW91IG5lZWQgdG8gZmluZCB0aGUgc21hbGxlc3QgcmVjdGFuZ2xlIGNvbnRhaW5pbmcgYSBjZXJ0YWluCi8vICAgICAgbnVtYmVyIG9mIHBvaW50cywgeW91IGNhbiBiaW5hcnkgc2VhcmNoIHRoZSBzaXplIGFuZCB1c2UgYQovLyAgICAgIDJEIHNlZ21lbnQgdHJlZSB0byBjb3VudCBwb2ludHMgaW4gYSByZWN0YW5nbGUuCi8vCi8vIDUuNSkgTmVnYXRpdmUgY29vcmRpbmF0ZXMgb3IgbGFyZ2UgcmFuZ2VzOgovLyAgICAgIEFsd2F5cyB1c2UgY29vcmRpbmF0ZSBjb21wcmVzc2lvbiAoRmVud2ljazJEKSBmb3Igc3VjaCBjYXNlcy4KLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQoKLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQovLyA2KSBTUEFSU0UgMkQgU0VHTUVOVCBUUkVFIChEWU5BTUlDIEFMTE9DQVRJT04pIOKAkyBOT1QgSU1QTEVNRU5URUQKLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQovLyBBIGZ1bGx5IGR5bmFtaWMgMkQgc2VnbWVudCB0cmVlIHdvdWxkIGFsbG9jYXRlIG5vZGVzIG9ubHkgd2hlbgovLyBuZWVkZWQuIEJlY2F1c2Ugb2YgaXRzIGNvbXBsZXhpdHksIHdlIHJlY29tbWVuZCB1c2luZyBGZW53aWNrMkQKLy8gd2l0aCBjb29yZGluYXRlIGNvbXByZXNzaW9uIGluc3RlYWQuCi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KLy8gNykgRVhBTVBMRSBVU0FHRQovLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09Ci8vIFRoZSBtYWluKCkgZnVuY3Rpb24gYmVsb3cgZGVtb25zdHJhdGVzIGhvdyB0byB1c2UgdGhlIHRocmVlIG1haW4KLy8gY2xhc3Nlcy4gUmVhZCB0aGUgY29tbWVudHMgaW5zaWRlIHRvIHNlZSBlYWNoIHN0ZXAuCi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KCmludCBtYWluKCkgewogICAgaW9zOjpzeW5jX3dpdGhfc3RkaW8oZmFsc2UpOwogICAgY2luLnRpZShudWxscHRyKTsKCiAgICAvLyAtLS0tLS0tLS0tIEV4YW1wbGUgMTogU3VtIDJEIFNlZ21lbnQgVHJlZSAtLS0tLS0tLS0tCiAgICB2ZWN0b3I8dmVjdG9yPGludD4+IGdyaWQgPSB7CiAgICAgICAgezEsIDIsIDN9LAogICAgICAgIHs0LCA1LCA2fSwKICAgICAgICB7NywgOCwgOX0KICAgIH07CiAgICBpbnQgbiA9IDMsIG0gPSAzOwogICAgU2VnVHJlZTJEU3VtIHNlZyhuLCBtKTsKICAgIHNlZy5idWlsZChncmlkKTsKCiAgICBjb3V0IDw8ICJTdW0gb2YgZW50aXJlIGdyaWQ6ICIgPDwgc2VnLnF1ZXJ5U3VtKDAsMCwyLDIpIDw8ICdcbic7IC8vIDQ1CiAgICBjb3V0IDw8ICJTdW0gb2Ygc3VicmVjdGFuZ2xlICgxLDEpLSgyLDIpOiAiIDw8IHNlZy5xdWVyeVN1bSgxLDEsMiwyKSA8PCAnXG4nOyAvLyA1KzYrOCs5PTI4CgogICAgc2VnLnVwZGF0ZVBvaW50KDEsMSwgMTApOyAvLyBhZGQgMTAgdG8gY2VsbCAoMSwxKSB3aGljaCB3YXMgNSAtPiBub3cgMTUKICAgIGNvdXQgPDwgIkFmdGVyIHVwZGF0ZSwgc3VtIG9mIHN1YnJlY3RhbmdsZSAoMSwxKS0oMiwyKTogIiA8PCBzZWcucXVlcnlTdW0oMSwxLDIsMikgPDwgJ1xuJzsgLy8gMTUrNis4Kzk9MzgKCiAgICAvLyAtLS0tLS0tLS0tIEV4YW1wbGUgMjogTWluIDJEIFNlZ21lbnQgVHJlZSAtLS0tLS0tLS0tCiAgICBTZWdUcmVlMkRNaW5NYXg8aW50LCBtaW5GdW5jPiBzZWdNaW4obiwgbSwgSU5UX01BWCk7CiAgICBzZWdNaW4uYnVpbGQoZ3JpZCk7CiAgICBjb3V0IDw8ICJNaW4gaW4gZW50aXJlIGdyaWQ6ICIgPDwgc2VnTWluLnF1ZXJ5KDAsMCwyLDIpIDw8ICdcbic7IC8vIDEKICAgIHNlZ01pbi51cGRhdGVQb2ludCgwLDAsIDApOyAvLyBzZXQgKDAsMCkgdG8gMAogICAgY291dCA8PCAiTWluIGFmdGVyIHVwZGF0ZTogIiA8PCBzZWdNaW4ucXVlcnkoMCwwLDIsMikgPDwgJ1xuJzsgLy8gMAoKICAgIC8vIC0tLS0tLS0tLS0gRXhhbXBsZSAzOiAyRCBGZW53aWNrIHdpdGggY29vcmRpbmF0ZSBjb21wcmVzc2lvbiAtLS0tLS0tLS0tCiAgICB2ZWN0b3I8cGFpcjxpbnQsaW50Pj4gcG9pbnRzID0ge3sxLDF9LCB7MiwzfSwgezUsN319OwogICAgRmVud2ljazJEIGZ3KHBvaW50cyk7CiAgICBmdy5hZGQoMSwxLCA1KTsKICAgIGZ3LmFkZCgyLDMsIDEwKTsKICAgIGNvdXQgPDwgIlByZWZpeCBzdW0gdXAgdG8gKDIsMyk6ICIgPDwgZncucHJlZml4U3VtKDIsMykgPDwgJ1xuJzsgLy8gMTUKICAgIGNvdXQgPDwgIlByZWZpeCBzdW0gdXAgdG8gKDUsNyk6ICIgPDwgZncucHJlZml4U3VtKDUsNykgPDwgJ1xuJzsgLy8gMTUKICAgIGZ3LmFkZCg1LDcsIDMpOwogICAgY291dCA8PCAiQWZ0ZXIgYWRkOiAiIDw8IGZ3LnByZWZpeFN1bSg1LDcpIDw8ICdcbic7IC8vIDE4CgogICAgcmV0dXJuIDA7Cn0KCi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0KLy8gQURESVRJT05BTCBOT1RFUyBGT1IgRUNQQy9BQ1BDIENPTVBFVElUT1JTOgovLyAtIDJEIFNlZ21lbnQgVHJlZXMgYXJlIG1lbW9yeSBoZWF2eTsgdXNlIHRoZW0gb25seSB3aGVuIE4gYW5kIE0gYXJlCi8vICAgc21hbGwgKDw9IDEwMDApIG9yIHdoZW4gY29vcmRpbmF0ZXMgYXJlIGNvbXByZXNzZWQuCi8vIC0gRm9yIGR5bmFtaWMgdXBkYXRlcyBhbmQgbGFyZ2UgY29vcmRpbmF0ZXMsIHByZWZlciBGZW53aWNrMkQgd2l0aAovLyAgIGNvbXByZXNzaW9uIChvZmZsaW5lKS4KLy8gLSBGb3Igb2ZmbGluZSBzdGF0aWMgcXVlcmllcywgYSBzd2VlcGxpbmUgKyAxRCBCSVQgaXMgb2Z0ZW4gc2ltcGxlcgovLyAgIGFuZCBmYXN0ZXIuCi8vIC0gV2hlbiBpbXBsZW1lbnRpbmcgeW91ciBvd24gMkQgc2VnbWVudCB0cmVlLCB3YXRjaCBvdXQgZm9yIHJlY3Vyc2lvbgovLyAgIGRlcHRoIGFuZCBtZW1vcnkgY29uc3VtcHRpb24uCi8vIC0gQWx3YXlzIHRlc3QgZWRnZSBjYXNlczogTj0xLCBNPTEsIGVtcHR5IHJlY3RhbmdsZXMsIG5lZ2F0aXZlCi8vICAgY29vcmRpbmF0ZXMgKEZlbndpY2syRCBoYW5kbGVzIHRoZW0gaWYgeW91IHByb3ZpZGUgdGhlbSkuCi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0=