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

typedef long long ll;
typedef long double ld;
typedef pair<int, int> ii;
typedef vector<int> vi;
typedef vector<ii> vii;
typedef vector<vi> vvi;
typedef vector<vii> vvii;
#define fi first
#define se second
#define ALL(x) (x).begin(), (x).end()
#define RALL(x) (x).rbegin(), (x).rend()
#define pf push_front
#define eb emplace_back
#define pb push_back
#define mp make_pair
#define mt make_tuple
#define ge(a, b) get<(b)>((a))
#define SZ(x) (x).size()
#define endl '\n'
#define FOR(a, b, c) for (auto(a) = (b); (a) < (c); ++(a))
#define ROF(a, b, c) for (auto(a) = (b); (a) > (c); --(a))
#define F0R(a, b) FOR ((a), 0, (b))
#define R0F(a, b) ROF ((a), (b), -1)
#define CEIL(a, b) ((a) + (b)-1) / (b)
#define CLR(a, b) memset((a), (b), sizeof((a)))
template <typename t> bool ckmin(t& a, const t& b) { return a > b ? a = b, true : false; }
template <typename t> bool ckmax(t& a, const t& b) { return a < b ? a = b, true : false; }

const int MAXN = 1e3 + 7,
          MAXK = 14;

int nxt[MAXN][26], fail[MAXN], nodeCnt;
ll sum[MAXN], dp[MAXN][1 << MAXK];

void insert(string& s, int cost) {
    int curr = 0;
    for(char c : s) {
        if(!nxt[curr][c - 'a'])
            nxt[curr][c - 'a'] = ++nodeCnt;
        curr = nxt[curr][c - 'a'];
    }
    sum[curr] += cost;
}

void build() {
    queue<int> q;
    F0R(i, MAXK)
        if(nxt[0][i])
            q.push(nxt[0][i]);

    while(!q.empty()) {
        int curr = q.front();
        q.pop();
        F0R(i, MAXK) {
            if(nxt[curr][i]) {
                fail[nxt[curr][i]] = nxt[fail[curr]][i];
                sum[nxt[curr][i]] += sum[nxt[fail[curr]][i]];
                q.push(nxt[curr][i]);
            } else {
                nxt[curr][i] = nxt[fail[curr]][i];
            }
        }
    }
}

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

    int n, cost;
    cin >> n;

    string s;
    F0R(i, n) {
        cin >> s >> cost;
        insert(s, cost);
    }
    cin >> s;

    build();

    F0R(i, cnt + 1)
        F0R(j, 1 << MAXK)
            dp[i][j] = -1e9;

    vi tmp(nodeCnt + 1, 0);
    vi to(nodeCnt + 1);
    iota(ALL(to), 0);

    dp[0][0] = 0;
    for(char c : s) {
        if(c == '?') {
            R0F(s, (1 << MAXK) - 1) {
                F0R(p, nodeCnt + 1) {
                    if(dp[p][s] == -1e9)
                        continue;
                    F0R(i, MAXK) {
                        if(s >> i & 1)
                            continue;
                        ckmax(dp[nxt[to[p]][i]][s|1<<i],
                              dp[p][s] + tmp[p] + sum[nxt[to[p]][i]]);
                    }
                    dp[p][s] = -1e9;
                }
            }
            fill(ALL(tmp), 0);
            iota(ALL(to), 0);
        } else {
            F0R(p, nodeCnt + 1) {
                to[p] = nxt[to[p]][c - 'a'];
                tmp[p] += sum[to[p]];
            }
        }
    }
    ll res = -1e9;
    F0R(p, nodeCnt + 1)
        F0R(s, 1 << MAXK)
            ckmax(res, dp[p][s] + tmp[p]);
    cout << res << endl;
}


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

typedef long long ll;
typedef long double ld;
typedef pair<int, int> ii;
typedef vector<int> vi;
typedef vector<ii> vii;
typedef vector<vi> vvi;
typedef vector<vii> vvii;
#define fi first
#define se second
#define ALL(x) (x).begin(), (x).end()
#define RALL(x) (x).rbegin(), (x).rend()
#define pf push_front
#define eb emplace_back
#define pb push_back
#define mp make_pair
#define mt make_tuple
#define ge(a, b) get<(b)>((a))
#define SZ(x) (x).size()
#define endl '\n'
#define FOR(a, b, c) for (auto(a) = (b); (a) < (c); ++(a))
#define ROF(a, b, c) for (auto(a) = (b); (a) > (c); --(a))
#define F0R(a, b) FOR ((a), 0, (b))
#define R0F(a, b) ROF ((a), (b), -1)
#define CEIL(a, b) ((a) + (b)-1) / (b)
#define CLR(a, b) memset((a), (b), sizeof((a)))
template <typename t> bool ckmin(t& a, const t& b) { return a > b ? a = b, true : false; }
template <typename t> bool ckmax(t& a, const t& b) { return a < b ? a = b, true : false; }

const int MAXN = 1e3 + 7,
          MAXK = 14,
          NINF = -1e9;

int nxt[MAXN][26], fail[MAXN], nodeCnt, to[MAXN];
ll sum[MAXN], dp[MAXN][1 << MAXK], tmp[MAXN];

void insert(string& s, int cost) {
    int curr = 0;
    for(char c : s) {
        if(!nxt[curr][c - 'a'])
            nxt[curr][c - 'a'] = ++nodeCnt;
        curr = nxt[curr][c - 'a'];
    }
    sum[curr] += cost;
}

void build() {
    queue<int> q;
    F0R(i, MAXK)
        if(nxt[0][i])
            q.push(nxt[0][i]);

    while(!q.empty()) {
        int now = q.front();
        q.pop();
        F0R(i, MAXK) {
            if(nxt[now][i]) {
                fail[nxt[now][i]] = nxt[fail[now]][i];
                sum[nxt[now][i]] += sum[nxt[fail[now]][i]];
                q.push(nxt[now][i]);
            }
            else {
                nxt[now][i] = nxt[fail[now]][i];
            }
        }
    }
}

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

    int n, cost;
    cin >> n;

    string s;
    F0R(i, n) {
        cin >> s >> cost;
        insert(s, cost);
    }
    cin >> s;

    build();

    F0R(i, nodeCnt + 1)
        F0R(j, 1 << 14)
            dp[i][j] = NINF;

    dp[0][0]=0;
    F0R(p, nodeCnt + 1) {
        tmp[p] = 0;
        to[p] = p;
    }

    for(char c: s) {
        if(c == '?') {
            R0F(s, (1 << 14) - 1) {
                F0R(p, nodeCnt + 1) {
                    if(dp[p][s] == NINF) continue;
                    F0R(i, 14) {
                        if(s >> i & 1) continue;
                        ckmax(dp[nxt[to[p]][i]][s|1<<i],
                              dp[p][s]+tmp[p]+sum[nxt[to[p]][i]]);
                    }
                    dp[p][s] = NINF;
                }
            }
            F0R(p, nodeCnt + 1) {
                tmp[p] = 0;
                to[p] = p;
            }
        }
        else {
            F0R(p, nodeCnt + 1)  {
                to[p] = nxt[to[p]][c - 'a'];
                tmp[p] += sum[to[p]];
            }
        }
    }
    ll ans = NINF;
    F0R(p, nodeCnt + 1)
        F0R(s, 1 << 14)
            ckmax(ans, dp[p][s] + tmp[p]);
    cout << ans << endl;
}


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

typedef long long ll;
typedef long double ld;
typedef pair<int, int> ii;
typedef vector<int> vi;
typedef vector<ii> vii;
typedef vector<vi> vvi;
typedef vector<vii> vvii;
#define fi first
#define se second
#define ALL(x) (x).begin(), (x).end()
#define RALL(x) (x).rbegin(), (x).rend()
#define pf push_front
#define eb emplace_back
#define pb push_back
#define mp make_pair
#define mt make_tuple
#define ge(a, b) get<(b)>((a))
#define SZ(x) (x).size()
#define endl '\n'
#define FOR(a, b, c) for (auto(a) = (b); (a) < (c); ++(a))
#define ROF(a, b, c) for (auto(a) = (b); (a) > (c); --(a))
#define F0R(a, b) FOR ((a), 0, (b))
#define R0F(a, b) ROF ((a), (b), -1)
#define CEIL(a, b) ((a) + (b)-1) / (b)
#define CLR(a, b) memset((a), (b), sizeof((a)))
template <typename t> bool ckmin(t& a, const t& b) { return a > b ? a = b, true : false; }
template <typename t> bool ckmax(t& a, const t& b) { return a < b ? a = b, true : false; }

const int MAXN = 1e3 + 7,
          MAXK = 14;

int nxt[MAXN][26], fail[MAXN], nodeCnt;
ll sum[MAXN], dp[MAXN][1 << MAXK];

void insert(string& s, int cost) {
    int curr = 0;
    for(char c : s) {
        if(!nxt[curr][c - 'a'])
            nxt[curr][c - 'a'] = ++nodeCnt;
        curr = nxt[curr][c - 'a'];
    }
    sum[curr] += cost;
}

void build() {
    queue<int> q;
    F0R(i, MAXK)
        if(nxt[0][i])
            q.push(nxt[0][i]);

    while(!q.empty()) {
        int curr = q.front();
        q.pop();
        F0R(i, MAXK) {
            if(nxt[curr][i]) {
                fail[nxt[curr][i]] = nxt[fail[curr]][i];
                sum[nxt[curr][i]] += sum[nxt[fail[curr]][i]];
                q.push(nxt[curr][i]);
            } else {
                nxt[curr][i] = nxt[fail[curr]][i];
            }
        }
    }
}

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

    int n, cost;
    cin >> n;

    string s;
    F0R(i, n) {
        cin >> s >> cost;
        insert(s, cost);
    }
    cin >> s;

    build();

    F0R(i, nodeCnt + 1)
        F0R(j, 1 << MAXK)
            dp[i][j] = -1e9;

    vi tmp(nodeCnt + 1, 0);
    vi to(nodeCnt + 1);
    iota(ALL(to), 0);

    dp[0][0] = 0;
    for(char c : s) {
        if(c == '?') {
            R0F(s, (1 << MAXK) - 1) {
                F0R(p, nodeCnt + 1) {
                    if(dp[p][s] == -1e9)
                        continue;
                    F0R(i, MAXK) {
                        if(s >> i & 1)
                            continue;
                        ckmax(dp[nxt[to[p]][i]][s|1<<i],
                              dp[p][s] + tmp[p] + sum[nxt[to[p]][i]]);
                    }
                    dp[p][s] = -1e9;
                }
            }
            fill(ALL(tmp), 0);
            iota(ALL(to), 0);
        } else {
            F0R(p, nodeCnt + 1) {
                to[p] = nxt[to[p]][c - 'a'];
                tmp[p] += sum[to[p]];
            }
        }
    }
    ll res = -1e9;
    F0R(p, nodeCnt + 1)
        F0R(s, 1 << MAXK)
            ckmax(res, dp[p][s] + tmp[p]);
    cout << res << endl;
}


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
using namespace std;
const long long inf=1e15;
struct Au
{
	int tot,ch[20][1010],fail[1010],q[1010],l,r,to[20][1010],num;
	long long c[1010],sum[20][1010],dp[1<<15][1010],ans;
	void init()
	{
		tot=0; num=0; ans=-inf;
		memset(ch,0,sizeof ch);
		memset(fail,-1,sizeof fail);
		memset(c,0,sizeof c);
		memset(to,0,sizeof to);
		memset(sum,0,sizeof sum);
	}
	void insert(char s[],int len,int v)
	{
		int now=0;
		for (int i=1;i<=len;i++)
		{
			if (!ch[s[i]-'a'][now]) ch[s[i]-'a'][now]=++tot;
			now=ch[s[i]-'a'][now];
			if (i==len) c[now]+=v;
		}
	}
	void getfail()
	{
		l=1,r=0;
		for (int i=0;i<14;i++) if (ch[i][0]) fail[ch[i][0]]=0,q[++r]=ch[i][0];
		while (l<=r)
		{
			int x=q[l++];
			for (int i=0;i<14;i++)
			if (ch[i][x])
			{
				fail[ch[i][x]]=ch[i][fail[x]];
				c[ch[i][x]]+=c[ch[i][fail[x]]];
				q[++r]=ch[i][x];
			}
			else ch[i][x]=ch[i][fail[x]];
		}
	}
	long long work()
	{
		getfail();
		char s[1000010]; int len;
		scanf("%s",s+1); len=strlen(s+1);
		for (int i=1;i<=len;i++) if (s[i]=='?') q[++num]=i;
		q[0]=0; q[num+1]=len+1;
		for (int i=0;i<(1<<14);i++)
		 for (int j=0;j<=tot;j++) dp[i][j]=-inf;
		for (int i=0;i<=num;i++)
		 for (int j=0;j<=tot;j++)
		 {
		 	int now=j; long long ss=0;
		    for (int k=q[i]+1;k<q[i+1];k++)
		    {
		    	now=ch[s[k]-'a'][now];
		    	ss+=c[now];
		    }
		    to[i][j]=now; sum[i][j]=ss;
		 }
		dp[0][to[0][0]]=sum[0][0];
	    for (int zt=0;zt<(1<<14);zt++)
	    {
	    	int num1=__builtin_popcount(zt);
	    	if (num1>=num) continue;
	    	for (int i=0;i<=tot;i++)
	    	 for (int j=0;j<14;j++)
	    	 if (!((zt>>j)&1))
	    	 {
	    	 	int u=ch[j][i],too=to[num1+1][u];
	    	 	dp[zt|(1<<j)][too]=max(dp[zt|(1<<j)][too],dp[zt][i]+c[u]+sum[num1+1][u]);
	    	 }
	    }
	    for (int zt=0;zt<(1<<14);zt++)
	     for (int i=0;i<=tot;i++)
	      if (__builtin_popcount(zt)==num) ans=max(ans,dp[zt][i]);
	 	return ans;
	}
}AC;
int main()
{
	int n,v; char s[1010]; scanf("%d",&n); AC.init();
	for (int i=1;i<=n;i++) scanf("%s%d",s+1,&v),AC.insert(s,strlen(s+1),v);
	printf("%lld\n",AC.work());
return 0;
}


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
using namespace std;
const long long inf=1e18;
struct Au
{
	int tot,ch[20][1010],fail[1010],q[1010],l,r,to[20][1010],num;
	long long c[1010],sum[20][1010],dp[1<<15][1010],ans;
	void init()
	{
		tot=0; num=0; ans=-inf;
		memset(ch,0,sizeof ch);
		memset(fail,-1,sizeof fail);
		memset(c,0,sizeof c);
		memset(to,0,sizeof to);
		memset(sum,0,sizeof sum);
	}
	void insert(char s[],int len,int v)
	{
		int now=0;
		for (int i=1;i<=len;i++)
		{
			if (!ch[s[i]-'a'][now]) ch[s[i]-'a'][now]=++tot;
			now=ch[s[i]-'a'][now];
			if (i==len) c[now]+=v;
		}
	}
	void getfail()
	{
		l=1,r=0;
		for (int i=0;i<14;i++) if (ch[i][0]) fail[ch[i][0]]=0,q[++r]=ch[i][0];
		while (l<=r)
		{
			int x=q[l++];
			for (int i=0;i<14;i++)
			if (ch[i][x])
			{
				fail[ch[i][x]]=ch[i][fail[x]];
				c[ch[i][x]]+=c[ch[i][fail[x]]];
				q[++r]=ch[i][x];
			}
			else ch[i][x]=ch[i][fail[x]];
		}
	}
	long long work()
	{
		getfail();
		char s[1000010]; int len;
		scanf("%s",s+1); len=strlen(s+1);
		for (int i=1;i<=len;i++) if (s[i]=='?') q[++num]=i;
		q[0]=0; q[num+1]=len+1;
		for (int i=0;i<(1<<14);i++)
		 for (int j=0;j<=tot;j++) dp[i][j]=-inf;
		for (int i=0;i<=num;i++)
		 for (int j=0;j<=tot;j++)
		 {
		 	int now=j; long long ss=0;
		    for (int k=q[i]+1;k<q[i+1];k++)
		    {
		    	now=ch[s[k]-'a'][now];
		    	ss+=c[now];
		    }
		    to[i][j]=now; sum[i][j]=ss;
		   	//if (!i) dp[0][to[i][j]]=sum[i][j];
		 }
		dp[0][to[0][0]]=sum[0][0];
	    for (int zt=0;zt<(1<<14);zt++)
	    {
	    	int num1=__builtin_popcount(zt);
	    	if (num1>=num) continue;
	    	for (int i=0;i<=tot;i++)
	    	 for (int j=0;j<14;j++)
	    	 if (!((zt>>j)&1))
	    	 {
	    	 	int u=ch[j][i],too=to[num1+1][i];
	    	 	dp[zt|(1<<j)][too]=max(dp[zt|(1<<j)][too],dp[zt][i]+c[u]+sum[i+1][u]);
	    	 }
	    }
	    for (int zt=0;zt<(1<<14);zt++)
	     for (int i=0;i<=tot;i++)
	      if (__builtin_popcount(zt)==num) ans=max(ans,dp[zt][i]);
	 	return ans;
	}
}AC;
int main()
{
	int n,v; char s[1010]; scanf("%d",&n); AC.init();
	for (int i=1;i<=n;i++) scanf("%s%d",s+1,&v),AC.insert(s,strlen(s+1),v);
	printf("%lld\n",AC.work());
return 0;
}


