#pragma GCC optimize("O3")
//#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("Ofast")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include<bits/stdc++.h>
using namespace std;
#define bll __int128
#define ll long long
#define ld  double
#define pii pair<int,int>
#define pip pair<int,pii>
#define ppi pair<pii,int>
#define ppp pair<pii,pii>
#define pb push_back
#define ppb pop_back
#define pf push_front
#define ppf pop_front
#define ff first
#define ss second
#define warmup ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
const int N = 200003, mod=1e9+7;
const ll inf=(1e18+11);
int freq[26], indeg[26], pres[26];
unordered_set<int> g[26];
string ans;

void dfs(int i)
{
    bool f=0;
    ans+=(char)(i+'a');

    for(auto it:g[i])
    {
        if(f)
            ans+=(char)(i+'a');

        --indeg[it];
        if(!indeg[it])
            --indeg[it];

        dfs(it);
        f=1;
    }
}

signed main()
{
    warmup

    int n;
    cin>>n;
    int i,j,x,y,sz;
    char ch;
    string s;
    for(j=0;j<n;++j)
    {
        cin>>s;
        sz=s.size();
        fill(freq,freq+26,0);
        freq[s[0]-'a']++;
        pres[s[0]-'a']++;
        for(i=1;i<sz;++i)
        {
            if(g[s[i]-'a'].count(s[i-1]-'a'))
                return cout<<"NO", 0;
            g[s[i-1]-'a'].insert(s[i]-'a');
            ++freq[s[i]-'a'];
            ++indeg[s[i]-'a'];
            pres[s[i]-'a']++;
        }

        for(i=0;i<26;++i)
            if(freq[i]>1)
                return cout<<"NO", 0;
    }

    ans="";
    for(i=0;i<26;++i)
        if(pres[i] and !indeg[i])
            dfs(i);

    fill(freq,freq+26,0);
    sz=ans.size();
    for(i=0;i<sz;++i)
        freq[ans[i]-'a']++;

    x=0;
    for(i=0;i<26;++i)
    {
        if(pres[i] and !freq[i])
            return cout<<"NO", 0;

        if(!freq[i] or freq[i]==x)
            continue;
        else if(!x)
            x=freq[i];
        else
            return cout<<"NO", 0;
    }

    if(!ans.size())
        ans="NO";

    cout<<ans;

    return 0;
}


#pragma GCC optimize("O3")
//#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("Ofast")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include<bits/stdc++.h>
using namespace std;
#define bll __int128
#define ll long long
#define ld  double
#define pii pair<int,int>
#define pip pair<int,pii>
#define ppi pair<pii,int>
#define ppp pair<pii,pii>
#define pb push_back
#define ppb pop_back
#define pf push_front
#define ppf pop_front
#define ff first
#define ss second
#define warmup ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
const int N = 200003, mod=1e9+7;
const ll inf=(1e18+11);
int freq[26], indeg[26], pres[26];
unordered_set<int> g[26];
string ans;

void dfs(int i)
{
    bool f=0;
    ans+=(char)(i+'a');

    for(auto it:g[i])
    {
        if(f)
            ans+=(char)(i+'a');

        --indeg[it];
        if(!indeg[it])
            --indeg[it];

        dfs(it);
        f=1;
    }
}

signed main()
{
    warmup

    int n;
    cin>>n;
    int i,j,x,y,sz;
    char ch;
    string s;
    for(j=0;j<n;++j)
    {
        cin>>s;
        sz=s.size();
        fill(freq,freq+26,0);
        freq[s[0]-'a']++;
        pres[s[0]-'a']++;
        for(i=1;i<sz;++i)
        {
            if(g[s[i]-'a'].count(s[i-1]-'a'))
                return cout<<"NO", 0;
            g[s[i-1]-'a'].insert(s[i]-'a');
            ++freq[s[i]-'a'];
            ++indeg[s[i]-'a'];
            pres[s[i]-'a']++;
        }

        for(i=0;i<26;++i)
            if(freq[i]>1)
                return cout<<"NO", 0;
    }

    ans="";
    for(i=0;i<26;++i)
        if(pres[i] and !indeg[i])
            dfs(i);

    fill(freq,freq+26,0);
    sz=ans.size();
    for(i=0;i<sz;++i)
        freq[ans[i]-'a']++;

    x=0;
    for(i=0;i<26;++i)
    {
        if(!freq[i] or freq[i]==x)
            continue;
        else if(!x)
            x=freq[i];
        else
            return cout<<"NO", 0;
    }

    if(!ans.size())
        ans="NO";

    cout<<ans;

    return 0;
}


#pragma GCC optimize("O3")
//#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("Ofast")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include<bits/stdc++.h>
using namespace std;
#define bll __int128
#define ll long long
#define ld  double
#define pii pair<int,int>
#define pip pair<int,pii>
#define ppi pair<pii,int>
#define ppp pair<pii,pii>
#define pb push_back
#define ppb pop_back
#define pf push_front
#define ppf pop_front
#define ff first
#define ss second
#define warmup ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
const int N = 200003, mod=1e9+7;
const ll inf=(1e18+11);
int freq[26], indeg[26], pres[26];
unordered_set<int> g[26];
string ans;

void dfs(int i)
{
    bool f=0;
    ans+=(char)(i+'a');

    for(auto it:g[i])
    {
        if(f)
            ans+=(char)(i+'a');

        --indeg[it];
        if(!indeg[it])
            --indeg[it];

        dfs(it);
        f=1;
    }
}

signed main()
{
    warmup

    int n;
    cin>>n;
    int i,j,x,y,sz;
    char ch;
    string s;
    for(j=0;j<n;++j)
    {
        cin>>s;
        sz=s.size();
        fill(freq,freq+26,0);
        freq[s[0]-'a']++;
        pres[s[0]-'a']=1;
        for(i=1;i<sz;++i)
            g[s[i-1]-'a'].insert(s[i]-'a'), ++freq[s[i]-'a'], ++indeg[s[i]-'a'], pres[s[i]-'a']=1;

        for(i=0;i<26;++i)
            if(freq[i]>1)
                return cout<<"NO", 0;
    }

    ans="";
    for(i=0;i<26;++i)
        if(pres[i] and !indeg[i])
            dfs(i);
    cout<<ans;

    return 0;
}


#include <bits/stdc++.h>

//#include <ext/pb_ds/tree_policy.hpp>
//#include <ext/pb_ds/assoc_container.hpp>

#pragma GCC optimize("Ofast")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
//#define INF 0x3F3F3F3F
using namespace std;
//using namespace __gnu_pbds;
//template <class T> using Tree = tree<T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;
typedef long long ll;
typedef long double ld;
//#define f first
//#define s second/
const ll mod = 1e9 + 7;
const int phash = 3;
const ll modhash = 1000000000000000003;
const ll INF = 1e12;

string s[100005];
bool used[26];
bool cnt[100005][26];

set <int> g[26], gr[26];
int main()
{
    //freopen("input.txt","r",stdin);
   // freopen("output.txt","w",stdout);
    ios_base::sync_with_stdio(false);

    int n;
    cin >> n;

    for (int i = 0; i < n; i++)
    {
        cin >> s[i];

        for (int j = 0; j < s[i].size(); j++)
        {
            used[s[i][j] - 'a'] = true;
            if (cnt[i][s[i][j] - 'a'])
            {
                cout << "NO";
                return 0;
            }
            cnt[i][s[i][j] - 'a'] = true;
        }
    }

    for (int i = 0; i < n; i++)
        for (int j = 0; j < s[i].size() - 1; j++)
        {
            g[s[i][j] - 'a'].insert(s[i][j + 1] - 'a');
            gr[s[i][j + 1] - 'a'].insert(s[i][j] - 'a');
        }

    for (int i = 0; i < 26; i++)
        if (g[i].size() > 1)
        {
            cout << "NO";
            return 0;
        }

    vector <string> ans;

    for (int i = 0; i < 26; i++)
    {
        if (used[i] && !gr[i].size())
        {
            string cur;
            int pos = i;

            while (true)
            {
                used[pos] = false;
                cur += (char)('a' + pos);

                if (!g[pos].size())
                    break;

                if (!used[*g[pos].begin()])
                {
                    cout << "NO";
                    return 0;
                }

                pos = *g[pos].begin();
            }

            ans.push_back(cur);
        }
    }

    for (int i = 0; i < 26; i++)
        if (used[i])
        {
            cout << "NO";
            return 0;
        }

    sort(ans.begin(), ans.end());
    for (auto it : ans)
        cout << it;
}


#include <bits/stdc++.h>

//#include <ext/pb_ds/tree_policy.hpp>
//#include <ext/pb_ds/assoc_container.hpp>

#pragma GCC optimize("Ofast")
#pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
//#define INF 0x3F3F3F3F
using namespace std;
//using namespace __gnu_pbds;
//template <class T> using Tree = tree<T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;
typedef long long ll;
typedef long double ld;
//#define f first
//#define s second/
const ll mod = 1e9 + 7;
const int phash = 3;
const ll modhash = 1000000000000000003;
const ll INF = 1e12;

string s[100005];
bool used[26];
bool cnt[100005][26];

set <int> g[26], gr[26];
int main()
{
    //freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    ios_base::sync_with_stdio(false);

    int n;
    cin >> n;

    for (int i = 0; i < n; i++)
    {
        cin >> s[i];

        for (int j = 0; j < s[i].size(); j++)
        {
            used[s[i][j] - 'a'] = true;
            if (cnt[i][s[i][j] - 'a'])
            {
                cout << "NO";
                return 0;
            }
            cnt[i][s[i][j] - 'a'] = true;
        }
    }

    for (int i = 0; i < n; i++)
        for (int j = 0; j < s[i].size() - 1; j++)
        {
            g[s[i][j] - 'a'].insert(s[i][j + 1] - 'a');
            gr[s[i][j + 1] - 'a'].insert(s[i][j] - 'a');
        }

    for (int i = 0; i < 26; i++)
        if (g[i].size() > 1)
        {
            cout << "NO";
            return 0;
        }

    vector <string> ans;

    for (int i = 0; i < 26; i++)
    {
        if (used[i] && !gr[i].size())
        {
            string cur;
            int pos = i;

            while (true)
            {
                used[pos] = false;
                cur += (char)('a' + pos);

                if (!g[pos].size())
                    break;

                if (!used[*g[pos].begin()])
                {
                    cout << "NO";
                    return 0;
                }

                pos = *g[pos].begin();
            }

            ans.push_back(cur);
        }
    }

    sort(ans.begin(), ans.end());
    for (auto it : ans)
        cout << it;
}


#include <bits/stdc++.h>
#define LL long long
#define PII pair<int, int>
const int MAXN = 100005;
using namespace std;

void goodbye() {
	cout << "NO\n";
	exit(EXIT_SUCCESS);
}

void check_occ(const string &s) {
	int occ[26] = {0};
	for (char c : s) {
		occ[c - 'a']++;
		if (occ[c - 'a'] > 1) {
			goodbye();
		}
	}
}

string merge(string s1, string s2) {
	int occ[26];
	fill(occ, occ + 26, -1);
	for (int i = 0; i < s1.size(); i++) {
		occ[s1[i] - 'a'] = i;
	}

	int pos1 = -1, pos2 = -1;
	for (int i = 0; i < s2.size(); i++) {
		if (occ[s2[i] - 'a'] != -1) {
			pos1 = occ[s2[i] - 'a'];
			pos2 = i;
			break;
		}
	}
	if (pos1 == -1) {
		return string();
	}
	if (pos1 < pos2) {
		swap(pos1, pos2);
		swap(s1, s2);
	}

	for (int i = 0; pos1 - i >= 0 && pos2 - i >= 0; i++) {
		if (s1[pos1 - i] != s2[pos2 - i]) {
			goodbye();
		}
	}
	for (int i = 0; pos1 + i < s1.size() && pos2 + i < s2.size(); i++) {
		if (s1[pos1 + i] != s2[pos2 + i]) {
			goodbye();
		}
	}

	string res = s1;
	if (s1.size() - pos1 >= s2.size() - pos2) {
		return s1;
	}
	for (int i = pos2 + (s1.size() - pos1); i < s2.size(); i++) {
		res.push_back(s2[i]);
	}
	check_occ(res);

	return res;
}

int N;
vector<string> vec;

void add(string s) {
	for (int i = 0; i < vec.size(); i++) {
		string m = merge(s, vec[i]);
		if (!m.empty()) {
			swap(vec[i], vec.back());
			vec.pop_back();
			add(m);
			return;
		}
	}
	vec.push_back(s);
}

int main() {
	ios_base::sync_with_stdio(0); cin.tie(0);

	cin >> N;
	for (int i = 0; i < N; i++) {
		string s;
		cin >> s;
		check_occ(s);
		add(s);
	}

	sort(vec.begin(), vec.end());
	for (string s : vec) {
		cout << s;
	}
	cout << '\n';
}


#include <iostream>
#include <string.h>
#include <algorithm>
#include <numeric>
using namespace std;

const int maxN = 1e5 + 326, W = 326;
int nxt[W], prv[W], N, head, dsu[maxN];

string s, pot[maxN];
bool vis[maxN], appear[W];

void Flat(int x){
	if(x == dsu[x]) return;
	Flat(dsu[x]);
	dsu[x] = dsu[dsu[x]];
}

bool Merge(int a, int b){
	Flat(a);
	Flat(b);
	if(dsu[a] == dsu[b]) return false;
	dsu[dsu[a]] = dsu[b];
	return true;
}

inline bool link(char a, char b){
	if(nxt[a] == b && prv[b] == a) return true;
	if((nxt[a] && nxt[a] != b) || (prv[b] && prv[b] != a)) return false;
	if(!Merge(a, b)) return false;
	nxt[a] = b;
	prv[b] = a;
	return true;
}

int main(){
	cin >> N;
	bool f = true;
	iota(dsu, dsu + W, 0);
	while(N--){
		cin >> s;
		for(char c : s) appear[c] = true;
		for(int i = 0; i < s.length() - 1; i++) f &= link(s[i], s[i + 1]);
	}
	if(!f){
		cout << "NO" << endl;
		return 0;
	}
	for(int i = 'a'; i <= 'z'; i++){
		if(!appear[i]) continue;
		if(!prv[i]){
			string tmp = "";
			int k = i;
			while(k){
				tmp += (char)k;
				k = nxt[k];
			}
			pot[head++] = tmp;
		}
	}
	sort(pot, pot + head);
	for(int i = 0; i < head; i++) cout << pot[i];
}


