#include <bits/stdc++.h>
using namespace std;
#include <bits/stdc++.h>
using namespace std;
//COPY THE BLACKBOX, there is no need to change anything in it.
//Check the main function at bottom for USAGE
//****************BLACKBOX START*****************
//START COPYING FROM HERE
typedef int ll;
class Hash {
public :
static int hash( int x) {
return hash( { 0 ,0 ,x} ) ;
}
static int hash( tuple< int ,int > x) {
return hash( { 0 ,get< 0 > ( x) ,get< 1 > ( x) } ) ;
}
static int hash( tuple< int ,int ,int > x) {
int k= get< 0 > ( x) ,u= get< 1 > ( x) ,v= get< 2 > ( x) ;
return k* 1873 * 1873 + u* 1873 + v;
}
} ;
class Graph {
bool is_directed;
public :
vector< vector< pair< int ,ll>>> adj;
int n,N= 2000000 ;
Graph( int n_, bool is_directed_) {
n= n_; is_directed = is_directed_;
adj.resize ( N,vector< pair< int ,ll>> ( ) ) ;
}
int hash( int u, int v) {
return Hash:: hash ( { u,v} ) ;
}
int hash( int u, int v, int k) {
return Hash:: hash ( { u,v,k} ) ;
}
void add_edge( int uR, int vR, ll c= 0 ) {
int u= Hash:: hash ( uR) , v= Hash:: hash ( vR) ;
add_edge_internal( u,v,c) ;
}
void add_edge( tuple< int ,int > uR, tuple< int ,int > vR, ll c= 0 ) {
int u= Hash:: hash ( uR) , v= Hash:: hash ( vR) ;
add_edge_internal( u,v,c) ;
}
void add_edge( tuple< int ,int ,int > uR, tuple< int ,int ,int > vR, ll c= 0 ) {
int u= Hash:: hash ( uR) , v= Hash:: hash ( vR) ;
add_edge_internal( u,v,c) ;
}
private :
void add_edge_internal( int u, int v, ll c= 0 ) {
add_edge_weighted_undirected( u,v,c) ;
if ( ! is_directed)
add_edge_weighted_undirected( v,u,c) ;
}
void add_edge_weighted_undirected( int u, int v, ll c) {
pair< int ,ll> p = make_pair( v,c) ;
adj[ u] .push_back ( p) ;
}
} ;
class BFS {
vector< ll> min_dist_from_source;
vector< bool > visited;
Graph * g;
public :
BFS( Graph * g_) {
g = g_;
clear( ) ;
}
void clear( ) {
min_dist_from_source.clear ( ) ;
min_dist_from_source.resize ( g- > N,- 1 ) ;
visited.clear ( ) ;
visited.resize ( g- > N, false ) ;
}
void run( int sourceR) {
int source = Hash:: hash ( sourceR) ;
run_internal( source) ;
}
void run( tuple< int ,int > sourceR) {
int source = Hash:: hash ( sourceR) ;
run_internal( source) ;
}
void run( tuple< int ,int ,int > sourceR) {
int source = Hash:: hash ( sourceR) ;
run_internal( source) ;
}
int min_dist( int targetR) {
int target = Hash:: hash ( targetR) ;
return min_dist_internal( target) ;
}
int min_dist( tuple< int ,int > targetR) {
int target = Hash:: hash ( targetR) ;
return min_dist_internal( target) ;
}
int min_dist( tuple< int ,int ,int > targetR) {
int target = Hash:: hash ( targetR) ;
return min_dist_internal( target) ;
}
bool is_visited( int targetR) {
int target = Hash:: hash ( targetR) ;
return is_visited_internal( target) ;
}
bool is_visited( tuple< int ,int > targetR) {
int target = Hash:: hash ( targetR) ;
return is_visited_internal( target) ;
}
bool is_visited( tuple< int ,int ,int > targetR) {
int target = Hash:: hash ( targetR) ;
return is_visited_internal( target) ;
}
private :
void run_internal( int source) {
queue< int > q;
q.push ( source) ;
visited[ source] = true ;
min_dist_from_source[ source] = 0 ;
while ( ! q.empty ( ) ) {
int cur_node = q.front ( ) ;
for ( unsigned int i = 0 ; i < ( g- > adj[ cur_node] ) .size ( ) ; ++ i) {
int adj_node = ( g- > adj[ cur_node] ) [ i] .first ;
if ( visited[ adj_node] == false ) {
visited[ adj_node] = true ;
min_dist_from_source[ adj_node] = min_dist_from_source[ cur_node] + 1 ;
q.push ( adj_node) ;
}
}
q.pop ( ) ;
}
return ;
}
int min_dist_internal( int target) {
return min_dist_from_source[ target] ;
}
bool is_visited_internal( int target) {
return visited[ target] ;
}
} ;
//END COPYING HERE
//********************BLACKBOX END******************
int main( ) {
int n,m; cin >> n>> m;
//initialise graph with `n*m` nodes, each cell is a node
Graph g( n* m,true ) ;
//intiatialise a 2D array of size `n*m
vector< vector< char >> grid( n,vector< char > ( m) ) ;
for ( int i= 0 ; i< n; i++ )
for ( int j= 0 ; j< m; j++ ) {
cin >> grid[ i] [ j] ;
}
//************GRAPH CONTRUCTION BEGIN*****************
//iterate through every cell
for ( int i= 0 ; i< n; i++ )
for ( int j= 0 ; j< m; j++ ) {
//if current cell is floor
if ( grid[ i] [ j] == '.' ) {
// if cell above is withing the grid and a floor, create an Edge from `current cell -> cell above`
if ( i- 1 >= 0 && grid[ i- 1 ] [ j] == '.' )
g.add_edge ( { i,j} ,{ i- 1 ,j} ) ;
// if cell below is withing the grid and a floor, create an Edge from `current cell -> cell below`
if ( i+ 1 < n && grid[ i+ 1 ] [ j] == '.' )
g.add_edge ( { i,j} ,{ i+ 1 ,j} ) ;
// if cell left is withing the grid and a floor, create an Edge from `current cell -> cell left`
if ( j- 1 >= 0 && grid[ i] [ j- 1 ] == '.' )
g.add_edge ( { i,j} ,{ i,j- 1 } ) ;
// if cell right is withing the grid and a floor, create an Edge from `current cell -> cell right`
if ( j+ 1 < m && grid[ i] [ j+ 1 ] == '.' )
g.add_edge ( { i,j} ,{ i,j+ 1 } ) ;
}
}
//************GRAPH CONTRUCTION END*****************
//Since the number of nodes is high, and the Blackbox BFS returns the vector min_dist of size 'n*m', returning an array of size x takes time x. We might get TLE as the BFS is being called multiple times, requiring returning min_dist multiple times.
//Therefore we need to go into the Blackbox and return the pointer to the min_dist instead of the whole array. Returning a point take 1 unit time only.
int num_rooms= 0 ;
BFS bfs( & g) ;
//iterate through every cell
for ( int i= 0 ; i< n; i++ )
for ( int j= 0 ; j< m; j++ ) {
//if the current cell is not reachable from any of the cell we already iterated, then we have found a new room
if ( ! bfs.is_visited ( { i,j} ) && grid[ i] [ j] == '.' ) {
num_rooms++ ;
//BFS from `i,j` will visit every cell reachable from `i,j`, aka in the same connected component(room) as `i,j`
//`min_dist[k]` for all the nodes reachable from `i,j` will be the shortest path length from node `i,j` to node `k`
bfs.run ( { i,j} ) ;
}
}
cout << num_rooms<< '\n ' ;
return 0 ;
}
I2luY2x1ZGUgPGJpdHMvc3RkYysrLmg+CnVzaW5nIG5hbWVzcGFjZSBzdGQ7CgojaW5jbHVkZSA8Yml0cy9zdGRjKysuaD4KdXNpbmcgbmFtZXNwYWNlIHN0ZDsKCgovL0NPUFkgVEhFIEJMQUNLQk9YLCB0aGVyZSBpcyBubyBuZWVkIHRvIGNoYW5nZSBhbnl0aGluZyBpbiBpdC4KLy9DaGVjayB0aGUgbWFpbiBmdW5jdGlvbiBhdCBib3R0b20gZm9yIFVTQUdFCgovLyoqKioqKioqKioqKioqKipCTEFDS0JPWCBTVEFSVCoqKioqKioqKioqKioqKioqCi8vU1RBUlQgQ09QWUlORyBGUk9NIEhFUkUKCnR5cGVkZWYgaW50IGxsOwoKY2xhc3MgSGFzaCB7CiAgcHVibGljOgogIAlzdGF0aWMgaW50IGhhc2goaW50IHgpewogIAkJcmV0dXJuIGhhc2goezAsMCx4fSk7CiAgCX0KICAJc3RhdGljIGludCBoYXNoKHR1cGxlPGludCxpbnQ+eCl7CiAgCQlyZXR1cm4gaGFzaCh7MCxnZXQ8MD4oeCksZ2V0PDE+KHgpfSk7CiAgCX0KICAJc3RhdGljIGludCBoYXNoKHR1cGxlPGludCxpbnQsaW50PngpewogIAkJaW50IGs9Z2V0PDA+KHgpLHU9Z2V0PDE+KHgpLHY9Z2V0PDI+KHgpOwogIAkJcmV0dXJuIGsqMTg3MyoxODczICsgdSoxODczICsgdjsKICAJfQp9OwoKY2xhc3MgR3JhcGggewoKCWJvb2wgaXNfZGlyZWN0ZWQ7CgoJcHVibGljOgoJCXZlY3Rvcjx2ZWN0b3I8cGFpcjxpbnQsbGw+Pj5hZGo7CiAgICBpbnQgbixOPTIwMDAwMDA7CgoJCUdyYXBoKGludCBuXywgYm9vbCBpc19kaXJlY3RlZF8pewoJCQluPW5fOyBpc19kaXJlY3RlZCA9IGlzX2RpcmVjdGVkXzsKCQkJYWRqLnJlc2l6ZShOLHZlY3RvcjxwYWlyPGludCxsbD4+KCkpOwoJCX0KCgkJaW50IGhhc2goaW50IHUsIGludCB2KXsKCQkJcmV0dXJuIEhhc2g6Omhhc2goe3Usdn0pOwoJCX0KCQlpbnQgaGFzaChpbnQgdSwgaW50IHYsIGludCBrKXsKCQkJcmV0dXJuIEhhc2g6Omhhc2goe3UsdixrfSk7CgkJfQoKCQl2b2lkIGFkZF9lZGdlKGludCB1UiwgaW50IHZSLCBsbCBjPTApewoJCSAgaW50IHU9SGFzaDo6aGFzaCh1UiksIHY9SGFzaDo6aGFzaCh2Uik7CgkJICBhZGRfZWRnZV9pbnRlcm5hbCh1LHYsYyk7CgkJfQoJCXZvaWQgYWRkX2VkZ2UodHVwbGU8aW50LGludD4gdVIsIHR1cGxlPGludCxpbnQ+IHZSLCBsbCBjPTApewoJCSAgaW50IHU9SGFzaDo6aGFzaCh1UiksIHY9SGFzaDo6aGFzaCh2Uik7CgkJICBhZGRfZWRnZV9pbnRlcm5hbCh1LHYsYyk7CgkJfQoJCQl2b2lkIGFkZF9lZGdlKHR1cGxlPGludCxpbnQsaW50PiB1UiwgdHVwbGU8aW50LGludCxpbnQ+IHZSLCBsbCBjPTApewoJCSAgaW50IHU9SGFzaDo6aGFzaCh1UiksIHY9SGFzaDo6aGFzaCh2Uik7CgkJICBhZGRfZWRnZV9pbnRlcm5hbCh1LHYsYyk7CgkJfQoKCglwcml2YXRlIDoKCgkgIHZvaWQgYWRkX2VkZ2VfaW50ZXJuYWwoaW50IHUsIGludCB2LCBsbCBjPTApewoJCQlhZGRfZWRnZV93ZWlnaHRlZF91bmRpcmVjdGVkKHUsdixjKTsKCQkJaWYoIWlzX2RpcmVjdGVkKQoJCQkJYWRkX2VkZ2Vfd2VpZ2h0ZWRfdW5kaXJlY3RlZCh2LHUsYyk7CgkJfQoJCXZvaWQgYWRkX2VkZ2Vfd2VpZ2h0ZWRfdW5kaXJlY3RlZChpbnQgdSwgaW50IHYsIGxsIGMpIHsKCQkJcGFpcjxpbnQsbGw+cCA9IG1ha2VfcGFpcih2LGMpOwoJCQlhZGpbdV0ucHVzaF9iYWNrKHApOwoJCX0KCn07CgpjbGFzcyBCRlMgewogICAgdmVjdG9yPGxsPm1pbl9kaXN0X2Zyb21fc291cmNlOwogICAgdmVjdG9yPGJvb2w+IHZpc2l0ZWQ7CiAgICBHcmFwaCAqZzsKCiAgICBwdWJsaWM6CiAgICAgIEJGUyhHcmFwaCAqZ18pIHsKICAgICAgICAgIGcgPSBnXzsKICAgICAgICAgIGNsZWFyKCk7CiAgICAgIH0KCgkgIAl2b2lkIGNsZWFyKCkgewogIAkJCW1pbl9kaXN0X2Zyb21fc291cmNlLmNsZWFyKCk7CiAgCQkJbWluX2Rpc3RfZnJvbV9zb3VyY2UucmVzaXplKGctPk4sLTEpOwogIAkJCXZpc2l0ZWQuY2xlYXIoKTsKICAJCQl2aXNpdGVkLnJlc2l6ZShnLT5OLCBmYWxzZSk7CiAgCQl9CgoKICAgICAgdm9pZCBydW4oaW50IHNvdXJjZVIpIHsKICAgICAgICBpbnQgc291cmNlID0gSGFzaDo6aGFzaChzb3VyY2VSKTsKICAgICAgICBydW5faW50ZXJuYWwoc291cmNlKTsKICAgICAgfQogICAgICB2b2lkIHJ1bih0dXBsZTxpbnQsaW50PiBzb3VyY2VSKSB7CiAgICAgICAgaW50IHNvdXJjZSA9IEhhc2g6Omhhc2goc291cmNlUik7CiAgICAgICAgcnVuX2ludGVybmFsKHNvdXJjZSk7CiAgICAgIH0KICAgICAgdm9pZCBydW4odHVwbGU8aW50LGludCxpbnQ+IHNvdXJjZVIpIHsKICAgICAgICBpbnQgc291cmNlID0gSGFzaDo6aGFzaChzb3VyY2VSKTsKICAgICAgICBydW5faW50ZXJuYWwoc291cmNlKTsKICAgICAgfQoKCiAgICAgIGludCBtaW5fZGlzdChpbnQgdGFyZ2V0Uil7CiAgICAgIAlpbnQgdGFyZ2V0ID0gSGFzaDo6aGFzaCh0YXJnZXRSKTsKICAgICAgCXJldHVybiBtaW5fZGlzdF9pbnRlcm5hbCh0YXJnZXQpOwogICAgICB9CiAgICAgIGludCBtaW5fZGlzdCh0dXBsZTxpbnQsaW50PiB0YXJnZXRSKXsKICAgICAgCWludCB0YXJnZXQgPSBIYXNoOjpoYXNoKHRhcmdldFIpOwogICAgICAJcmV0dXJuIG1pbl9kaXN0X2ludGVybmFsKHRhcmdldCk7CiAgICAgIH0KICAgICAgaW50IG1pbl9kaXN0KHR1cGxlPGludCxpbnQsaW50PiB0YXJnZXRSKXsKICAgICAgCWludCB0YXJnZXQgPSBIYXNoOjpoYXNoKHRhcmdldFIpOwogICAgICAJcmV0dXJuIG1pbl9kaXN0X2ludGVybmFsKHRhcmdldCk7CiAgICAgIH0KCiAgICAgIGJvb2wgaXNfdmlzaXRlZChpbnQgdGFyZ2V0Uil7CiAgICAgIAlpbnQgdGFyZ2V0ID0gSGFzaDo6aGFzaCh0YXJnZXRSKTsKICAgICAgCXJldHVybiBpc192aXNpdGVkX2ludGVybmFsKHRhcmdldCk7CiAgICAgIH0KICAgICAgYm9vbCBpc192aXNpdGVkKHR1cGxlPGludCxpbnQ+IHRhcmdldFIpewogICAgICAJaW50IHRhcmdldCA9IEhhc2g6Omhhc2godGFyZ2V0Uik7CiAgICAgIAlyZXR1cm4gaXNfdmlzaXRlZF9pbnRlcm5hbCh0YXJnZXQpOwogICAgICB9CiAgICAgIGJvb2wgaXNfdmlzaXRlZCh0dXBsZTxpbnQsaW50LGludD4gdGFyZ2V0Uil7CiAgICAgIAlpbnQgdGFyZ2V0ID0gSGFzaDo6aGFzaCh0YXJnZXRSKTsKICAgICAgCXJldHVybiBpc192aXNpdGVkX2ludGVybmFsKHRhcmdldCk7CiAgICAgIH0KCiAgcHJpdmF0ZToKICAgIHZvaWQgcnVuX2ludGVybmFsKGludCBzb3VyY2UpIHsKCQkJcXVldWU8aW50PiBxOwoJCQlxLnB1c2goc291cmNlKTsKCgkJCXZpc2l0ZWRbc291cmNlXSA9IHRydWU7CgkJCW1pbl9kaXN0X2Zyb21fc291cmNlW3NvdXJjZV0gPSAwOwoKCQkJd2hpbGUoIXEuZW1wdHkoKSkgewoJCQkJaW50IGN1cl9ub2RlID0gcS5mcm9udCgpOwoJCQkJZm9yICh1bnNpZ25lZCBpbnQgaSA9IDA7IGkgPCAoZy0+YWRqW2N1cl9ub2RlXSkuc2l6ZSgpOyArK2kpIHsKCQkJCQlpbnQgYWRqX25vZGUgPSAgKGctPmFkaltjdXJfbm9kZV0pW2ldLmZpcnN0OwoJCQkJCWlmICh2aXNpdGVkW2Fkal9ub2RlXSA9PSBmYWxzZSkgewoJCQkJCQl2aXNpdGVkW2Fkal9ub2RlXSA9IHRydWU7CgkJCQkJCW1pbl9kaXN0X2Zyb21fc291cmNlW2Fkal9ub2RlXSA9IG1pbl9kaXN0X2Zyb21fc291cmNlW2N1cl9ub2RlXSArIDE7CgkJCQkJCXEucHVzaChhZGpfbm9kZSk7CgkJCQkJfQoJCQkJfQoJCQkJcS5wb3AoKTsKCQkJfQoKCQkJcmV0dXJuOwogICAgfQoKICAgIGludCBtaW5fZGlzdF9pbnRlcm5hbChpbnQgdGFyZ2V0KXsKICAgIAlyZXR1cm4gbWluX2Rpc3RfZnJvbV9zb3VyY2VbdGFyZ2V0XTsKICAgIH0KCiAgICBib29sIGlzX3Zpc2l0ZWRfaW50ZXJuYWwoaW50IHRhcmdldCl7CiAgICAJcmV0dXJuIHZpc2l0ZWRbdGFyZ2V0XTsKICAgIH0KCn07Ci8vRU5EIENPUFlJTkcgSEVSRQovLyoqKioqKioqKioqKioqKioqKioqQkxBQ0tCT1ggRU5EKioqKioqKioqKioqKioqKioqCgppbnQgbWFpbigpIHsKCiAgICBpbnQgbixtOyBjaW4+Pm4+Pm07CiAgICAKICAgIC8vaW5pdGlhbGlzZSBncmFwaCB3aXRoIGBuKm1gIG5vZGVzLCBlYWNoIGNlbGwgaXMgYSBub2RlCiAgICBHcmFwaCBnKG4qbSx0cnVlKTsKICAgIAoJLy9pbnRpYXRpYWxpc2UgYSAyRCBhcnJheSBvZiBzaXplIGBuKm0KICAgIHZlY3Rvcjx2ZWN0b3I8Y2hhcj4+Z3JpZChuLHZlY3RvcjxjaGFyPihtKSk7CiAgIAogICAgZm9yKGludCBpPTA7aTxuO2krKykKICAgICAgZm9yKGludCBqPTA7ajxtO2orKyl7CiAgICAgICAgY2luPj5ncmlkW2ldW2pdOwogICAgICAgCiAgICAgIH0KICAgCiAgIAogICAvLyoqKioqKioqKioqKkdSQVBIIENPTlRSVUNUSU9OIEJFR0lOKioqKioqKioqKioqKioqKioKICAgCiAgIC8vaXRlcmF0ZSB0aHJvdWdoIGV2ZXJ5IGNlbGwKICAgIGZvcihpbnQgaT0wO2k8bjtpKyspCiAgICAgIGZvcihpbnQgaj0wO2o8bTtqKyspIHsKICAgICAgCQogICAgICAJLy9pZiBjdXJyZW50IGNlbGwgaXMgZmxvb3IKICAgICAgICBpZihncmlkW2ldW2pdPT0nLicpIHsKCgkJLy8gaWYgY2VsbCBhYm92ZSBpcyB3aXRoaW5nIHRoZSBncmlkIGFuZCBhIGZsb29yLCBjcmVhdGUgYW4gRWRnZSBmcm9tIGBjdXJyZW50IGNlbGwgLT4gY2VsbCBhYm92ZWAgCiAgICAgICAgICBpZihpLTE+PTAgJiYgZ3JpZFtpLTFdW2pdPT0nLicpIAogICAgICAgICAgICBnLmFkZF9lZGdlKHtpLGp9LHtpLTEsan0pOwogICAgICAgIAkKICAgICAgICAvLyBpZiBjZWxsIGJlbG93IGlzIHdpdGhpbmcgdGhlIGdyaWQgYW5kIGEgZmxvb3IsIGNyZWF0ZSBhbiBFZGdlIGZyb20gYGN1cnJlbnQgY2VsbCAtPiBjZWxsIGJlbG93YCAJCiAgICAgICAgICBpZihpKzE8biAmJiBncmlkW2krMV1bal09PScuJykgCiAgICAgICAgICAgIGcuYWRkX2VkZ2Uoe2ksan0se2krMSxqfSk7CgoJCS8vIGlmIGNlbGwgbGVmdCBpcyB3aXRoaW5nIHRoZSBncmlkIGFuZCBhIGZsb29yLCBjcmVhdGUgYW4gRWRnZSBmcm9tIGBjdXJyZW50IGNlbGwgLT4gY2VsbCBsZWZ0YCAKCQkgIGlmKGotMT49MCAmJiBncmlkW2ldW2otMV09PScuJykKICAgICAgICAgICAgZy5hZGRfZWRnZSh7aSxqfSx7aSxqLTF9KTsKICAgICAgICAgCiAgICAgICAgIC8vIGlmIGNlbGwgcmlnaHQgaXMgd2l0aGluZyB0aGUgZ3JpZCBhbmQgYSBmbG9vciwgY3JlYXRlIGFuIEVkZ2UgZnJvbSBgY3VycmVudCBjZWxsIC0+IGNlbGwgcmlnaHRgIAogICAgICAgICAgaWYoaisxPG0gJiYgZ3JpZFtpXVtqKzFdPT0nLicpCiAgICAgICAgICAgIGcuYWRkX2VkZ2Uoe2ksan0se2ksaisxfSk7CiAgICAgICAgfQogICAgICB9CiAgICAgIC8vKioqKioqKioqKioqR1JBUEggQ09OVFJVQ1RJT04gRU5EKioqKioqKioqKioqKioqKioKICAgICAgCiAgIAogICAvL1NpbmNlIHRoZSBudW1iZXIgb2Ygbm9kZXMgaXMgaGlnaCwgYW5kIHRoZSBCbGFja2JveCBCRlMgcmV0dXJucyB0aGUgdmVjdG9yIG1pbl9kaXN0IG9mIHNpemUgJ24qbScsIHJldHVybmluZyBhbiBhcnJheSBvZiBzaXplIHggdGFrZXMgdGltZSB4LiBXZSBtaWdodCBnZXQgVExFIGFzIHRoZSBCRlMgaXMgYmVpbmcgY2FsbGVkIG11bHRpcGxlIHRpbWVzLCByZXF1aXJpbmcgcmV0dXJuaW5nIG1pbl9kaXN0IG11bHRpcGxlIHRpbWVzLgogICAvL1RoZXJlZm9yZSB3ZSBuZWVkIHRvIGdvIGludG8gdGhlIEJsYWNrYm94IGFuZCByZXR1cm4gdGhlIHBvaW50ZXIgdG8gdGhlIG1pbl9kaXN0IGluc3RlYWQgb2YgdGhlIHdob2xlIGFycmF5LiBSZXR1cm5pbmcgYSBwb2ludCB0YWtlIDEgdW5pdCB0aW1lIG9ubHkuCiAgIAogIAogICBpbnQgbnVtX3Jvb21zPTA7CiAgIAogICBCRlMgYmZzKCZnKTsKICAgLy9pdGVyYXRlIHRocm91Z2ggZXZlcnkgY2VsbAogICAgZm9yKGludCBpPTA7aTxuO2krKykKICAgICAgZm9yKGludCBqPTA7ajxtO2orKyl7CiAgICAJLy9pZiB0aGUgY3VycmVudCBjZWxsIGlzIG5vdCByZWFjaGFibGUgZnJvbSBhbnkgb2YgdGhlIGNlbGwgd2UgYWxyZWFkeSBpdGVyYXRlZCwgdGhlbiB3ZSBoYXZlIGZvdW5kIGEgbmV3IHJvb20JCiAgICAgIGlmKCFiZnMuaXNfdmlzaXRlZCh7aSxqfSkgJiYgZ3JpZFtpXVtqXT09Jy4nKXsKICAgICAgICBudW1fcm9vbXMrKzsKICAgICAgICAKICAgICAgIC8vQkZTIGZyb20gYGksamAgd2lsbCB2aXNpdCBldmVyeSBjZWxsIHJlYWNoYWJsZSBmcm9tIGBpLGpgLCBha2EgaW4gdGhlIHNhbWUgY29ubmVjdGVkIGNvbXBvbmVudChyb29tKSBhcyBgaSxqYAogICAgICAgIC8vYG1pbl9kaXN0W2tdYCBmb3IgYWxsIHRoZSBub2RlcyByZWFjaGFibGUgZnJvbSBgaSxqYCB3aWxsIGJlIHRoZSBzaG9ydGVzdCBwYXRoIGxlbmd0aCBmcm9tIG5vZGUgYGksamAgdG8gbm9kZSBga2AKICAgICAgICBiZnMucnVuKHtpLGp9KTsKICAgICAgfQogICAgfQogICAgCiAgICAKICAgIGNvdXQ8PG51bV9yb29tczw8J1xuJzsKICAgIAogICAgcmV0dXJuIDA7CgoKICB9