#include <bits/stdc++.h>
using namespace std;
std::mt19937 rnd(
    (int)std::chrono::steady_clock::now().time_since_epoch().count());
long long gcd(long long a, long long b) { return b == 0 ? a : gcd(b, a % b); }
const int MAXPATTERN = 1000;
const int MAXSUMPATTERNLEN = 1000;
const int MAXTRIE = MAXSUMPATTERNLEN + 1;
const int ALPH = 14;
const int MAXSLEN = 400000;
struct TrieNode {
  int nxt[ALPH];
  int safenxt[ALPH];
  int val, sumval;
  int suff;
};
int npattern;
string pattern[MAXPATTERN];
int patternval[MAXPATTERN];
string s;
TrieNode trie[MAXTRIE];
int ntrie, trieroot;
int maketrie() {
  assert(ntrie < MAXTRIE);
  int ret = ntrie++;
  for (int i = (0); i < (ALPH); ++i)
    trie[ret].nxt[i] = trie[ret].safenxt[i] = -1;
  trie[ret].val = trie[ret].sumval = 0;
  trie[ret].suff = -1;
  return ret;
}
void buildtrie() {
  ntrie = 0;
  trieroot = maketrie();
  for (int i = (0); i < (npattern); ++i) {
    int at = trieroot;
    for (int j = (0); j < (((int)(pattern[i]).size())); ++j) {
      int x = pattern[i][j] - 'a';
      assert(0 <= x && x < ALPH);
      int to = trie[at].nxt[x];
      if (to == -1) {
        to = maketrie();
        trie[at].nxt[x] = to;
      }
      at = to;
    }
    trie[at].val += patternval[i];
  }
  queue<int> q;
  q.push(trieroot);
  while (!q.empty()) {
    int at = q.front();
    q.pop();
    for (int k = (0); k < (ALPH); ++k) {
      int suff;
      if (at == trieroot) {
        suff = at;
      } else {
        suff = trie[at].suff;
        while (suff != trieroot && trie[suff].nxt[k] == -1)
          suff = trie[suff].suff;
        if (trie[suff].nxt[k] != -1) suff = trie[suff].nxt[k];
      }
      int to = trie[at].nxt[k];
      trie[at].safenxt[k] = to == -1 ? suff : to;
      if (to != -1) {
        trie[to].suff = suff;
        trie[to].sumval = trie[to].val + trie[suff].sumval;
        q.push(to);
      }
    }
  }
}
long long dp[1 << ALPH][MAXTRIE];
long long ndp[1 << ALPH][MAXTRIE];
void upd(long long& a, long long b) { a = max(a, b); }
char t[MAXSLEN + 1];
int tlen;
pair<int, long long> trans[MAXTRIE];
void calctrans() {
  int separate = min(tlen, ntrie);
  for (int s = (0); s < (ntrie); ++s) {
    int at = s;
    long long sum = 0;
    for (int i = (0); i < (separate); ++i) {
      int k = t[i] - 'a';
      at = trie[at].safenxt[k];
      sum += trie[at].sumval;
    }
    trans[s] = make_pair(at, sum);
  }
  if (tlen > separate) {
    int at = trans[0].first;
    long long sum = 0;
    for (int s = (0); s < (ntrie); ++s) assert(trans[s].first == at);
    for (int i = (separate); i < (tlen); ++i) {
      int k = t[i] - 'a';
      at = trie[at].safenxt[k];
      sum += trie[at].sumval;
    }
    for (int s = (0); s < (ntrie); ++s)
      trans[s] = make_pair(at, trans[s].second + sum);
  }
}
long long solve() {
  buildtrie();
  for (int mask = (0); mask < (1 << ALPH); ++mask)
    for (int at = (0); at < (ntrie); ++at) dp[mask][at] = LLONG_MIN;
  dp[0][trieroot] = 0;
  int pos = 0;
  while (pos < ((int)(s).size())) {
    for (int mask = (0); mask < (1 << ALPH); ++mask)
      for (int at = (0); at < (ntrie); ++at) ndp[mask][at] = LLONG_MIN;
    if (s[pos] == '?') {
      for (int mask = (0); mask < (1 << ALPH); ++mask)
        for (int at = (0); at < (ntrie); ++at)
          if (dp[mask][at] != LLONG_MIN)
            for (int k = (0); k < (ALPH); ++k)
              if ((mask & (1 << k)) == 0) {
                int nmask = mask | (1 << k), to = trie[at].safenxt[k];
                long long nval = dp[mask][at] + trie[to].sumval;
                upd(ndp[nmask][to], nval);
              }
      ++pos;
    } else {
      tlen = 0;
      while (pos < ((int)(s).size()) && s[pos] != '?') t[tlen++] = s[pos++];
      calctrans();
      for (int mask = (0); mask < (1 << ALPH); ++mask)
        for (int at = (0); at < (ntrie); ++at)
          if (dp[mask][at] != LLONG_MIN) {
            int nmask = mask, to = trans[at].first;
            long long nval = dp[mask][at] + trans[at].second;
            upd(ndp[nmask][to], nval);
          }
    }
    for (int mask = (0); mask < (1 << ALPH); ++mask)
      for (int at = (0); at < (ntrie); ++at) dp[mask][at] = ndp[mask][at];
  }
  long long ret = LLONG_MIN;
  for (int mask = (0); mask < (1 << ALPH); ++mask)
    for (int at = (0); at < (ntrie); ++at)
      if (dp[mask][at] != LLONG_MIN) upd(ret, dp[mask][at]);
  return ret;
}
void run() {
  scanf("%d", &npattern);
  for (int i = (0); i < (npattern); ++i) cin >> pattern[i] >> patternval[i];
  cin >> s;
  printf("%lld\n", solve());
}
int main() {
  run();
  return 0;
}