#include <bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define endl "\n"
#define mod 1000000007
// #define int long long
#define ll long long
#define EPS 0.000000001
#define ld long double
#define PI 3.14159265358979323846
#define inf 10000000
const int N = 500000;

set<string> ans;
set<int> alive;
vector<string> v;
vector<set<int>>  g(26);

int fposi(string& s,char z)
{
    for(int i = 0;i < s.length();i++)
        if(s[i] == z)
            return i;
    return -1;
}
void fail()
{
    cout << "NO";
    exit(0);
}
void check(string& s)
{
    vector<int> f(26,0);
    for(int i = 0;i < s.length();i++)
    {
        f[s[i]-'a']++;
        if(f[s[i]-'a'] == 2)
            fail();
    }

}
string func(string& s,string& t,char z)
{
    int posa = fposi(s,z);
    int posb = fposi(t,z);
    // cerr << posa << " " << posb << endl;
    int i = posa;
    int j = posb;
    while(i < s.length() and j < t.length())
    {
        if(s[i] == t[j])
        {
            i++;
            j++;
        }
        else
            fail();
    }

    while(j < t.length())
    {
        s += t[j];
        j++;
    }
    // cerr << j << " " << s << endl;
    i = posa;
    j = posb;
    while(i >= 0 and j >= 0)
    {
        if(s[i] == t[j])
        {
            i--;
            j--;
        }
        else
            fail();
    }
    // cerr << i << " " << j << endl;
    string temp = "";
    int k = 0;
    while(k <= j)
    {
        temp += t[k];
        k++;
    }
    // cerr << s << " " << temp << endl;
    s = temp + s;

    return s;
}

void process(int i)
{
    alive.erase(i);
    string s = v[i];
    // cerr << s << endl;
    set<int> pr;
    set<int> rm;
    for(int j = 0;j < s.length();j++)
        pr.insert(s[j]-'a');
    while(!pr.empty())
    {
        int f = *pr.begin();
        for(auto it : g[f])
        {
            if(alive.find(it) != alive.end())
            {
                string t = v[it];
                alive.erase(it);
                // cerr << s << " " << t << endl;
                s = func(s,t,(char)(f+97));
                // cerr << s <<  " " << t << endl;
                check(s);
            }
        }
        pr.erase(pr.begin());
        rm.insert(f);
        for(int j = 0;j < s.length();j++)
        {
            int x = s[j] - 'a';
            if(rm.find(x) == rm.end())
                pr.insert(x);
        }
    }
    ans.insert(s);
}

