#include <fstream>
#include <vector>
#include <algorithm>
#define mp make_pair
using namespace std;
int const N = 1 << 19 , M = 19 , m1 = 666013 , m2 = 1e9 + 7 , Lg = 30010 , inf = 1 << 29;
string S [100];
bool viz [M];
pair <int , int> hL [M][Lg] , hR [M][Lg] , t [N][M];
int R , C [M][M] , n , dp [N][M];
vector <int> v [M];
int value (char x){
if (x == 'A')
return 1;
if (x == 'C')
return 2;
if (x == 'T')
return 3;
return 4;
}
void gethash (int line){
hL [line][0] = mp (value (S [line][0]) , value (S [line][0]));
for(int i = 1 ; i < (int)S [line].size () ; ++ i){
int v1 = (5LL * hL [line][i - 1].first + value (S [line][i])) % m1;
int v2 = (5LL * hL [line][i - 1].second + value (S [line][i])) % m2;
hL [line][i] = mp (v1 , v2);
}
int sz = (int)S [line].size () - 1 , p1 = 5 , p2 = 5;
hR [line][sz] = mp (value (S [line][sz]) , value (S [line][sz]));
for(int i = sz - 1 ; i >= 0 ; -- i){
int v1 = (1LL * hR [line][i + 1].first + 1LL * p1 * value (S [line][i])) % m1;
int v2 = (1LL * hR [line][i + 1].second + 1LL * p2 * value (S [line][i])) % m2;
hR [line][i] = mp (v1 , v2);
p1 = 5LL * p1 % m1;
p2 = 5LL * p2 % m2;
}
return;
}
int Delete (){
string* S2 = new string [M];
pair <int , int> **A , **B;
A = new pair <int , int>* [M];
B = new pair <int , int>* [M];
for(int i = 0 ; i < M ; ++ i){
A [i] = new pair <int , int> [Lg];
B [i] = new pair <int , int> [Lg];
}
int k = 0;
for(int i = 0 ; i < n ; ++ i){
if (viz [i]){
R -= S [i].size ();
continue;
}
S2 [k ++] = S [i];
copy (hL [i] , hL [i] + S [i].size () , A [k - 1]);
copy (hR [i] , hR [i] + S [i].size () , B [k - 1]);
}
for(int i = 0 ; i < k ; ++ i){
copy (A [i], A [i]+ S2 [i].size () , hL [i]);
copy (B [i], B [i]+ S2 [i].size () , hR [i]);
}
copy (S2 , S2 + k , S);
delete S2;
delete A;
delete B;
return k;
}
bool match (string A , string B , int x , int y){
if (A.size () > B.size ())
return false;
pair <int , int> val = hL [x][A.size () - 1];
pair <int , int> k = hL [y][A.size () - 1];
if (val == k)
return true;
int p1 = 5 , p2 = 5;
for(int i = 1 ; i < (int)A.size () ; ++ i){
p1 = (5LL * p1) % m1;
p2 = (5LL * p2) % m2;
}
for(int i = (int)A.size () ; i < (int)B.size () ; ++ i){
int v1 = k.first , v2 = k.second;
v1 = (5LL * v1 + value (B[i]) + 1LL * p1 * m1 - 1LL * p1 * value (B[i - A.size ()])) % m1;
v2 = (5LL * v2 + value (B[i]) + 1LL * p2 * m2 - 1LL * p2 * value (B[i - A.size ()])) % m2;
if ((k = mp (v1 , v2)) == val)
return true;
}
return false;
}
int getEdge (int x , int y){
int sz = S [x].size () - 1 , r = -1;
for(int i = 0 ; i < min (int(S [x].size ()) , int(S [y].size ())) ; ++ i)
if (hL [y][i] == hR [x][sz - i])
r = i;
return 1 + r;
}
ifstream f ("adn.in");
ofstream g ("adn.out");
int main()
{
f >> n;
for(int i = 0 ; i < n ; ++ i){
f >> S [i];
R += S [i].size ();
gethash (i);
}
for(int i = 0 ; i < n ; ++ i)
for(int j = 0 ; j < n ; ++ j){
if (i == j)
continue;
if (match (S [i] , S [j] , i , j))
viz [i] = true;
}
n = Delete ();
for(int i = 0 ; i < n ; ++ i){
for(int j = 0 ; j < n ; ++ j){
if (i == j)
continue;
v[j].push_back (i);
C [i][j] = getEdge (i , j);
}
}
for(int i = 0 ; i < (1 << n) ; ++ i)
for(int j = 0 ; j < n ; ++ j)
dp [i][j] = -inf;
for(int i = 0 ; i < n ; ++ i)
dp [(1 << i)][i] = 0;
for(int i = 1 ; i < (1 << n) ; ++ i)
for(int j = 0 ; j < n ; ++ j)
if ((1 << j) & i)
for(int k = 0 ; k < (int)v [j].size () ; ++ k)
if ((1 << v [j][k]) & i){
if (dp [i][j] < dp [i ^ (1 << j)][v [j][k]] + C [v [j][k]][j]){
dp [i][j] = dp [i ^ (1 << j)][v [j][k]] + C [v [j][k]][j];
t [i][j] = mp (v [j][k] , j);
}
}
int ans = -inf , ind = 0;
vector <int> sol;
for(int i = 0 ; i < n ; ++ i)
if (dp [(1 << n) - 1][i] >= ans){
ans = dp [(1 << n) - 1][i];
ind = i;
}
int cfg = (1 << n) - 1;
pair <int , int> x = t [cfg][ind];
sol.push_back (ind);
cfg ^= (1 << ind);
for(int i = 1 ; i < n ; ++ i){
ind = x.first;
sol.push_back (ind);
x = t [cfg][ind];
cfg ^= (1 << ind);
}
reverse (sol.begin () , sol.end ());
g << S [sol [0]];
for(int i = 1 ; i < n ; ++ i){
for(int j = C [sol [i - 1]][sol [i]] ; j < (int)S [sol [i]].size () ; ++ j)
g << S [sol [i]][j];
}
return 0;
}