#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
using namespace std;
const long long inf=1e15;
struct Au
{
	int tot,ch[20][1010],fail[1010],q[1010],l,r,to[20][1010],num;
	long long c[1010],sum[20][1010],dp[1<<15][1010],ans;
	void init()
	{
		tot=0; num=0; ans=-inf;
		memset(ch,0,sizeof ch);
		memset(fail,-1,sizeof fail);
		memset(c,0,sizeof c);
		memset(to,0,sizeof to);
		memset(sum,0,sizeof sum);
	}
	void insert(char s[],int len,int v)
	{
		int now=0;
		for (int i=1;i<=len;i++)
		{
			if (!ch[s[i]-'a'][now]) ch[s[i]-'a'][now]=++tot;
			now=ch[s[i]-'a'][now];
			if (i==len) c[now]+=v;
		}
	}
	void getfail()
	{
		l=1,r=0;
		for (int i=0;i<14;i++) if (ch[i][0]) fail[ch[i][0]]=0,q[++r]=ch[i][0];
		while (l<=r)
		{
			int x=q[l++];
			for (int i=0;i<14;i++)
			if (ch[i][x])
			{
				fail[ch[i][x]]=ch[i][fail[x]];
				c[ch[i][x]]+=c[ch[i][fail[x]]];
				q[++r]=ch[i][x];
			}
			else ch[i][x]=ch[i][fail[x]];
		}
	}
	long long work()
	{
		getfail();
		char s[1000010]; int len;
		scanf("%s",s+1); len=strlen(s+1);
		for (int i=1;i<=len;i++) if (s[i]=='?') q[++num]=i;
		q[0]=0; q[num+1]=len+1;
		for (int i=0;i<(1<<14);i++)
		 for (int j=0;j<=tot;j++) dp[i][j]=-inf;
		for (int i=0;i<=num;i++)
		 for (int j=0;j<=tot;j++)
		 {
		 	int now=j; long long ss=0;
		    for (int k=q[i]+1;k<q[i+1];k++)
		    {
		    	now=ch[s[k]-'a'][now];
		    	ss+=c[now];
		    }
		    to[i][j]=now; sum[i][j]=ss;
		 }
		dp[0][to[0][0]]=sum[0][0];
	    for (int zt=0;zt<(1<<14);zt++)
	    {
	    	int num1=__builtin_popcount(zt);
	    	if (num1>=num) continue;
	    	for (int i=0;i<=tot;i++)
	    	 for (int j=0;j<14;j++)
	    	 if (!((zt>>j)&1))
	    	 {
	    	 	int u=ch[j][i],too=to[num1+1][i];
	    	 	dp[zt|(1<<j)][too]=max(dp[zt|(1<<j)][too],dp[zt][i]+c[u]+sum[i+1][u]);
	    	 }
	    }
	    for (int zt=0;zt<(1<<14);zt++)
	     for (int i=0;i<=tot;i++)
	      if (__builtin_popcount(zt)==num) ans=max(ans,dp[zt][i]);
	 	return ans;
	}
}AC;
int main()
{
	int n,v; char s[1010]; scanf("%d",&n); AC.init();
	for (int i=1;i<=n;i++) scanf("%s%d",s+1,&v),AC.insert(s,strlen(s+1),v);
	printf("%lld\n",AC.work());
return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define mod 998244353
#define oo 1000000010
const int N = 400010;
string arr[N];
char tmpread[N];
int k ;
string s;

vector< int > f[N];

const int M = 3010 , C = 14;

vector< int > cur[M][M];

int val[M][M] , cnt = 0 , c[N];

int nxt[M][C] , cost[M][C] , dpnxt[2][M];

long long dp[(1 << C)][M] , dpcost[2][M];

int tmpnxt[C];

long long tmpcost[C];

int num[C + 2];

vector< int > g[C + 1];

void make(int idx){
	f[idx].resize((int)arr[idx].size());
	f[idx][0] = 0;
	int cnt = 0;
	for(int i = 1;i < (int)arr[idx].size();i++){
		while(cnt > 0 && arr[idx][i] != arr[idx][cnt]) cnt = f[idx][cnt - 1];
		if(arr[idx][cnt] == arr[idx][i]) cnt++;
		f[idx][i] = cnt;
	}
}

void make2(int idx){
	vector< int > tmp(k , 0);
	cur[idx][0] = tmp;
	val[idx][0] = cnt++;
	for(int i = 0 ;i < (int)arr[idx].size() - 1;i++){
		val[idx][i + 1] = cnt++;
		for(int j = 0 ;j < k;j++){
			while(tmp[j] > 0 && arr[idx][i] != arr[j][tmp[j]]) tmp[j] = f[j][tmp[j] - 1];
			if(arr[idx][i] == arr[j][tmp[j]]) tmp[j]++;
		}
		for(int j = 0 ;j < k;j++){
			if(tmp[j] == (int)arr[j].size()) tmp[j] = f[j][tmp[j] - 1];
		}
		cur[idx][i + 1] = tmp;
	}
}

vector< string > v;

int main(){
	for(int i = 0 ;i < (1 << C);i++){
		int tmp = i , ones = 0;
		while(tmp > 0){
			ones++;
			tmp ^= (tmp & (-tmp));
		}
		g[ones].push_back(i);
	}
	scanf("%d",&k);
	for(int i = 0 ;i < k;i++){
		scanf("%s %d",tmpread,&c[i]);
		arr[i] = (string)tmpread;
	}
	for(int i = 0 ;i < k;i++) make(i);
	for(int i = 0 ;i < k;i++) make2(i);
	for(int i = 0 ;i < k;i++){
		for(int j = 0 ;j < (int)arr[i].size();j++){
			//printf("val[%d][%d] = %d\n",i , j , val[i][j]);
			int inc = 0;
			for(char x = 'a'; x <= 'n';x++){
				vector< int > tmp = cur[i][j];
				for(int l = 0 ; l < k;l++){
					while(tmp[l] > 0 && arr[l][tmp[l]] != x) tmp[l] = f[l][tmp[l] - 1];
					if(arr[l][tmp[l]] == x) tmp[l]++;
				}
				inc = 0;
				for(int l = 0 ;l < k;l++){
					if(tmp[l] == (int)arr[l].size()){
						inc += c[l];
						tmp[l] = f[l][tmp[l] - 1];
					}
				}
				int mx = -1, idx = 0;
				for(int l = 0 ;l < k;l++){
					if(tmp[l] > mx)
						mx = tmp[l] , idx = l;
				}
				nxt[val[i][j]][x - 'a'] = val[idx][mx];
				cost[val[i][j]][x - 'a'] = inc;
			}
		}
	}
	scanf("%s",tmpread);
	s = (string)tmpread;
	string tmps;
	for(int i = 0 ;i < (int)s.size();i++){
		if(s[i] == '?'){
			if((int)tmps.size() > 0)
				v.push_back(tmps);
			tmps.clear();
		}
		tmps += s[i];
	}
	v.push_back(tmps);
	num[0] = 0;
	for(int i = 0 ;i < (int)v.size();i++){
		num[i + 1] = num[i];
		if(v[i][0] == '?')
			num[i + 1]++;
	}
	int mask , node;
	long long inc = 0;
	for(int i = (int)v.size() - 1 ;i >= 0;i--){
		if(v[i][0] != '?') continue;
		for(int j = (int)v[i].size();j > 0;j--){
			for(int pre = 0 ; pre < cnt;pre++){
				if(j == (int)v[i].size())
					dpnxt[j & 1][pre] = pre , dpcost[j & 1][pre] = 0;
				else{
					dpnxt[j & 1][pre] = dpnxt[(j & 1) ^ 1][nxt[pre][v[i][j] - 'a']];
					dpcost[j & 1][pre] = cost[pre][v[i][j] - 'a'] + dpcost[(j & 1) ^ 1][nxt[pre][v[i][j] - 'a']];
				}
			}
		}
		for(int pre = 0 ; pre < cnt;pre++){
			for(int k = 0 ;k < C;k++){
				tmpnxt[k] = dpnxt[1][nxt[pre][k]];
				tmpcost[k] = cost[pre][k] + dpcost[1][nxt[pre][k]];
			}
			for(int it =0 ; it < (int)g[num[i]].size();it++){
				mask = g[num[i]][it];
				dp[mask][pre] = -(long long)1e18;
				for(int j = 0 ;j < C;j++){
					if(((mask >> j) & 1) == 1) continue;
					dp[mask][pre] = max(dp[mask][pre] , dp[(mask | (1 << j))][tmpnxt[j]] + tmpcost[j]);
				}
			}
		}
	}
	long long ans;
	if(v[0][0] != '?'){
		inc = 0;
		node = 0;
		for(int i = 0 ;i < (int)v[0].size();i++){
			inc += cost[node][v[0][i] - 'a'];
			node = nxt[node][v[0][i] - 'a'];
		}
		ans = inc + dp[0][node];
	}
	else
		ans = dp[0][0];
	cout << ans << endl;
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define mod 998244353
#define oo 1000000010
const int N = 400010;
string arr[N];
char tmpread[N];
int k ;
string s;

vector< int > f[N];

const int M = 3010 , C = 14;

vector< int > cur[M][M];

int val[M][M] , cnt = 0 , c[N];

int nxt[M][C] , cost[M][C] , dpnxt[2][M];

long long dp[(1 << C)][M] , dpcost[2][M];

int tmpnxt[C];

long long tmpcost[C];

int num[C + 2];

vector< int > g[C + 1];

void make(int idx){
	f[idx].resize((int)arr[idx].size());
	f[idx][0] = 0;
	int cnt = 0;
	for(int i = 1;i < (int)arr[idx].size();i++){
		while(cnt > 0 && arr[idx][i] != arr[idx][cnt]) cnt = f[idx][cnt - 1];
		if(arr[idx][cnt] == arr[idx][i]) cnt++;
		f[idx][i] = cnt;
	}
}

void make2(int idx){
	vector< int > tmp(k , 0);
	cur[idx][0] = tmp;
	val[idx][0] = cnt++;
	for(int i = 0 ;i < (int)arr[idx].size();i++){
		val[idx][i + 1] = cnt++;
		for(int j = 0 ;j < k;j++){
			while(tmp[j] > 0 && arr[idx][i] != arr[j][tmp[j]]) tmp[j] = f[j][tmp[j] - 1];
			if(arr[idx][i] == arr[j][tmp[j]]) tmp[j]++;
		}
		for(int j = 0 ;j < k;j++){
			if(tmp[j] == (int)arr[j].size()) tmp[j] = f[j][tmp[j] - 1];
		}
		cur[idx][i + 1] = tmp;
	}
}

vector< string > v;

int main(){
	for(int i = 0 ;i < (1 << C);i++){
		int tmp = i , ones = 0;
		while(tmp > 0){
			ones++;
			tmp ^= (tmp & (-tmp));
		}
		g[ones].push_back(i);
	}
	scanf("%d",&k);
	for(int i = 0 ;i < k;i++){
		scanf("%s %d",tmpread,&c[i]);
		arr[i] = (string)tmpread;
	}
	for(int i = 0 ;i < k;i++) make(i);
	for(int i = 0 ;i < k;i++) make2(i);
	for(int i = 0 ;i < k;i++){
		for(int j = 0 ;j <= (int)arr[i].size();j++){
			//printf("val[%d][%d] = %d\n",i , j , val[i][j]);
			int inc = 0;
			for(char x = 'a'; x <= 'n';x++){
				vector< int > tmp = cur[i][j];
				for(int l = 0 ; l < k;l++){
					while(tmp[l] > 0 && arr[l][tmp[l]] != x) tmp[l] = f[l][tmp[l] - 1];
					if(arr[l][tmp[l]] == x) tmp[l]++;
				}
				inc = 0;
				for(int l = 0 ;l < k;l++){
					if(tmp[l] == (int)arr[l].size()){
						inc += c[l];
						tmp[l] = f[l][tmp[l] - 1];
					}
				}
				int mx = -1, idx = 0;
				for(int l = 0 ;l < k;l++){
					if(tmp[l] > mx)
						mx = tmp[l] , idx = l;
				}
				nxt[val[i][j]][x - 'a'] = val[idx][mx];
				cost[val[i][j]][x - 'a'] = inc;
			}
		}
	}
	scanf("%s",tmpread);
	s = (string)tmpread;
	string tmps;
	for(int i = 0 ;i < (int)s.size();i++){
		if(s[i] == '?'){
			if((int)tmps.size() > 0)
				v.push_back(tmps);
			tmps.clear();
		}
		tmps += s[i];
	}
	v.push_back(tmps);
	num[0] = 0;
	for(int i = 0 ;i < (int)v.size();i++){
		num[i + 1] = num[i];
		if(v[i][0] == '?')
			num[i + 1]++;
	}
	int mask , node;
	long long inc = 0;
	for(int i = (int)v.size() - 1 ;i >= 0;i--){
		if(v[i][0] != '?') continue;
		for(int j = (int)v[i].size();j > 0;j--){
			for(int pre = 0 ; pre < cnt;pre++){
				if(j == (int)v.size())
					dpnxt[j & 1][pre] = pre , dpcost[j & 1][pre] = 0;
				else{
					dpnxt[j & 1][pre] = dpnxt[(j & 1) ^ 1][nxt[pre][v[i][j] - 'a']];
					dpcost[j & 1][pre] = cost[pre][v[i][j] - 'a'] + dpcost[(j & 1) ^ 1][nxt[pre][v[i][j] - 'a']];
				}
			}
		}
		for(int pre = 0 ; pre < cnt;pre++){
			for(int k = 0 ;k < C;k++){
				tmpnxt[k] = dpnxt[1][nxt[pre][k]];
				tmpcost[k] = cost[pre][k] + dpcost[1][nxt[pre][k]];
			}
			for(int it =0 ; it < (int)g[num[i]].size();it++){
				mask = g[num[i]][it];
				dp[mask][pre] = -(long long)1e18;
				for(int j = 0 ;j < C;j++){
					if(((mask >> j) & 1) == 1) continue;
					dp[mask][pre] = max(dp[mask][pre] , dp[(mask | (1 << j))][tmpnxt[j]] + tmpcost[j]);
				}
			}
		}
	}
	long long ans;
	if(v[0][0] != '?'){
		inc = 0;
		node = 0;
		for(int i = 0 ;i < (int)v[0].size();i++){
			inc += cost[node][v[0][i] - 'a'];
			node = nxt[node][v[0][i] - 'a'];
		}
		ans = inc + dp[0][node];
	}
	else
		ans = dp[0][0];
	cout << ans << endl;
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define mod 998244353
#define oo 1000000010
const int N = 400010;
string arr[N];
char tmpread[N];
int k ;
string s;

vector< int > f[N];

const int M = 3010 , C = 14;

vector< int > cur[M][M];

int val[M][M] , cnt = 0 , c[N];

int nxt[M][C] , cost[M][C] , tmpnxt[M][C];

long long dp[(1 << C)][M] , tmpcost[M][C];

int num[C + 2];

vector< int > g[C + 1];

void make(int idx){
	f[idx].resize((int)arr[idx].size());
	f[idx][0] = 0;
	int cnt = 0;
	for(int i = 1;i < (int)arr[idx].size();i++){
		while(cnt > 0 && arr[idx][i] != arr[idx][cnt]) cnt = f[idx][cnt - 1];
		if(arr[idx][cnt] == arr[idx][i]) cnt++;
		f[idx][i] = cnt;
	}
}

void make2(int idx){
	vector< int > tmp(k , 0);
	cur[idx][0] = tmp;
	val[idx][0] = cnt++;
	for(int i = 0 ;i < (int)arr[idx].size();i++){
		for(int j = 0 ;j < k;j++){
			if(tmp[j] == (int)arr[j].size()) tmp[j] = f[idx][tmp[j] - 1];
		}
		val[idx][i + 1] = cnt++;
		for(int j = 0 ;j < k;j++){
			while(tmp[j] > 0 && arr[idx][i] != arr[idx][tmp[j]]) tmp[j] = f[j][tmp[j] - 1];
			if(arr[idx][i] == arr[j][tmp[j]]) tmp[j]++;
		}
		cur[idx][i + 1] = tmp;
	}
}

vector< string > v;

int main(){
	for(int i = 0 ;i < (1 << C);i++){
		int tmp = i , ones = 0;
		while(tmp > 0){
			ones++;
			tmp ^= (tmp & (-tmp));
		}
		g[ones].push_back(i);
	}
	scanf("%d",&k);
	for(int i = 0 ;i < k;i++){
		scanf("%s %d",tmpread,&c[i]);
		arr[i] = (string)tmpread;
	}
	for(int i = 0 ;i < k;i++) make(i);
	for(int i = 0 ;i < k;i++) make2(i);
	for(int i = 0 ;i < k;i++){
		for(int j = 0 ;j <= (int)arr[i].size();j++){
			//printf("val[%d][%d] = %d\n",i , j , val[i][j]);
			int inc = 0;
			for(char x = 'a'; x <= 'n';x++){
				vector< int > tmp = cur[i][j];
				for(int l = 0 ; l < k;l++){
					while(tmp[l] > 0 && arr[l][tmp[l]] != x) tmp[l] = f[l][tmp[l] - 1];
					if(arr[l][tmp[l]] == x) tmp[l]++;
				}
				inc = 0;
				for(int l = 0 ;l < k;l++){
					if(tmp[l] == (int)arr[l].size()){
						inc += c[l];
						tmp[l] = f[l][tmp[l] - 1];
					}
				}
				int mx = -1, idx = 0;
				for(int l = 0 ;l < k;l++){
					if(tmp[l] > mx)
						mx = tmp[l] , idx = l;
				}
				nxt[val[i][j]][x - 'a'] = val[idx][mx];
				cost[val[i][j]][x - 'a'] = inc;
			}
		}
	}
	scanf("%s",tmpread);
	s = (string)tmpread;
	string tmps;
	for(int i = 0 ;i < (int)s.size();i++){
		if(s[i] == '?'){
			if((int)tmps.size() > 0)
				v.push_back(tmps);
			tmps.clear();
		}
		tmps += s[i];
	}
	v.push_back(tmps);
	num[0] = 0;
	for(int i = 0 ;i < (int)v.size();i++){
		num[i + 1] = num[i];
		if(v[i][0] == '?')
			num[i + 1]++;
	}
	int mask , node;
	long long inc = 0;
	for(int i = (int)v.size() - 1 ;i >= 0;i--){
		if(v[i][0] != '?') continue;
		for(int pre = 0 ; pre < cnt;pre++){
			for(int k = 0 ;k < C;k++){
				v[i][0] = k + 'a';
				tmpcost[pre][k] = 0;
				node = pre;
				for(int j = 0 ;j < (int)v[i].size();j++){
					tmpcost[pre][k] += cost[node][v[i][j] - 'a'];
					node = nxt[node][v[i][j] - 'a'];
				}
				tmpnxt[pre][k] = node;
			}
			for(int it =0 ; it < (int)g[num[i]].size();it++){
				mask = g[num[i]][it];
				dp[mask][pre] = -(long long)1e18;
				for(int j = 0 ;j < C;j++){
					if(((mask >> j) & 1) == 1) continue;
					dp[mask][pre] = max(dp[mask][pre] , dp[(mask | (1 << j))][tmpnxt[pre][j]] + tmpcost[pre][j]);
				}
			}
		}
		v[i][0] = '?';
	}
	long long ans;
	if(v[0][0] != '?'){
		inc = 0;
		node = 0;
		for(int i = 0 ;i < (int)v[0].size();i++){
			inc += cost[node][v[0][i] - 'a'];
			node = nxt[node][v[0][i] - 'a'];
		}
		ans = inc + dp[0][node];
	}
	else
		ans = dp[0][0];
	cout << ans << endl;
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define mod 998244353
#define oo 1000000010
const int N = 400010;
string arr[N];
char tmpread[N];
int k ;
string s;

vector< int > f[N];

const int M = 3010 , C = 14;

vector< int > cur[M][M];

int val[M][M] , cnt = 0 , c[N];

int nxt[M][C] , cost[M][C] , dpnxt[2][M];

long long dp[(1 << C)][M] , dpcost[2][M];

int tmpnxt[C];

long long tmpcost[C];

int num[C + 2];

vector< int > g[C + 1];

void make(int idx){
	f[idx].resize((int)arr[idx].size());
	f[idx][0] = 0;
	int cnt = 0;
	for(int i = 1;i < (int)arr[idx].size();i++){
		while(cnt > 0 && arr[idx][i] != arr[idx][cnt]) cnt = f[idx][cnt - 1];
		if(arr[idx][cnt] == arr[idx][i]) cnt++;
		f[idx][i] = cnt;
	}
}

void make2(int idx){
	vector< int > tmp(k , 0);
	cur[idx][0] = tmp;
	val[idx][0] = cnt++;
	for(int i = 0 ;i < (int)arr[idx].size();i++){
		val[idx][i + 1] = cnt++;
		for(int j = 0 ;j < k;j++){
			while(tmp[j] > 0 && arr[idx][i] != arr[j][tmp[j]]) tmp[j] = f[j][tmp[j] - 1];
			if(arr[idx][i] == arr[j][tmp[j]]) tmp[j]++;
		}
		for(int j = 0 ;j < k;j++){
			if(tmp[j] == (int)arr[j].size()) tmp[j] = f[j][tmp[j] - 1];
		}
		cur[idx][i + 1] = tmp;
	}
}

vector< string > v;

int main(){
	for(int i = 0 ;i < (1 << C);i++){
		int tmp = i , ones = 0;
		while(tmp > 0){
			ones++;
			tmp ^= (tmp & (-tmp));
		}
		g[ones].push_back(i);
	}
	scanf("%d",&k);
	for(int i = 0 ;i < k;i++){
		scanf("%s %d",tmpread,&c[i]);
		arr[i] = (string)tmpread;
	}
	for(int i = 0 ;i < k;i++) make(i);
	for(int i = 0 ;i < k;i++) make2(i);
	for(int i = 0 ;i < k;i++){
		for(int j = 0 ;j <= (int)arr[i].size();j++){
			//printf("val[%d][%d] = %d\n",i , j , val[i][j]);
			int inc = 0;
			for(char x = 'a'; x <= 'n';x++){
				vector< int > tmp = cur[i][j];
				for(int l = 0 ; l < k;l++){
					while(tmp[l] > 0 && arr[l][tmp[l]] != x) tmp[l] = f[l][tmp[l] - 1];
					if(arr[l][tmp[l]] == x) tmp[l]++;
				}
				inc = 0;
				for(int l = 0 ;l < k;l++){
					if(tmp[l] == (int)arr[l].size()){
						inc += c[l];
						tmp[l] = f[l][tmp[l] - 1];
					}
				}
				int mx = -1, idx = 0;
				for(int l = 0 ;l < k;l++){
					if(tmp[l] > mx)
						mx = tmp[l] , idx = l;
				}
				nxt[val[i][j]][x - 'a'] = val[idx][mx];
				cost[val[i][j]][x - 'a'] = inc;
			}
		}
	}
	scanf("%s",tmpread);
	s = (string)tmpread;
	string tmps;
	for(int i = 0 ;i < (int)s.size();i++){
		if(s[i] == '?'){
			if((int)tmps.size() > 0)
				v.push_back(tmps);
			tmps.clear();
		}
		tmps += s[i];
	}
	v.push_back(tmps);
	num[0] = 0;
	for(int i = 0 ;i < (int)v.size();i++){
		num[i + 1] = num[i];
		if(v[i][0] == '?')
			num[i + 1]++;
	}
	int mask , node;
	long long inc = 0;
	for(int i = (int)v.size() - 1 ;i >= 0;i--){
		if(v[i][0] != '?') continue;
		for(int j = (int)v[i].size();j > 0;j--){
			for(int pre = 0 ; pre < cnt;pre++){
				if(j == (int)v[i].size())
					dpnxt[j & 1][pre] = pre , dpcost[j & 1][pre] = 0;
				else{
					dpnxt[j & 1][pre] = dpnxt[(j & 1) ^ 1][nxt[pre][v[i][j] - 'a']];
					dpcost[j & 1][pre] = cost[pre][v[i][j] - 'a'] + dpcost[(j & 1) ^ 1][nxt[pre][v[i][j] - 'a']];
				}
			}
		}
		for(int pre = 0 ; pre < cnt;pre++){
			for(int k = 0 ;k < C;k++){
				tmpnxt[k] = dpnxt[1][nxt[pre][k]];
				tmpcost[k] = cost[pre][k] + dpcost[1][nxt[pre][k]];
			}
			for(int it =0 ; it < (int)g[num[i]].size();it++){
				mask = g[num[i]][it];
				dp[mask][pre] = -(long long)1e18;
				for(int j = 0 ;j < C;j++){
					if(((mask >> j) & 1) == 1) continue;
					dp[mask][pre] = max(dp[mask][pre] , dp[(mask | (1 << j))][tmpnxt[j]] + tmpcost[j]);
				}
			}
		}
	}
	long long ans;
	if(v[0][0] != '?'){
		inc = 0;
		node = 0;
		for(int i = 0 ;i < (int)v[0].size();i++){
			inc += cost[node][v[0][i] - 'a'];
			node = nxt[node][v[0][i] - 'a'];
		}
		ans = inc + dp[0][node];
	}
	else
		ans = dp[0][0];
	cout << ans << endl;
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define mod 998244353
#define oo 1000000010
const int N = 400010;
string arr[N];
char tmpread[N];
int k ;
string s;

vector< int > f[N];

const int M = 3010 , C = 14;

vector< int > cur[M][M];

int val[M][M] , cnt = 0 , c[N];

int nxt[M][C] , cost[M][C] , dpnxt[2][M];

long long dp[(1 << C)][M] , dpcost[2][M];

int tmpnxt[C] , tmpcost[C];

int num[C + 2];

vector< int > g[C + 1];

void make(int idx){
	f[idx].resize((int)arr[idx].size());
	f[idx][0] = 0;
	int cnt = 0;
	for(int i = 1;i < (int)arr[idx].size();i++){
		while(cnt > 0 && arr[idx][i] != arr[idx][cnt]) cnt = f[idx][cnt - 1];
		if(arr[idx][cnt] == arr[idx][i]) cnt++;
		f[idx][i] = cnt;
	}
}

void make2(int idx){
	vector< int > tmp(k , 0);
	cur[idx][0] = tmp;
	val[idx][0] = cnt++;
	for(int i = 0 ;i < (int)arr[idx].size() - 1;i++){
		val[idx][i + 1] = cnt++;
		for(int j = 0 ;j < k;j++){
			while(tmp[j] > 0 && arr[idx][i] != arr[j][tmp[j]]) tmp[j] = f[j][tmp[j] - 1];
			if(arr[idx][i] == arr[j][tmp[j]]) tmp[j]++;
		}
		for(int j = 0 ;j < k;j++){
			if(tmp[j] == (int)arr[j].size()) tmp[j] = f[j][tmp[j] - 1];
		}
		cur[idx][i + 1] = tmp;
	}
}

vector< string > v;

int main(){
	for(int i = 0 ;i < (1 << C);i++){
		int tmp = i , ones = 0;
		while(tmp > 0){
			ones++;
			tmp ^= (tmp & (-tmp));
		}
		g[ones].push_back(i);
	}
	scanf("%d",&k);
	for(int i = 0 ;i < k;i++){
		scanf("%s %d",tmpread,&c[i]);
		arr[i] = (string)tmpread;
	}
	for(int i = 0 ;i < k;i++) make(i);
	for(int i = 0 ;i < k;i++) make2(i);
	for(int i = 0 ;i < k;i++){
		for(int j = 0 ;j < (int)arr[i].size();j++){
			//printf("val[%d][%d] = %d\n",i , j , val[i][j]);
			int inc = 0;
			for(char x = 'a'; x <= 'n';x++){
				vector< int > tmp = cur[i][j];
				for(int l = 0 ; l < k;l++){
					while(tmp[l] > 0 && arr[l][tmp[l]] != x) tmp[l] = f[l][tmp[l] - 1];
					if(arr[l][tmp[l]] == x) tmp[l]++;
				}
				inc = 0;
				for(int l = 0 ;l < k;l++){
					if(tmp[l] == (int)arr[l].size()){
						inc += c[l];
						tmp[l] = f[l][tmp[l] - 1];
					}
				}
				int mx = -1, idx = 0;
				for(int l = 0 ;l < k;l++){
					if(tmp[l] > mx)
						mx = tmp[l] , idx = l;
				}
				nxt[val[i][j]][x - 'a'] = val[idx][mx];
				cost[val[i][j]][x - 'a'] = inc;
			}
		}
	}
	scanf("%s",tmpread);
	s = (string)tmpread;
	string tmps;
	for(int i = 0 ;i < (int)s.size();i++){
		if(s[i] == '?'){
			if((int)tmps.size() > 0)
				v.push_back(tmps);
			tmps.clear();
		}
		tmps += s[i];
	}
	v.push_back(tmps);
	num[0] = 0;
	for(int i = 0 ;i < (int)v.size();i++){
		num[i + 1] = num[i];
		if(v[i][0] == '?')
			num[i + 1]++;
	}
	int mask , node;
	long long inc = 0;
	for(int i = (int)v.size() - 1 ;i >= 0;i--){
		if(v[i][0] != '?') continue;
		for(int j = (int)v.size();j > 0;j--){
			for(int pre = 0 ; pre < cnt;pre++){
				if(j == (int)v.size())
					dpnxt[j & 1][pre] = pre , dpcost[j & 1][pre] = 0;
				else{
					dpnxt[j & 1][pre] = nxt[pre][v[i][j] - 'a'];
					dpcost[j & 1][pre] = cost[pre][v[i][j] - 'a'] + dpcost[(j & 1) ^ 1][dpnxt[j & 1][pre]];
				}
			}
		}
		for(int pre = 0 ; pre < cnt;pre++){
			for(int k = 0 ;k < C;k++){
				tmpnxt[k] = dpnxt[1][nxt[pre][k]];
				tmpcost[k] = cost[pre][k] + dpcost[1][tmpnxt[k]];
			}
			for(int it =0 ; it < (int)g[num[i]].size();it++){
				mask = g[num[i]][it];
				dp[mask][pre] = -(long long)1e18;
				for(int j = 0 ;j < C;j++){
					if(((mask >> j) & 1) == 1) continue;
					dp[mask][pre] = max(dp[mask][pre] , dp[(mask | (1 << j))][tmpnxt[j]] + tmpcost[j]);
				}
			}
		}
		v[i][0] = '?';
	}
	long long ans;
	if(v[0][0] != '?'){
		inc = 0;
		node = 0;
		for(int i = 0 ;i < (int)v[0].size();i++){
			inc += cost[node][v[0][i] - 'a'];
			node = nxt[node][v[0][i] - 'a'];
		}
		ans = inc + dp[0][node];
	}
	else
		ans = dp[0][0];
	cout << ans << endl;
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define mod 998244353
#define oo 1000000010
const int N = 400010;
string arr[N];
char tmpread[N];
int k ;
string s;

vector< int > f[N];

const int M = 3010 , C = 14;

vector< int > cur[M][M];

int val[M][M] , cnt = 0 , c[N];

int nxt[M][C] , cost[M][C] , dpnxt[2][M];

long long dp[(1 << C)][M] , dpcost[2][M];

int tmpnxt[C] , tmpcost[C];

int num[C + 2];

vector< int > g[C + 1];

void make(int idx){
	f[idx].resize((int)arr[idx].size());
	f[idx][0] = 0;
	int cnt = 0;
	for(int i = 1;i < (int)arr[idx].size();i++){
		while(cnt > 0 && arr[idx][i] != arr[idx][cnt]) cnt = f[idx][cnt - 1];
		if(arr[idx][cnt] == arr[idx][i]) cnt++;
		f[idx][i] = cnt;
	}
}

void make2(int idx){
	vector< int > tmp(k , 0);
	cur[idx][0] = tmp;
	val[idx][0] = cnt++;
	for(int i = 0 ;i < (int)arr[idx].size();i++){
		val[idx][i + 1] = cnt++;
		for(int j = 0 ;j < k;j++){
			while(tmp[j] > 0 && arr[idx][i] != arr[j][tmp[j]]) tmp[j] = f[j][tmp[j] - 1];
			if(arr[idx][i] == arr[j][tmp[j]]) tmp[j]++;
		}
		for(int j = 0 ;j < k;j++){
			if(tmp[j] == (int)arr[j].size()) tmp[j] = f[j][tmp[j] - 1];
		}
		cur[idx][i + 1] = tmp;
	}
}

vector< string > v;

int main(){
	for(int i = 0 ;i < (1 << C);i++){
		int tmp = i , ones = 0;
		while(tmp > 0){
			ones++;
			tmp ^= (tmp & (-tmp));
		}
		g[ones].push_back(i);
	}
	scanf("%d",&k);
	for(int i = 0 ;i < k;i++){
		scanf("%s %d",tmpread,&c[i]);
		arr[i] = (string)tmpread;
	}
	for(int i = 0 ;i < k;i++) make(i);
	for(int i = 0 ;i < k;i++) make2(i);
	for(int i = 0 ;i < k;i++){
		for(int j = 0 ;j <= (int)arr[i].size();j++){
			//printf("val[%d][%d] = %d\n",i , j , val[i][j]);
			int inc = 0;
			for(char x = 'a'; x <= 'n';x++){
				vector< int > tmp = cur[i][j];
				for(int l = 0 ; l < k;l++){
					while(tmp[l] > 0 && arr[l][tmp[l]] != x) tmp[l] = f[l][tmp[l] - 1];
					if(arr[l][tmp[l]] == x) tmp[l]++;
				}
				inc = 0;
				for(int l = 0 ;l < k;l++){
					if(tmp[l] == (int)arr[l].size()){
						inc += c[l];
						tmp[l] = f[l][tmp[l] - 1];
					}
				}
				int mx = -1, idx = 0;
				for(int l = 0 ;l < k;l++){
					if(tmp[l] > mx)
						mx = tmp[l] , idx = l;
				}
				nxt[val[i][j]][x - 'a'] = val[idx][mx];
				cost[val[i][j]][x - 'a'] = inc;
			}
		}
	}
	scanf("%s",tmpread);
	s = (string)tmpread;
	string tmps;
	for(int i = 0 ;i < (int)s.size();i++){
		if(s[i] == '?'){
			if((int)tmps.size() > 0)
				v.push_back(tmps);
			tmps.clear();
		}
		tmps += s[i];
	}
	v.push_back(tmps);
	num[0] = 0;
	for(int i = 0 ;i < (int)v.size();i++){
		num[i + 1] = num[i];
		if(v[i][0] == '?')
			num[i + 1]++;
	}
	int mask , node;
	long long inc = 0;
	for(int i = (int)v.size() - 1 ;i >= 0;i--){
		if(v[i][0] != '?') continue;
		for(int j = (int)v.size();j > 0;j--){
			for(int pre = 0 ; pre < cnt;pre++){
				if(j == (int)v.size())
					dpnxt[j & 1][pre] = pre , dpcost[j & 1][pre] = 0;
				else{
					dpnxt[j & 1][pre] = nxt[pre][v[i][j] - 'a'];
					dpcost[j & 1][pre] = cost[pre][v[i][j] - 'a'] + dpcost[(j & 1) ^ 1][dpnxt[j & 1][pre]];
				}
			}
		}
		for(int pre = 0 ; pre < cnt;pre++){
			for(int k = 0 ;k < C;k++){
				tmpnxt[k] = dpnxt[1][nxt[pre][k]];
				tmpcost[k] = cost[pre][k] + dpcost[1][tmpnxt[k]];
			}
			for(int it =0 ; it < (int)g[num[i]].size();it++){
				mask = g[num[i]][it];
				dp[mask][pre] = -(long long)1e18;
				for(int j = 0 ;j < C;j++){
					if(((mask >> j) & 1) == 1) continue;
					dp[mask][pre] = max(dp[mask][pre] , dp[(mask | (1 << j))][tmpnxt[j]] + tmpcost[j]);
				}
			}
		}
		v[i][0] = '?';
	}
	long long ans;
	if(v[0][0] != '?'){
		inc = 0;
		node = 0;
		for(int i = 0 ;i < (int)v[0].size();i++){
			inc += cost[node][v[0][i] - 'a'];
			node = nxt[node][v[0][i] - 'a'];
		}
		ans = inc + dp[0][node];
	}
	else
		ans = dp[0][0];
	cout << ans << endl;
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define mod 998244353
#define oo 1000000010
const int N = 400010;
string arr[N];
char tmpread[N];
int k ;
string s;

vector< int > f[N];

const int M = 3010 , C = 14;

vector< int > cur[M][M];

int val[M][M] , cnt = 0 , c[N];

int nxt[M][C] , cost[M][C] , dpnxt[2][M];

long long dp[(1 << C)][M] , dpcost[2][M];

int tmpnxt[C] , tmpcost[C];

int num[C + 2];

vector< int > g[C + 1];

void make(int idx){
	f[idx].resize((int)arr[idx].size());
	f[idx][0] = 0;
	int cnt = 0;
	for(int i = 1;i < (int)arr[idx].size();i++){
		while(cnt > 0 && arr[idx][i] != arr[idx][cnt]) cnt = f[idx][cnt - 1];
		if(arr[idx][cnt] == arr[idx][i]) cnt++;
		f[idx][i] = cnt;
	}
}

void make2(int idx){
	vector< int > tmp(k , 0);
	cur[idx][0] = tmp;
	val[idx][0] = cnt++;
	for(int i = 0 ;i < (int)arr[idx].size() - 1;i++){
		val[idx][i + 1] = cnt++;
		for(int j = 0 ;j < k;j++){
			while(tmp[j] > 0 && arr[idx][i] != arr[j][tmp[j]]) tmp[j] = f[j][tmp[j] - 1];
			if(arr[idx][i] == arr[j][tmp[j]]) tmp[j]++;
		}
		for(int j = 0 ;j < k;j++){
			if(tmp[j] == (int)arr[j].size()) tmp[j] = f[j][tmp[j] - 1];
		}
		cur[idx][i + 1] = tmp;
	}
}

vector< string > v;

int main(){
	for(int i = 0 ;i < (1 << C);i++){
		int tmp = i , ones = 0;
		while(tmp > 0){
			ones++;
			tmp ^= (tmp & (-tmp));
		}
		g[ones].push_back(i);
	}
	scanf("%d",&k);
	for(int i = 0 ;i < k;i++){
		scanf("%s %d",tmpread,&c[i]);
		arr[i] = (string)tmpread;
	}
	for(int i = 0 ;i < k;i++) make(i);
	for(int i = 0 ;i < k;i++) make2(i);
	for(int i = 0 ;i < k;i++){
		for(int j = 0 ;j < (int)arr[i].size();j++){
			//printf("val[%d][%d] = %d\n",i , j , val[i][j]);
			int inc = 0;
			for(char x = 'a'; x <= 'n';x++){
				vector< int > tmp = cur[i][j];
				for(int l = 0 ; l < k;l++){
					while(tmp[l] > 0 && arr[l][tmp[l]] != x) tmp[l] = f[l][tmp[l] - 1];
					if(arr[l][tmp[l]] == x) tmp[l]++;
				}
				inc = 0;
				for(int l = 0 ;l < k;l++){
					if(tmp[l] == (int)arr[l].size()){
						inc += c[l];
						tmp[l] = f[l][tmp[l] - 1];
					}
				}
				int mx = -1, idx = 0;
				for(int l = 0 ;l < k;l++){
					if(tmp[l] > mx)
						mx = tmp[l] , idx = l;
				}
				nxt[val[i][j]][x - 'a'] = val[idx][mx];
				cost[val[i][j]][x - 'a'] = inc;
			}
		}
	}
	scanf("%s",tmpread);
	s = (string)tmpread;
	string tmps;
	for(int i = 0 ;i < (int)s.size();i++){
		if(s[i] == '?'){
			if((int)tmps.size() > 0)
				v.push_back(tmps);
			tmps.clear();
		}
		tmps += s[i];
	}
	v.push_back(tmps);
	num[0] = 0;
	for(int i = 0 ;i < (int)v.size();i++){
		num[i + 1] = num[i];
		if(v[i][0] == '?')
			num[i + 1]++;
	}
	int mask , node;
	long long inc = 0;
	for(int i = (int)v.size() - 1 ;i >= 0;i--){
		if(v[i][0] != '?') continue;
		for(int j = (int)v.size();j > 0;j--){
			for(int pre = 0 ; pre < cnt;pre++){
				if(j == (int)v.size())
					dpnxt[j & 1][pre] = pre , dpcost[j & 1][pre] = 0;
				else{
					dpnxt[j & 1][pre] = dpnxt[(j & 1) ^ 1][nxt[pre][v[i][j] - 'a']];
					dpcost[j & 1][pre] = cost[pre][v[i][j] - 'a'] + dpcost[(j & 1) ^ 1][nxt[pre][v[i][j] - 'a']];
				}
			}
		}
		for(int pre = 0 ; pre < cnt;pre++){
			for(int k = 0 ;k < C;k++){
				tmpnxt[k] = dpnxt[1][nxt[pre][k]];
				tmpcost[k] = cost[pre][k] + dpcost[1][nxt[pre][k]];
			}
			for(int it =0 ; it < (int)g[num[i]].size();it++){
				mask = g[num[i]][it];
				dp[mask][pre] = -(long long)1e18;
				for(int j = 0 ;j < C;j++){
					if(((mask >> j) & 1) == 1) continue;
					dp[mask][pre] = max(dp[mask][pre] , dp[(mask | (1 << j))][tmpnxt[j]] + tmpcost[j]);
				}
			}
		}
		v[i][0] = '?';
	}
	long long ans;
	if(v[0][0] != '?'){
		inc = 0;
		node = 0;
		for(int i = 0 ;i < (int)v[0].size();i++){
			inc += cost[node][v[0][i] - 'a'];
			node = nxt[node][v[0][i] - 'a'];
		}
		ans = inc + dp[0][node];
	}
	else
		ans = dp[0][0];
	cout << ans << endl;
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define mod 998244353
#define oo 1000000010
const int N = 400010;
string arr[N];
char tmpread[N];
int k ;
string s;

vector< int > f[N];

const int M = 3010 , C = 14;

vector< int > cur[M][M];

int val[M][M] , cnt = 0 , c[N];

int nxt[M][C] , cost[M][C] , tmpnxt[M][C];

long long dp[(1 << C)][M] , tmpcost[M][C];

int num[C + 2];

vector< int > g[C + 1];

void make(int idx){
	f[idx].resize((int)arr[idx].size());
	f[idx][0] = 0;
	int cnt = 0;
	for(int i = 1;i < (int)arr[idx].size();i++){
		while(cnt > 0 && arr[idx][i] != arr[idx][cnt]) cnt = f[idx][cnt - 1];
		if(arr[idx][cnt] == arr[idx][i]) cnt++;
		f[idx][i] = cnt;
	}
}

void make2(int idx){
	vector< int > tmp(k , 0);
	cur[idx][0] = tmp;
	val[idx][0] = cnt++;
	for(int i = 0 ;i < (int)arr[idx].size();i++){
		val[idx][i + 1] = cnt++;
		for(int j = 0 ;j < k;j++){
			while(tmp[j] > 0 && arr[idx][i] != arr[j][tmp[j]]) tmp[j] = f[j][tmp[j] - 1];
			if(arr[idx][i] == arr[j][tmp[j]]) tmp[j]++;
		}
		for(int j = 0 ;j < k;j++){
			if(tmp[j] == (int)arr[j].size()) tmp[j] = f[j][tmp[j] - 1];
		}
		cur[idx][i + 1] = tmp;
	}
}

vector< string > v;

int main(){
	for(int i = 0 ;i < (1 << C);i++){
		int tmp = i , ones = 0;
		while(tmp > 0){
			ones++;
			tmp ^= (tmp & (-tmp));
		}
		g[ones].push_back(i);
	}
	scanf("%d",&k);
	for(int i = 0 ;i < k;i++){
		scanf("%s %d",tmpread,&c[i]);
		arr[i] = (string)tmpread;
	}
	for(int i = 0 ;i < k;i++) make(i);
	for(int i = 0 ;i < k;i++) make2(i);
	for(int i = 0 ;i < k;i++){
		for(int j = 0 ;j <= (int)arr[i].size();j++){
			//printf("val[%d][%d] = %d\n",i , j , val[i][j]);
			int inc = 0;
			for(char x = 'a'; x <= 'n';x++){
				vector< int > tmp = cur[i][j];
				for(int l = 0 ; l < k;l++){
					while(tmp[l] > 0 && arr[l][tmp[l]] != x) tmp[l] = f[l][tmp[l] - 1];
					if(arr[l][tmp[l]] == x) tmp[l]++;
				}
				inc = 0;
				for(int l = 0 ;l < k;l++){
					if(tmp[l] == (int)arr[l].size()){
						inc += c[l];
						tmp[l] = f[l][tmp[l] - 1];
					}
				}
				int mx = -1, idx = 0;
				for(int l = 0 ;l < k;l++){
					if(tmp[l] > mx)
						mx = tmp[l] , idx = l;
				}
				nxt[val[i][j]][x - 'a'] = val[idx][mx];
				cost[val[i][j]][x - 'a'] = inc;
			}
		}
	}
	scanf("%s",tmpread);
	s = (string)tmpread;
	string tmps;
	for(int i = 0 ;i < (int)s.size();i++){
		if(s[i] == '?'){
			if((int)tmps.size() > 0)
				v.push_back(tmps);
			tmps.clear();
		}
		tmps += s[i];
	}
	v.push_back(tmps);
	num[0] = 0;
	for(int i = 0 ;i < (int)v.size();i++){
		num[i + 1] = num[i];
		if(v[i][0] == '?')
			num[i + 1]++;
	}
	int mask , node;
	long long inc = 0;
	for(int i = (int)v.size() - 1 ;i >= 0;i--){
		if(v[i][0] != '?') continue;
		for(int pre = 0 ; pre < cnt;pre++){
			for(int k = 0 ;k < C;k++){
				v[i][0] = k + 'a';
				tmpcost[pre][k] = 0;
				node = pre;
				for(int j = 0 ;j < (int)v[i].size();j++){
					tmpcost[pre][k] += cost[node][v[i][j] - 'a'];
					node = nxt[node][v[i][j] - 'a'];
				}
				tmpnxt[pre][k] = node;
			}
			for(int it =0 ; it < (int)g[num[i]].size();it++){
				mask = g[num[i]][it];
				dp[mask][pre] = -(long long)1e18;
				for(int j = 0 ;j < C;j++){
					if(((mask >> j) & 1) == 1) continue;
					dp[mask][pre] = max(dp[mask][pre] , dp[(mask | (1 << j))][tmpnxt[pre][j]] + tmpcost[pre][j]);
				}
			}
		}
		v[i][0] = '?';
	}
	long long ans;
	if(v[0][0] != '?'){
		inc = 0;
		node = 0;
		for(int i = 0 ;i < (int)v[0].size();i++){
			inc += cost[node][v[0][i] - 'a'];
			node = nxt[node][v[0][i] - 'a'];
		}
		ans = inc + dp[0][node];
	}
	else
		ans = dp[0][0];
	cout << ans << endl;
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
#define mod 998244353
#define oo 1000000010
const int N = 400010;
string arr[N];
char tmpread[N];
int k ;
string s;

vector< int > f[N];

const int M = 3010 , C = 14;

vector< int > cur[M][M];

int val[M][M] , cnt = 0 , c[N];

int nxt[M][C] , cost[M][C] , tmpnxt[M][C];

long long dp[(1 << C)][M] , tmpcost[M][C];

int num[C + 2];

vector< int > g[C + 1];

void make(int idx){
	f[idx].resize((int)arr[idx].size());
	f[idx][0] = 0;
	int cnt = 0;
	for(int i = 1;i < (int)arr[idx].size();i++){
		while(cnt > 0 && arr[idx][i] != arr[idx][cnt]) cnt = f[idx][cnt - 1];
		if(arr[idx][cnt] == arr[idx][i]) cnt++;
		f[idx][i] = cnt;
	}
}

void make2(int idx){
	vector< int > tmp(k , 0);
	cur[idx][0] = tmp;
	val[idx][0] = cnt++;
	for(int i = 0 ;i < (int)arr[idx].size();i++){
		val[idx][i + 1] = cnt++;
		for(int j = 0 ;j < k;j++){
			while(tmp[j] > 0 && arr[idx][i] != arr[idx][tmp[j]]) tmp[j] = f[j][tmp[j] - 1];
			if(arr[idx][i] == arr[j][tmp[j]]) tmp[j]++;
		}
		for(int j = 0 ;j < k;j++){
			if(tmp[j] == (int)arr[j].size()) tmp[j] = f[idx][tmp[j] - 1];
		}
		cur[idx][i + 1] = tmp;
	}
}

vector< string > v;

int main(){
	for(int i = 0 ;i < (1 << C);i++){
		int tmp = i , ones = 0;
		while(tmp > 0){
			ones++;
			tmp ^= (tmp & (-tmp));
		}
		g[ones].push_back(i);
	}
	scanf("%d",&k);
	for(int i = 0 ;i < k;i++){
		scanf("%s %d",tmpread,&c[i]);
		arr[i] = (string)tmpread;
	}
	for(int i = 0 ;i < k;i++) make(i);
	for(int i = 0 ;i < k;i++) make2(i);
	for(int i = 0 ;i < k;i++){
		for(int j = 0 ;j <= (int)arr[i].size();j++){
			//printf("val[%d][%d] = %d\n",i , j , val[i][j]);
			int inc = 0;
			for(char x = 'a'; x <= 'n';x++){
				vector< int > tmp = cur[i][j];
				for(int l = 0 ; l < k;l++){
					while(tmp[l] > 0 && arr[l][tmp[l]] != x) tmp[l] = f[l][tmp[l] - 1];
					if(arr[l][tmp[l]] == x) tmp[l]++;
				}
				inc = 0;
				for(int l = 0 ;l < k;l++){
					if(tmp[l] == (int)arr[l].size()){
						inc += c[l];
						tmp[l] = f[l][tmp[l] - 1];
					}
				}
				int mx = -1, idx = 0;
				for(int l = 0 ;l < k;l++){
					if(tmp[l] > mx)
						mx = tmp[l] , idx = l;
				}
				nxt[val[i][j]][x - 'a'] = val[idx][mx];
				cost[val[i][j]][x - 'a'] = inc;
			}
		}
	}
	scanf("%s",tmpread);
	s = (string)tmpread;
	string tmps;
	for(int i = 0 ;i < (int)s.size();i++){
		if(s[i] == '?'){
			if((int)tmps.size() > 0)
				v.push_back(tmps);
			tmps.clear();
		}
		tmps += s[i];
	}
	v.push_back(tmps);
	num[0] = 0;
	for(int i = 0 ;i < (int)v.size();i++){
		num[i + 1] = num[i];
		if(v[i][0] == '?')
			num[i + 1]++;
	}
	int mask , node;
	long long inc = 0;
	for(int i = (int)v.size() - 1 ;i >= 0;i--){
		if(v[i][0] != '?') continue;
		for(int pre = 0 ; pre < cnt;pre++){
			for(int k = 0 ;k < C;k++){
				v[i][0] = k + 'a';
				tmpcost[pre][k] = 0;
				node = pre;
				for(int j = 0 ;j < (int)v[i].size();j++){
					tmpcost[pre][k] += cost[node][v[i][j] - 'a'];
					node = nxt[node][v[i][j] - 'a'];
				}
				tmpnxt[pre][k] = node;
			}
			for(int it =0 ; it < (int)g[num[i]].size();it++){
				mask = g[num[i]][it];
				dp[mask][pre] = -(long long)1e18;
				for(int j = 0 ;j < C;j++){
					if(((mask >> j) & 1) == 1) continue;
					dp[mask][pre] = max(dp[mask][pre] , dp[(mask | (1 << j))][tmpnxt[pre][j]] + tmpcost[pre][j]);
				}
			}
		}
		v[i][0] = '?';
	}
	long long ans;
	if(v[0][0] != '?'){
		inc = 0;
		node = 0;
		for(int i = 0 ;i < (int)v[0].size();i++){
			inc += cost[node][v[0][i] - 'a'];
			node = nxt[node][v[0][i] - 'a'];
		}
		ans = inc + dp[0][node];
	}
	else
		ans = dp[0][0];
	cout << ans << endl;
	return 0;
}


//#pragma GCC optimize("Ofast")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
//#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
using namespace std;

#define rep(i,n) for (int i=0;i<(int)(n);++i)
#define rep1(i,n) for (int i=1;i<=(int)(n);++i)
#define range(x) begin(x), end(x)
#define sz(x) (int)(x).size()
#define pb push_back
#define F first
#define S second

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pii;
typedef vector<int> vi;
/*
计算u^v % mod
*/
ll power(ll u,ll v,ll mod){
    ll ret=1,t=u%mod;
    while (v){
        if (v&1) ret=t*ret%mod;
        t=t*t%mod, v>>=1;
    }
    return ret%mod;
}

/*
计算gcd(a,b)并找寻ax+by=gcd(a,b)的一组解
ret=exgcd(a,b,x,y);
*/
ll exgcd(ll a,ll b,ll &x,ll &y){
    if (b){
        ll d=exgcd(b,a%b,y,x);
        return y-=a/b*x, d;
    }
    return x=1,y=0,a;
}

/*
计算x=a(mod m), x=b(mod n)的一组解，若无解返回-1
ret=crt(a,m,b,n);
*/
ll crt(ll a,ll m,ll b,ll n){
    if (n>m) swap(a,b), swap(n,m);
    ll x,y,g=exgcd(m,n,x,y);
    if ((b-a)%g) return -1;
    x=(b-a)%n*x%n/g*m+a;
    return x<0?x+m*n/g:x;
}

/*
生成<=n的质数
gen_prime<5000>(ret);
*/

void gen_prime(int n,vi &ret){
    vector<bool> p;
    p.resize(n+1,1);
    p[0]=p[1]=0;
    for (int i=4;i<=n;i+=2) p[i]=0;
    for (int i=3;i*i<=n;i+=2){
        if (p[i]){
            for (int j=i*i;j<=n;j+=2*i){
                p[j]=0;
            }
        }
    }
    for (int i=2;i<=n;++i){
        if (p[i]) ret.pb(i);
    }
}

/*
生成<=n的phi
gen_phi<5000>(ret);
*/
void gen_phi(int n,vi &phi){
    phi.resize(n+1);
    for (int i=0;i<=n;++i) phi[i]=i&1?i:i/2;
    for (int i=3;i<=n;i+=2){
        if (phi[i]==i){
            for (int j=i;j<=n;j+=i) phi[j]-=phi[j]/i;
        }
    }
}

/*
支持更高的快速幂操作
expower.mod_pow(a,b,mod);
*/

struct expower{
    ull mod_mul(ull a,ull b,ull M) {
        ll ret=a*b-M*ull(ld(a)* ld(b)/ld(M));
        return ret+M*(ret<0)-M*(ret>=(ll)M);
    }
    ull mod_pow(ull b,ull e,ull mod) {
        ull ans=1;
        for (; e; b=mod_mul(b,b,mod), e/=2)
            if (e&1) ans=mod_mul(ans,b,mod);
        return ans%mod;
    }
}expower;

/*
Miller-Rubin素数判别
is_prime(n);
*/
bool is_prime(ull n){
    if (n<2||n%6%4!=1) return n-2<2;
    ull A[]={2,325,9375,28178,450775,9780504,1795265022},
    s=__builtin_ctzll(n-1), d = n >> s;
    for (auto a:A){
        ull p=expower.mod_pow(a,d,n),i=s;
        while (p!=1&&p!=n-1&&a%n&&i--)
            p=expower.mod_mul(p,p,n);
        if (p!=n-1&&i!=s) return 0;
    }
    return 1;
}

/*
素因数分解
ret=factorization(n);
*/
ull pollard(ull n){
    auto f=[n](ull x){return (expower.mod_mul(x,x,n)+1)%n;};
    if (!(n&1)) return 2;
    for (ull i=2;;i++){
        ull x=i,y=f(x),p;
        while ((p=__gcd(n+y-x,n))==1)
            x=f(x),y=f(f(y));
        if (p!=n) return p;
    }
}

vector<ull> factorization(ull n){
    if (n==1) return {};
    if (is_prime(n)) return {n};
    ull x=pollard(n);
    auto l=factorization(x),r=factorization(n/x);
    l.insert(l.end(),range(r));
    return l;
}

struct DSU{
    //insert info.
    vector<int> p;
    DSU(int n){
        p.resize(n+1);
        for (int i=1;i<=n;++i) p[i]=i;
    }
    int find(int u){
        if (p[u]==u) return u;
        return p[u]=find(find(p[u]));
    }
    bool unite(int u,int v){
        int pu=find(u), pv=find(v);
        if (pu!=pv){
            p[pu]=pv;
        }
        return pu!=pv;
    }
};

/* (u,v,w) */
template<class T> vector<tuple<int,int,T> > MST(int n,vector<tuple<int,int,T> >g){
    vector<tuple<int,int,T> > ret;
    ret.clear();
    DSU dsu(n);
    auto cmp=[&](tuple<int,int,T> x,tuple<int,int,T> y){
        int ux,uy,vx,vy;
        T wx,wy;
        tie(ux,vx,wx)=x, tie(uy,vy,wy)=y;
        return wx<wy;
    };
    sort(range(g),cmp);
    for (auto c:g){
        int u,v;
        T w;
        tie(u,v,w)=c;
        if(dsu.unite(u,v)) ret.push_back(c);
    }
    return ret;
}

template<int n,class T>
struct SegmentTree{
    typedef struct{
        T lz,mx,mn,sum;
    }Node;
    vector<Node> tree;
    SegmentTree(){
        tree.resize((n+7)<<2);
    }
    void pushup(int num){
        tree[num].mx=max(tree[num<<1].mx,tree[num<<1|1].mx);
        tree[num].mn=min(tree[num<<1].mn,tree[num<<1|1].mn);
        tree[num].sum=tree[num<<1].sum+tree[num<<1|1].sum;
    }
    void pushdown(int num,int l,int r,int md){
        if (tree[num].lz){
            tree[num<<1].mx+=tree[num].lz;
            tree[num<<1|1].mx+=tree[num].lz;
            tree[num<<1].mn+=tree[num].lz;
            tree[num<<1|1].mn+=tree[num].lz;
            tree[num<<1].sum+=tree[num].lz*(md-l+1);
            tree[num<<1|1].sum+=tree[num].lz*(r-md);
            tree[num<<1].lz+=tree[num].lz;
            tree[num<<1|1].lz+=tree[num].lz;
            tree[num].lz=0;
        }
    }
    void update1(int num,int l,int r,int L,int R,T val){
        if (L<=l&&r<=R){
            tree[num].mx+=val;
            tree[num].mn+=val;
            tree[num].sum+=val*(r-l+1);
            tree[num].lz+=val;
            return;
        }
        int md=(l+r)>>1;
        pushdown(num,l,r,md);
        if (md>=L) update1(num<<1,l,md,L,R,val);
        if (md<R) update1(num<<1|1,md+1,r,L,R,val);
        pushup(num);
    }
    tuple<T,T,T> query1(int num,int l,int r,int L,int R){
        if (L<=l&&r<=R){
            return {tree[num].mn,tree[num].mx,tree[num].sum};
        }
        int md=(l+r)>>1;
        pushdown(num,l,r,md);
        if (md>=R){
            return query1(num<<1,l,md,L,R);
        }
        else{
            if (md<L){
                return query1(num<<1|1,md+1,r,L,R);
            }
            else{
                tuple<T,T,T> ret1=query1(num<<1,l,md,L,R), ret2=query1(num<<1|1,md+1,r,L,R);
                T a,b,c,d,e,f;
                tie(a,b,c)=ret1, tie(d,e,f)=ret2;
                return {min(a,d),max(b,e),c+f};
            }
        }
    }
    void update(int L,int R,int w){
        update1(1,1,n,L,R,w);
    }
    tuple<T,T,T> query(int L,int R){
        return query1(1,1,n,L,R);
    }
    void debug1(int num,int l,int r){
        if (l==r){
            cout<<tree[num].mn<<" "; return;
        }
        int md=(l+r)>>1;
        pushdown(num,l,r,md);
        debug1(num<<1,l,md);
         debug1(num<<1|1,md+1,r);
    }
    void debug(){
        debug1(1,1,n);
        cout<<endl;
    }
};

struct XORBasis{
    int n;
    vector<ull> p;
    vector<ull> ans;
    XORBasis(int k):n(k){
        p.resize(k+1);
    }
    void rebuilt(){
        ans.clear();
        for (int i=0;i<=n;++i){
            if (p[i]) ans.push_back(p[i]);
        }
    }
    void insert(ull u){
        for (int i=n;i>=0;--i){
            if (u&(1ull<<i)){
                if (p[i]) u^=p[i];
                else{
                    p[i]=u;
                    for (int j=i-1;j>=0;--j){
                        if (p[i]&(1ull<<j)) p[i]^=p[j];
                    }
                    for (int j=i+1;j<=n;++j){
                        if (p[j]&(1ull<<i)) p[j]^=p[i];
                    }
                    break;
                }
            }
        }
        rebuilt();
    }
    ull kth(ull t){ // the k-th smallest, excluding 0.
        if (t>=(1ull<<sz(ans))) return -1;
        ull ret=0;
        for (int i=0;i<sz(ans);++i){
            if (t&(1ull<<i)) ret^=ans[i];
        }
        return ret;
    }
    ull total(){
        return (1ull<<sz(ans));
    }
};

vi pi(const string& s) {
	vi p(sz(s));
	for (int i=1;i<=sz(s);++i) {
		int g = p[i-1];
		while (g && s[i] != s[g]) g = p[g-1];
		p[i] = g + (s[i] == s[g]);
	}
	return p;
}

vi match(const string& s, const string& pat) {
	vi p = pi(pat + '\0' + s), res;
	for(int i=sz(p)-sz(s);i<=sz(p);++i)
		if (p[i] == sz(pat)) res.push_back(i - 2 * sz(pat));
	return res;
}

struct AhoCorasick {
	enum {alpha = 26, first = 'a'};
	struct Node {
		// (nmatches is optional)
		int back, next[alpha], start = -1, end = -1;
        ll nmatches = 0;
		Node(int v) { memset(next, v, sizeof(next)); }
	};
	vector<Node> N;
	vector<int> backp;
	void insert(string& s, int j,ll val) {
		assert(!s.empty());
		int n = 0;
		for(auto c:s) {
			int& m = N[n].next[c - first];
			if (m == -1) { n = m = sz(N); N.emplace_back(-1); }
			else n = m;
		}
		if (N[n].end == -1) N[n].start = j;
		backp.push_back(N[n].end);
		N[n].end = j;
		N[n].nmatches+=val;
	}
	AhoCorasick(vector<string>& pat,vi val) {
		N.emplace_back(-1);
		for (int i=0;i<sz(pat);++i) insert(pat[i], i, val[i]);
		N[0].back = sz(N);
		N.emplace_back(0);

		queue<int> q;
		for (q.push(0); !q.empty(); q.pop()) {
			int n = q.front(), prev = N[n].back;
			for (int i=0;i<alpha;++i) {
				int &ed = N[n].next[i], y = N[prev].next[i];
				if (ed == -1) ed = y;
				else {
					N[ed].back = y;
					(N[ed].end == -1 ? N[ed].end : backp[N[ed].start])
						= N[y].end;
					N[ed].nmatches += N[y].nmatches;
					q.push(ed);
				}
			}
		}
	}
	vi find(string& word,ll& ans) {
		int n = 0;
		vi res;
		for(auto c:word) {
			n = N[n].next[c - first];
			res.push_back(N[n].end);
			ans += N[n].nmatches;
		}
		return res;
	}
	vector<vi> findAll(vector<string>& pat, string word) {
		ll ans=0;
        vi r = find(word,ans);
		vector<vi> res(sz(word));
		for (int i=0;i<sz(word);++i) {
			int ind = r[i];
			while (ind != -1) {
				res[i - sz(pat[ind]) + 1].push_back(ind);
				ind = backp[ind];
			}
		}
		return res;
	}
};

const int maxn=1007;
int n;
vi val;
vector<string> st;
string s;
ll dp[1007][1<<14],dpt[1007][1<<14],f[1007],g[1007];
int main(){
    cin>>n;
    for (int i=0;i<n;++i){
        string r;
        int t;
        cin>>r>>t;
        st.emplace_back(r), val.emplace_back(t);
    }
    AhoCorasick aca(st,val);
    cin>>s;
    memset(dp,0x80,sizeof(dp));
    dp[0][0]=0;
    for (int j=0;j<sz(aca.N);++j){
        f[j]=j,g[j]=0;
    }
    for (auto c:s){
        if (c=='?'){
            memset(dpt,0x80,sizeof(dpt));
            for (int j=0;j<sz(aca.N);++j){
                for (int k=0;k<(1<<14);++k){
                    if (dp[j][k]<-1e15) continue;
                    for (int r=0;r<14;++r){
                        if (k>>r&1) continue;
                        int to=aca.N[f[j]].next[r], val=g[j]+aca.N[to].nmatches;
                        dpt[to][k^(1<<r)]=max(dpt[to][k^(1<<r)],dp[j][k]+val);
                    }
                }
            }
            for (int j=0;j<sz(aca.N);++j){
                for (int k=0;k<(1<<14);++k){
                    dp[j][k]=dpt[j][k];
                }
            }
            for (int j=0;j<sz(aca.N);++j){
                f[j]=j,g[j]=0;
            }
        }
        else{
            for (int j=0;j<sz(aca.N);++j){
                f[j]=aca.N[f[j]].next[c-'a'], g[j]+=aca.N[f[j]].nmatches;
            }
        }
    }
    ll ans=-1e15;
    for (int j=0;j<sz(aca.N);++j){
        for (int k=0;k<(1<<14);++k){
            ans=max(ans,dp[j][k]+g[j]);
        }
    }
    cout<<ans<<endl;
    return 0;
}


//#pragma GCC optimize("Ofast")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
//#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
using namespace std;

#define rep(i,n) for (int i=0;i<(int)(n);++i)
#define rep1(i,n) for (int i=1;i<=(int)(n);++i)
#define range(x) begin(x), end(x)
#define sz(x) (int)(x).size()
#define pb push_back
#define F first
#define S second

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pii;
typedef vector<int> vi;
/*
计算u^v % mod
*/
ll power(ll u,ll v,ll mod){
    ll ret=1,t=u%mod;
    while (v){
        if (v&1) ret=t*ret%mod;
        t=t*t%mod, v>>=1;
    }
    return ret%mod;
}

/*
计算gcd(a,b)并找寻ax+by=gcd(a,b)的一组解
ret=exgcd(a,b,x,y);
*/
ll exgcd(ll a,ll b,ll &x,ll &y){
    if (b){
        ll d=exgcd(b,a%b,y,x);
        return y-=a/b*x, d;
    }
    return x=1,y=0,a;
}

/*
计算x=a(mod m), x=b(mod n)的一组解，若无解返回-1
ret=crt(a,m,b,n);
*/
ll crt(ll a,ll m,ll b,ll n){
    if (n>m) swap(a,b), swap(n,m);
    ll x,y,g=exgcd(m,n,x,y);
    if ((b-a)%g) return -1;
    x=(b-a)%n*x%n/g*m+a;
    return x<0?x+m*n/g:x;
}

/*
生成<=n的质数
gen_prime<5000>(ret);
*/

void gen_prime(int n,vi &ret){
    vector<bool> p;
    p.resize(n+1,1);
    p[0]=p[1]=0;
    for (int i=4;i<=n;i+=2) p[i]=0;
    for (int i=3;i*i<=n;i+=2){
        if (p[i]){
            for (int j=i*i;j<=n;j+=2*i){
                p[j]=0;
            }
        }
    }
    for (int i=2;i<=n;++i){
        if (p[i]) ret.pb(i);
    }
}

/*
生成<=n的phi
gen_phi<5000>(ret);
*/
void gen_phi(int n,vi &phi){
    phi.resize(n+1);
    for (int i=0;i<=n;++i) phi[i]=i&1?i:i/2;
    for (int i=3;i<=n;i+=2){
        if (phi[i]==i){
            for (int j=i;j<=n;j+=i) phi[j]-=phi[j]/i;
        }
    }
}

/*
支持更高的快速幂操作
expower.mod_pow(a,b,mod);
*/

struct expower{
    ull mod_mul(ull a,ull b,ull M) {
        ll ret=a*b-M*ull(ld(a)* ld(b)/ld(M));
        return ret+M*(ret<0)-M*(ret>=(ll)M);
    }
    ull mod_pow(ull b,ull e,ull mod) {
        ull ans=1;
        for (; e; b=mod_mul(b,b,mod), e/=2)
            if (e&1) ans=mod_mul(ans,b,mod);
        return ans%mod;
    }
}expower;

/*
Miller-Rubin素数判别
is_prime(n);
*/
bool is_prime(ull n){
    if (n<2||n%6%4!=1) return n-2<2;
    ull A[]={2,325,9375,28178,450775,9780504,1795265022},
    s=__builtin_ctzll(n-1), d = n >> s;
    for (auto a:A){
        ull p=expower.mod_pow(a,d,n),i=s;
        while (p!=1&&p!=n-1&&a%n&&i--)
            p=expower.mod_mul(p,p,n);
        if (p!=n-1&&i!=s) return 0;
    }
    return 1;
}

/*
素因数分解
ret=factorization(n);
*/
ull pollard(ull n){
    auto f=[n](ull x){return (expower.mod_mul(x,x,n)+1)%n;};
    if (!(n&1)) return 2;
    for (ull i=2;;i++){
        ull x=i,y=f(x),p;
        while ((p=__gcd(n+y-x,n))==1)
            x=f(x),y=f(f(y));
        if (p!=n) return p;
    }
}

vector<ull> factorization(ull n){
    if (n==1) return {};
    if (is_prime(n)) return {n};
    ull x=pollard(n);
    auto l=factorization(x),r=factorization(n/x);
    l.insert(l.end(),range(r));
    return l;
}

struct DSU{
    //insert info.
    vector<int> p;
    DSU(int n){
        p.resize(n+1);
        for (int i=1;i<=n;++i) p[i]=i;
    }
    int find(int u){
        if (p[u]==u) return u;
        return p[u]=find(find(p[u]));
    }
    bool unite(int u,int v){
        int pu=find(u), pv=find(v);
        if (pu!=pv){
            p[pu]=pv;
        }
        return pu!=pv;
    }
};

/* (u,v,w) */
template<class T> vector<tuple<int,int,T> > MST(int n,vector<tuple<int,int,T> >g){
    vector<tuple<int,int,T> > ret;
    ret.clear();
    DSU dsu(n);
    auto cmp=[&](tuple<int,int,T> x,tuple<int,int,T> y){
        int ux,uy,vx,vy;
        T wx,wy;
        tie(ux,vx,wx)=x, tie(uy,vy,wy)=y;
        return wx<wy;
    };
    sort(range(g),cmp);
    for (auto c:g){
        int u,v;
        T w;
        tie(u,v,w)=c;
        if(dsu.unite(u,v)) ret.push_back(c);
    }
    return ret;
}

template<int n,class T>
struct SegmentTree{
    typedef struct{
        T lz,mx,mn,sum;
    }Node;
    vector<Node> tree;
    SegmentTree(){
        tree.resize((n+7)<<2);
    }
    void pushup(int num){
        tree[num].mx=max(tree[num<<1].mx,tree[num<<1|1].mx);
        tree[num].mn=min(tree[num<<1].mn,tree[num<<1|1].mn);
        tree[num].sum=tree[num<<1].sum+tree[num<<1|1].sum;
    }
    void pushdown(int num,int l,int r,int md){
        if (tree[num].lz){
            tree[num<<1].mx+=tree[num].lz;
            tree[num<<1|1].mx+=tree[num].lz;
            tree[num<<1].mn+=tree[num].lz;
            tree[num<<1|1].mn+=tree[num].lz;
            tree[num<<1].sum+=tree[num].lz*(md-l+1);
            tree[num<<1|1].sum+=tree[num].lz*(r-md);
            tree[num<<1].lz+=tree[num].lz;
            tree[num<<1|1].lz+=tree[num].lz;
            tree[num].lz=0;
        }
    }
    void update1(int num,int l,int r,int L,int R,T val){
        if (L<=l&&r<=R){
            tree[num].mx+=val;
            tree[num].mn+=val;
            tree[num].sum+=val*(r-l+1);
            tree[num].lz+=val;
            return;
        }
        int md=(l+r)>>1;
        pushdown(num,l,r,md);
        if (md>=L) update1(num<<1,l,md,L,R,val);
        if (md<R) update1(num<<1|1,md+1,r,L,R,val);
        pushup(num);
    }
    tuple<T,T,T> query1(int num,int l,int r,int L,int R){
        if (L<=l&&r<=R){
            return {tree[num].mn,tree[num].mx,tree[num].sum};
        }
        int md=(l+r)>>1;
        pushdown(num,l,r,md);
        if (md>=R){
            return query1(num<<1,l,md,L,R);
        }
        else{
            if (md<L){
                return query1(num<<1|1,md+1,r,L,R);
            }
            else{
                tuple<T,T,T> ret1=query1(num<<1,l,md,L,R), ret2=query1(num<<1|1,md+1,r,L,R);
                T a,b,c,d,e,f;
                tie(a,b,c)=ret1, tie(d,e,f)=ret2;
                return {min(a,d),max(b,e),c+f};
            }
        }
    }
    void update(int L,int R,int w){
        update1(1,1,n,L,R,w);
    }
    tuple<T,T,T> query(int L,int R){
        return query1(1,1,n,L,R);
    }
    void debug1(int num,int l,int r){
        if (l==r){
            cout<<tree[num].mn<<" "; return;
        }
        int md=(l+r)>>1;
        pushdown(num,l,r,md);
        debug1(num<<1,l,md);
         debug1(num<<1|1,md+1,r);
    }
    void debug(){
        debug1(1,1,n);
        cout<<endl;
    }
};

struct XORBasis{
    int n;
    vector<ull> p;
    vector<ull> ans;
    XORBasis(int k):n(k){
        p.resize(k+1);
    }
    void rebuilt(){
        ans.clear();
        for (int i=0;i<=n;++i){
            if (p[i]) ans.push_back(p[i]);
        }
    }
    void insert(ull u){
        for (int i=n;i>=0;--i){
            if (u&(1ull<<i)){
                if (p[i]) u^=p[i];
                else{
                    p[i]=u;
                    for (int j=i-1;j>=0;--j){
                        if (p[i]&(1ull<<j)) p[i]^=p[j];
                    }
                    for (int j=i+1;j<=n;++j){
                        if (p[j]&(1ull<<i)) p[j]^=p[i];
                    }
                    break;
                }
            }
        }
        rebuilt();
    }
    ull kth(ull t){ // the k-th smallest, excluding 0.
        if (t>=(1ull<<sz(ans))) return -1;
        ull ret=0;
        for (int i=0;i<sz(ans);++i){
            if (t&(1ull<<i)) ret^=ans[i];
        }
        return ret;
    }
    ull total(){
        return (1ull<<sz(ans));
    }
};

vi pi(const string& s) {
	vi p(sz(s));
	for (int i=1;i<=sz(s);++i) {
		int g = p[i-1];
		while (g && s[i] != s[g]) g = p[g-1];
		p[i] = g + (s[i] == s[g]);
	}
	return p;
}

vi match(const string& s, const string& pat) {
	vi p = pi(pat + '\0' + s), res;
	for(int i=sz(p)-sz(s);i<=sz(p);++i)
		if (p[i] == sz(pat)) res.push_back(i - 2 * sz(pat));
	return res;
}

struct AhoCorasick {
	enum {alpha = 26, first = 'a'};
	struct Node {
		// (nmatches is optional)
		int back, next[alpha], start = -1, end = -1;
        ll nmatches = 0;
		Node(int v) { memset(next, v, sizeof(next)); }
	};
	vector<Node> N;
	vector<int> backp;
	void insert(string& s, int j,ll val) {
		assert(!s.empty());
		int n = 0;
		for(auto c:s) {
			int& m = N[n].next[c - first];
			if (m == -1) { n = m = sz(N); N.emplace_back(-1); }
			else n = m;
		}
		if (N[n].end == -1) N[n].start = j;
		backp.push_back(N[n].end);
		N[n].end = j;
		N[n].nmatches+=val;
	}
	AhoCorasick(vector<string>& pat,vi val) {
		N.emplace_back(-1);
		for (int i=0;i<sz(pat);++i) insert(pat[i], i, val[i]);
		N[0].back = sz(N);
		N.emplace_back(0);

		queue<int> q;
		for (q.push(0); !q.empty(); q.pop()) {
			int n = q.front(), prev = N[n].back;
			for (int i=0;i<alpha;++i) {
				int &ed = N[n].next[i], y = N[prev].next[i];
				if (ed == -1) ed = y;
				else {
					N[ed].back = y;
					(N[ed].end == -1 ? N[ed].end : backp[N[ed].start])
						= N[y].end;
					N[ed].nmatches += N[y].nmatches;
					q.push(ed);
				}
			}
		}
	}
	vi find(string& word,ll& ans) {
		int n = 0;
		vi res;
		for(auto c:word) {
			n = N[n].next[c - first];
			res.push_back(N[n].end);
			ans += N[n].nmatches;
		}
		return res;
	}
	vector<vi> findAll(vector<string>& pat, string word) {
		ll ans=0;
        vi r = find(word,ans);
		vector<vi> res(sz(word));
		for (int i=0;i<sz(word);++i) {
			int ind = r[i];
			while (ind != -1) {
				res[i - sz(pat[ind]) + 1].push_back(ind);
				ind = backp[ind];
			}
		}
		return res;
	}
};

const int maxn=1007;
int n;
vi val;
vector<string> st;
string s;
ll dp[1007][1<<14],dpt[1007][1<<14],f[1007],g[1007];
int main(){
    cin>>n;
    for (int i=0;i<n;++i){
        string r;
        int t;
        cin>>r>>t;
        st.emplace_back(r), val.emplace_back(t);
    }
    AhoCorasick aca(st,val);
    cin>>s;
    memset(dp,0x80,sizeof(dp));
    dp[0][0]=0;
    for (int j=0;j<sz(aca.N);++j){
        f[j]=j,g[j]=0;
    }
    for (auto c:s){
        if (c=='?'){
            memset(dpt,0x80,sizeof(dpt));
            for (int j=0;j<sz(aca.N);++j){
                for (int k=0;k<(1<<14);++k){
                    if (dp[j][k]<-1e15) continue;
                    for (int r=0;r<14;++r){
                        if (k>>r&1) continue;
                        int to=aca.N[f[j]].next[r], val=g[j]+aca.N[to].nmatches;
                        dpt[to][k^(1<<r)]=max(dpt[to][k^(1<<r)],dp[j][k]+val);
                    }
                }
            }
            for (int j=0;j<sz(aca.N);++j){
                for (int k=0;k<(1<<14);++k){
                    dp[j][k]=dpt[j][k];
                }
            }
            for (int j=0;j<sz(aca.N);++j){
                f[j]=j,g[j]=0;
            }
        }
        else{
            for (int j=0;j<sz(aca.N);++j){
                f[j]=aca.N[f[j]].next[c-'a'], g[j]+=aca.N[f[j]].nmatches;
            }
        }
    }
    ll ans=-1e15;
    for (int j=0;j<sz(aca.N);++j){
        for (int k=0;k<(1<<14);++k){
            if (dp[j][k]<0) continue;
            ans=max(ans,dp[j][k]+g[j]);
        }
    }
    cout<<ans<<endl;
    return 0;
}


#include <bits/stdc++.h>

template <int N, int C> struct AhoCorasick {
  AhoCorasick() : n(1) {
    memset(weight, 0, sizeof(weight));
    memset(go, -1, sizeof(go));
  }

  void insert(const char *s, int w = 1) {
    int p = 0;
    for (int i = 0; s[i]; ++i) {
      int c = s[i] - 'a';
      if (go[p][c] == -1) {
        go[p][c] = n++;
      }
      p = go[p][c];
    }
    weight[p] += w;
  }

  void initialize() {
    std::queue<int> queue;
    for (int c = 0; c < C; ++c) {
      int &v = go[0][c];
      if (~v) {
        queue.push(v);
      }
      (~v ? fail[v] : v) = 0;
    }
    while (!queue.empty()) {
      int u = queue.front();
      queue.pop();
      weight[u] += weight[fail[u]];
      for (int c = 0; c < C; ++c) {
        int &v = go[u][c];
        if (~v) {
          queue.push(v);
        }
        (~v ? fail[v] : v) = go[fail[u]][c];
      }
    }
  }

  int n, weight[N], go[N][C], fail[N];
};

void update(int64_t &x, int64_t a) { x = std::max(x, a); }

const int N = 1001;
const int M = 14;
const int C = 14;
const int64_t MIN = std::numeric_limits<int64_t>::min() / 2;

char s[400001];
AhoCorasick<N, C> ac;
int tgo[C][N], dest[N];
int64_t util[N], dp[1 << M][N];

int main() {
  int n,nn=0;
  scanf("%d", &n);
  while (n--) {
    int w;
    scanf("%s%d", s, &w);
    ac.insert(s, w);
    nn=std::max(nn,(int)strlen(s));
  }
  ac.initialize();
  n = ac.n;
  for (int i = 0; i < n; ++i) {
    for (int c = 0; c < C; ++c) {
      tgo[c][i] = ac.go[i][c];
    }
  }
  scanf("%s", s);
  for (int i = 0; i < n; ++i) {
    dest[i] = i, util[i] = 0;
  }
  for (int mask = 0; mask < 1 << M; ++mask) {
    for (int i = 0; i < n; ++i) {
      dp[mask][i] = MIN;
    }
  }
  dp[0][0] = 0;
  int m = 0, steps = 0, sole_dest = 0;
  int64_t sole_util = 0;
  auto get_dest = [&](int j) { return steps <= nn ? dest[j] : sole_dest; };
  auto get_util = [&](int j) {
    return steps <= nn ? util[j] : util[j] + sole_util;
  };
  for (int _ = 0; s[_]; ++_) {
    if (s[_] == '?') {
      for (int mask = 0; mask < 1 << M; ++mask) {
        if (__builtin_popcount(mask) == m) {
          for (int j = 0; j < n; ++j) {
            if (dp[mask][j] != MIN) {
              for (int i = 0; i < M; ++i) {
                if (~mask >> i & 1) {
                  int v = ac.go[get_dest(j)][i];
                  update(dp[mask | 1 << i][v],
                         dp[mask][j] + get_util(j) + ac.weight[v]);
                }
              }
            }
          }
        }
      }
      steps = 0;
      for (int i = 0; i < n; ++i) {
        dest[i] = i, util[i] = 0;
      }
      m++;
    } else {
      int c = s[_] - 'a';
      ++steps;
      if (steps <= nn) {
        for (int i = 0; i < n; ++i) {
          util[i] += ac.weight[dest[i] = tgo[c][dest[i]]];
        }
      } else {
        if (steps == nn + 1) {
          sole_dest = dest[0], sole_util = 0;
        }
        sole_util += ac.weight[sole_dest = tgo[c][sole_dest]];
      }
    }
  }
  int64_t result = MIN;
  for (int mask = 0; mask < 1 << M; ++mask) {
    if (__builtin_popcount(mask) == m) {
      for (int j = 0; j < n; ++j) {
        update(result, dp[mask][j] + get_util(j));
      }
    }
  }
  std::cout << result << std::endl;
}


//#pragma GCC optimize("Ofast")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
//#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
using namespace std;

#define rep(i,n) for (int i=0;i<(int)(n);++i)
#define rep1(i,n) for (int i=1;i<=(int)(n);++i)
#define range(x) begin(x), end(x)
#define sz(x) (int)(x).size()
#define pb push_back
#define F first
#define S second

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pii;
typedef vector<int> vi;
/*
计算u^v % mod
*/
ll power(ll u,ll v,ll mod){
    ll ret=1,t=u%mod;
    while (v){
        if (v&1) ret=t*ret%mod;
        t=t*t%mod, v>>=1;
    }
    return ret%mod;
}

/*
计算gcd(a,b)并找寻ax+by=gcd(a,b)的一组解
ret=exgcd(a,b,x,y);
*/
ll exgcd(ll a,ll b,ll &x,ll &y){
    if (b){
        ll d=exgcd(b,a%b,y,x);
        return y-=a/b*x, d;
    }
    return x=1,y=0,a;
}

/*
计算x=a(mod m), x=b(mod n)的一组解，若无解返回-1
ret=crt(a,m,b,n);
*/
ll crt(ll a,ll m,ll b,ll n){
    if (n>m) swap(a,b), swap(n,m);
    ll x,y,g=exgcd(m,n,x,y);
    if ((b-a)%g) return -1;
    x=(b-a)%n*x%n/g*m+a;
    return x<0?x+m*n/g:x;
}

/*
生成<=n的质数
gen_prime<5000>(ret);
*/

void gen_prime(int n,vi &ret){
    vector<bool> p;
    p.resize(n+1,1);
    p[0]=p[1]=0;
    for (int i=4;i<=n;i+=2) p[i]=0;
    for (int i=3;i*i<=n;i+=2){
        if (p[i]){
            for (int j=i*i;j<=n;j+=2*i){
                p[j]=0;
            }
        }
    }
    for (int i=2;i<=n;++i){
        if (p[i]) ret.pb(i);
    }
}

/*
生成<=n的phi
gen_phi<5000>(ret);
*/
void gen_phi(int n,vi &phi){
    phi.resize(n+1);
    for (int i=0;i<=n;++i) phi[i]=i&1?i:i/2;
    for (int i=3;i<=n;i+=2){
        if (phi[i]==i){
            for (int j=i;j<=n;j+=i) phi[j]-=phi[j]/i;
        }
    }
}

/*
支持更高的快速幂操作
expower.mod_pow(a,b,mod);
*/

struct expower{
    ull mod_mul(ull a,ull b,ull M) {
        ll ret=a*b-M*ull(ld(a)* ld(b)/ld(M));
        return ret+M*(ret<0)-M*(ret>=(ll)M);
    }
    ull mod_pow(ull b,ull e,ull mod) {
        ull ans=1;
        for (; e; b=mod_mul(b,b,mod), e/=2)
            if (e&1) ans=mod_mul(ans,b,mod);
        return ans%mod;
    }
}expower;

/*
Miller-Rubin素数判别
is_prime(n);
*/
bool is_prime(ull n){
    if (n<2||n%6%4!=1) return n-2<2;
    ull A[]={2,325,9375,28178,450775,9780504,1795265022},
    s=__builtin_ctzll(n-1), d = n >> s;
    for (auto a:A){
        ull p=expower.mod_pow(a,d,n),i=s;
        while (p!=1&&p!=n-1&&a%n&&i--)
            p=expower.mod_mul(p,p,n);
        if (p!=n-1&&i!=s) return 0;
    }
    return 1;
}

/*
素因数分解
ret=factorization(n);
*/
ull pollard(ull n){
    auto f=[n](ull x){return (expower.mod_mul(x,x,n)+1)%n;};
    if (!(n&1)) return 2;
    for (ull i=2;;i++){
        ull x=i,y=f(x),p;
        while ((p=__gcd(n+y-x,n))==1)
            x=f(x),y=f(f(y));
        if (p!=n) return p;
    }
}

vector<ull> factorization(ull n){
    if (n==1) return {};
    if (is_prime(n)) return {n};
    ull x=pollard(n);
    auto l=factorization(x),r=factorization(n/x);
    l.insert(l.end(),range(r));
    return l;
}

struct DSU{
    //insert info.
    vector<int> p;
    DSU(int n){
        p.resize(n+1);
        for (int i=1;i<=n;++i) p[i]=i;
    }
    int find(int u){
        if (p[u]==u) return u;
        return p[u]=find(find(p[u]));
    }
    bool unite(int u,int v){
        int pu=find(u), pv=find(v);
        if (pu!=pv){
            p[pu]=pv;
        }
        return pu!=pv;
    }
};

/* (u,v,w) */
template<class T> vector<tuple<int,int,T> > MST(int n,vector<tuple<int,int,T> >g){
    vector<tuple<int,int,T> > ret;
    ret.clear();
    DSU dsu(n);
    auto cmp=[&](tuple<int,int,T> x,tuple<int,int,T> y){
        int ux,uy,vx,vy;
        T wx,wy;
        tie(ux,vx,wx)=x, tie(uy,vy,wy)=y;
        return wx<wy;
    };
    sort(range(g),cmp);
    for (auto c:g){
        int u,v;
        T w;
        tie(u,v,w)=c;
        if(dsu.unite(u,v)) ret.push_back(c);
    }
    return ret;
}

template<int n,class T>
struct SegmentTree{
    typedef struct{
        T lz,mx,mn,sum;
    }Node;
    vector<Node> tree;
    SegmentTree(){
        tree.resize((n+7)<<2);
    }
    void pushup(int num){
        tree[num].mx=max(tree[num<<1].mx,tree[num<<1|1].mx);
        tree[num].mn=min(tree[num<<1].mn,tree[num<<1|1].mn);
        tree[num].sum=tree[num<<1].sum+tree[num<<1|1].sum;
    }
    void pushdown(int num,int l,int r,int md){
        if (tree[num].lz){
            tree[num<<1].mx+=tree[num].lz;
            tree[num<<1|1].mx+=tree[num].lz;
            tree[num<<1].mn+=tree[num].lz;
            tree[num<<1|1].mn+=tree[num].lz;
            tree[num<<1].sum+=tree[num].lz*(md-l+1);
            tree[num<<1|1].sum+=tree[num].lz*(r-md);
            tree[num<<1].lz+=tree[num].lz;
            tree[num<<1|1].lz+=tree[num].lz;
            tree[num].lz=0;
        }
    }
    void update1(int num,int l,int r,int L,int R,T val){
        if (L<=l&&r<=R){
            tree[num].mx+=val;
            tree[num].mn+=val;
            tree[num].sum+=val*(r-l+1);
            tree[num].lz+=val;
            return;
        }
        int md=(l+r)>>1;
        pushdown(num,l,r,md);
        if (md>=L) update1(num<<1,l,md,L,R,val);
        if (md<R) update1(num<<1|1,md+1,r,L,R,val);
        pushup(num);
    }
    tuple<T,T,T> query1(int num,int l,int r,int L,int R){
        if (L<=l&&r<=R){
            return {tree[num].mn,tree[num].mx,tree[num].sum};
        }
        int md=(l+r)>>1;
        pushdown(num,l,r,md);
        if (md>=R){
            return query1(num<<1,l,md,L,R);
        }
        else{
            if (md<L){
                return query1(num<<1|1,md+1,r,L,R);
            }
            else{
                tuple<T,T,T> ret1=query1(num<<1,l,md,L,R), ret2=query1(num<<1|1,md+1,r,L,R);
                T a,b,c,d,e,f;
                tie(a,b,c)=ret1, tie(d,e,f)=ret2;
                return {min(a,d),max(b,e),c+f};
            }
        }
    }
    void update(int L,int R,int w){
        update1(1,1,n,L,R,w);
    }
    tuple<T,T,T> query(int L,int R){
        return query1(1,1,n,L,R);
    }
    void debug1(int num,int l,int r){
        if (l==r){
            cout<<tree[num].mn<<" "; return;
        }
        int md=(l+r)>>1;
        pushdown(num,l,r,md);
        debug1(num<<1,l,md);
         debug1(num<<1|1,md+1,r);
    }
    void debug(){
        debug1(1,1,n);
        cout<<endl;
    }
};

struct XORBasis{
    int n;
    vector<ull> p;
    vector<ull> ans;
    XORBasis(int k):n(k){
        p.resize(k+1);
    }
    void rebuilt(){
        ans.clear();
        for (int i=0;i<=n;++i){
            if (p[i]) ans.push_back(p[i]);
        }
    }
    void insert(ull u){
        for (int i=n;i>=0;--i){
            if (u&(1ull<<i)){
                if (p[i]) u^=p[i];
                else{
                    p[i]=u;
                    for (int j=i-1;j>=0;--j){
                        if (p[i]&(1ull<<j)) p[i]^=p[j];
                    }
                    for (int j=i+1;j<=n;++j){
                        if (p[j]&(1ull<<i)) p[j]^=p[i];
                    }
                    break;
                }
            }
        }
        rebuilt();
    }
    ull kth(ull t){ // the k-th smallest, excluding 0.
        if (t>=(1ull<<sz(ans))) return -1;
        ull ret=0;
        for (int i=0;i<sz(ans);++i){
            if (t&(1ull<<i)) ret^=ans[i];
        }
        return ret;
    }
    ull total(){
        return (1ull<<sz(ans));
    }
};

vi pi(const string& s) {
	vi p(sz(s));
	for (int i=1;i<=sz(s);++i) {
		int g = p[i-1];
		while (g && s[i] != s[g]) g = p[g-1];
		p[i] = g + (s[i] == s[g]);
	}
	return p;
}

vi match(const string& s, const string& pat) {
	vi p = pi(pat + '\0' + s), res;
	for(int i=sz(p)-sz(s);i<=sz(p);++i)
		if (p[i] == sz(pat)) res.push_back(i - 2 * sz(pat));
	return res;
}

struct AhoCorasick {
	enum {alpha = 26, first = 'a'};
	struct Node {
		// (nmatches is optional)
		int back, next[alpha], start = -1, end = -1;
        ll nmatches = 0;
		Node(int v) { memset(next, v, sizeof(next)); }
	};
	vector<Node> N;
	vector<int> backp;
	void insert(string& s, int j,ll val) {
		assert(!s.empty());
		int n = 0;
		for(auto c:s) {
			int& m = N[n].next[c - first];
			if (m == -1) { n = m = sz(N); N.emplace_back(-1); }
			else n = m;
		}
		if (N[n].end == -1) N[n].start = j;
		backp.push_back(N[n].end);
		N[n].end = j;
		N[n].nmatches+=val;
	}
	AhoCorasick(vector<string>& pat,vi val) {
		N.emplace_back(-1);
		for (int i=0;i<sz(pat);++i) insert(pat[i], i, val[i]);
		N[0].back = sz(N);
		N.emplace_back(0);

		queue<int> q;
		for (q.push(0); !q.empty(); q.pop()) {
			int n = q.front(), prev = N[n].back;
			for (int i=0;i<alpha;++i) {
				int &ed = N[n].next[i], y = N[prev].next[i];
				if (ed == -1) ed = y;
				else {
					N[ed].back = y;
					(N[ed].end == -1 ? N[ed].end : backp[N[ed].start])
						= N[y].end;
					N[ed].nmatches += N[y].nmatches;
					q.push(ed);
				}
			}
		}
	}
	vi find(string& word,ll& ans) {
		int n = 0;
		vi res;
		for(auto c:word) {
			n = N[n].next[c - first];
			res.push_back(N[n].end);
			ans += N[n].nmatches;
		}
		return res;
	}
	vector<vi> findAll(vector<string>& pat, string word) {
		ll ans=0;
        vi r = find(word,ans);
		vector<vi> res(sz(word));
		for (int i=0;i<sz(word);++i) {
			int ind = r[i];
			while (ind != -1) {
				res[i - sz(pat[ind]) + 1].push_back(ind);
				ind = backp[ind];
			}
		}
		return res;
	}
};

const int maxn=1007;
int n;
vi val;
vector<string> st;
string s;
ll dp[1007][1<<14],dpt[1007][1<<14],f[1007],g[1007];
int main(){
    cin>>n;
    for (int i=0;i<n;++i){
        string r;
        int t;
        cin>>r>>t;
        st.emplace_back(r), val.emplace_back(t);
    }
    AhoCorasick aca(st,val);
    cin>>s;
    memset(dp,0x80,sizeof(dp));
    dp[0][0]=0;
    for (int j=0;j<sz(aca.N);++j){
        f[j]=j,g[j]=0;
    }
    for (auto c:s){
        if (c=='?'){
            memset(dpt,0x80,sizeof(dpt));
            for (int j=0;j<sz(aca.N);++j){
                for (int k=0;k<(1<<14);++k){
                    if (dp[j][k]<-1e15) continue;
                    for (int r=0;r<14;++r){
                        if (k>>r&1) continue;
                        int to=aca.N[f[j]].next[r], val=g[j]+aca.N[to].nmatches;
                        dpt[to][k^(1<<r)]=max(dpt[to][k^(1<<r)],dp[j][k]+val);
                    }
                }
            }
            for (int j=0;j<sz(aca.N);++j){
                for (int k=0;k<(1<<14);++k){
                    dp[j][k]=dpt[j][k];
                }
            }
            for (int j=0;j<sz(aca.N);++j){
                f[j]=j,g[j]=0;
            }
        }
        else{
            for (int j=0;j<sz(aca.N);++j){
                f[j]=aca.N[f[j]].next[c-'a'], g[j]+=aca.N[f[j]].nmatches;
            }
        }
    }
    ll ans=0;
    for (int j=0;j<sz(aca.N);++j){
        for (int k=0;k<(1<<14);++k){
            if (dp[j][k]<0) continue;
            ans=max(ans,dp[j][k]+g[j]);
        }
    }
    cout<<ans<<endl;
    return 0;
}


//#pragma GCC optimize("Ofast")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
//#pragma GCC optimize("unroll-loops")
#include<bits/stdc++.h>
#define int long long
using namespace std;

#define rep(i,n) for (int i=0;i<(int)(n);++i)
#define rep1(i,n) for (int i=1;i<=(int)(n);++i)
#define range(x) begin(x), end(x)
#define sz(x) (int)(x).size()
#define pb push_back
#define F first
#define S second

typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pii;
typedef vector<int> vi;
/*
计算u^v % mod
*/
ll power(ll u,ll v,ll mod){
    ll ret=1,t=u%mod;
    while (v){
        if (v&1) ret=t*ret%mod;
        t=t*t%mod, v>>=1;
    }
    return ret%mod;
}

/*
计算gcd(a,b)并找寻ax+by=gcd(a,b)的一组解
ret=exgcd(a,b,x,y);
*/
ll exgcd(ll a,ll b,ll &x,ll &y){
    if (b){
        ll d=exgcd(b,a%b,y,x);
        return y-=a/b*x, d;
    }
    return x=1,y=0,a;
}

/*
计算x=a(mod m), x=b(mod n)的一组解，若无解返回-1
ret=crt(a,m,b,n);
*/
ll crt(ll a,ll m,ll b,ll n){
    if (n>m) swap(a,b), swap(n,m);
    ll x,y,g=exgcd(m,n,x,y);
    if ((b-a)%g) return -1;
    x=(b-a)%n*x%n/g*m+a;
    return x<0?x+m*n/g:x;
}

/*
生成<=n的质数
gen_prime<5000>(ret);
*/

void gen_prime(int n,vi &ret){
    vector<bool> p;
    p.resize(n+1,1);
    p[0]=p[1]=0;
    for (int i=4;i<=n;i+=2) p[i]=0;
    for (int i=3;i*i<=n;i+=2){
        if (p[i]){
            for (int j=i*i;j<=n;j+=2*i){
                p[j]=0;
            }
        }
    }
    for (int i=2;i<=n;++i){
        if (p[i]) ret.pb(i);
    }
}

/*
生成<=n的phi
gen_phi<5000>(ret);
*/
void gen_phi(int n,vi &phi){
    phi.resize(n+1);
    for (int i=0;i<=n;++i) phi[i]=i&1?i:i/2;
    for (int i=3;i<=n;i+=2){
        if (phi[i]==i){
            for (int j=i;j<=n;j+=i) phi[j]-=phi[j]/i;
        }
    }
}

/*
支持更高的快速幂操作
expower.mod_pow(a,b,mod);
*/

struct expower{
    ull mod_mul(ull a,ull b,ull M) {
        ll ret=a*b-M*ull(ld(a)* ld(b)/ld(M));
        return ret+M*(ret<0)-M*(ret>=(ll)M);
    }
    ull mod_pow(ull b,ull e,ull mod) {
        ull ans=1;
        for (; e; b=mod_mul(b,b,mod), e/=2)
            if (e&1) ans=mod_mul(ans,b,mod);
        return ans%mod;
    }
}expower;

/*
Miller-Rubin素数判别
is_prime(n);
*/
bool is_prime(ull n){
    if (n<2||n%6%4!=1) return n-2<2;
    ull A[]={2,325,9375,28178,450775,9780504,1795265022},
    s=__builtin_ctzll(n-1), d = n >> s;
    for (auto a:A){
        ull p=expower.mod_pow(a,d,n),i=s;
        while (p!=1&&p!=n-1&&a%n&&i--)
            p=expower.mod_mul(p,p,n);
        if (p!=n-1&&i!=s) return 0;
    }
    return 1;
}

/*
素因数分解
ret=factorization(n);
*/
ull pollard(ull n){
    auto f=[n](ull x){return (expower.mod_mul(x,x,n)+1)%n;};
    if (!(n&1)) return 2;
    for (ull i=2;;i++){
        ull x=i,y=f(x),p;
        while ((p=__gcd(n+y-x,n))==1)
            x=f(x),y=f(f(y));
        if (p!=n) return p;
    }
}

vector<ull> factorization(ull n){
    if (n==1) return {};
    if (is_prime(n)) return {n};
    ull x=pollard(n);
    auto l=factorization(x),r=factorization(n/x);
    l.insert(l.end(),range(r));
    return l;
}

struct DSU{
    //insert info.
    vector<int> p;
    DSU(int n){
        p.resize(n+1);
        for (int i=1;i<=n;++i) p[i]=i;
    }
    int find(int u){
        if (p[u]==u) return u;
        return p[u]=find(find(p[u]));
    }
    bool unite(int u,int v){
        int pu=find(u), pv=find(v);
        if (pu!=pv){
            p[pu]=pv;
        }
        return pu!=pv;
    }
};

/* (u,v,w) */
template<class T> vector<tuple<int,int,T> > MST(int n,vector<tuple<int,int,T> >g){
    vector<tuple<int,int,T> > ret;
    ret.clear();
    DSU dsu(n);
    auto cmp=[&](tuple<int,int,T> x,tuple<int,int,T> y){
        int ux,uy,vx,vy;
        T wx,wy;
        tie(ux,vx,wx)=x, tie(uy,vy,wy)=y;
        return wx<wy;
    };
    sort(range(g),cmp);
    for (auto c:g){
        int u,v;
        T w;
        tie(u,v,w)=c;
        if(dsu.unite(u,v)) ret.push_back(c);
    }
    return ret;
}

template<int n,class T>
struct SegmentTree{
    typedef struct{
        T lz,mx,mn,sum;
    }Node;
    vector<Node> tree;
    SegmentTree(){
        tree.resize((n+7)<<2);
    }
    void pushup(int num){
        tree[num].mx=max(tree[num<<1].mx,tree[num<<1|1].mx);
        tree[num].mn=min(tree[num<<1].mn,tree[num<<1|1].mn);
        tree[num].sum=tree[num<<1].sum+tree[num<<1|1].sum;
    }
    void pushdown(int num,int l,int r,int md){
        if (tree[num].lz){
            tree[num<<1].mx+=tree[num].lz;
            tree[num<<1|1].mx+=tree[num].lz;
            tree[num<<1].mn+=tree[num].lz;
            tree[num<<1|1].mn+=tree[num].lz;
            tree[num<<1].sum+=tree[num].lz*(md-l+1);
            tree[num<<1|1].sum+=tree[num].lz*(r-md);
            tree[num<<1].lz+=tree[num].lz;
            tree[num<<1|1].lz+=tree[num].lz;
            tree[num].lz=0;
        }
    }
    void update1(int num,int l,int r,int L,int R,T val){
        if (L<=l&&r<=R){
            tree[num].mx+=val;
            tree[num].mn+=val;
            tree[num].sum+=val*(r-l+1);
            tree[num].lz+=val;
            return;
        }
        int md=(l+r)>>1;
        pushdown(num,l,r,md);
        if (md>=L) update1(num<<1,l,md,L,R,val);
        if (md<R) update1(num<<1|1,md+1,r,L,R,val);
        pushup(num);
    }
    tuple<T,T,T> query1(int num,int l,int r,int L,int R){
        if (L<=l&&r<=R){
            return {tree[num].mn,tree[num].mx,tree[num].sum};
        }
        int md=(l+r)>>1;
        pushdown(num,l,r,md);
        if (md>=R){
            return query1(num<<1,l,md,L,R);
        }
        else{
            if (md<L){
                return query1(num<<1|1,md+1,r,L,R);
            }
            else{
                tuple<T,T,T> ret1=query1(num<<1,l,md,L,R), ret2=query1(num<<1|1,md+1,r,L,R);
                T a,b,c,d,e,f;
                tie(a,b,c)=ret1, tie(d,e,f)=ret2;
                return {min(a,d),max(b,e),c+f};
            }
        }
    }
    void update(int L,int R,int w){
        update1(1,1,n,L,R,w);
    }
    tuple<T,T,T> query(int L,int R){
        return query1(1,1,n,L,R);
    }
    void debug1(int num,int l,int r){
        if (l==r){
            cout<<tree[num].mn<<" "; return;
        }
        int md=(l+r)>>1;
        pushdown(num,l,r,md);
        debug1(num<<1,l,md);
         debug1(num<<1|1,md+1,r);
    }
    void debug(){
        debug1(1,1,n);
        cout<<endl;
    }
};

struct XORBasis{
    int n;
    vector<ull> p;
    vector<ull> ans;
    XORBasis(int k):n(k){
        p.resize(k+1);
    }
    void rebuilt(){
        ans.clear();
        for (int i=0;i<=n;++i){
            if (p[i]) ans.push_back(p[i]);
        }
    }
    void insert(ull u){
        for (int i=n;i>=0;--i){
            if (u&(1ull<<i)){
                if (p[i]) u^=p[i];
                else{
                    p[i]=u;
                    for (int j=i-1;j>=0;--j){
                        if (p[i]&(1ull<<j)) p[i]^=p[j];
                    }
                    for (int j=i+1;j<=n;++j){
                        if (p[j]&(1ull<<i)) p[j]^=p[i];
                    }
                    break;
                }
            }
        }
        rebuilt();
    }
    ull kth(ull t){ // the k-th smallest, excluding 0.
        if (t>=(1ull<<sz(ans))) return -1;
        ull ret=0;
        for (int i=0;i<sz(ans);++i){
            if (t&(1ull<<i)) ret^=ans[i];
        }
        return ret;
    }
    ull total(){
        return (1ull<<sz(ans));
    }
};

vi pi(const string& s) {
	vi p(sz(s));
	for (int i=1;i<=sz(s);++i) {
		int g = p[i-1];
		while (g && s[i] != s[g]) g = p[g-1];
		p[i] = g + (s[i] == s[g]);
	}
	return p;
}

vi match(const string& s, const string& pat) {
	vi p = pi(pat + '\0' + s), res;
	for(int i=sz(p)-sz(s);i<=sz(p);++i)
		if (p[i] == sz(pat)) res.push_back(i - 2 * sz(pat));
	return res;
}

struct AhoCorasick {
	enum {alpha = 26, first = 'a'};
	struct Node {
		// (nmatches is optional)
		int back, next[alpha], start = -1, end = -1;
        ll nmatches = 0;
		Node(int v) { memset(next, v, sizeof(next)); }
	};
	vector<Node> N;
	vector<int> backp;
	void insert(string& s, int j,ll val) {
		assert(!s.empty());
		int n = 0;
		for(auto c:s) {
			int& m = N[n].next[c - first];
			if (m == -1) { n = m = sz(N); N.emplace_back(-1); }
			else n = m;
		}
		if (N[n].end == -1) N[n].start = j;
		backp.push_back(N[n].end);
		N[n].end = j;
		N[n].nmatches+=val;
	}
	AhoCorasick(vector<string>& pat,vi val) {
		N.emplace_back(-1);
		for (int i=0;i<sz(pat);++i) insert(pat[i], i, val[i]);
		N[0].back = sz(N);
		N.emplace_back(0);

		queue<int> q;
		for (q.push(0); !q.empty(); q.pop()) {
			int n = q.front(), prev = N[n].back;
			for (int i=0;i<alpha;++i) {
				int &ed = N[n].next[i], y = N[prev].next[i];
				if (ed == -1) ed = y;
				else {
					N[ed].back = y;
					(N[ed].end == -1 ? N[ed].end : backp[N[ed].start])
						= N[y].end;
					N[ed].nmatches += N[y].nmatches;
					q.push(ed);
				}
			}
		}
	}
	vi find(string& word,ll& ans) {
		int n = 0;
		vi res;
		for(auto c:word) {
			n = N[n].next[c - first];
			res.push_back(N[n].end);
			ans += N[n].nmatches;
		}
		return res;
	}
	vector<vi> findAll(vector<string>& pat, string word) {
		ll ans=0;
        vi r = find(word,ans);
		vector<vi> res(sz(word));
		for (int i=0;i<sz(word);++i) {
			int ind = r[i];
			while (ind != -1) {
				res[i - sz(pat[ind]) + 1].push_back(ind);
				ind = backp[ind];
			}
		}
		return res;
	}
};

const int maxn=1007;
int n;
vi val;
vector<string> st;
string s;
ll dp[1007][1<<14],dpt[1007][1<<14],f[1007],g[1007];
signed main(){
    cin>>n;
    for (int i=0;i<n;++i){
        string r;
        int t;
        cin>>r>>t;
        st.emplace_back(r), val.emplace_back(t);
    }
    AhoCorasick aca(st,val);
    cin>>s;
    memset(dp,0x80,sizeof(dp));
    dp[0][0]=0;
    for (int j=0;j<sz(aca.N);++j){
        f[j]=j,g[j]=0;
    }
    for (auto c:s){
        if (c=='?'){
            memset(dpt,0x80,sizeof(dpt));
            for (int j=0;j<sz(aca.N);++j){
                for (int k=0;k<(1<<14);++k){
                    if (dp[j][k]<-1e15) continue;
                    for (int r=0;r<14;++r){
                        if (k>>r&1) continue;
                        int to=aca.N[f[j]].next[r], val=g[j]+aca.N[to].nmatches;
                        dpt[to][k^(1<<r)]=max(dpt[to][k^(1<<r)],dp[j][k]+val);
                    }
                }
            }
            for (int j=0;j<sz(aca.N);++j){
                for (int k=0;k<(1<<14);++k){
                    dp[j][k]=dpt[j][k];
                }
            }
            for (int j=0;j<sz(aca.N);++j){
                f[j]=j,g[j]=0;
            }
        }
        else{
            for (int j=0;j<sz(aca.N);++j){
                f[j]=aca.N[f[j]].next[c-'a'], g[j]+=aca.N[f[j]].nmatches;
            }
        }
    }
    ll ans=-1e15;
    for (int j=0;j<sz(aca.N);++j){
        for (int k=0;k<(1<<14);++k){
            ans=max(ans,dp[j][k]+g[j]);
        }
    }
    cout<<ans<<endl;
    return 0;
}