int32_t main()
{
    IOS;
    #ifndef ONLINE_JUDGE
    freopen("int.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
    int n;
    cin >> n;
    v.resize(n);
    for(int i = 0;i < n;i++)
    {
        cin >> v[i];
        check(v[i]);
        for(int j = 0;j < v[i].length();j++)
            g[v[i][j]-'a'].insert(i);
        alive.insert(i);
    }
    while(!alive.empty())
    {
        process(*alive.begin());
    }
    for(auto it : ans)
        cout << it;

}


#include <bits/stdc++.h>

using namespace std;

#define SZ(x) ((int)(x).size())
#define PB(x) push_back(x)
#define MEMSET(x,v) memset(x,v,sizeof(x))
#define REP(i,n) for(int i=0;(i)<(n);++(i))
#define x first
#define y second
#define INF (0x3f3f3f3f)

typedef long long LL;
typedef pair<int, int> P2;
template<class A, class B> inline bool mina(A &x, B y) {return (x > y)?(x=y,1):0;}
template<class A, class B> inline bool maxa(A &x, B y) {return (x < y)?(x=y,1):0;}

const int MAXN = 1e5+5;
int N;
string in[MAXN];
int nxt[26];
int pre[26];
bool have[26];
bool contains[26];

int main() {
    MEMSET(nxt, -1);
    MEMSET(pre, -1);
    cin >> N;
    REP(i, N) {
        cin >> in[i];
        REP(j, SZ(in[i])) have[in[i][j] - 'a'] = true;
        REP(j, SZ(in[i]) - 1) {
            int u = in[i][j] - 'a';
            int v = in[i][j + 1] - 'a';
            if (pre[v] != -1 && pre[v] != u) {
                cout << "NO" << endl;
                return 0;
            }
            if (nxt[u] != -1 && nxt[u] != v) {
                cout << "NO" << endl;
                return 0;
            }
            nxt[u] = v;
            pre[v] = u;
        }
    }

    vector<string> ans;

    REP(i, 26) {
        if (nxt[i] != -1 && pre[i] == -1) {
            int now = i;
            string temp = "";
            temp += 'a' + now;
            while (nxt[now] != -1) {
                now = nxt[now];
                temp += 'a' + now;
            }
            ans.PB(temp);
        } else if (nxt[i] == -1 && pre[i] == -1 && have[i]) {
            string temp = "";
            temp += 'a' + i;
            ans.PB(temp);
        }
    }
    sort(ans.begin(), ans.end());
    string ans2 = "";
    for (auto s : ans) {
        ans2 += s;
    }
    for (char c : ans2) {
        contains[c - 'a'] = true;
    }
    REP(i, 26) {
        if (have[i] && !contains[i]) {
            cout << "NO" << endl;
            return 0;
        }
    }

    cout << ans2 << endl;

    return 0;
}


#include <bits/stdc++.h>

using namespace std;

#define SZ(x) ((int)(x).size())
#define PB(x) push_back(x)
#define MEMSET(x,v) memset(x,v,sizeof(x))
#define REP(i,n) for(int i=0;(i)<(n);++(i))
#define x first
#define y second
#define INF (0x3f3f3f3f)

typedef long long LL;
typedef pair<int, int> P2;
template<class A, class B> inline bool mina(A &x, B y) {return (x > y)?(x=y,1):0;}
template<class A, class B> inline bool maxa(A &x, B y) {return (x < y)?(x=y,1):0;}

const int MAXN = 1e5+5;
int N;
string in[MAXN];
int nxt[26];
int pre[26];
bool have[26];

int main() {
    MEMSET(nxt, -1);
    MEMSET(pre, -1);
    cin >> N;
    REP(i, N) {
        cin >> in[i];
        REP(j, SZ(in[i])) have[in[i][j] - 'a'] = true;
        REP(j, SZ(in[i]) - 1) {
            int u = in[i][j] - 'a';
            int v = in[i][j + 1] - 'a';
            if (pre[v] != -1 && pre[v] != u) {
                cout << "NO" << endl;
                return 0;
            }
            if (nxt[u] != -1 && nxt[u] != v) {
                cout << "NO" << endl;
                return 0;
            }
            nxt[u] = v;
            pre[v] = u;
        }
    }

    vector<string> ans;

    REP(i, 26) {
        if (nxt[i] != -1 && pre[i] == -1) {
            int now = i;
            string temp = "";
            temp += 'a' + now;
            while (nxt[now] != -1) {
                now = nxt[now];
                temp += 'a' + now;
            }
            ans.PB(temp);
        } else if (nxt[i] == -1 && pre[i] == -1 && have[i]) {
            string temp = "";
            temp += 'a' + i;
            ans.PB(temp);
        }
    }

    sort(ans.begin(), ans.end());

    for (auto s : ans) {
        cout << s;
    }
    cout << endl;

    return 0;
}


#include <bits/stdc++.h>

using namespace std;

#define SZ(x) ((int)(x).size())
#define PB(x) push_back(x)
#define MEMSET(x,v) memset(x,v,sizeof(x))
#define REP(i,n) for(int i=0;(i)<(n);++(i))
#define x first
#define y second
#define INF (0x3f3f3f3f)

typedef long long LL;
typedef pair<int, int> P2;
template<class A, class B> inline bool mina(A &x, B y) {return (x > y)?(x=y,1):0;}
template<class A, class B> inline bool maxa(A &x, B y) {return (x < y)?(x=y,1):0;}

const int MAXN = 1e5+5;
int N;
string in[MAXN];
int nxt[26];
int pre[26];

int main() {
    MEMSET(nxt, -1);
    MEMSET(pre, -1);
    cin >> N;
    REP(i, N) {
        cin >> in[i];
        REP(j, SZ(in[i]) - 1) {
            int u = in[i][j] - 'a';
            int v = in[i][j + 1] - 'a';
            if (pre[v] != -1 && pre[v] != u) {
                cout << "NO" << endl;
                return 0;
            }
            if (nxt[u] != -1 && nxt[u] != v) {
                cout << "NO" << endl;
                return 0;
            }
            nxt[u] = v;
            pre[v] = u;
        }
    }

    vector<string> ans;

    REP(i, 26) {
        if (nxt[i] != -1 && pre[i] == -1) {
            int now = i;
            string temp = "";
            temp += 'a' + now;
            while (nxt[now] != -1) {
                now = nxt[now];
                temp += 'a' + now;
            }
            ans.PB(temp);
        }
    }

    sort(ans.begin(), ans.end());

    for (auto s : ans) {
        cout << s;
    }
    cout << endl;

    return 0;
}


#include<bits/stdc++.h>
using namespace std;

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;

#define ll long long
#define db double
#define el "\n"
#define ld long double
#define rep(i,n) for(int i=0;i<n;i++)
#define rev(i,n) for(int i=n;i>=0;i--)
#define rep_a(i,a,n) for(int i=a;i<n;i++)
#define tr(ds, it) for(auto it=ds.begin(); it!=ds.end(); it++)
#define rtr(ds, it) for(auto it=ds.rbegin(); it!=ds.rend(); it++)
#define all(ds) ds.begin(), ds.end()
#define ff first
#define ss second
#define pb push_back
#define mp make_pair
typedef vector< long long > vi;
typedef pair<long long, long long> ii;
typedef priority_queue <ll> pq;
#define o_set tree<ll, null_type,less<ll>, rb_tree_tag,tree_order_statistics_node_update>
#define graph vector<set<ll> >

const ll mod = 1000000007;
ll po(ll x, ll n ){
  ll ans=1;
     while(n>0){
       if(n&1) ans=(ans*x)%mod;
       x=(x*x)%mod;
       n/=2;
     }
     return ans;
}

graph g;
int vis[30]={0};
string z="";
int fl=1;

void dfs(int i){
  if(vis[i]) fl=0;
  vis[i]=1;
  z+=(char)('a'+i);
  if(g[i].size()==0) return;
  ll x=*g[i].begin();

  if(vis[x]){
    fl=0;
    return;
  }
  else dfs(x);
}

int main(){
  ios_base::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  #ifndef ONLINE_JUDGE
  freopen("input.txt", "r" , stdin);
  freopen("output.txt", "w" , stdout);
  #endif
  int T=1;
  //cin >> T;
  while(T--){
    ll n;
    cin>>n;
    string s[n];
    rep(i,n) cin>>s[i];

    g.assign(30, set<ll>());
    int a[30]={0}, b[30]={0};

    rep(i,n){
      rep(j,s[i].length()-1){
        g[(int)(s[i][j]-'a')].insert((int)(s[i][j+1]-'a'));
        b[(int)(s[i][j+1]-'a')]=1;
        a[(int)(s[i][j]-'a')]=1;
      }
      a[(int)(s[i][s[i].length()-1]-'a')]=1;
    }

    rep(i,26){
      if(g[i].size()>1){
        cout<<"NO"<<el;
        return 0;
      }
    }
    int f1=1;
    vector<string> r;
    rep(i,26){
      if(b[i]==0 && a[i]==1){
        f1=0;
        dfs(i);
        r.pb(z);
        z="";
      }
    }

    if(!fl || f1) cout<<"NO"<<el;
    else{
      sort(all(r));
      rep(i,r.size()) cout<<r[i];
      cout<<el;
    }

  }
  cerr << "Time : " << 1000 * ((double)clock()) / (double)CLOCKS_PER_SEC << "ms\n";
  return 0;
}


#include<bits/stdc++.h>
using namespace std;

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;

#define ll long long
#define db double
#define el "\n"
#define ld long double
#define rep(i,n) for(int i=0;i<n;i++)
#define rev(i,n) for(int i=n;i>=0;i--)
#define rep_a(i,a,n) for(int i=a;i<n;i++)
#define tr(ds, it) for(auto it=ds.begin(); it!=ds.end(); it++)
#define rtr(ds, it) for(auto it=ds.rbegin(); it!=ds.rend(); it++)
#define all(ds) ds.begin(), ds.end()
#define ff first
#define ss second
#define pb push_back
#define mp make_pair
typedef vector< long long > vi;
typedef pair<long long, long long> ii;
typedef priority_queue <ll> pq;
#define o_set tree<ll, null_type,less<ll>, rb_tree_tag,tree_order_statistics_node_update>
#define graph vector<set<int> >

const ll mod = 1000000007;
ll po(ll x, ll n ){
  ll ans=1;
     while(n>0){
       if(n&1) ans=(ans*x)%mod;
       x=(x*x)%mod;
       n/=2;
     }
     return ans;
}

graph g;
int vis[30]={0};
string z="";
int fl=1;

void dfs(int i){
  if(vis[i]){
    fl=0;
    return;
  }
  vis[i]=1;
  z+=(char)('a'+i);
  if(g[i].size()==0) return;
  int x=*g[i].begin();

  dfs(x);
}

int main(){
  ios_base::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  #ifndef ONLINE_JUDGE
  freopen("input.txt", "r" , stdin);
  freopen("output.txt", "w" , stdout);
  #endif
  int T=1;
  //cin >> T;
  while(T--){
    ll n;
    cin>>n;
    string s[n];
    rep(i,n) cin>>s[i];

    g.assign(30, set<int>());
    int a[30]={0}, b[30]={0}, c[30]={0};

    rep(i,n){
      rep(j,s[i].length()-1){
        g[(int)(s[i][j]-'a')].insert((int)(s[i][j+1]-'a'));
        b[(int)(s[i][j+1]-'a')]=1;
        a[(int)(s[i][j]-'a')]=1;
      }
      a[(int)(s[i][s[i].length()-1]-'a')]=1;
    }

    rep(i,26){
      if(g[i].size()>1){
        cout<<"NO"<<el;
        return 0;
      }
    }
    int f1=1;
    vector<string> r;
    rep(i,26){
      if(b[i]==0 && a[i]==1 && !vis[i]){
        f1=0;
        z="";
        dfs(i);
        r.pb(z);
        rep(j,z.size()) c[(int)(z[j]-'a')]=1;
      }
    }
    rep(i,26) if(a[i] && !c[i]) f1=1;
    if(fl==0 || f1) cout<<"NO"<<el;
    else{
      sort(all(r));
      rep(i,r.size()) cout<<r[i];
      cout<<el;
    }

  }
  cerr << "Time : " << 1000 * ((double)clock()) / (double)CLOCKS_PER_SEC << "ms\n";
  return 0;
}


#include<bits/stdc++.h>
using namespace std;

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;

#define ll long long
#define db double
#define el "\n"
#define ld long double
#define rep(i,n) for(int i=0;i<n;i++)
#define rev(i,n) for(int i=n;i>=0;i--)
#define rep_a(i,a,n) for(int i=a;i<n;i++)
#define tr(ds, it) for(auto it=ds.begin(); it!=ds.end(); it++)
#define rtr(ds, it) for(auto it=ds.rbegin(); it!=ds.rend(); it++)
#define all(ds) ds.begin(), ds.end()
#define ff first
#define ss second
#define pb push_back
#define mp make_pair
typedef vector< long long > vi;
typedef pair<long long, long long> ii;
typedef priority_queue <ll> pq;
#define o_set tree<ll, null_type,less<ll>, rb_tree_tag,tree_order_statistics_node_update>
#define graph vector<set<ll> >

const ll mod = 1000000007;
ll po(ll x, ll n ){
  ll ans=1;
     while(n>0){
       if(n&1) ans=(ans*x)%mod;
       x=(x*x)%mod;
       n/=2;
     }
     return ans;
}

graph g;
int vis[30]={0};
string z="";
int fl=1;

void dfs(int i){
  if(vis[i]) fl=0;
  vis[i]=1;
  z+=(char)('a'+i);
  if(g[i].size()==0) return;
  ll x=*g[i].begin();

  if(vis[x]){
    fl=0;
    return;
  }
  else dfs(x);
}

int main(){
  ios_base::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  #ifndef ONLINE_JUDGE
  freopen("input.txt", "r" , stdin);
  freopen("output.txt", "w" , stdout);
  #endif
  int T=1;
  //cin >> T;
  while(T--){
    ll n;
    cin>>n;
    string s[n];
    rep(i,n) cin>>s[i];

    g.assign(30, set<ll>());
    int a[30]={0}, b[30]={0};

    rep(i,n){
      rep(j,s[i].length()-1){
        g[(int)(s[i][j]-'a')].insert((int)(s[i][j+1]-'a'));
        b[(int)(s[i][j+1]-'a')]=1;
        a[(int)(s[i][j]-'a')]=1;
      }
      a[(int)(s[i][s[i].length()-1]-'a')]=1;
    }

    rep(i,26){
      if(g[i].size()>1){
        cout<<"NO"<<el;
        return 0;
      }
    }
    int f1=1;
    vector<string> r;
    rep(i,26){
      if(b[i]==0 && a[i]==1 && !vis[i]){
        f1=0;
        z="";
        dfs(i);
        r.pb(z);
      }
    }

    if(fl==0 || f1) cout<<"NO"<<el;
    else{
      sort(all(r));
      rep(i,r.size()) cout<<r[i];
      cout<<el;
    }

  }
  cerr << "Time : " << 1000 * ((double)clock()) / (double)CLOCKS_PER_SEC << "ms\n";
  return 0;
}


#include<bits/stdc++.h>
using namespace std;

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;

#define ll long long
#define db double
#define el "\n"
#define ld long double
#define rep(i,n) for(int i=0;i<n;i++)
#define rev(i,n) for(int i=n;i>=0;i--)
#define rep_a(i,a,n) for(int i=a;i<n;i++)
#define tr(ds, it) for(auto it=ds.begin(); it!=ds.end(); it++)
#define rtr(ds, it) for(auto it=ds.rbegin(); it!=ds.rend(); it++)
#define all(ds) ds.begin(), ds.end()
#define ff first
#define ss second
#define pb push_back
#define mp make_pair
typedef vector< long long > vi;
typedef pair<long long, long long> ii;
typedef priority_queue <ll> pq;
#define o_set tree<ll, null_type,less<ll>, rb_tree_tag,tree_order_statistics_node_update>
#define graph vector<set<ll> >

const ll mod = 1000000007;
ll po(ll x, ll n ){
  ll ans=1;
     while(n>0){
       if(n&1) ans=(ans*x)%mod;
       x=(x*x)%mod;
       n/=2;
     }
     return ans;
}

graph g;
int vis[30]={0};
string z="";
int fl=1;

void dfs(int i){
  if(vis[i]) fl=0;
  vis[i]=1;
  z+=(char)('a'+i);
  if(g[i].size()==0) return;
  ll x=*g[i].begin();

  if(!vis[x]) dfs(x);
}

int main(){
  ios_base::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  #ifndef ONLINE_JUDGE
  freopen("input.txt", "r" , stdin);
  freopen("output.txt", "w" , stdout);
  #endif
  int T=1;
  //cin >> T;
  while(T--){
    ll n;
    cin>>n;
    string s[n];
    rep(i,n) cin>>s[i];

    g.assign(30, set<ll>());
    int a[30]={0}, b[30]={0};

    rep(i,n){
      rep(j,s[i].length()-1){
        g[(int)(s[i][j]-'a')].insert((int)(s[i][j+1]-'a'));
        b[(int)(s[i][j+1]-'a')]=1;
        a[(int)(s[i][j]-'a')]=1;
      }
      a[(int)(s[i][s[i].length()-1]-'a')]=1;
    }

    rep(i,26){
      if(g[i].size()>1){
        cout<<"NO"<<el;
        return 0;
      }
    }
    int f1=1;
    vector<string> r;
    rep(i,26){
      if(b[i]==0 && a[i]==1 && !vis[i]){
        f1=0;
        z="";
        dfs(i);
        r.pb(z);
      }
    }

    if(fl==0 || f1) cout<<"NO"<<el;
    else{
      sort(all(r));
      rep(i,r.size()) cout<<r[i];
      cout<<el;
    }

  }
  cerr << "Time : " << 1000 * ((double)clock()) / (double)CLOCKS_PER_SEC << "ms\n";
  return 0;
}


#include<bits/stdc++.h>
using namespace std;

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;

#define ll long long
#define db double
#define el "\n"
#define ld long double
#define rep(i,n) for(int i=0;i<n;i++)
#define rev(i,n) for(int i=n;i>=0;i--)
#define rep_a(i,a,n) for(int i=a;i<n;i++)
#define tr(ds, it) for(auto it=ds.begin(); it!=ds.end(); it++)
#define rtr(ds, it) for(auto it=ds.rbegin(); it!=ds.rend(); it++)
#define all(ds) ds.begin(), ds.end()
#define ff first
#define ss second
#define pb push_back
#define mp make_pair
typedef vector< long long > vi;
typedef pair<long long, long long> ii;
typedef priority_queue <ll> pq;
#define o_set tree<ll, null_type,less<ll>, rb_tree_tag,tree_order_statistics_node_update>
#define graph vector<set<ll> >

const ll mod = 1000000007;
ll po(ll x, ll n ){
  ll ans=1;
     while(n>0){
       if(n&1) ans=(ans*x)%mod;
       x=(x*x)%mod;
       n/=2;
     }
     return ans;
}

graph g;
int vis[30]={0};
string z="";
int fl=1;

void dfs(int i){
  if(vis[i]) fl=0;
  vis[i]=1;
  z+=(char)('a'+i);
  if(g[i].size()==0) return;
  ll x=*g[i].begin();

  if(vis[x]){
    fl=0;
    return;
  }
  else dfs(x);
}

int main(){
  ios_base::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  #ifndef ONLINE_JUDGE
  freopen("input.txt", "r" , stdin);
  freopen("output.txt", "w" , stdout);
  #endif
  int T=1;
  //cin >> T;
  while(T--){
    ll n;
    cin>>n;
    string s[n];
    rep(i,n) cin>>s[i];

    g.assign(30, set<ll>());
    int a[30]={0}, b[30]={0};

    rep(i,n){
      rep(j,s[i].length()-1){
        g[(int)(s[i][j]-'a')].insert((int)(s[i][j+1]-'a'));
        b[(int)(s[i][j+1]-'a')]=1;
        a[(int)(s[i][j]-'a')]=1;
      }
      a[(int)(s[i][s[i].length()-1]-'a')]=1;
    }

    rep(i,26){
      if(g[i].size()>1){
        cout<<"NO"<<el;
        return 0;
      }
    }

    vector<string> r;
    rep(i,26){
      if(b[i]==0 && a[i]==1){

        dfs(i);
        r.pb(z);
        z="";
      }
    }
    if(!fl) cout<<"NO"<<el;
    else{
      sort(all(r));
      rep(i,r.size()) cout<<r[i];
      cout<<el;
    }

  }
  cerr << "Time : " << 1000 * ((double)clock()) / (double)CLOCKS_PER_SEC << "ms\n";
  return 0;
}


#include<bits/stdc++.h>
using namespace std;

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;

#define ll long long
#define db double
#define el "\n"
#define ld long double
#define rep(i,n) for(int i=0;i<n;i++)
#define rev(i,n) for(int i=n;i>=0;i--)
#define rep_a(i,a,n) for(int i=a;i<n;i++)
#define tr(ds, it) for(auto it=ds.begin(); it!=ds.end(); it++)
#define rtr(ds, it) for(auto it=ds.rbegin(); it!=ds.rend(); it++)
#define all(ds) ds.begin(), ds.end()
#define ff first
#define ss second
#define pb push_back
#define mp make_pair
typedef vector< long long > vi;
typedef pair<long long, long long> ii;
typedef priority_queue <ll> pq;
#define o_set tree<ll, null_type,less<ll>, rb_tree_tag,tree_order_statistics_node_update>
#define graph vector<set<int> >

const ll mod = 1000000007;
ll po(ll x, ll n ){
  ll ans=1;
     while(n>0){
       if(n&1) ans=(ans*x)%mod;
       x=(x*x)%mod;
       n/=2;
     }
     return ans;
}

graph g;
int vis[30]={0};
string z="";
int fl=1;

void dfs(int i){
  if(vis[i]){
    fl=0;
    return;
  }
  vis[i]=1;
  z+=(char)('a'+i);
  if(g[i].size()==0) return;
  int x=*g[i].begin();

  dfs(x);
}

int main(){
  ios_base::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  #ifndef ONLINE_JUDGE
  freopen("input.txt", "r" , stdin);
  freopen("output.txt", "w" , stdout);
  #endif
  int T=1;
  //cin >> T;
  while(T--){
    ll n;
    cin>>n;
    string s[n];
    rep(i,n) cin>>s[i];

    g.assign(30, set<int>());
    int a[30]={0}, b[30]={0}, c[30]={0};

    rep(i,n){
      rep(j,s[i].length()-1){
        g[(int)(s[i][j]-'a')].insert((int)(s[i][j+1]-'a'));
        b[(int)(s[i][j+1]-'a')]=1;
        a[(int)(s[i][j]-'a')]=1;
      }
      a[(int)(s[i][s[i].length()-1]-'a')]=1;
    }

    rep(i,26){
      if(g[i].size()>1){
        cout<<"NO"<<el;
        return 0;
      }
    }
    int f1=1;
    vector<string> r;
    rep(i,26){
      if(b[i]==0 && a[i]==1 && !vis[i]){
        f1=0;
        z="";
        dfs(i);
        r.pb(z);
        rep(j,z.size()) c[z[j]]=1;
      }
    }
    rep(i,26) if(a[i] && !c[i]) f1=1;
    if(fl==0 || f1) cout<<"NO"<<el;
    else{
      sort(all(r));
      rep(i,r.size()) cout<<r[i];
      cout<<el;
    }

  }
  cerr << "Time : " << 1000 * ((double)clock()) / (double)CLOCKS_PER_SEC << "ms\n";
  return 0;
}


#include<bits/stdc++.h>
using namespace std;

#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;

#define ll long long
#define db double
#define el "\n"
#define ld long double
#define rep(i,n) for(int i=0;i<n;i++)
#define rev(i,n) for(int i=n;i>=0;i--)
#define rep_a(i,a,n) for(int i=a;i<n;i++)
#define tr(ds, it) for(auto it=ds.begin(); it!=ds.end(); it++)
#define rtr(ds, it) for(auto it=ds.rbegin(); it!=ds.rend(); it++)
#define all(ds) ds.begin(), ds.end()
#define ff first
#define ss second
#define pb push_back
#define mp make_pair
typedef vector< long long > vi;
typedef pair<long long, long long> ii;
typedef priority_queue <ll> pq;
#define o_set tree<ll, null_type,less<ll>, rb_tree_tag,tree_order_statistics_node_update>
#define graph vector<set<ll> >

const ll mod = 1000000007;
ll po(ll x, ll n ){
  ll ans=1;
     while(n>0){
       if(n&1) ans=(ans*x)%mod;
       x=(x*x)%mod;
       n/=2;
     }
     return ans;
}

graph g;
int vis[30]={0};
string z="";
int fl=1;

void dfs(int i){
  if(vis[i]){
    fl=0;
    return;
  }
  vis[i]=1;
  z+=(char)('a'+i);
  if(g[i].size()==0) return;
  ll x=*g[i].begin();

  dfs(x);
}

int main(){
  ios_base::sync_with_stdio(false);
  cin.tie(0);
  cout.tie(0);
  #ifndef ONLINE_JUDGE
  freopen("input.txt", "r" , stdin);
  freopen("output.txt", "w" , stdout);
  #endif
  int T=1;
  //cin >> T;
  while(T--){
    ll n;
    cin>>n;
    string s[n];
    rep(i,n) cin>>s[i];

    g.assign(30, set<ll>());
    int a[30]={0}, b[30]={0};

    rep(i,n){
      rep(j,s[i].length()-1){
        g[(int)(s[i][j]-'a')].insert((int)(s[i][j+1]-'a'));
        b[(int)(s[i][j+1]-'a')]=1;
        a[(int)(s[i][j]-'a')]=1;
      }
      a[(int)(s[i][s[i].length()-1]-'a')]=1;
    }

    rep(i,26){
      if(g[i].size()>1){
        cout<<"NO"<<el;
        return 0;
      }
    }
    int f1=1;
    vector<string> r;
    rep(i,26){
      if(b[i]==0 && a[i]==1 && !vis[i]){
        f1=0;
        z="";
        dfs(i);
        r.pb(z);
      }
    }

    if(fl==0 || f1) cout<<"NO"<<el;
    else{
      sort(all(r));
      rep(i,r.size()) cout<<r[i];
      cout<<el;
    }

  }
  cerr << "Time : " << 1000 * ((double)clock()) / (double)CLOCKS_PER_SEC << "ms\n";
  return 0;
}


#include "bits/stdc++.h"
using namespace std;
typedef long long ll;
const int MAX = 30;
set <int, greater <int>> g[MAX], rg[MAX];
vector <int> order;
int col[MAX];
bool cycle;
void dfs(int u) {
	col[u] = 1;
	order.push_back(u);
	for(int v : g[u]) {
		if(col[v] == 2) continue;
		if(!col[v]) dfs(v);
		else cycle = true;
	}
	col[u] = 2;
}
int main() {
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);

	set <int> used;
	int n; cin >> n;
	for(int i = 0; i < n; i ++) {
		string s; cin >> s;
		if(n == 1 && (int) s.size() == 1) return cout << s, 0;
		int l = s.size();
		for(int j = 0; j < l - 1; j ++) {
			g[s[j] - 'a'].insert(s[j + 1] - 'a');
			rg[s[j + 1] - 'a'].insert(s[j] - 'a');
		}
		for(char c : s) used.insert(c - 'a');
	}
	cycle = false;
	for(int i = 0; i < 26; i ++) {
		if((int) rg[i].size() > 1 || (int) g[i].size() > 1) return cout << "NO", 0;
		if(!col[i]) dfs(i);
	}
	if(cycle) return cout << "NO", 0;
	memset(col, 0, sizeof(col));
	order.clear();
	for(int i = 0; i < 26; i ++) {
		if(used.find(i) != used.end() && (int) rg[i].size() == 0) {
			if(!col[i]) dfs(i);
		}
	}
	for(int x : order) cout << char(x + 'a');

	return 0;
}

