/** * @Author Mehdi Maick * Created on 13/12/2016. */ import java.util.*; import java.io.*; import static java.lang.Math.*; public class C { static char[] s; static final long mod = (long) 1e9 + 7L; static long count(String S) { char[] str = S.toCharArray(); int len = str.length; long[][] f = new long[len + 1][len + 1]; for (int i = 0; i <= len; i++) for (int j = 0; j <= len; j++) f[i][j] = 0; for (int offset = 1; offset <= len; offset++) { for (int si = 0; si <= len - offset; si++) { int endPos = si + offset; long count = f[si + 1][endPos] % mod; char ch = str[si]; for (int searchPos = si; searchPos < endPos; searchPos++) { if (str[searchPos] == ch) count += 1 + f[si + 1][searchPos]; } f[si][endPos] = count % mod; } } return f[0][len] % mod; } public static void solve(FastReader fs, PrintWriter pw) { int n = fs.nextInt(), q = fs.nextInt(); s = fs.next().toCharArray(); while (q-- > 0) { int type = fs.nextInt(); if (type == 1) { int from = fs.nextInt(), to = fs.nextInt(), value = fs.nextInt(); for (int i = from; i <= to; i++) { s[i] = (char) (((s[i] - 'a' + value % 26) % 26) + 'a'); } } else { int from = fs.nextInt(), to = fs.nextInt(); StringBuilder sb = new StringBuilder(new String(Arrays.copyOfRange(s, from, to + 1))); pw.println(count(sb.toString())); } } } static class FenwickTree { int[] tree; public FenwickTree(int size) { tree = new int[size + 1]; } public long query(int ind) { long sum = 0L; while (ind > 0) { sum += tree[ind]; ind -= ind & (-ind); } return sum; } public long query(int a, int b) { return query(b) - query(a - 1); } public void update(int ind, int value) { while (ind < tree.length) { tree[ind] += value; ind += (ind & (-ind)); } } public int size() { return tree.length - 1; } } public static void main(String[] args) throws Exception { FastReader fs = new FastReader(System.in); PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out)); solve(fs, pw); fs.close(); pw.close(); } static class FastReader { BufferedReader reader; StringTokenizer st; FastReader(InputStream stream) { reader = new BufferedReader(new InputStreamReader(stream)); st = null; } String next() { while (st == null || !st.hasMoreTokens()) { try { String line = reader.readLine(); if (line == null) { return null; } st = new StringTokenizer(line); } catch (Exception e) { throw new RuntimeException(); } } return st.nextToken(); } String nextLine() { String s = null; try { s = reader.readLine(); } catch (IOException e) { e.printStackTrace(); } return s; } int nextInt() { return Integer.parseInt(next()); } long nextLong() { return Long.parseLong(next()); } double nextDouble() { return Double.parseDouble(next()); } char nextChar() { return next().charAt(0); } int[] nextIntArray(int n) { int[] arr = new int[n]; int i = 0; while (i < n) { arr[i++] = nextInt(); } return arr; } long[] nextLongArray(int n) { long[] arr = new long[n]; int i = 0; while (i < n) { arr[i++] = nextLong(); } return arr; } int[] nextIntArrayOneBased(int n) { int[] arr = new int[n + 1]; int i = 1; while (i <= n) { arr[i++] = nextInt(); } return arr; } long[] nextLongArrayOneBased(int n) { long[] arr = new long[n + 1]; int i = 1; while (i <= n) { arr[i++] = nextLong(); } return arr; } void close() { try { reader.close(); } catch (IOException e) { System.err.println("There's been an error trying closing the reader "); e.printStackTrace(); } } } }