from collections import Counter

from functools import reduce

# import statistics

import bisect

import copy

import string

import fractions

import math

import pprint

# for debug

pp = pprint.PrettyPrinter(width = 150)

import random

import sys

import time

sys.setrecursionlimit(10**7)

INF = 10 ** 18

MOD = 10 ** 9 + 7

def LI(): return [int(x) for x in sys.stdin.readline().split()]

def LF(): return [float(x) for x in sys.stdin.readline().split()]

def LS(): return sys.stdin.readline().split()

def MI(): return list(map(int, sys.stdin.readline().split()))

def II(): return int(sys.stdin.readline())

def IS(): return eval(input())

def C(x): return Counter(x)

def GCD_LIST(numbers):

    return reduce(fractions.gcd, numbers)

def LCM_LIST(numbers):

    return reduce(LCM, numbers)

def LCM(m, n):

    return (m * n // fractions.gcd(m, n))

def unite(x, y):

    # それぞれのノードの根を求める

    x = root(x)

    y = root(y)

    if x == y:

        return

    # node[x]の根をyに変更する

    node[x] = y

def same(x,y): return bool(root(x) == root(y))

def root(x):

    if node[x] == x:  # xが根の場合

        return x

    else:

        node[x] = root(node[x])  # 経路圧縮

        return node[x]

def dfs(v):

    # ノードに訪れた

    visited[v] = True

    for v2 in range(n):

        if graph[v][v2] == False:  # そもそもvとv2が辺でつながっていない

            continue

        if visited[v2] == True:  # もう見た

            continue

        dfs(v2)





n = II()

s = sorted([IS() for _ in range(n)])

counter = []

for i in range(len(s)):

    counter.append(C(s[i]))

ans = []

for char in string.ascii_lowercase:

    mini = 50

    for c in counter:

        mini = min(mini, c[char])

    ans.append(char * mini)

print((''.join(ans)))

from collections import Counter

import string

import sys

def II(): return int(sys.stdin.readline())

def IS(): return eval(input())

def C(x): return Counter(x)



n = II()

s = sorted([IS() for _ in range(n)])

counter = []

for i in range(len(s)):

    counter.append(C(s[i]))

ans = []

for char in string.ascii_lowercase:

    mini = 50

    for c in counter:

        mini = min(mini, c[char])

    ans.append(char * mini)

print((''.join(ans)))
from collections import Counter
from functools import reduce

# import statistics
import bisect
import copy
import string
import fractions
import math
import pprint

# for debug
pp = pprint.PrettyPrinter(width=150)
import random
import sys
import time

sys.setrecursionlimit(10**7)
INF = 10**18
MOD = 10**9 + 7


def LI():
    return [int(x) for x in sys.stdin.readline().split()]


def LF():
    return [float(x) for x in sys.stdin.readline().split()]


def LS():
    return sys.stdin.readline().split()


def MI():
    return list(map(int, sys.stdin.readline().split()))


def II():
    return int(sys.stdin.readline())


def IS():
    return eval(input())


def C(x):
    return Counter(x)


def GCD_LIST(numbers):
    return reduce(fractions.gcd, numbers)


def LCM_LIST(numbers):
    return reduce(LCM, numbers)


def LCM(m, n):
    return m * n // fractions.gcd(m, n)


def unite(x, y):
    # それぞれのノードの根を求める
    x = root(x)
    y = root(y)
    if x == y:
        return
    # node[x]の根をyに変更する
    node[x] = y


def same(x, y):
    return bool(root(x) == root(y))


def root(x):
    if node[x] == x:  # xが根の場合
        return x
    else:
        node[x] = root(node[x])  # 経路圧縮
        return node[x]


def dfs(v):
    # ノードに訪れた
    visited[v] = True
    for v2 in range(n):
        if graph[v][v2] == False:  # そもそもvとv2が辺でつながっていない
            continue
        if visited[v2] == True:  # もう見た
            continue
        dfs(v2)


n = II()
s = sorted([IS() for _ in range(n)])
counter = []
for i in range(len(s)):
    counter.append(C(s[i]))
ans = []
for char in string.ascii_lowercase:
    mini = 50
    for c in counter:
        mini = min(mini, c[char])
    ans.append(char * mini)
print(("".join(ans)))

from collections import Counter
import string
import sys


def II():
    return int(sys.stdin.readline())


def IS():
    return eval(input())


def C(x):
    return Counter(x)


n = II()
s = sorted([IS() for _ in range(n)])
counter = []
for i in range(len(s)):
    counter.append(C(s[i]))
ans = []
for char in string.ascii_lowercase:
    mini = 50
    for c in counter:
        mini = min(mini, c[char])
    ans.append(char * mini)
print(("".join(ans)))

-from functools import reduce - -# import statistics -import bisect -import copy -import fractions -import math -import pprint - -# for debug -pp = pprint.PrettyPrinter(width=150) -import random -import time - -sys.setrecursionlimit(10**7) -INF = 10**18 -MOD = 10**9 + 7 - - -def LI(): -    return [int(x) for x in sys.stdin.readline().split()] - - -def LF(): -    return [float(x) for x in sys.stdin.readline().split()] - - -def LS(): -    return sys.stdin.readline().split() - - -def MI(): -    return list(map(int, sys.stdin.readline().split())) -def GCD_LIST(numbers): -    return reduce(fractions.gcd, numbers) - - -def LCM_LIST(numbers): -    return reduce(LCM, numbers) - - -def LCM(m, n): -    return m * n // fractions.gcd(m, n) - - -def unite(x, y): -    # それぞれのノードの根を求める -    x = root(x) -    y = root(y) -    if x == y: -        return -    # node[x]の根をyに変更する -    node[x] = y - - -def same(x, y): -    return bool(root(x) == root(y)) - - -def root(x): -    if node[x] == x:  # xが根の場合 -        return x -    else: -        node[x] = root(node[x])  # 経路圧縮 -        return node[x] - - -def dfs(v): -    # ノードに訪れた -    visited[v] = True -    for v2 in range(n): -        if graph[v][v2] == False:  # そもそもvとv2が辺でつながっていない -            continue -        if visited[v2] == True:  # もう見た -            continue -        dfs(v2) - -