// Hope for us because I believed


/* Author : Aaryan Srivastava ^__^ */
#include <bits/stdc++.h>
#include <random>
#include <chrono>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define pb push_back
#define mp make_pair
#define ff first
#define ss second
#define rep(i,n) for(int i = 0 ; i < (n) ; i++)
#define repA(i,x,y) for(int i = (x) ; i <= (y) ; i++)
#define repD(i,x,y) for(int i = (x) ; i >= (y) ; i--)
#define all(c) (c).begin(),(c).end()
#define rall(c) (c).rbegin(),(c).rend()
#define setval(a,val) memset(a,val,sizeof(a))
#define Randomize mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define trav(x , a) for(auto &x : a)
#define sz(a) ((int)a.size())
typedef long long ll ;
#define int ll
using namespace std;

const int N = 3e5 + 5 ;
const int mod = 1e9 + 7 ;
const ll inf = 1e18 ;
const int SZ = 101 ;
const long double eps = 1e-9 ;

using namespace __gnu_pbds;
using ordered_set =  tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> ;

typedef pair<int, int> pii;
typedef pair<int , pii> ipii ;
typedef pair<pii , int> piii ;
typedef unsigned long long ull ;
typedef long double ld;

ll po(ll x,ll y,ll p = mod) {ll res=1;x%=p;while(y>0){if(y&1)res=(res*x)%p;y=y>>1;x=(x*x)%p;}return res;}

void kek(int x = 0){
    cout << "NO";
    // cout << x;
    exit(0);
}

bool merge_str(string &a , string &b){
    string s = a + '#' + b ;
    int n = s.length();
    vector<int> pi(n , 0);
    for(int i = 1; i < n  ; ++i){
        int j = pi[i-1];
        while(j && s[i] != s[j]) j = pi[j-1];
        j += (s[i] == s[j]);
        pi[i] = j;
    }
    int skip = pi[n-1];
    string ans = b;
    for(int i = skip ; i < sz(a) ; ++i) ans.pb(a[i]);
    if(sz(ans) > 26) return false;
    int cnt[26] = {};
    trav(c , ans) if(++cnt[c - 'a'] > 1) return false;
    a.swap(ans);
    return true ;
}
void solve()
{
    int n ;
    cin >> n ;
    map<string , bool> m;
    rep(i , n){
        string s;
        cin >> s;
        m[s];
    }
    trav(x , m){
        string s = x.ff;
        if(s.length() > 26) kek(1);
        int cnt[26] = {};
        trav(c , s)
            if(++cnt[c - 'a'] > 1) kek(2);
        rep(i , sz(s)){
            string tmp = "" ;
            repA(j , i , sz(s) - 1){
                tmp += s[j] ;
                if(tmp == s) break ;
                if(m.find(tmp) != m.end()) m.erase(m.find(tmp));
            }
        }
    }

    vector<string> pos[26];
    trav(x , m){
        string s = x.ff;
        trav(c , s){
            pos[c - 'a'].pb(s);
            if(sz(pos[c - 'a']) > 2) kek(3);
        }
    }
    // rep(i , 26){
    //     if(!sz(pos[i])) continue ;
    //     cout << char(i + 'a') << ":\n" ;
    //     trav(s , pos[i]) cout << s << ' ';
    //     cout << '\n';
    // }

    rep(i , 26){
        int cnt = 0;
        string tmp[2];
        trav(x , m){
            trav(c , x.ff){
                if(c == char(i + 'a')){
                    if(cnt > 2) kek(4);
                    tmp[cnt++] = x.ff;
                    break;
                }
            }
        }
        if(cnt < 2) continue ;
        rep(j,2) m.erase(m.find(tmp[j]));
        string a = tmp[0] , b = tmp[1];
        vector<string> res;
        // cout << a << "-" << b << "\n";
        if(merge_str(a , tmp[1])){
            res.pb(a);
        }
        if(merge_str(b , tmp[0])){
            res.pb(b);
        }
        if(res.empty()) kek(5);
        if(sz(res) == 2 && res[1] < res[0]) swap(res[0] , res[1]);
        m[res[0]];
    }
    // assert(sz(m) == 1);`
    trav(x , m) cout << x.ff ;
    // cout << m.begin()->ff;
}

int32_t main(int32_t argc, char *argv[])
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    int TC = 1, t = 0;
    //cin >> TC ;
    while(t++ < TC)
    {
        //cout << "Case #" << t << ": " ;
        solve();
        cout << "\n" ;
    }
    return 0;
}


/* Author : Aaryan Srivastava ^__^ */
#include <bits/stdc++.h>
#include <random>
#include <chrono>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define pb push_back
#define mp make_pair
#define ff first
#define ss second
#define rep(i,n) for(int i = 0 ; i < (n) ; i++)
#define repA(i,x,y) for(int i = (x) ; i <= (y) ; i++)
#define repD(i,x,y) for(int i = (x) ; i >= (y) ; i--)
#define all(c) (c).begin(),(c).end()
#define rall(c) (c).rbegin(),(c).rend()
#define setval(a,val) memset(a,val,sizeof(a))
#define Randomize mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define trav(x , a) for(auto &x : a)
#define sz(a) ((int)a.size())
typedef long long ll ;
#define int ll
using namespace std;

const int N = 3e5 + 5 ;
const int mod = 1e9 + 7 ;
const ll inf = 1e18 ;
const int SZ = 101 ;
const long double eps = 1e-9 ;

using namespace __gnu_pbds;
using ordered_set =  tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> ;

typedef pair<int, int> pii;
typedef pair<int , pii> ipii ;
typedef pair<pii , int> piii ;
typedef unsigned long long ull ;
typedef long double ld;

ll po(ll x,ll y,ll p = mod) {ll res=1;x%=p;while(y>0){if(y&1)res=(res*x)%p;y=y>>1;x=(x*x)%p;}return res;}

int n ;
void kek(int x = 0){
    cout << "NO";
    if(n == 88)
        cout << x;
    exit(0);
}

bool merge_str(string &a , string &b){
    string s = a + '#' + b ;
    int n = s.length();
    vector<int> pi(n , 0);
    for(int i = 1; i < n  ; ++i){
        int j = pi[i-1];
        while(j && s[i] != s[j]) j = pi[j-1];
        j += (s[i] == s[j]);
        pi[i] = j;
        if(pi[i] == (int)a.length()){
            a.swap(b);
            return true;
        }
    }
    int skip = pi[n-1];
    string ans = b;
    for(int i = skip ; i < sz(a) ; ++i) ans.pb(a[i]);
    if(sz(ans) > 26) return false;
    int cnt[26] = {};
    trav(c , ans) if(++cnt[c - 'a'] > 1) return false;
    a.swap(ans);
    return true ;
}
void solve()
{
    cin >> n ;
    map<string , bool> m;
    rep(i , n){
        string s;
        cin >> s;
        m[s];
    }
    trav(x , m){
        string s = x.ff;
        if(s.length() > 26) kek(1);
        int cnt[26] = {};
        trav(c , s)
            if(++cnt[c - 'a'] > 1) kek(2);
        rep(i , sz(s)){
            string tmp = "" ;
            repA(j , i , sz(s) - 1){
                tmp += s[j] ;
                if(tmp == s) break ;
                if(m.find(tmp) != m.end()) m.erase(m.find(tmp));
            }
        }
    }

    vector<string> pos[26];
    // trav(x , m){
    //     string s = x.ff;
    //     trav(c , s){
    //         pos[c - 'a'].pb(s);
    //         break;
    //         if(sz(pos[c - 'a']) > 2){
    //             cout << sz(pos[c - 'a']) << ek(3);
    //     }
    // }
    // rep(i , 26){
    //     if(!sz(pos[i])) continue ;
    //     cout << char(i + 'a') << ":\n" ;
    //     trav(s , pos[i]) cout << s << ' ';
    //     cout << '\n';
    // }

    rep(i , 26){
        int cnt = 0;
        string tmp[2];
        trav(x , m){
            trav(c , x.ff){
                if(c == char(i + 'a')){
                    if(cnt > 2) kek(4);
                    tmp[cnt++] = x.ff;
                    break;
                }
            }
        }
        if(cnt < 2) continue ;
        rep(j,2) m.erase(m.find(tmp[j]));
        string a = tmp[0] , b = tmp[1];
        vector<string> res;
        // cout << a << "-" << b << "\n";
        if(merge_str(a , tmp[1])){
            res.pb(a);
        }
        if(merge_str(b , tmp[0])){
            res.pb(b);
        }
        if(res.empty()){
            // if(n == 88) cout << char(i + 'a') <<  a << ' ' << b << '\n' ;
            kek(5);
        }
        sort(all(res));
        // if(sz(res) == 2 && res[1] < res[0]) swap(res[0] , res[1]);
        m[res[0]];
    }
    // assert(sz(m) == 1);`
    trav(x , m) cout << x.ff ;
    // cout << m.begin()->ff;
}

int32_t main(int32_t argc, char *argv[])
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    int TC = 1, t = 0;
    //cin >> TC ;
    while(t++ < TC)
    {
        //cout << "Case #" << t << ": " ;
        solve();
        cout << "\n" ;
    }
    return 0;
}


/* Author : Aaryan Srivastava ^__^ */
#include <bits/stdc++.h>
#include <random>
#include <chrono>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define pb push_back
#define mp make_pair
#define ff first
#define ss second
#define rep(i,n) for(int i = 0 ; i < (n) ; i++)
#define repA(i,x,y) for(int i = (x) ; i <= (y) ; i++)
#define repD(i,x,y) for(int i = (x) ; i >= (y) ; i--)
#define all(c) (c).begin(),(c).end()
#define rall(c) (c).rbegin(),(c).rend()
#define setval(a,val) memset(a,val,sizeof(a))
#define Randomize mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define trav(x , a) for(auto &x : a)
#define sz(a) ((int)a.size())
typedef long long ll ;
#define int ll
using namespace std;

const int N = 3e5 + 5 ;
const int mod = 1e9 + 7 ;
const ll inf = 1e18 ;
const int SZ = 101 ;
const long double eps = 1e-9 ;

using namespace __gnu_pbds;
using ordered_set =  tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> ;

typedef pair<int, int> pii;
typedef pair<int , pii> ipii ;
typedef pair<pii , int> piii ;
typedef unsigned long long ull ;
typedef long double ld;

ll po(ll x,ll y,ll p = mod) {ll res=1;x%=p;while(y>0){if(y&1)res=(res*x)%p;y=y>>1;x=(x*x)%p;}return res;}

int n ;
void kek(int x = 0){
    cout << "NO";
    if(n == 88)
        cout << x;
    exit(0);
}

bool merge_str(string &a , string &b){
    string s = a + '#' + b ;
    int n = s.length();
    vector<int> pi(n , 0);
    for(int i = 1; i < n  ; ++i){
        int j = pi[i-1];
        while(j && s[i] != s[j]) j = pi[j-1];
        j += (s[i] == s[j]);
        pi[i] = j;
    }
    int skip = pi[n-1];
    string ans = b;
    for(int i = skip ; i < sz(a) ; ++i) ans.pb(a[i]);
    if(sz(ans) > 26) return false;
    int cnt[26] = {};
    trav(c , ans) if(++cnt[c - 'a'] > 1) return false;
    a.swap(ans);
    return true ;
}
void solve()
{
    cin >> n ;
    map<string , bool> m;
    rep(i , n){
        string s;
        cin >> s;
        m[s];
    }
    trav(x , m){
        string s = x.ff;
        if(s.length() > 26) kek(1);
        int cnt[26] = {};
        trav(c , s)
            if(++cnt[c - 'a'] > 1) kek(2);
        rep(i , sz(s)){
            string tmp = "" ;
            repA(j , i , sz(s) - 1){
                tmp += s[j] ;
                if(tmp == s) break ;
                if(m.find(tmp) != m.end()) m.erase(m.find(tmp));
            }
        }
    }

    vector<string> pos[26];
    // trav(x , m){
    //     string s = x.ff;
    //     trav(c , s){
    //         pos[c - 'a'].pb(s);
    //         break;
    //         if(sz(pos[c - 'a']) > 2){
    //             cout << sz(pos[c - 'a']) << ek(3);
    //     }
    // }
    // rep(i , 26){
    //     if(!sz(pos[i])) continue ;
    //     cout << char(i + 'a') << ":\n" ;
    //     trav(s , pos[i]) cout << s << ' ';
    //     cout << '\n';
    // }

    rep(i , 26){
        int cnt = 0;
        string tmp[2];
        trav(x , m){
            trav(c , x.ff){
                if(c == char(i + 'a')){
                    if(cnt > 2) kek(4);
                    tmp[cnt++] = x.ff;
                    break;
                }
            }
        }
        if(cnt < 2) continue ;
        rep(j,2) m.erase(m.find(tmp[j]));
        string a = tmp[0] , b = tmp[1];
        vector<string> res;
        // cout << a << "-" << b << "\n";
        if(merge_str(a , tmp[1])){
            res.pb(a);
        }
        if(merge_str(b , tmp[0])){
            res.pb(b);
        }
        if(res.empty()) kek(5);
        if(sz(res) == 2 && res[1] < res[0]) swap(res[0] , res[1]);
        m[res[0]];
    }
    // assert(sz(m) == 1);`
    trav(x , m) cout << x.ff ;
    // cout << m.begin()->ff;
}

