#include <bits/stdc++.h>
#define ll long long
#define INF 1000000005
#define MOD 1000000007
#define EPS 1e-10
#define rep(i,n) for(int i=0;i<(int)(n);++i)
#define rrep(i,n) for(int i=(int)(n)-1;i>=0;--i)
#define srep(i,s,t) for(int i=(int)(s);i<(int)(t);++i)
#define each(a,b) for(auto& (a): (b))
#define all(v) (v).begin(),(v).end()
#define len(v) (int)(v).size()
#define zip(v) sort(all(v)),v.erase(unique(all(v)),v.end())
#define cmx(x,y) x=max(x,y)
#define cmn(x,y) x=min(x,y)
#define fi first
#define se second
#define pb push_back
#define show(x) cout<<#x<<" = "<<(x)<<endl
#define sar(a,n) {cout<<#a<<":";rep(pachico,n)cout<<" "<<a[pachico];cout<<endl;}
using namespace std;
template<typename S,typename T>auto&operator<<(ostream&o,pair<S,T>p){return o<<"{"<<p.fi<<","<<p.se<<"}";}
template<typename T>auto&operator<<(ostream&o,set<T>s){for(auto&e:s)o<<e<<" ";return o;}
template<typename S,typename T,typename U>
auto&operator<<(ostream&o,priority_queue<S,T,U>q){while(!q.empty())o<<q.top()<<" ",q.pop();return o;}
template<typename K,typename T>auto&operator<<(ostream&o,map<K,T>&m){for(auto&e:m)o<<e<<" ";return o;}
template<typename T>auto&operator<<(ostream&o,vector<T>v){for(auto&e:v)o<<e<<" ";return o;}
void ashow(){cout<<endl;}template<typename T,typename...A>void ashow(T t,A...a){cout<<t<<" ";ashow(a...);}
template<typename S,typename T,typename U>
struct TRI{S fi;T se;U th;TRI(){}TRI(S f,T s,U t):fi(f),se(s),th(t){}
bool operator<(const TRI&_)const{return(fi==_.fi)?((se==_.se)?(th<_.th):(se<_.se)):(fi<_.fi);}};
template<typename S,typename T,typename U>
auto&operator<<(ostream&o,TRI<S,T,U>&t){return o<<"{"<<t.fi<<","<<t.se<<","<<t.th<<"}";}
typedef pair<int, int> P;
typedef pair<ll, ll> pll;
typedef TRI<int, int, int> tri;
typedef vector<int> vi;
typedef vector<ll> vl;
typedef vector<vi> vvi;
typedef vector<vl> vvl;
typedef vector<P> vp;
typedef vector<double> vd;
typedef vector<string> vs;
const int MAX_N = 100005;
class FindingAllCycles {
private:
struct node {
int prev, next, to;
node(const int _prev, const int _next, const int _to)
: prev(_prev), next(_next), to(_to){}
};
const int V;
vector<vector<node> > G;
vector<stack<int> > block_stack;
stack<int> st;
bool *fix, *blocked, *used;
bool enumerate;
void erase_edge(const int u, const int id){
G[u][G[u][id].next].prev = G[u][id].prev;
G[u][G[u][id].prev].next = G[u][id].next;
}
void scc_dfs(const int u, int& tm, int& cnt,
vector<int>& ord, vector<int>& low, vector<int>& cmp, stack<int>& st){
ord[u] = low[u] = tm++, st.push(u);
for(int id = G[u][0].next; id != 0; id = G[u][id].next){
const int v = G[u][id].to;
if(ord[v] < 0){
scc_dfs(v, tm, cnt, ord, low, cmp, st);
low[u] = min(low[u], low[v]);
}else if(cmp[v] < 0){
low[u] = min(low[u], ord[v]);
}
if(cmp[v] >= 0) erase_edge(u, id);
}
if(ord[u] == low[u]){
while(true){
const int v = st.top();
st.pop(), cmp[v] = cnt;
if(v == u) break;
}
++cnt;
}
}
void scc(){
vector<int> ord(V, -1), low(V), cmp(V, -1);
stack<int> st;
int tm = 0, cnt = 0;
for(int i = 0; i < V; ++i){
if(ord[i] < 0) scc_dfs(i, tm, cnt, ord, low, cmp, st);
}
}
void unblock(const int u){
blocked[u] = false;
while(!block_stack[u].empty()){
const int v = block_stack[u].top();
block_stack[u].pop();
if(blocked[v]) unblock(v);
}
}
bool dfs(const int u, const int s, vector<int>& path, vector<int>& ver_list){
bool flag = false;
path.push_back(u);
blocked[u] = true;
if(!used[u]) used[u] = true, ver_list.push_back(u);
for(int id = G[u][0].next; id != 0; id = G[u][id].next){
const int v = G[u][id].to;
if(fix[v]){
erase_edge(u, id);
continue;
}
if(v == s){
if(enumerate) ans.push_back(path);
++count, flag = true;
}else if(!blocked[v]){
if(dfs(v, s, path, ver_list)) flag = true;
}
}
if(flag) unblock(u);
else{
for(int id = G[u][0].next; id != 0; id = G[u][id].next){
block_stack[G[u][id].to].push(u);
}
}
path.pop_back();
return flag;
}
public:
vector<vector<int> > ans;
int count;
FindingAllCycles(const int node_size)
: V(node_size), G(V, vector<node>{{0, 0, -1}}), block_stack(V),
fix(new bool[V]()), blocked(new bool[V]()), used(new bool[V]()), count(0){}
~FindingAllCycles(){
delete[] fix, delete[] blocked, delete[] used;
}
void add_edge(const int u, const int v){
if(u == v){
ans.push_back({u});
return;
}
G[u][0].prev = G[u].back().next = (int)G[u].size();
G[u].push_back((node){(int)G[u].size() - 1, 0, v});
}
int solve(bool _enumerate=true){
scc();
enumerate = _enumerate;
for(int i = 0; i < V; ++i){
vector<int> path, ver_list;
dfs(i, i, path, ver_list);
fix[i] = true;
for(int j : ver_list){
used[j] = blocked[j] = false, block_stack[j] = stack<int>();
}
}
return count;
}
};
template<typename T> class segtree {
private:
int n,sz;
vector<pair<T, int> > node;
public:
void resize(vector<T>& v){
sz = (int)v.size();
n = 1;
while(n < sz){
n *= 2;
}
node.resize(2*n);
for(int i = 0; i < sz; i++){
node[i+n] = make_pair(v[i], i);
}
for(int i=n-1; i>=1; i--){
node[i] = min(node[2*i], node[2*i+1]);
}
}
void update(int k, T a)
{
node[k+=n] = make_pair(a, k);
while(k>>=1){
node[k] = min(node[2*k], node[2*k+1]);
}
}
pair<T, int> query(int a,int b)
{
pair<T, int> res1 = make_pair(numeric_limits<T>::max(), -1);
pair<T, int> res2 = make_pair(numeric_limits<T>::max(), -1);
a += n, b += n;
while(a != b){
if(a % 2) res1 = min(res1, node[a++]);
if(b % 2) res2 = min(res2, node[--b]);
a >>= 1, b >>= 1;
}
return min(res1, res2);
}
};
struct edge {
int from, to, id;
edge(const int _from, const int _to, const int _id)
: from(_from), to(_to), id(_id){}
};
class LCA{
public:
int V;
vector<vector<int> > G;
vector<int> ord,depth,id;
segtree<int> st;
LCA(int node_size) : V(node_size), G(V), depth(V), id(V, -1){}
void add_edge(int from,int to){
G[from].push_back(to),G[to].push_back(from);
}
void dfs(int u,int p,int k){
id[u] = (int)ord.size();
ord.push_back(u);
depth[u] = k;
for(int v : G[u]){
if(v != p){
dfs(v,u,k+1);
ord.push_back(u);
}
}
}
void build(){
ord.reserve(2*V-2);
for(int i = 0; i < V; i++){
if(id[i] < 0){
dfs(i,-1,0);
}
}
vector<int> stvec(2*V-2);
for(int i = 0; i < 2*V-2; i++){
stvec[i] = depth[ord[i]];
}
st.resize(stvec);
}
int solve(int u,int v){
return ord[st.query(min(id[u],id[v]),max(id[u],id[v])+1).second];
}
int dist(int u,int v){
int lca = solve(u,v);
return depth[u] + depth[v] - 2*depth[lca];
}
pair<int, int> construct_virtual_tree(vector<int>& ver_list, unordered_map<int, int>& mapping);
};
vector<pair<int, int> > es;
pair<int, int> LCA::construct_virtual_tree(vector<int>& ver_list, unordered_map<int, int>& mapping){
const int n = (int)ver_list.size();
sort(ver_list.begin(), ver_list.end(), [&](const int a, const int b){
return id[a] < id[b];
});
stack<int> st;
st.push(ver_list[0]), mapping[ver_list[0]] = 0;
int id = n;
for(int i = 0; i < n-1; ++i){
const int u = solve(ver_list[i], ver_list[i+1]);
if(u != ver_list[i]){
int mapped_ver = mapping[st.top()];
while(true){
st.pop();
if(st.empty() || depth[u] >= depth[st.top()]) break;
const int tmp = mapping[st.top()];
es.push_back({tmp, mapped_ver});
mapped_ver = tmp;
}
if(st.empty() || st.top() != u){
st.push(u), ver_list.push_back(u);
es.push_back({id, mapped_ver});
mapping[u] = id++;
}else{
es.push_back({mapping[u], mapped_ver});
}
}
st.push(ver_list[i+1]), mapping[ver_list[i+1]] = i+1;
}
int mapped_ver = ((st.size() > 1) ? mapping[st.top()] : -1);
while(st.size() > 1){
st.pop();
const int tmp = mapping[st.top()];
es.push_back({tmp, mapped_ver});
mapped_ver = tmp;
}
return {id, es.size()};
}
vector<int> G[MAX_N];
int visit[MAX_N];
vector<P> ot;
vector<int> ver_list;
void dfs(const int u, const int p, LCA& lca){
visit[u] = 1;
for(const int v : G[u]){
if(v == p) continue;
if(visit[v] == 0){
lca.add_edge(u, v);
dfs(v, u, lca);
}else if(visit[v] == 1){
ver_list.push_back(u), ver_list.push_back(v);
ot.push_back({u, v});
}
}
visit[u] = 2;
}
int main()
{
cin.tie(0);
ios::sync_with_stdio(false);
int n, m;
cin >> n >> m;
rep(i, m){
int a, b;
cin >> a >> b;
--a, --b;
G[a].pb(b), G[b].pb(a);
}
if(m == n-1){
cout << "0\n";
return 0;
}
LCA lca(n);
dfs(0, -1, lca);
lca.build();
zip(ver_list);
unordered_map<int, int> mp;
auto res = lca.construct_virtual_tree(ver_list, mp);
int N = res.first, M = res.second;
FindingAllCycles fac(N);
for(const P& e : es){
fac.add_edge(e.first, e.second), fac.add_edge(e.second, e.first);
}
for(const P& p : ot){
const int u = mp[p.first], v = mp[p.second];
fac.add_edge(u, v), fac.add_edge(v, u);
++M;
}
cout << (fac.solve(false) - M) / 2 << "\n";
return 0;
}
I2luY2x1ZGUgPGJpdHMvc3RkYysrLmg+CiNkZWZpbmUgbGwgbG9uZyBsb25nCiNkZWZpbmUgSU5GIDEwMDAwMDAwMDUKI2RlZmluZSBNT0QgMTAwMDAwMDAwNwojZGVmaW5lIEVQUyAxZS0xMAojZGVmaW5lIHJlcChpLG4pIGZvcihpbnQgaT0wO2k8KGludCkobik7KytpKQojZGVmaW5lIHJyZXAoaSxuKSBmb3IoaW50IGk9KGludCkobiktMTtpPj0wOy0taSkKI2RlZmluZSBzcmVwKGkscyx0KSBmb3IoaW50IGk9KGludCkocyk7aTwoaW50KSh0KTsrK2kpCiNkZWZpbmUgZWFjaChhLGIpIGZvcihhdXRvJiAoYSk6IChiKSkKI2RlZmluZSBhbGwodikgKHYpLmJlZ2luKCksKHYpLmVuZCgpCiNkZWZpbmUgbGVuKHYpIChpbnQpKHYpLnNpemUoKQojZGVmaW5lIHppcCh2KSBzb3J0KGFsbCh2KSksdi5lcmFzZSh1bmlxdWUoYWxsKHYpKSx2LmVuZCgpKQojZGVmaW5lIGNteCh4LHkpIHg9bWF4KHgseSkKI2RlZmluZSBjbW4oeCx5KSB4PW1pbih4LHkpCiNkZWZpbmUgZmkgZmlyc3QKI2RlZmluZSBzZSBzZWNvbmQKI2RlZmluZSBwYiBwdXNoX2JhY2sKI2RlZmluZSBzaG93KHgpIGNvdXQ8PCN4PDwiID0gIjw8KHgpPDxlbmRsCiNkZWZpbmUgc2FyKGEsbikge2NvdXQ8PCNhPDwiOiI7cmVwKHBhY2hpY28sbiljb3V0PDwiICI8PGFbcGFjaGljb107Y291dDw8ZW5kbDt9Cgp1c2luZyBuYW1lc3BhY2Ugc3RkOwoKdGVtcGxhdGU8dHlwZW5hbWUgUyx0eXBlbmFtZSBUPmF1dG8mb3BlcmF0b3I8PChvc3RyZWFtJm8scGFpcjxTLFQ+cCl7cmV0dXJuIG88PCJ7Ijw8cC5maTw8IiwiPDxwLnNlPDwifSI7fQp0ZW1wbGF0ZTx0eXBlbmFtZSBUPmF1dG8mb3BlcmF0b3I8PChvc3RyZWFtJm8sc2V0PFQ+cyl7Zm9yKGF1dG8mZTpzKW88PGU8PCIgIjtyZXR1cm4gbzt9CnRlbXBsYXRlPHR5cGVuYW1lIFMsdHlwZW5hbWUgVCx0eXBlbmFtZSBVPgphdXRvJm9wZXJhdG9yPDwob3N0cmVhbSZvLHByaW9yaXR5X3F1ZXVlPFMsVCxVPnEpe3doaWxlKCFxLmVtcHR5KCkpbzw8cS50b3AoKTw8IiAiLHEucG9wKCk7cmV0dXJuIG87fQp0ZW1wbGF0ZTx0eXBlbmFtZSBLLHR5cGVuYW1lIFQ+YXV0byZvcGVyYXRvcjw8KG9zdHJlYW0mbyxtYXA8SyxUPiZtKXtmb3IoYXV0byZlOm0pbzw8ZTw8IiAiO3JldHVybiBvO30KdGVtcGxhdGU8dHlwZW5hbWUgVD5hdXRvJm9wZXJhdG9yPDwob3N0cmVhbSZvLHZlY3RvcjxUPnYpe2ZvcihhdXRvJmU6dilvPDxlPDwiICI7cmV0dXJuIG87fQp2b2lkIGFzaG93KCl7Y291dDw8ZW5kbDt9dGVtcGxhdGU8dHlwZW5hbWUgVCx0eXBlbmFtZS4uLkE+dm9pZCBhc2hvdyhUIHQsQS4uLmEpe2NvdXQ8PHQ8PCIgIjthc2hvdyhhLi4uKTt9CnRlbXBsYXRlPHR5cGVuYW1lIFMsdHlwZW5hbWUgVCx0eXBlbmFtZSBVPgpzdHJ1Y3QgVFJJe1MgZmk7VCBzZTtVIHRoO1RSSSgpe31UUkkoUyBmLFQgcyxVIHQpOmZpKGYpLHNlKHMpLHRoKHQpe30KYm9vbCBvcGVyYXRvcjwoY29uc3QgVFJJJl8pY29uc3R7cmV0dXJuKGZpPT1fLmZpKT8oKHNlPT1fLnNlKT8odGg8Xy50aCk6KHNlPF8uc2UpKTooZmk8Xy5maSk7fX07CnRlbXBsYXRlPHR5cGVuYW1lIFMsdHlwZW5hbWUgVCx0eXBlbmFtZSBVPgphdXRvJm9wZXJhdG9yPDwob3N0cmVhbSZvLFRSSTxTLFQsVT4mdCl7cmV0dXJuIG88PCJ7Ijw8dC5maTw8IiwiPDx0LnNlPDwiLCI8PHQudGg8PCJ9Ijt9Cgp0eXBlZGVmIHBhaXI8aW50LCBpbnQ+IFA7CnR5cGVkZWYgcGFpcjxsbCwgbGw+IHBsbDsKdHlwZWRlZiBUUkk8aW50LCBpbnQsIGludD4gdHJpOwp0eXBlZGVmIHZlY3RvcjxpbnQ+IHZpOwp0eXBlZGVmIHZlY3RvcjxsbD4gdmw7CnR5cGVkZWYgdmVjdG9yPHZpPiB2dmk7CnR5cGVkZWYgdmVjdG9yPHZsPiB2dmw7CnR5cGVkZWYgdmVjdG9yPFA+IHZwOwp0eXBlZGVmIHZlY3Rvcjxkb3VibGU+IHZkOwp0eXBlZGVmIHZlY3RvcjxzdHJpbmc+IHZzOwoKY29uc3QgaW50IE1BWF9OID0gMTAwMDA1OwoKY2xhc3MgRmluZGluZ0FsbEN5Y2xlcyB7CnByaXZhdGU6CiAgICBzdHJ1Y3Qgbm9kZSB7CiAgICAgICAgaW50IHByZXYsIG5leHQsIHRvOwogICAgICAgIG5vZGUoY29uc3QgaW50IF9wcmV2LCBjb25zdCBpbnQgX25leHQsIGNvbnN0IGludCBfdG8pCiAgICAgICAgICAgIDogcHJldihfcHJldiksIG5leHQoX25leHQpLCB0byhfdG8pe30KICAgIH07CiAgICBjb25zdCBpbnQgVjsKICAgIHZlY3Rvcjx2ZWN0b3I8bm9kZT4gPiBHOwogICAgdmVjdG9yPHN0YWNrPGludD4gPiBibG9ja19zdGFjazsKICAgIHN0YWNrPGludD4gc3Q7CiAgICBib29sICpmaXgsICpibG9ja2VkLCAqdXNlZDsKICAgIGJvb2wgZW51bWVyYXRlOwogICAgdm9pZCBlcmFzZV9lZGdlKGNvbnN0IGludCB1LCBjb25zdCBpbnQgaWQpewogICAgICAgIEdbdV1bR1t1XVtpZF0ubmV4dF0ucHJldiA9IEdbdV1baWRdLnByZXY7CiAgICAgICAgR1t1XVtHW3VdW2lkXS5wcmV2XS5uZXh0ID0gR1t1XVtpZF0ubmV4dDsKICAgIH0KICAgIHZvaWQgc2NjX2Rmcyhjb25zdCBpbnQgdSwgaW50JiB0bSwgaW50JiBjbnQsCiAgICAgICAgICAgIHZlY3RvcjxpbnQ+JiBvcmQsIHZlY3RvcjxpbnQ+JiBsb3csIHZlY3RvcjxpbnQ+JiBjbXAsIHN0YWNrPGludD4mIHN0KXsKICAgICAgICBvcmRbdV0gPSBsb3dbdV0gPSB0bSsrLCBzdC5wdXNoKHUpOwogICAgICAgIGZvcihpbnQgaWQgPSBHW3VdWzBdLm5leHQ7IGlkICE9IDA7IGlkID0gR1t1XVtpZF0ubmV4dCl7CiAgICAgICAgICAgIGNvbnN0IGludCB2ID0gR1t1XVtpZF0udG87CiAgICAgICAgICAgIGlmKG9yZFt2XSA8IDApewogICAgICAgICAgICAgICAgc2NjX2Rmcyh2LCB0bSwgY250LCBvcmQsIGxvdywgY21wLCBzdCk7CiAgICAgICAgICAgICAgICBsb3dbdV0gPSBtaW4obG93W3VdLCBsb3dbdl0pOwogICAgICAgICAgICB9ZWxzZSBpZihjbXBbdl0gPCAwKXsKICAgICAgICAgICAgICAgIGxvd1t1XSA9IG1pbihsb3dbdV0sIG9yZFt2XSk7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYoY21wW3ZdID49IDApIGVyYXNlX2VkZ2UodSwgaWQpOwogICAgICAgIH0KICAgICAgICBpZihvcmRbdV0gPT0gbG93W3VdKXsKICAgICAgICAgICAgd2hpbGUodHJ1ZSl7CiAgICAgICAgICAgICAgICBjb25zdCBpbnQgdiA9IHN0LnRvcCgpOwogICAgICAgICAgICAgICAgc3QucG9wKCksIGNtcFt2XSA9IGNudDsKICAgICAgICAgICAgICAgIGlmKHYgPT0gdSkgYnJlYWs7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgKytjbnQ7CiAgICAgICAgfQogICAgfQogICAgdm9pZCBzY2MoKXsKICAgICAgICB2ZWN0b3I8aW50PiBvcmQoViwgLTEpLCBsb3coViksIGNtcChWLCAtMSk7CiAgICAgICAgc3RhY2s8aW50PiBzdDsKICAgICAgICBpbnQgdG0gPSAwLCBjbnQgPSAwOwogICAgICAgIGZvcihpbnQgaSA9IDA7IGkgPCBWOyArK2kpewogICAgICAgICAgICBpZihvcmRbaV0gPCAwKSBzY2NfZGZzKGksIHRtLCBjbnQsIG9yZCwgbG93LCBjbXAsIHN0KTsKICAgICAgICB9CiAgICB9CiAgICB2b2lkIHVuYmxvY2soY29uc3QgaW50IHUpewogICAgICAgIGJsb2NrZWRbdV0gPSBmYWxzZTsKICAgICAgICB3aGlsZSghYmxvY2tfc3RhY2tbdV0uZW1wdHkoKSl7CiAgICAgICAgICAgIGNvbnN0IGludCB2ID0gYmxvY2tfc3RhY2tbdV0udG9wKCk7CiAgICAgICAgICAgIGJsb2NrX3N0YWNrW3VdLnBvcCgpOwogICAgICAgICAgICBpZihibG9ja2VkW3ZdKSB1bmJsb2NrKHYpOwogICAgICAgIH0KICAgIH0KICAgIGJvb2wgZGZzKGNvbnN0IGludCB1LCBjb25zdCBpbnQgcywgdmVjdG9yPGludD4mIHBhdGgsIHZlY3RvcjxpbnQ+JiB2ZXJfbGlzdCl7CiAgICAgICAgYm9vbCBmbGFnID0gZmFsc2U7CiAgICAgICAgcGF0aC5wdXNoX2JhY2sodSk7CiAgICAgICAgYmxvY2tlZFt1XSA9IHRydWU7CiAgICAgICAgaWYoIXVzZWRbdV0pIHVzZWRbdV0gPSB0cnVlLCB2ZXJfbGlzdC5wdXNoX2JhY2sodSk7CiAgICAgICAgZm9yKGludCBpZCA9IEdbdV1bMF0ubmV4dDsgaWQgIT0gMDsgaWQgPSBHW3VdW2lkXS5uZXh0KXsKICAgICAgICAgICAgY29uc3QgaW50IHYgPSBHW3VdW2lkXS50bzsKICAgICAgICAgICAgaWYoZml4W3ZdKXsKICAgICAgICAgICAgICAgIGVyYXNlX2VkZ2UodSwgaWQpOwogICAgICAgICAgICAgICAgY29udGludWU7CiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYodiA9PSBzKXsKICAgICAgICAgICAgICAgIGlmKGVudW1lcmF0ZSkgYW5zLnB1c2hfYmFjayhwYXRoKTsKICAgICAgICAgICAgICAgICsrY291bnQsIGZsYWcgPSB0cnVlOwogICAgICAgICAgICB9ZWxzZSBpZighYmxvY2tlZFt2XSl7CiAgICAgICAgICAgICAgICBpZihkZnModiwgcywgcGF0aCwgdmVyX2xpc3QpKSBmbGFnID0gdHJ1ZTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBpZihmbGFnKSB1bmJsb2NrKHUpOwogICAgICAgIGVsc2V7CiAgICAgICAgICAgIGZvcihpbnQgaWQgPSBHW3VdWzBdLm5leHQ7IGlkICE9IDA7IGlkID0gR1t1XVtpZF0ubmV4dCl7CiAgICAgICAgICAgICAgICBibG9ja19zdGFja1tHW3VdW2lkXS50b10ucHVzaCh1KTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICBwYXRoLnBvcF9iYWNrKCk7CiAgICAgICAgcmV0dXJuIGZsYWc7CiAgICB9CgpwdWJsaWM6CiAgICB2ZWN0b3I8dmVjdG9yPGludD4gPiBhbnM7CiAgICBpbnQgY291bnQ7CiAgICBGaW5kaW5nQWxsQ3ljbGVzKGNvbnN0IGludCBub2RlX3NpemUpCiAgICAgICAgOiBWKG5vZGVfc2l6ZSksIEcoViwgdmVjdG9yPG5vZGU+e3swLCAwLCAtMX19KSwgYmxvY2tfc3RhY2soViksCiAgICAgICAgICAgIGZpeChuZXcgYm9vbFtWXSgpKSwgYmxvY2tlZChuZXcgYm9vbFtWXSgpKSwgdXNlZChuZXcgYm9vbFtWXSgpKSwgY291bnQoMCl7fQogICAgfkZpbmRpbmdBbGxDeWNsZXMoKXsKICAgICAgICBkZWxldGVbXSBmaXgsIGRlbGV0ZVtdIGJsb2NrZWQsIGRlbGV0ZVtdIHVzZWQ7CiAgICB9CiAgICB2b2lkIGFkZF9lZGdlKGNvbnN0IGludCB1LCBjb25zdCBpbnQgdil7CiAgICAgICAgaWYodSA9PSB2KXsKICAgICAgICAgICAgYW5zLnB1c2hfYmFjayh7dX0pOwogICAgICAgICAgICByZXR1cm47CiAgICAgICAgfQogICAgICAgIEdbdV1bMF0ucHJldiA9IEdbdV0uYmFjaygpLm5leHQgPSAoaW50KUdbdV0uc2l6ZSgpOwogICAgICAgIEdbdV0ucHVzaF9iYWNrKChub2RlKXsoaW50KUdbdV0uc2l6ZSgpIC0gMSwgMCwgdn0pOwogICAgfQogICAgaW50IHNvbHZlKGJvb2wgX2VudW1lcmF0ZT10cnVlKXsKICAgICAgICBzY2MoKTsKICAgICAgICBlbnVtZXJhdGUgPSBfZW51bWVyYXRlOwogICAgICAgIGZvcihpbnQgaSA9IDA7IGkgPCBWOyArK2kpewogICAgICAgICAgICB2ZWN0b3I8aW50PiBwYXRoLCB2ZXJfbGlzdDsKICAgICAgICAgICAgZGZzKGksIGksIHBhdGgsIHZlcl9saXN0KTsKICAgICAgICAgICAgZml4W2ldID0gdHJ1ZTsKICAgICAgICAgICAgZm9yKGludCBqIDogdmVyX2xpc3QpewogICAgICAgICAgICAgICAgdXNlZFtqXSA9IGJsb2NrZWRbal0gPSBmYWxzZSwgYmxvY2tfc3RhY2tbal0gPSBzdGFjazxpbnQ+KCk7CiAgICAgICAgICAgIH0KICAgICAgICB9CiAgICAgICAgcmV0dXJuIGNvdW50OwogICAgfQp9OwoKdGVtcGxhdGU8dHlwZW5hbWUgVD4gY2xhc3Mgc2VndHJlZSB7CnByaXZhdGU6CiAgICBpbnQgbixzejsKICAgIHZlY3RvcjxwYWlyPFQsIGludD4gPiBub2RlOwpwdWJsaWM6CiAgICB2b2lkIHJlc2l6ZSh2ZWN0b3I8VD4mIHYpewogICAgICAgIHN6ID0gKGludCl2LnNpemUoKTsKICAgICAgICBuID0gMTsKICAgICAgICB3aGlsZShuIDwgc3opewogICAgICAgICAgICBuICo9IDI7CiAgICAgICAgfQogICAgICAgIG5vZGUucmVzaXplKDIqbik7CiAgICAgICAgZm9yKGludCBpID0gMDsgaSA8IHN6OyBpKyspewogICAgICAgICAgICBub2RlW2krbl0gPSBtYWtlX3BhaXIodltpXSwgaSk7CiAgICAgICAgfQogICAgICAgIGZvcihpbnQgaT1uLTE7IGk+PTE7IGktLSl7CiAgICAgICAgICAgIG5vZGVbaV0gPSBtaW4obm9kZVsyKmldLCBub2RlWzIqaSsxXSk7CiAgICAgICAgfQogICAgfQogICAgdm9pZCB1cGRhdGUoaW50IGssIFQgYSkKICAgIHsKICAgIAlub2RlW2srPW5dID0gbWFrZV9wYWlyKGEsIGspOwogICAgCXdoaWxlKGs+Pj0xKXsKICAgICAgICAgICAgbm9kZVtrXSA9IG1pbihub2RlWzIqa10sIG5vZGVbMiprKzFdKTsKICAgIAl9CiAgICB9CiAgICBwYWlyPFQsIGludD4gcXVlcnkoaW50IGEsaW50IGIpCiAgICB7CiAgICAgICAgcGFpcjxULCBpbnQ+IHJlczEgPSBtYWtlX3BhaXIobnVtZXJpY19saW1pdHM8VD46Om1heCgpLCAtMSk7CiAgICAgICAgcGFpcjxULCBpbnQ+IHJlczIgPSBtYWtlX3BhaXIobnVtZXJpY19saW1pdHM8VD46Om1heCgpLCAtMSk7CiAgICAgICAgYSArPSBuLCBiICs9IG47CiAgICAgICAgd2hpbGUoYSAhPSBiKXsKICAgICAgICAgICAgaWYoYSAlIDIpIHJlczEgPSBtaW4ocmVzMSwgbm9kZVthKytdKTsKICAgICAgICAgICAgaWYoYiAlIDIpIHJlczIgPSBtaW4ocmVzMiwgbm9kZVstLWJdKTsKICAgICAgICAgICAgYSA+Pj0gMSwgYiA+Pj0gMTsKICAgICAgICB9CiAgICAgICAgcmV0dXJuIG1pbihyZXMxLCByZXMyKTsKICAgIH0KfTsKCnN0cnVjdCBlZGdlIHsKICAgIGludCBmcm9tLCB0bywgaWQ7CiAgICBlZGdlKGNvbnN0IGludCBfZnJvbSwgY29uc3QgaW50IF90bywgY29uc3QgaW50IF9pZCkKICAgICAgICA6IGZyb20oX2Zyb20pLCB0byhfdG8pLCBpZChfaWQpe30KfTsKCmNsYXNzIExDQXsKcHVibGljOgogICAgaW50IFY7CiAgICB2ZWN0b3I8dmVjdG9yPGludD4gPiBHOwogICAgdmVjdG9yPGludD4gb3JkLGRlcHRoLGlkOwogICAgc2VndHJlZTxpbnQ+IHN0OwogICAgTENBKGludCBub2RlX3NpemUpIDogVihub2RlX3NpemUpLCBHKFYpLCBkZXB0aChWKSwgaWQoViwgLTEpe30KICAgIHZvaWQgYWRkX2VkZ2UoaW50IGZyb20saW50IHRvKXsKICAgICAgICBHW2Zyb21dLnB1c2hfYmFjayh0byksR1t0b10ucHVzaF9iYWNrKGZyb20pOwogICAgfQogICAgdm9pZCBkZnMoaW50IHUsaW50IHAsaW50IGspewogICAgICAgIGlkW3VdID0gKGludClvcmQuc2l6ZSgpOwogICAgICAgIG9yZC5wdXNoX2JhY2sodSk7CiAgICAgICAgZGVwdGhbdV0gPSBrOwogICAgICAgIGZvcihpbnQgdiA6IEdbdV0pewogICAgICAgICAgICBpZih2ICE9IHApewogICAgICAgICAgICAgICAgZGZzKHYsdSxrKzEpOwogICAgICAgICAgICAgICAgb3JkLnB1c2hfYmFjayh1KTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgIH0KICAgIHZvaWQgYnVpbGQoKXsKICAgICAgICBvcmQucmVzZXJ2ZSgyKlYtMik7CiAgICAgICAgZm9yKGludCBpID0gMDsgaSA8IFY7IGkrKyl7CiAgICAgICAgICAgIGlmKGlkW2ldIDwgMCl7CiAgICAgICAgICAgICAgICBkZnMoaSwtMSwwKTsKICAgICAgICAgICAgfQogICAgICAgIH0KICAgICAgICB2ZWN0b3I8aW50PiBzdHZlYygyKlYtMik7CiAgICAJZm9yKGludCBpID0gMDsgaSA8IDIqVi0yOyBpKyspewogICAgCQlzdHZlY1tpXSA9IGRlcHRoW29yZFtpXV07CiAgICAJfQogICAgICAgIHN0LnJlc2l6ZShzdHZlYyk7CiAgICB9CiAgICBpbnQgc29sdmUoaW50IHUsaW50IHYpewogICAgICAgIHJldHVybiBvcmRbc3QucXVlcnkobWluKGlkW3VdLGlkW3ZdKSxtYXgoaWRbdV0saWRbdl0pKzEpLnNlY29uZF07CiAgICB9CiAgICBpbnQgZGlzdChpbnQgdSxpbnQgdil7CiAgICAgICAgaW50IGxjYSA9IHNvbHZlKHUsdik7CiAgICAgICAgcmV0dXJuIGRlcHRoW3VdICsgZGVwdGhbdl0gLSAyKmRlcHRoW2xjYV07CiAgICB9CiAgICBwYWlyPGludCwgaW50PiBjb25zdHJ1Y3RfdmlydHVhbF90cmVlKHZlY3RvcjxpbnQ+JiB2ZXJfbGlzdCwgdW5vcmRlcmVkX21hcDxpbnQsIGludD4mIG1hcHBpbmcpOwp9OwoKdmVjdG9yPHBhaXI8aW50LCBpbnQ+ID4gZXM7CgpwYWlyPGludCwgaW50PiBMQ0E6OmNvbnN0cnVjdF92aXJ0dWFsX3RyZWUodmVjdG9yPGludD4mIHZlcl9saXN0LCB1bm9yZGVyZWRfbWFwPGludCwgaW50PiYgbWFwcGluZyl7CiAgICBjb25zdCBpbnQgbiA9IChpbnQpdmVyX2xpc3Quc2l6ZSgpOwogICAgc29ydCh2ZXJfbGlzdC5iZWdpbigpLCB2ZXJfbGlzdC5lbmQoKSwgWyZdKGNvbnN0IGludCBhLCBjb25zdCBpbnQgYil7CiAgICAgICAgcmV0dXJuIGlkW2FdIDwgaWRbYl07CiAgICB9KTsKICAgIHN0YWNrPGludD4gc3Q7CiAgICBzdC5wdXNoKHZlcl9saXN0WzBdKSwgbWFwcGluZ1t2ZXJfbGlzdFswXV0gPSAwOwogICAgaW50IGlkID0gbjsKICAgIGZvcihpbnQgaSA9IDA7IGkgPCBuLTE7ICsraSl7CiAgICAgICAgY29uc3QgaW50IHUgPSBzb2x2ZSh2ZXJfbGlzdFtpXSwgdmVyX2xpc3RbaSsxXSk7CiAgICAgICAgaWYodSAhPSB2ZXJfbGlzdFtpXSl7CiAgICAgICAgICAgIGludCBtYXBwZWRfdmVyID0gbWFwcGluZ1tzdC50b3AoKV07CiAgICAgICAgICAgIHdoaWxlKHRydWUpewogICAgICAgICAgICAgICAgc3QucG9wKCk7CiAgICAgICAgICAgICAgICBpZihzdC5lbXB0eSgpIHx8IGRlcHRoW3VdID49IGRlcHRoW3N0LnRvcCgpXSkgYnJlYWs7CiAgICAgICAgICAgICAgICBjb25zdCBpbnQgdG1wID0gbWFwcGluZ1tzdC50b3AoKV07CiAgICAgICAgICAgICAgICBlcy5wdXNoX2JhY2soe3RtcCwgbWFwcGVkX3Zlcn0pOwogICAgICAgICAgICAgICAgbWFwcGVkX3ZlciA9IHRtcDsgCiAgICAgICAgICAgIH0KICAgICAgICAgICAgaWYoc3QuZW1wdHkoKSB8fCBzdC50b3AoKSAhPSB1KXsKICAgICAgICAgICAgICAgIHN0LnB1c2godSksIHZlcl9saXN0LnB1c2hfYmFjayh1KTsKICAgICAgICAgICAgICAgIGVzLnB1c2hfYmFjayh7aWQsIG1hcHBlZF92ZXJ9KTsKICAgICAgICAgICAgICAgIG1hcHBpbmdbdV0gPSBpZCsrOwogICAgICAgICAgICB9ZWxzZXsKICAgICAgICAgICAgICAgIGVzLnB1c2hfYmFjayh7bWFwcGluZ1t1XSwgbWFwcGVkX3Zlcn0pOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHN0LnB1c2godmVyX2xpc3RbaSsxXSksIG1hcHBpbmdbdmVyX2xpc3RbaSsxXV0gPSBpKzE7CiAgICB9CiAgICBpbnQgbWFwcGVkX3ZlciA9ICgoc3Quc2l6ZSgpID4gMSkgPyBtYXBwaW5nW3N0LnRvcCgpXSA6IC0xKTsKICAgIHdoaWxlKHN0LnNpemUoKSA+IDEpewogICAgICAgIHN0LnBvcCgpOwogICAgICAgIGNvbnN0IGludCB0bXAgPSBtYXBwaW5nW3N0LnRvcCgpXTsKICAgICAgICBlcy5wdXNoX2JhY2soe3RtcCwgbWFwcGVkX3Zlcn0pOwogICAgICAgIG1hcHBlZF92ZXIgPSB0bXA7CiAgICB9CiAgICByZXR1cm4ge2lkLCBlcy5zaXplKCl9Owp9Cgp2ZWN0b3I8aW50PiBHW01BWF9OXTsKaW50IHZpc2l0W01BWF9OXTsKdmVjdG9yPFA+IG90Owp2ZWN0b3I8aW50PiB2ZXJfbGlzdDsKCnZvaWQgZGZzKGNvbnN0IGludCB1LCBjb25zdCBpbnQgcCwgTENBJiBsY2EpewogICAgdmlzaXRbdV0gPSAxOwogICAgZm9yKGNvbnN0IGludCB2IDogR1t1XSl7CiAgICAgICAgaWYodiA9PSBwKSBjb250aW51ZTsKICAgICAgICBpZih2aXNpdFt2XSA9PSAwKXsKICAgICAgICAgICAgbGNhLmFkZF9lZGdlKHUsIHYpOwogICAgICAgICAgICBkZnModiwgdSwgbGNhKTsKICAgICAgICB9ZWxzZSBpZih2aXNpdFt2XSA9PSAxKXsKICAgICAgICAgICAgdmVyX2xpc3QucHVzaF9iYWNrKHUpLCB2ZXJfbGlzdC5wdXNoX2JhY2sodik7CiAgICAgICAgICAgIG90LnB1c2hfYmFjayh7dSwgdn0pOwogICAgICAgIH0KICAgIH0KICAgIHZpc2l0W3VdID0gMjsKfQoKaW50IG1haW4oKQp7CiAgICBjaW4udGllKDApOwogICAgaW9zOjpzeW5jX3dpdGhfc3RkaW8oZmFsc2UpOwogICAgaW50IG4sIG07CiAgICBjaW4gPj4gbiA+PiBtOwogICAgcmVwKGksIG0pewogICAgICAgIGludCBhLCBiOwogICAgICAgIGNpbiA+PiBhID4+IGI7CiAgICAgICAgLS1hLCAtLWI7CiAgICAgICAgR1thXS5wYihiKSwgR1tiXS5wYihhKTsKICAgIH0KICAgIGlmKG0gPT0gbi0xKXsKICAgICAgICBjb3V0IDw8ICIwXG4iOwogICAgICAgIHJldHVybiAwOwogICAgfQogICAgTENBIGxjYShuKTsKICAgIGRmcygwLCAtMSwgbGNhKTsKICAgIGxjYS5idWlsZCgpOwogICAgemlwKHZlcl9saXN0KTsKICAgIHVub3JkZXJlZF9tYXA8aW50LCBpbnQ+IG1wOwogICAgYXV0byByZXMgPSBsY2EuY29uc3RydWN0X3ZpcnR1YWxfdHJlZSh2ZXJfbGlzdCwgbXApOwogICAgaW50IE4gPSByZXMuZmlyc3QsIE0gPSByZXMuc2Vjb25kOwogICAgRmluZGluZ0FsbEN5Y2xlcyBmYWMoTik7CiAgICBmb3IoY29uc3QgUCYgZSA6IGVzKXsKICAgICAgICBmYWMuYWRkX2VkZ2UoZS5maXJzdCwgZS5zZWNvbmQpLCBmYWMuYWRkX2VkZ2UoZS5zZWNvbmQsIGUuZmlyc3QpOwogICAgfQogICAgZm9yKGNvbnN0IFAmIHAgOiBvdCl7CiAgICAgICAgY29uc3QgaW50IHUgPSBtcFtwLmZpcnN0XSwgdiA9IG1wW3Auc2Vjb25kXTsKICAgICAgICBmYWMuYWRkX2VkZ2UodSwgdiksIGZhYy5hZGRfZWRnZSh2LCB1KTsKICAgICAgICArK007CiAgICB9CiAgICBjb3V0IDw8IChmYWMuc29sdmUoZmFsc2UpIC0gTSkgLyAyIDw8ICJcbiI7CiAgICByZXR1cm4gMDsKfQo=