#include <bits/stdc++.h>
using namespace std;
const int MAXL = 15;
const int MAXQ = 15;
const int MAXS = 1010;
const int EXP = 1024 * 16 + 10;
const long long int INF = 1000000000000000000LL;
class AhoCorasick {
 public:
  int toNumber(char a) {
    if ('a' <= a && a <= 'z') return a - 'a';
    if ('A' <= a && a <= 'Z') return 26 + a - 'A';
    return 26 + 26 + a - '0';
  }
  void addString(string& s, int cost) {
    int curState = 0;
    for (int i = 0; i < s.size(); i++) {
      int c = toNumber(s[i]);
      if (t[curState].next[c] == -1) {
        t[curState].next[c] = t.size();
        t.push_back(node(curState, s[i]));
      }
      curState = t[curState].next[c];
    }
    t[curState].sumCost += cost;
  }
  int qtdStates() { return t.size(); }
  int getSuffixLink(int curState) {
    int& link = t[curState].link;
    if (link == -1) {
      if (curState == 0 || t[curState].p == 0)
        link = 0;
      else {
        char c = t[curState].pc;
        int nextState = getSuffixLink(t[curState].p);
        link = go(nextState, c);
      }
    }
    return link;
  }
  int go(int curState, char ch) {
    int c = toNumber(ch);
    int& nextState = t[curState].go[c];
    if (nextState == -1) {
      if (t[curState].next[c] != -1)
        nextState = t[curState].next[c];
      else if (curState == 0)
        nextState = 0;
      else
        nextState = go(getSuffixLink(curState), ch);
    }
    return nextState;
  }
  long long int cost(int curState) {
    if (!t[curState].isCalculated) {
      if (curState != 0) t[curState].sumCost += cost(getSuffixLink(curState));
      t[curState].isCalculated = true;
    }
    return t[curState].sumCost;
  }
  void getNewState(string& s, int& initialState, long long int& sumCost) {
    for (int i = 0; i < s.size(); i++) {
      sumCost += cost(initialState);
      initialState = go(initialState, s[i]);
    }
    sumCost += cost(initialState);
  }
  AhoCorasick() { t.push_back(node()); }

 private:
  struct node {
    int p;
    int link;
    char pc;
    int go[MAXL];
    int next[MAXL];
    long long int sumCost;
    bool isCalculated;
    node(int p = -1, char c = '$')
        : p(p), pc(c), link(-1), sumCost(0), isCalculated(false) {
      memset(go, -1, sizeof(go));
      memset(next, -1, sizeof(next));
    }
  };
  vector<node> t;
};
int n;
string s;
int jump[MAXQ][MAXS];
long long int dp[MAXS][EXP];
long long int sumCost[MAXQ][MAXS];
vector<int> posMark;
AhoCorasick Aho;
int main() {
  cin >> n;
  for (int i = 1; i <= n; i++) {
    string t;
    int c;
    cin >> t >> c;
    Aho.addString(t, c);
  }
  cin >> s;
  s.push_back('?');
  for (int i = 0; i < s.size() - 1; i++) {
    if (s[i] != '?') continue;
    int ind = posMark.size();
    posMark.push_back(i);
    int L = i + 1;
    int R = i + 1;
    while (R < s.size() && s[R] != '?') R++;
    string curSubstring = s.substr(L, R - L);
    for (int j = 0; j < Aho.qtdStates(); j++) {
      jump[ind][j] = j;
      Aho.getNewState(curSubstring, jump[ind][j], sumCost[ind][j]);
    }
  }
  int state = 0;
  long long int sum = Aho.cost(0);
  for (int i = 0; i < s.size() - 1 && s[i] != '?'; i++) {
    state = Aho.go(state, s[i]);
    sum += Aho.cost(state);
  }
  int qtdStates = Aho.qtdStates();
  for (int mask = (1 << 14) - 1; mask >= 0; mask--) {
    int i = __builtin_popcount(mask);
    if (i >= posMark.size()) continue;
    for (int state = 0; state < qtdStates; state++) {
      long long int& ans = dp[state][mask];
      ans = -INF;
      for (int c = 0; c < 14; c++) {
        if (mask & (1 << c)) continue;
        int newMask = mask + (1 << c);
        int newState = Aho.go(state, c + 'a');
        long long int cost = sumCost[i][newState];
        newState = jump[i][newState];
        ans = max(ans, dp[newState][newMask] + cost);
      }
    }
  }
  printf("%lld\n", dp[state][0] + sum);
}