int32_t main(int32_t argc, char *argv[])
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    int TC = 1, t = 0;
    //cin >> TC ;
    while(t++ < TC)
    {
        //cout << "Case #" << t << ": " ;
        solve();
        cout << "\n" ;
    }
    return 0;
}


/* Author : Aaryan Srivastava ^__^ */
#include <bits/stdc++.h>
#include <random>
#include <chrono>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define pb push_back
#define mp make_pair
#define ff first
#define ss second
#define rep(i,n) for(int i = 0 ; i < (n) ; i++)
#define repA(i,x,y) for(int i = (x) ; i <= (y) ; i++)
#define repD(i,x,y) for(int i = (x) ; i >= (y) ; i--)
#define all(c) (c).begin(),(c).end()
#define rall(c) (c).rbegin(),(c).rend()
#define setval(a,val) memset(a,val,sizeof(a))
#define Randomize mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define trav(x , a) for(auto &x : a)
#define sz(a) ((int)a.size())
typedef long long ll ;
#define int ll
using namespace std;

const int N = 3e5 + 5 ;
const int mod = 1e9 + 7 ;
const ll inf = 1e18 ;
const int SZ = 101 ;
const long double eps = 1e-9 ;

using namespace __gnu_pbds;
using ordered_set =  tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> ;

typedef pair<int, int> pii;
typedef pair<int , pii> ipii ;
typedef pair<pii , int> piii ;
typedef unsigned long long ull ;
typedef long double ld;

ll po(ll x,ll y,ll p = mod) {ll res=1;x%=p;while(y>0){if(y&1)res=(res*x)%p;y=y>>1;x=(x*x)%p;}return res;}

int n ;
void kek(int x = 0){
    cout << "NO";
    if(n == 88)
        cout << x;
    exit(0);
}

bool merge_str(string &a , string &b){
    string s = a + '#' + b ;
    int n = s.length();
    vector<int> pi(n , 0);
    for(int i = 1; i < n  ; ++i){
        int j = pi[i-1];
        while(j && s[i] != s[j]) j = pi[j-1];
        j += (s[i] == s[j]);
        pi[i] = j;
        if(pi[i] == (int)a.length()){
            a.swap(b);
            return true;
        }
    }
    int skip = pi[n-1];
    string ans = b;
    for(int i = skip ; i < sz(a) ; ++i) ans.pb(a[i]);
    if(sz(ans) > 26) return false;
    int cnt[26] = {};
    trav(c , ans) if(++cnt[c - 'a'] > 1) return false;
    a.swap(ans);
    return true ;
}
void solve()
{
    cin >> n ;
    map<string , bool> m;
    rep(i , n){
        string s;
        cin >> s;
        m[s];
    }
    trav(x , m){
        string s = x.ff;
        if(s.length() > 26) kek(1);
        int cnt[26] = {};
        trav(c , s)
            if(++cnt[c - 'a'] > 1) kek(2);
        rep(i , sz(s)){
            string tmp = "" ;
            repA(j , i , sz(s) - 1){
                tmp += s[j] ;
                if(tmp == s) break ;
                if(m.find(tmp) != m.end()) m.erase(m.find(tmp));
            }
        }
    }

    vector<string> pos[26];
    // trav(x , m){
    //     string s = x.ff;
    //     trav(c , s){
    //         pos[c - 'a'].pb(s);
    //         break;
    //         if(sz(pos[c - 'a']) > 2){
    //             cout << sz(pos[c - 'a']) << ek(3);
    //     }
    // }
    // rep(i , 26){
    //     if(!sz(pos[i])) continue ;
    //     cout << char(i + 'a') << ":\n" ;
    //     trav(s , pos[i]) cout << s << ' ';
    //     cout << '\n';
    // }

    rep(i , 26){
        vector<string> tmp;
        trav(x , m){
            trav(c , x.ff){
                if(c == char(i + 'a')){
                    if(sz(tmp) == 2) kek(4);
                    tmp.pb(x.ff);
                    break;
                }
            }
        }
        if(sz(tmp) < 2) continue ;
        rep(j,sz(tmp)) m.erase(m.find(tmp[j]));
        vector<string> use(all(tmp));
        string a = tmp[0] , b = tmp[1];
        vector<string> res;
        // cout << a << "-" << b << "\n";
        if(merge_str(a , tmp[1])){
            res.pb(a);
            rep(j , sz(tmp)) tmp[j] = use[j];
        }
        if(merge_str(b , tmp[0])){
            res.pb(b);
            rep(j , sz(tmp)) tmp[j] = use[j];
        }
        if(res.empty()){
            // if(n == 88) cout << char(i + 'a') <<  a << ' ' << b << '\n' ;
            kek(5);
        }
        sort(all(res));
        // if(sz(res) == 2 && res[1] < res[0]) swap(res[0] , res[1]);
        m[res[0]];
    }
    // assert(sz(m) == 1);`
    trav(x , m) cout << x.ff ;
    // cout << m.begin()->ff;
}

int32_t main(int32_t argc, char *argv[])
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    int TC = 1, t = 0;
    //cin >> TC ;
    while(t++ < TC)
    {
        //cout << "Case #" << t << ": " ;
        solve();
        cout << "\n" ;
    }
    return 0;
}


/* Author : Aaryan Srivastava ^__^ */
#include <bits/stdc++.h>
#include <random>
#include <chrono>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define pb push_back
#define mp make_pair
#define ff first
#define ss second
#define rep(i,n) for(int i = 0 ; i < (n) ; i++)
#define repA(i,x,y) for(int i = (x) ; i <= (y) ; i++)
#define repD(i,x,y) for(int i = (x) ; i >= (y) ; i--)
#define all(c) (c).begin(),(c).end()
#define rall(c) (c).rbegin(),(c).rend()
#define setval(a,val) memset(a,val,sizeof(a))
#define Randomize mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define trav(x , a) for(auto &x : a)
#define sz(a) ((int)a.size())
typedef long long ll ;
#define int ll
using namespace std;

const int N = 3e5 + 5 ;
const int mod = 1e9 + 7 ;
const ll inf = 1e18 ;
const int SZ = 101 ;
const long double eps = 1e-9 ;

using namespace __gnu_pbds;
using ordered_set =  tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> ;

typedef pair<int, int> pii;
typedef pair<int , pii> ipii ;
typedef pair<pii , int> piii ;
typedef unsigned long long ull ;
typedef long double ld;

ll po(ll x,ll y,ll p = mod) {ll res=1;x%=p;while(y>0){if(y&1)res=(res*x)%p;y=y>>1;x=(x*x)%p;}return res;}

int n ;
void kek(int x = 0){
    cout << "NO";
    if(n == 88)
        cout << x;
    exit(0);
}

bool merge_str(string &a , string &b){
    string s = a + '#' + b ;
    int n = s.length();
    vector<int> pi(n , 0);
    for(int i = 1; i < n  ; ++i){
        int j = pi[i-1];
        while(j && s[i] != s[j]) j = pi[j-1];
        j += (s[i] == s[j]);
        pi[i] = j;
    }
    int skip = pi[n-1];
    string ans = b;
    for(int i = skip ; i < sz(a) ; ++i) ans.pb(a[i]);
    if(sz(ans) > 26) return false;
    int cnt[26] = {};
    trav(c , ans) if(++cnt[c - 'a'] > 1) return false;
    a.swap(ans);
    return true ;
}
void solve()
{
    cin >> n ;
    map<string , bool> m;
    rep(i , n){
        string s;
        cin >> s;
        m[s];
    }
    trav(x , m){
        string s = x.ff;
        if(s.length() > 26) kek(1);
        int cnt[26] = {};
        trav(c , s)
            if(++cnt[c - 'a'] > 1) kek(2);
        rep(i , sz(s)){
            string tmp = "" ;
            repA(j , i , sz(s) - 1){
                tmp += s[j] ;
                if(tmp == s) break ;
                if(m.find(tmp) != m.end()) m.erase(m.find(tmp));
            }
        }
    }

    vector<string> pos[26];
    trav(x , m){
        string s = x.ff;
        trav(c , s){
            pos[c - 'a'].pb(s);
            if(sz(pos[c - 'a']) > 2) kek(3);
        }
    }
    // rep(i , 26){
    //     if(!sz(pos[i])) continue ;
    //     cout << char(i + 'a') << ":\n" ;
    //     trav(s , pos[i]) cout << s << ' ';
    //     cout << '\n';
    // }

    rep(i , 26){
        int cnt = 0;
        string tmp[2];
        trav(x , m){
            trav(c , x.ff){
                if(c == char(i + 'a')){
                    if(cnt > 2) kek(4);
                    tmp[cnt++] = x.ff;
                    break;
                }
            }
        }
        if(cnt < 2) continue ;
        rep(j,2) m.erase(m.find(tmp[j]));
        string a = tmp[0] , b = tmp[1];
        vector<string> res;
        // cout << a << "-" << b << "\n";
        if(merge_str(a , tmp[1])){
            res.pb(a);
        }
        if(merge_str(b , tmp[0])){
            res.pb(b);
        }
        if(res.empty()) kek(5);
        if(sz(res) == 2 && res[1] < res[0]) swap(res[0] , res[1]);
        m[res[0]];
    }
    // assert(sz(m) == 1);`
    trav(x , m) cout << x.ff ;
    // cout << m.begin()->ff;
}

int32_t main(int32_t argc, char *argv[])
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    int TC = 1, t = 0;
    //cin >> TC ;
    while(t++ < TC)
    {
        //cout << "Case #" << t << ": " ;
        solve();
        cout << "\n" ;
    }
    return 0;
}


/* Author : Aaryan Srivastava ^__^ */
#include <bits/stdc++.h>
#include <random>
#include <chrono>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define pb push_back
#define mp make_pair
#define ff first
#define ss second
#define rep(i,n) for(int i = 0 ; i < (n) ; i++)
#define repA(i,x,y) for(int i = (x) ; i <= (y) ; i++)
#define repD(i,x,y) for(int i = (x) ; i >= (y) ; i--)
#define all(c) (c).begin(),(c).end()
#define rall(c) (c).rbegin(),(c).rend()
#define setval(a,val) memset(a,val,sizeof(a))
#define Randomize mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define trav(x , a) for(auto &x : a)
#define sz(a) ((int)a.size())
typedef long long ll ;
#define int ll
using namespace std;

const int N = 3e5 + 5 ;
const int mod = 1e9 + 7 ;
const ll inf = 1e18 ;
const int SZ = 101 ;
const long double eps = 1e-9 ;

using namespace __gnu_pbds;
using ordered_set =  tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> ;

typedef pair<int, int> pii;
typedef pair<int , pii> ipii ;
typedef pair<pii , int> piii ;
typedef unsigned long long ull ;
typedef long double ld;

ll po(ll x,ll y,ll p = mod) {ll res=1;x%=p;while(y>0){if(y&1)res=(res*x)%p;y=y>>1;x=(x*x)%p;}return res;}

int n ;
void kek(int x = 0){
    cout << "NO";
    if(n == 88)
        cout << x;
    exit(0);
}

bool merge_str(string &a , string &b){
    string s = a + '#' + b ;
    int n = s.length();
    vector<int> pi(n , 0);
    for(int i = 1; i < n  ; ++i){
        int j = pi[i-1];
        while(j && s[i] != s[j]) j = pi[j-1];
        j += (s[i] == s[j]);
        pi[i] = j;
    }
    int skip = pi[n-1];
    string ans = b;
    for(int i = skip ; i < sz(a) ; ++i) ans.pb(a[i]);
    if(sz(ans) > 26) return false;
    int cnt[26] = {};
    trav(c , ans) if(++cnt[c - 'a'] > 1) return false;
    a.swap(ans);
    return true ;
}
void solve()
{
    cin >> n ;
    map<string , bool> m;
    rep(i , n){
        string s;
        cin >> s;
        m[s];
    }
    trav(x , m){
        string s = x.ff;
        if(s.length() > 26) kek(1);
        int cnt[26] = {};
        trav(c , s)
            if(++cnt[c - 'a'] > 1) kek(2);
        rep(i , sz(s)){
            string tmp = "" ;
            repA(j , i , sz(s) - 1){
                tmp += s[j] ;
                if(tmp == s) break ;
                if(m.find(tmp) != m.end()) m.erase(m.find(tmp));
            }
        }
    }

    vector<string> pos[26];
    // trav(x , m){
    //     string s = x.ff;
    //     trav(c , s){
    //         pos[c - 'a'].pb(s);
    //         break;
    //         if(sz(pos[c - 'a']) > 2){
    //             cout << sz(pos[c - 'a']) << ek(3);
    //     }
    // }
    // rep(i , 26){
    //     if(!sz(pos[i])) continue ;
    //     cout << char(i + 'a') << ":\n" ;
    //     trav(s , pos[i]) cout << s << ' ';
    //     cout << '\n';
    // }

    rep(i , 26){
        int cnt = 0;
        string tmp[2];
        trav(x , m){
            trav(c , x.ff){
                if(c == char(i + 'a')){
                    if(cnt > 2) kek(4);
                    tmp[cnt++] = x.ff;
                    break;
                }
            }
        }
        if(cnt < 2) continue ;
        rep(j,2) m.erase(m.find(tmp[j]));
        string a = tmp[0] , b = tmp[1];
        vector<string> res;
        // cout << a << "-" << b << "\n";
        if(merge_str(a , tmp[1])){
            res.pb(a);
        }
        if(merge_str(b , tmp[0])){
            res.pb(b);
        }
        if(res.empty()){
            if(n == 88) cout << char(i + 'a') <<  a << ' ' << b << '\n' ;
            kek(5);
        }
        if(sz(res) == 2 && res[1] < res[0]) swap(res[0] , res[1]);
        m[res[0]];
    }
    // assert(sz(m) == 1);`
    trav(x , m) cout << x.ff ;
    // cout << m.begin()->ff;
}

int32_t main(int32_t argc, char *argv[])
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    int TC = 1, t = 0;
    //cin >> TC ;
    while(t++ < TC)
    {
        //cout << "Case #" << t << ": " ;
        solve();
        cout << "\n" ;
    }
    return 0;
}


/* Author : Aaryan Srivastava ^__^ */
#include <bits/stdc++.h>
#include <random>
#include <chrono>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define pb push_back
#define mp make_pair
#define ff first
#define ss second
#define rep(i,n) for(int i = 0 ; i < (n) ; i++)
#define repA(i,x,y) for(int i = (x) ; i <= (y) ; i++)
#define repD(i,x,y) for(int i = (x) ; i >= (y) ; i--)
#define all(c) (c).begin(),(c).end()
#define rall(c) (c).rbegin(),(c).rend()
#define setval(a,val) memset(a,val,sizeof(a))
#define Randomize mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define trav(x , a) for(auto &x : a)
#define sz(a) ((int)a.size())
typedef long long ll ;
#define int ll
using namespace std;

const int N = 3e5 + 5 ;
const int mod = 1e9 + 7 ;
const ll inf = 1e18 ;
const int SZ = 101 ;
const long double eps = 1e-9 ;

using namespace __gnu_pbds;
using ordered_set =  tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> ;

typedef pair<int, int> pii;
typedef pair<int , pii> ipii ;
typedef pair<pii , int> piii ;
typedef unsigned long long ull ;
typedef long double ld;

ll po(ll x,ll y,ll p = mod) {ll res=1;x%=p;while(y>0){if(y&1)res=(res*x)%p;y=y>>1;x=(x*x)%p;}return res;}

int n ;
void kek(int x = 0){
    cout << "NO";
    if(n == 88)
        cout << x;
    exit(0);
}

bool merge_str(string &a , string &b){
    string s = a + '#' + b ;
    int n = s.length();
    vector<int> pi(n , 0);
    for(int i = 1; i < n  ; ++i){
        int j = pi[i-1];
        while(j && s[i] != s[j]) j = pi[j-1];
        j += (s[i] == s[j]);
        pi[i] = j;
        if(pi[i] == (int)a.length()){
            a.swap(b);
            return true;
        }
    }
    int skip = pi[n-1];
    string ans = b;
    for(int i = skip ; i < sz(a) ; ++i) ans.pb(a[i]);
    if(sz(ans) > 26) return false;
    int cnt[26] = {};
    trav(c , ans) if(++cnt[c - 'a'] > 1) return false;
    a.swap(ans);
    return true ;
}
void solve()
{
    cin >> n ;
    map<string , bool> m;
    rep(i , n){
        string s;
        cin >> s;
        m[s];
    }
    trav(x , m){
        string s = x.ff;
        if(s.length() > 26) kek(1);
        int cnt[26] = {};
        trav(c , s)
            if(++cnt[c - 'a'] > 1) kek(2);
        rep(i , sz(s)){
            string tmp = "" ;
            repA(j , i , sz(s) - 1){
                tmp += s[j] ;
                if(tmp == s) break ;
                if(m.find(tmp) != m.end()) m.erase(m.find(tmp));
            }
        }
    }

    vector<string> pos[26];
    // trav(x , m){
    //     string s = x.ff;
    //     trav(c , s){
    //         pos[c - 'a'].pb(s);
    //         break;
    //         if(sz(pos[c - 'a']) > 2){
    //             cout << sz(pos[c - 'a']) << ek(3);
    //     }
    // }
    // rep(i , 26){
    //     if(!sz(pos[i])) continue ;
    //     cout << char(i + 'a') << ":\n" ;
    //     trav(s , pos[i]) cout << s << ' ';
    //     cout << '\n';
    // }

    rep(i , 26){
        vector<string> tmp;
        trav(x , m){
            trav(c , x.ff){
                if(c == char(i + 'a')){
                    tmp.pb(x.ff);
                    break;
                }
            }
        }
        if(sz(tmp) > 2){
            if(n == 88) trav(s , tmp) cout << s << '\n';
            kek(4);
        }
        if(sz(tmp) < 2) continue ;
        rep(j,sz(tmp)) m.erase(m.find(tmp[j]));
        vector<string> use(all(tmp));
        string a = tmp[0] , b = tmp[1];
        vector<string> res;
        // cout << a << "-" << b << "\n";
        if(merge_str(a , tmp[1])){
            res.pb(a);
            rep(j , sz(tmp)) tmp[j] = use[j];
        }
        if(merge_str(b , tmp[0])){
            res.pb(b);
            rep(j , sz(tmp)) tmp[j] = use[j];
        }
        if(res.empty()){
            // if(n == 88) cout << char(i + 'a') <<  a << ' ' << b << '\n' ;
            kek(5);
        }
        sort(all(res));
        // if(sz(res) == 2 && res[1] < res[0]) swap(res[0] , res[1]);
        m[res[0]];
    }
    // assert(sz(m) == 1);`
    trav(x , m) cout << x.ff ;
    // cout << m.begin()->ff;
}

int32_t main(int32_t argc, char *argv[])
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    int TC = 1, t = 0;
    //cin >> TC ;
    while(t++ < TC)
    {
        //cout << "Case #" << t << ": " ;
        solve();
        cout << "\n" ;
    }
    return 0;
}


/* Author : Aaryan Srivastava ^__^ */
#include <bits/stdc++.h>
#include <random>
#include <chrono>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define pb push_back
#define mp make_pair
#define ff first
#define ss second
#define rep(i,n) for(int i = 0 ; i < (n) ; i++)
#define repA(i,x,y) for(int i = (x) ; i <= (y) ; i++)
#define repD(i,x,y) for(int i = (x) ; i >= (y) ; i--)
#define all(c) (c).begin(),(c).end()
#define rall(c) (c).rbegin(),(c).rend()
#define setval(a,val) memset(a,val,sizeof(a))
#define Randomize mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define trav(x , a) for(auto &x : a)
#define sz(a) ((int)a.size())
typedef long long ll ;
#define int ll
using namespace std;

const int N = 3e5 + 5 ;
const int mod = 1e9 + 7 ;
const ll inf = 1e18 ;
const int SZ = 101 ;
const long double eps = 1e-9 ;

using namespace __gnu_pbds;
using ordered_set =  tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> ;

typedef pair<int, int> pii;
typedef pair<int , pii> ipii ;
typedef pair<pii , int> piii ;
typedef unsigned long long ull ;
typedef long double ld;

ll po(ll x,ll y,ll p = mod) {ll res=1;x%=p;while(y>0){if(y&1)res=(res*x)%p;y=y>>1;x=(x*x)%p;}return res;}

int n ;
void kek(int x = 0){
    cout << "NO";
    if(n == 88)
        cout << x;
    exit(0);
}

bool merge_str(string &a , string &b){
    string s = a + '#' + b ;
    int n = s.length();
    vector<int> pi(n , 0);
    for(int i = 1; i < n  ; ++i){
        int j = pi[i-1];
        while(j && s[i] != s[j]) j = pi[j-1];
        j += (s[i] == s[j]);
        pi[i] = j;
        if(pi[i] == (int)a.length()){
            a.swap(b);
            return true;
        }
    }
    int skip = pi[n-1];
    string ans = b;
    for(int i = skip ; i < sz(a) ; ++i) ans.pb(a[i]);
    if(sz(ans) > 26) return false;
    int cnt[26] = {};
    trav(c , ans) if(++cnt[c - 'a'] > 1) return false;
    a.swap(ans);
    return true ;
}
void solve()
{
    cin >> n ;
    map<string , bool> m;
    rep(i , n){
        string s;
        cin >> s;
        m[s];
    }
    trav(x , m){
        string s = x.ff;
        if(s.length() > 26) kek(1);
        int cnt[26] = {};
        trav(c , s)
            if(++cnt[c - 'a'] > 1) kek(2);
        rep(i , sz(s)){
            string tmp = "" ;
            repA(j , i , sz(s) - 1){
                tmp += s[j] ;
                if(tmp == s) break ;
                if(m.find(tmp) != m.end()) m.erase(m.find(tmp));
            }
        }
    }

    vector<string> pos[26];
    // trav(x , m){
    //     string s = x.ff;
    //     trav(c , s){
    //         pos[c - 'a'].pb(s);
    //         break;
    //         if(sz(pos[c - 'a']) > 2){
    //             cout << sz(pos[c - 'a']) << ek(3);
    //     }
    // }
    // rep(i , 26){
    //     if(!sz(pos[i])) continue ;
    //     cout << char(i + 'a') << ":\n" ;
    //     trav(s , pos[i]) cout << s << ' ';
    //     cout << '\n';
    // }

    rep(i , 26){
        vector<string> v;
        string tmp = "";
        trav(x , m){
            trav(c , x.ff){
                if(c == char(i + 'a')){
                    v.pb(x.ff);
                    string b(all(x.ff));
                    if( merge_str(tmp , b) ){
                        //
                    } else if (merge_str(b , tmp)){
                        tmp.swap(b);
                    }else kek(-1);
                    break;
                }
            }
        }
        trav(s , v) m.erase(m.find(s));
        if(!tmp.empty()) m[tmp];
        // if(sz(tmp) > 2){
        //     if(n == 88) trav(s , tmp) cout << s << '\n';
        //     kek(4);
        // }
        // if(sz(tmp) < 2) continue ;
        // rep(j,sz(tmp)) m.erase(m.find(tmp[j]));
        // vector<string> use(all(tmp));
        // string a = tmp[0] , b = tmp[1];
        // vector<string> res;
        // // cout << a << "-" << b << "\n";
        // if(merge_str(a , tmp[1])){
        //     res.pb(a);
        //     rep(j , sz(tmp)) tmp[j] = use[j];
        // }
        // if(merge_str(b , tmp[0])){
        //     res.pb(b);
        //     rep(j , sz(tmp)) tmp[j] = use[j];
        // }
        // if(res.empty()){
        //     // if(n == 88) cout << char(i + 'a') <<  a << ' ' << b << '\n' ;
        //     kek(5);
        // }
        // sort(all(res));
        // // if(sz(res) == 2 && res[1] < res[0]) swap(res[0] , res[1]);
        // m[res[0]];
    }
    // assert(sz(m) == 1);`
    trav(x , m) cout << x.ff ;
    // cout << m.begin()->ff;
}

int32_t main(int32_t argc, char *argv[])
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    int TC = 1, t = 0;
    //cin >> TC ;
    while(t++ < TC)
    {
        //cout << "Case #" << t << ": " ;
        solve();
        cout << "\n" ;
    }
    return 0;
}


/* Author : Aaryan Srivastava ^__^ */
#include <bits/stdc++.h>
#include <random>
#include <chrono>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define pb push_back
#define mp make_pair
#define ff first
#define ss second
#define rep(i,n) for(int i = 0 ; i < (n) ; i++)
#define repA(i,x,y) for(int i = (x) ; i <= (y) ; i++)
#define repD(i,x,y) for(int i = (x) ; i >= (y) ; i--)
#define all(c) (c).begin(),(c).end()
#define rall(c) (c).rbegin(),(c).rend()
#define setval(a,val) memset(a,val,sizeof(a))
#define Randomize mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define trav(x , a) for(auto &x : a)
#define sz(a) ((int)a.size())
typedef long long ll ;
#define int ll
using namespace std;

const int N = 3e5 + 5 ;
const int mod = 1e9 + 7 ;
const ll inf = 1e18 ;
const int SZ = 101 ;
const long double eps = 1e-9 ;

using namespace __gnu_pbds;
using ordered_set =  tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> ;

typedef pair<int, int> pii;
typedef pair<int , pii> ipii ;
typedef pair<pii , int> piii ;
typedef unsigned long long ull ;
typedef long double ld;

ll po(ll x,ll y,ll p = mod) {ll res=1;x%=p;while(y>0){if(y&1)res=(res*x)%p;y=y>>1;x=(x*x)%p;}return res;}

int n ;
void kek(int x = 0){
    cout << "NO";
    if(n == 88)
        cout << x;
    exit(0);
}

bool merge_str(string &a , string &b){
    string s = a + '#' + b ;
    int n = s.length();
    vector<int> pi(n , 0);
    for(int i = 1; i < n  ; ++i){
        int j = pi[i-1];
        while(j && s[i] != s[j]) j = pi[j-1];
        j += (s[i] == s[j]);
        pi[i] = j;
    }
    int skip = pi[n-1];
    string ans = b;
    for(int i = skip ; i < sz(a) ; ++i) ans.pb(a[i]);
    if(sz(ans) > 26) return false;
    int cnt[26] = {};
    trav(c , ans) if(++cnt[c - 'a'] > 1) return false;
    a.swap(ans);
    return true ;
}
void solve()
{
    cin >> n ;
    map<string , bool> m;
    rep(i , n){
        string s;
        cin >> s;
        m[s];
    }
    trav(x , m){
        string s = x.ff;
        if(s.length() > 26) kek(1);
        int cnt[26] = {};
        trav(c , s)
            if(++cnt[c - 'a'] > 1) kek(2);
        rep(i , sz(s)){
            string tmp = "" ;
            repA(j , i , sz(s) - 1){
                tmp += s[j] ;
                if(tmp == s) break ;
                if(m.find(tmp) != m.end()) m.erase(m.find(tmp));
            }
        }
    }

    vector<string> pos[26];
    // trav(x , m){
    //     string s = x.ff;
    //     trav(c , s){
    //         pos[c - 'a'].pb(s);
    //         break;
    //         if(sz(pos[c - 'a']) > 2){
    //             cout << sz(pos[c - 'a']) << ek(3);
    //     }
    // }
    // rep(i , 26){
    //     if(!sz(pos[i])) continue ;
    //     cout << char(i + 'a') << ":\n" ;
    //     trav(s , pos[i]) cout << s << ' ';
    //     cout << '\n';
    // }

    rep(i , 26){
        int cnt = 0;
        string tmp[2];
        trav(x , m){
            trav(c , x.ff){
                if(c == char(i + 'a')){
                    if(cnt > 2) kek(4);
                    tmp[cnt++] = x.ff;
                    break;
                }
            }
        }
        if(cnt < 2) continue ;
        rep(j,2) m.erase(m.find(tmp[j]));
        string a = tmp[0] , b = tmp[1];
        vector<string> res;
        // cout << a << "-" << b << "\n";
        if(merge_str(a , tmp[1])){
            res.pb(a);
        }
        if(merge_str(b , tmp[0])){
            res.pb(b);
        }
        if(res.empty()){
            if(n == 88) cout << a << ' ' << b << '\n' ;
            kek(5);
        }
        if(sz(res) == 2 && res[1] < res[0]) swap(res[0] , res[1]);
        m[res[0]];
    }
    // assert(sz(m) == 1);`
    trav(x , m) cout << x.ff ;
    // cout << m.begin()->ff;
}

int32_t main(int32_t argc, char *argv[])
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    int TC = 1, t = 0;
    //cin >> TC ;
    while(t++ < TC)
    {
        //cout << "Case #" << t << ": " ;
        solve();
        cout << "\n" ;
    }
    return 0;
}


/* Author : Aaryan Srivastava ^__^ */
#include <bits/stdc++.h>
#include <random>
#include <chrono>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define pb push_back
#define mp make_pair
#define ff first
#define ss second
#define rep(i,n) for(int i = 0 ; i < (n) ; i++)
#define repA(i,x,y) for(int i = (x) ; i <= (y) ; i++)
#define repD(i,x,y) for(int i = (x) ; i >= (y) ; i--)
#define all(c) (c).begin(),(c).end()
#define rall(c) (c).rbegin(),(c).rend()
#define setval(a,val) memset(a,val,sizeof(a))
#define Randomize mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define trav(x , a) for(auto &x : a)
#define sz(a) ((int)a.size())
typedef long long ll ;
#define int ll
using namespace std;

const int N = 3e5 + 5 ;
const int mod = 1e9 + 7 ;
const ll inf = 1e18 ;
const int SZ = 101 ;
const long double eps = 1e-9 ;

using namespace __gnu_pbds;
using ordered_set =  tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> ;

typedef pair<int, int> pii;
typedef pair<int , pii> ipii ;
typedef pair<pii , int> piii ;
typedef unsigned long long ull ;
typedef long double ld;

ll po(ll x,ll y,ll p = mod) {ll res=1;x%=p;while(y>0){if(y&1)res=(res*x)%p;y=y>>1;x=(x*x)%p;}return res;}

int n ;
void kek(int x = 0){
    cout << "NO";
    // if(n == 88)
    //     cout << x;
    exit(0);
}

bool merge_str(string &a , string &b){
    string s = a + '#' + b ;
    int n = s.length();
    vector<int> pi(n , 0);
    for(int i = 1; i < n  ; ++i){
        int j = pi[i-1];
        while(j && s[i] != s[j]) j = pi[j-1];
        j += (s[i] == s[j]);
        pi[i] = j;
    }
    int skip = pi[n-1];
    string ans = b;
    for(int i = skip ; i < sz(a) ; ++i) ans.pb(a[i]);
    if(sz(ans) > 26) return false;
    int cnt[26] = {};
    trav(c , ans) if(++cnt[c - 'a'] > 1) return false;
    a.swap(ans);
    return true ;
}
void solve()
{
    cin >> n ;
    map<string , bool> m;
    rep(i , n){
        string s;
        cin >> s;
        m[s];
    }
    trav(x , m){
        string s = x.ff;
        if(s.length() > 26) kek(1);
        int cnt[26] = {};
        trav(c , s)
            if(++cnt[c - 'a'] > 1) kek(2);
        rep(i , sz(s)){
            string tmp = "" ;
            repA(j , i , sz(s) - 1){
                tmp += s[j] ;
                if(tmp == s) break ;
                if(m.find(tmp) != m.end()) m.erase(m.find(tmp));
            }
        }
    }

    vector<string> pos[26];
    // trav(x , m){
    //     string s = x.ff;
    //     trav(c , s){
    //         pos[c - 'a'].pb(s);
    //         break;
    //         if(sz(pos[c - 'a']) > 2){
    //             cout << sz(pos[c - 'a']) << ek(3);
    //     }
    // }
    // rep(i , 26){
    //     if(!sz(pos[i])) continue ;
    //     cout << char(i + 'a') << ":\n" ;
    //     trav(s , pos[i]) cout << s << ' ';
    //     cout << '\n';
    // }

    rep(i , 26){
        int cnt = 0;
        string tmp[2];
        trav(x , m){
            trav(c , x.ff){
                if(c == char(i + 'a')){
                    if(cnt > 2) kek(4);
                    tmp[cnt++] = x.ff;
                    break;
                }
            }
        }
        if(cnt < 2) continue ;
        rep(j,2) m.erase(m.find(tmp[j]));
        string a = tmp[0] , b = tmp[1];
        vector<string> res;
        // cout << a << "-" << b << "\n";
        if(merge_str(a , tmp[1])){
            res.pb(a);
        }
        if(merge_str(b , tmp[0])){
            res.pb(b);
        }
        if(res.empty()) kek(5);
        if(sz(res) == 2 && res[1] < res[0]) swap(res[0] , res[1]);
        m[res[0]];
    }
    // assert(sz(m) == 1);`
    trav(x , m) cout << x.ff ;
    // cout << m.begin()->ff;
}

int32_t main(int32_t argc, char *argv[])
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    int TC = 1, t = 0;
    //cin >> TC ;
    while(t++ < TC)
    {
        //cout << "Case #" << t << ": " ;
        solve();
        cout << "\n" ;
    }
    return 0;
}


/* Author : Aaryan Srivastava ^__^ */
#include <bits/stdc++.h>
#include <random>
#include <chrono>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#define pb push_back
#define mp make_pair
#define ff first
#define ss second
#define rep(i,n) for(int i = 0 ; i < (n) ; i++)
#define repA(i,x,y) for(int i = (x) ; i <= (y) ; i++)
#define repD(i,x,y) for(int i = (x) ; i >= (y) ; i--)
#define all(c) (c).begin(),(c).end()
#define rall(c) (c).rbegin(),(c).rend()
#define setval(a,val) memset(a,val,sizeof(a))
#define Randomize mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define trav(x , a) for(auto &x : a)
#define sz(a) ((int)a.size())
typedef long long ll ;
#define int ll
using namespace std;

const int N = 3e5 + 5 ;
const int mod = 1e9 + 7 ;
const ll inf = 1e18 ;
const int SZ = 101 ;
const long double eps = 1e-9 ;

using namespace __gnu_pbds;
using ordered_set =  tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> ;

typedef pair<int, int> pii;
typedef pair<int , pii> ipii ;
typedef pair<pii , int> piii ;
typedef unsigned long long ull ;
typedef long double ld;

ll po(ll x,ll y,ll p = mod) {ll res=1;x%=p;while(y>0){if(y&1)res=(res*x)%p;y=y>>1;x=(x*x)%p;}return res;}

int n ;
void kek(int x = 0){
    cout << "NO";
    if(n == 88)
        cout << x;
    exit(0);
}

bool merge_str(string &a , string &b){
    string s = a + '#' + b ;
    int n = s.length();
    vector<int> pi(n , 0);
    for(int i = 1; i < n  ; ++i){
        int j = pi[i-1];
        while(j && s[i] != s[j]) j = pi[j-1];
        j += (s[i] == s[j]);
        pi[i] = j;
        if(pi[i] == sz(a)){
            a = b;
            return true;
        }
    }
    int skip = pi[n-1];
    string ans = b;
    for(int i = skip ; i < sz(a) ; ++i) ans.pb(a[i]);
    if(sz(ans) > 26) return false;
    int cnt[26] = {};
    trav(c , ans) if(++cnt[c - 'a'] > 1) return false;
    a.swap(ans);
    return true ;
}
void solve()
{
    cin >> n ;
    map<string , bool> m;
    rep(i , n){
        string s;
        cin >> s;
        m[s];
    }
    trav(x , m){
        string s = x.ff;
        if(s.length() > 26) kek(1);
        int cnt[26] = {};
        trav(c , s)
            if(++cnt[c - 'a'] > 1) kek(2);
        rep(i , sz(s)){
            string tmp = "" ;
            repA(j , i , sz(s) - 1){
                tmp += s[j] ;
                if(tmp == s) break ;
                if(m.find(tmp) != m.end()) m.erase(m.find(tmp));
            }
        }
    }

    vector<string> pos[26];
    // trav(x , m){
    //     string s = x.ff;
    //     trav(c , s){
    //         pos[c - 'a'].pb(s);
    //         break;
    //         if(sz(pos[c - 'a']) > 2){
    //             cout << sz(pos[c - 'a']) << ek(3);
    //     }
    // }
    // rep(i , 26){
    //     if(!sz(pos[i])) continue ;
    //     cout << char(i + 'a') << ":\n" ;
    //     trav(s , pos[i]) cout << s << ' ';
    //     cout << '\n';
    // }

    rep(i , 26){
        int cnt = 0;
        string tmp[2];
        trav(x , m){
            trav(c , x.ff){
                if(c == char(i + 'a')){
                    if(cnt > 2) kek(4);
                    tmp[cnt++] = x.ff;
                    break;
                }
            }
        }
        if(cnt < 2) continue ;
        rep(j,2) m.erase(m.find(tmp[j]));
        string a = tmp[0] , b = tmp[1];
        vector<string> res;
        // cout << a << "-" << b << "\n";
        if(merge_str(a , tmp[1])){
            res.pb(a);
        }
        if(merge_str(b , tmp[0])){
            res.pb(b);
        }
        if(res.empty()){
            if(n == 88) cout << char(i + 'a') <<  a << ' ' << b << '\n' ;
            kek(5);
        }
        if(sz(res) == 2 && res[1] < res[0]) swap(res[0] , res[1]);
        m[res[0]];
    }
    // assert(sz(m) == 1);`
    trav(x , m) cout << x.ff ;
    // cout << m.begin()->ff;
}

int32_t main(int32_t argc, char *argv[])
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    int TC = 1, t = 0;
    //cin >> TC ;
    while(t++ < TC)
    {
        //cout << "Case #" << t << ": " ;
        solve();
        cout << "\n" ;
    }
    return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define f first
#define s second
#define pb push_back

vector<vector<int>>adj;
bool che;
int co[26];

void dfs(int v){
	co[v]=1;
	for(auto u:adj[v]){
		if(co[u]==1){
			che=1;
		}
		if(co[u]==0){
			dfs(u);
		}
	}
	co[v]=2;
}

int main() {
	int n;
	cin>>n;
	adj.resize(26);
	bool b=1;
	int pa[26];
	for(int i=0; i<26; i++){
		pa[i]=-1;
	}
	bool ex[26];
	for(int i=0; i<26; i++){
		ex[i]=0;
	}
	for(int i=0; i<n; i++){
		string s;
		cin>>s;
		ex[(s[0]-'a')]=1;
		string t;
		t=s;
		sort(t.begin(), t.end());
		for(int j=0; j<t.size()-1; j++){
			if(t[j]==t[j+1]){
				cout<<"NO";
				return 0;
			}
		}
		for(int i=0; i<s.size()-1; i++){
			if(pa[(s[i]-'a')]!=-1 && pa[(s[i]-'a')]!=(s[(i+1)]-'a')){
				cout<<"NO";
				return 0;
			}
			pa[(s[i]-'a')]=(s[(i+1)]-'a');
			ex[(s[i]-'a')]=1;
			ex[(s[(i+1)]-'a')]=1;
		}
	}
	for(int i=0; i<26; i++){
		if(pa[i]!=-1){
			adj[i].pb(pa[i]);
		}
	}

	for(int i=0; i<26; i++){
		if(ex[i] && co[i]==0){
			dfs(i);
		}
	}
	if(che){
		cout<<"NO";
		return 0;
	}
	for(int i=0; i<26; i++){
		for(int j=0; j<26; j++){
			if(i!=j && pa[i]!=-1 && pa[i]==pa[j]){
				cout<<"NO";
				return 0;
			}
		}
	}
	bool iso[26];
	for(int i=0; i<26; i++){
		iso[i]=0;
	}
	for(int i=0; i<26; i++){
		if(pa[i]!=-1){
			iso[pa[i]]=1;
		}
	}
	vector<int>vec;
	for(int i=0; i<26; i++){
		if(ex[i] && iso[i]==0){
			vec.pb(i);
		}
	}
	sort(vec.begin(), vec.end());
	for(auto u:vec){
		int node=u;
		while(node!=-1){
			cout<<char('a'+node);
			node=pa[node];
		}
	}
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define f first
#define s second
#define pb push_back

vector<vector<int>>adj;
bool che;
int co[26];

void dfs(int v){
	co[v]=1;
	for(auto u:adj[v]){
		if(co[u]==1){
			che=1;
		}
		if(co[u]==0){
			dfs(u);
		}
	}
	co[v]=2;
}

int main() {
	int n;
	cin>>n;
	adj.resize(26);
	bool b=1;
	int pa[26];
	for(int i=0; i<26; i++){
		pa[i]=-1;
	}
	bool ex[26];
	for(int i=0; i<26; i++){
		ex[i]=0;
	}
	for(int i=0; i<n; i++){
		string s;
		cin>>s;
		string t;
		t=s;
		sort(t.begin(), t.end());
		for(int j=0; j<t.size()-1; j++){
			if(t[j]==t[j+1]){
				cout<<"NO";
				return 0;
			}
		}
		for(int i=0; i<s.size()-1; i++){
			if(pa[(s[i]-'a')]!=-1 && pa[(s[i]-'a')]!=(s[(i+1)]-'a')){
				cout<<"NO";
				return 0;
			}
			pa[(s[i]-'a')]=(s[(i+1)]-'a');
			ex[(s[i]-'a')]=1;
			ex[(s[(i+1)]-'a')]=1;
		}
	}
	for(int i=0; i<26; i++){
		if(pa[i]!=-1){
			adj[i].pb(pa[i]);
		}
	}

	for(int i=0; i<26; i++){
		if(ex[i] && co[i]==0){
			dfs(i);
		}
	}
	if(che){
		cout<<"NO";
		return 0;
	}
	for(int i=0; i<26; i++){
		for(int j=0; j<26; j++){
			if(i!=j && pa[i]!=-1 && pa[i]==pa[j]){
				cout<<"NO";
				return 0;
			}
		}
	}
	bool iso[26];
	for(int i=0; i<26; i++){
		iso[i]=0;
	}
	for(int i=0; i<26; i++){
		if(pa[i]!=-1){
			iso[pa[i]]=1;
		}
	}
	vector<int>vec;
	for(int i=0; i<26; i++){
		if(ex[i] && iso[i]==0){
			vec.pb(i);
		}
	}
	sort(vec.begin(), vec.end());
	for(auto u:vec){
		int node=u;
		while(node!=-1){
			cout<<char('a'+node);
			node=pa[node];
		}
	}
	return 0;
}


//   __________________
//  | ________________ |
//  ||          ____  ||
//  ||   /\    |      ||
//  ||  /__\   |      ||
//  || /    \  |____  ||
//  ||________________||
//  |__________________|
//  \###################\
//   \###################\
//    \        ____       \
//     \_______\___\_______\
// An AC a day keeps the doctor away.

#ifdef local
#include <bits/extc++.h>
#define safe std::cerr<<__PRETTY_FUNCTION__<<" line "<<__LINE__<<" safe\n"
#define debug(args...) qqbx(#args, args)
template <typename ...T> void qqbx(const char *s, T ...args) {
    std::cerr << "\033[1;32m" << '(' << s << ')' << " = " << '(';
    constexpr int size = sizeof...(T);
    int cnt = size, dummy[size] = { (std::cerr << args << (--cnt ? ", " : ")\033[0m\n"), 0)... };
}
#else
#pragma GCC optimize("Ofast")
#pragma loop_opt(on)
#include <bits/extc++.h>
#include <bits/stdc++.h>
#define debug(...) ((void)0)
#define safe ((void)0)
#endif // local
#define all(v) begin(v),end(v)
#define get_pos(v,x) int(lower_bound(begin(v),end(v),x)-begin(v))
#define sort_uni(v) sort(begin(v),end(v)),v.erase(unique(begin(v),end(v)),end(v))
#define pb emplace_back
#define ff first
#define ss second
#define mem(v,x) memset(v,x,sizeof v)

using namespace std;
using namespace __gnu_pbds;
typedef int64_t ll;
typedef long double ld;
typedef pair<ll,ll> pll;
typedef pair<ld,ld> pld;
template <typename T> using max_heap = std::priority_queue<T,vector<T>,less<T> >;
template <typename T> using min_heap = std::priority_queue<T,vector<T>,greater<T> >;
template <typename T> using rbt = tree<T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;
constexpr ld PI = acos(-1), eps = 1e-7;
constexpr ll N = 525, INF = 1e18, MOD = 1000000007, K = 26, inf = 1e9;
constexpr inline ll cdiv(ll x, ll m) { return x/m + ((x<0 ^ m>0) && (x%m)); } // ceiling divide
constexpr inline ll modpow(ll e,ll p,ll m=MOD) { ll r=1; for(e%=m;p;p>>=1,e=e*e%m) if(p&1) r=r*e%m; return r; }

int match(const string &T, const string &P) {
    vector<int> fail(P.size());
    for(int i = 1, j = 0; i < P.size(); i++) {
        while(j && P[i] != P[j]) j = fail[j-1];
        if(P[i] == P[j]) ++j;
        fail[i] = j;
    }
    int res = 0;
    for(int i = 0, j = 0; i < T.size(); i++) {
        while(j && T[i] != P[j]) j = fail[j-1];
        if(T[i] == P[j]) ++j;
        if(j == P.size()) {
            ++res;
            j = fail[j-1];
        }
    }
    return res;
}
struct AhoCorasick {
    int ch[N][K], fail[N], isEnd[N], tot;
    int newnode() {
        ++tot;
        for(int c = 0; c < K; c++) ch[tot][c] = 0;
        fail[tot] = 0, isEnd[tot] = 0;
        return tot;
    }
    void ins(string s, int d) {
        int i = 0;
        for(char c: s) {
            c -= 'a';
            if(!ch[i][c])
                ch[i][c] = newnode();
            i = ch[i][c];
        }
        isEnd[i] |= d;
    }
    void buildFail() {
        queue<int> q;
        for(int c = 0; c < K; c++) if(ch[0][c]) q.push(ch[0][c]);
        while(!q.empty()) {
            int i = q.front(); q.pop();
            int f = fail[i];
            isEnd[i] |= isEnd[f];
            for(int c = 0; c < K; c++) {
                if(ch[i][c]) {
                    fail[ ch[i][c] ] = ch[f][c];
                    q.push(ch[i][c]);
                } else {
                    ch[i][c] = ch[f][c];
                }
            }
        }
    }
    pair<int,int> getnext(pair<int,int> now, int c) {
        int to = ch[now.first][c], mask = now.second;
        if(mask & isEnd[to]) {
            return {0, 0};
        }
        /* if(isEnd[to] && (mask | isEnd[to]) == 5) debug(rrr[now.first], mask, rrr[to]); */
        return {to, mask | isEnd[to]};
    }
} AC;
template <typename U, typename V> ostream & operator<<(ostream &O, pair<U,V> p) { return O << "(" << p.first << ", " << p.second << ")"; }
signed main() {
    ios_base::sync_with_stdio(0), cin.tie(0);
    int n;
    cin >> n;
    vector<string> v(n);
    for(auto &s: v) cin >> s;
    if(n > 500) return cout << "NO\n", 0;
    for(auto s: v) {
        if(s.size() > 26) return cout << "NO\n", 0;
        bool has[26] = {};
        for(char c: s) {
            if(has[c-'a']) return cout << "NO\n", 0;
            has[c-'a'] = true;
        }
    }
    int m = 0;
    for(int i = 0; i < n; i++) {
        bool ok = 1;
        for(int j = 0; j < n; j++) {
            if(j == i) continue;
            int occ = match(v[j], v[i]);
            if(occ > 1) return cout << "NO\n", 0;
            if(occ == 1) {
                ok = 0;
                break;
            }
        }
        if(ok) {
            debug(v[i]);
            AC.ins(v[i], 1<<m);
            ++m;
        }
    }
    AC.buildFail();
    queue<pair<int,int>> q;
    map<pair<int,int>,pair<pair<int,int>,int>> fr;
    fr[{0,0}] = {{0, 0}, -1};
    q.push({0, 0});
    /* for(int c = 0; c < K; c++) debug(c, AC.getnext({0, 0}, c)); */
    while(!q.empty()) {
        auto p = q.front(); q.pop();
        for(int c = 0; c < 26; c++) {
            auto nxt = AC.getnext(p, c);
            if(nxt.second == ((1<<m)-1)) {
                auto now = p;
                string ans;
                ans += char('a'+c);
                while(now != pair<int,int>{0, 0}) {
                    debug(now.first, now.second);
                    ans += char('a'+fr[now].second);
                    now = fr[now].first;
                }
                reverse(all(ans));
                cout << ans << '\n';
                return 0;
            }
            if(!fr.count(nxt)) {
                fr[nxt] = {p, c};
                q.push(nxt);
            }
        }
    }
    cout << "JIZZ\n";
}


//   __________________
//  | ________________ |
//  ||          ____  ||
//  ||   /\    |      ||
//  ||  /__\   |      ||
//  || /    \  |____  ||
//  ||________________||
//  |__________________|
//  \###################\
//   \###################\
//    \        ____       \
//     \_______\___\_______\
// An AC a day keeps the doctor away.

#ifdef local
#include <bits/extc++.h>
#define safe std::cerr<<__PRETTY_FUNCTION__<<" line "<<__LINE__<<" safe\n"
#define debug(args...) qqbx(#args, args)
template <typename ...T> void qqbx(const char *s, T ...args) {
    std::cerr << "\033[1;32m" << '(' << s << ')' << " = " << '(';
    constexpr int size = sizeof...(T);
    int cnt = size, dummy[size] = { (std::cerr << args << (--cnt ? ", " : ")\033[0m\n"), 0)... };
}
#else
#pragma GCC optimize("Ofast")
#pragma loop_opt(on)
#include <bits/extc++.h>
#include <bits/stdc++.h>
#define debug(...) ((void)0)
#define safe ((void)0)
#endif // local
#define all(v) begin(v),end(v)
#define get_pos(v,x) int(lower_bound(begin(v),end(v),x)-begin(v))
#define sort_uni(v) sort(begin(v),end(v)),v.erase(unique(begin(v),end(v)),end(v))
#define pb emplace_back
#define ff first
#define ss second
#define mem(v,x) memset(v,x,sizeof v)

using namespace std;
using namespace __gnu_pbds;
typedef int64_t ll;
typedef long double ld;
typedef pair<ll,ll> pll;
typedef pair<ld,ld> pld;
template <typename T> using max_heap = std::priority_queue<T,vector<T>,less<T> >;
template <typename T> using min_heap = std::priority_queue<T,vector<T>,greater<T> >;
template <typename T> using rbt = tree<T,null_type,less<T>,rb_tree_tag,tree_order_statistics_node_update>;
constexpr ld PI = acos(-1), eps = 1e-7;
constexpr ll N = 525, INF = 1e18, MOD = 1000000007, K = 26, inf = 1e9;
constexpr inline ll cdiv(ll x, ll m) { return x/m + ((x<0 ^ m>0) && (x%m)); } // ceiling divide
constexpr inline ll modpow(ll e,ll p,ll m=MOD) { ll r=1; for(e%=m;p;p>>=1,e=e*e%m) if(p&1) r=r*e%m; return r; }

template <typename U, typename V> ostream & operator<<(ostream &O, pair<U,V> p) { return O << "(" << p.first << ", " << p.second << ")"; }
int match(const string &T, const string &P) {
    vector<int> fail(P.size());
    for(int i = 1, j = 0; i < P.size(); i++) {
        while(j && P[i] != P[j]) j = fail[j-1];
        if(P[i] == P[j]) ++j;
        fail[i] = j;
    }
    int res = 0;
    for(int i = 0, j = 0; i < T.size(); i++) {
        while(j && T[i] != P[j]) j = fail[j-1];
        if(T[i] == P[j]) ++j;
        if(j == P.size()) {
            ++res;
            j = fail[j-1];
        }
    }
    return res;
}

signed main() {
    ios_base::sync_with_stdio(0), cin.tie(0);
    int n;
    cin >> n;
    vector<string> v(n);
    for(auto &s: v) cin >> s;
    if(n > 500) return cout << "NO\n", 0;
    for(auto s: v) {
        if(s.size() > 26) return cout << "NO\n", 0;
        bool has[26] = {};
        for(char c: s) {
            if(has[c-'a']) return cout << "NO\n", 0;
            has[c-'a'] = true;
        }
    }
    vector<int> nxt(26, -1);
    vector<int> in(26), has(26);
    for(string s: v) {
        for(int i = 1; i < s.size(); i++) {
            int a = s[i-1]-'a', b = s[i]-'a';
            if(nxt[a] != -1 && nxt[a] != b) return cout << "NO\n", 0;
            nxt[a] = b;
            ++in[b];
        }
        for(char c: s) has[c-'a'] = true;
    }
    vector<string> chain;
    for(int i = 0; i < 26; i++) {
        if(in[i] == 0 && has[i]) {
            string ans;
            ans += char('a'+i);
            for(int x = nxt[i]; x != i && x != -1; x = nxt[x]) ans += char('a'+x);
            chain.pb(ans);
            debug(ans);
        }
    }
    sort(all(chain));
    string res;
    for(string s: chain) res += s;
    debug(res);
    if(res.empty()) return cout << "NO\n", 0;
    for(int i = 0, h = res.size(); i < h; i++) {
        for(int j = 1; i+j <= h; j++) {
            if(match(res, res.substr(i, j)) != 1) {
                return cout << "NO\n", 0;
            }
        }
    }
    cout << res << '\n';
}


#include <bits/stdc++.h>
using namespace std;
char me[100005];
int main()
{
    int i, j, k, l, p, q, m, n;
    int r = 0, s = 0, t, u = 0, v = 0, w;

    scanf("%d",&t);
    for (i = 0; i < t; i++){
    scanf("%c",&me[i]);
    }

    for (i = 0; i < t; i+=2){
        if (me[i] == 'b') r++;
        else if (me[i] == 'r') s++;
        if (me[i+1] == 'b') u++;
        else if (me[i+1] == 'r') v++;
    }

    if (r > u) m = r;
    else m = u;
    if (s > u) n = s;
    else n = u;

    if (m > n) printf("%d\n",n);
    else printf("%d\n",m);

    return 0;
}


#include <functional>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <numeric>
#include <cstring>
#include <climits>
#include <cassert>
#include <complex>
#include <cstdio>
#include <string>
#include <vector>
#include <bitset>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <list>
#include <set>
#include <map>

using namespace std ;
typedef long long LL ;
const int N = 1e5 + 10 ;
int mark[2] ;
int num[N] ;
string s1 ;
int main(void) {
	int n ;
	cin >> n ;
	cin >> s1 ;
	for(int i = 0 ; i < n ; ++ i) {
		if(s1[i] == 'r') num[i] = 0 ;
		else if(s1[i] == 'b') num[i] = 1 ;
	}
	int last = num[0] ;
	for(int i = 1 ; i < n ; ++ i) {
		if(num[i] == ~last) {
			last = ~last ;
			continue ;
		}
		else {
			mark[num[i]] ++ ;
			last = ~last ;
			continue ;
		}
	}
	int res = 0 ;
	if(mark[0] == mark[1]) res = (mark[0] + mark[1]) >> 1 ;
	else {
		res = max(mark[0] , mark[1]) - min(mark[0] , mark[1]) ;
	}
	cout << res << endl ;
	return 0 ;
}


#include <functional>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <numeric>
#include <cstring>
#include <climits>
#include <cassert>
#include <complex>
#include <cstdio>
#include <string>
#include <vector>
#include <bitset>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <list>
#include <set>
#include <map>

using namespace std ;
typedef long long LL ;
const int N = 1e5 + 10 ;
int mark[2] ;
int num[N] ;
string s1 ;
int main(void) {
	int n , res = 0 ;
	cin >> n ;
	cin >> s1 ;
	for(int i = 0 ; i < n ; ++ i) {
		if(s1[i] == 'r') num[i] = 1 ;
	}
	int last ;
	last = num[0] ;
	for(int i = 1 ; i < n ; ++ i) {
		if(num[i] == (last ^ 1)) {
			last = (last ^ 1) ;
		}
		else {
			mark[num[i]] ++ ;
			last = (last ^ 1) ;
		}
	}
	res = max(mark[0] , mark[1]) ;
	mark[0] = 0 ; mark[1] = 0 ;
	last = num[0] ^ 1 ;
	mark[num[0]] ++ ;
	for(int i = 1 ; i < n ; ++ i) {
		if(num[i] == last ^ 1) {
			last = last ^ 1 ;
		}
		else {
			mark[num[i]] ++ ;
			last = (last ^ 1) ;
		}
	}
	res = min(res , max(mark[0] , mark[1])) ;
	cout << res << endl ;
	return 0 ;
}