#include <bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;
const int INF = 0x3f3f3f3f;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
struct String_Hash {
  long long MUL = 1e9 + 9, MOD = 1e9 + 7;
  long long quick(long long A, long long B) {
    if (!B) return 1ll;
    long long tmp = quick(A, B >> 1);
    tmp *= tmp;
    tmp %= MOD;
    if (B & 1) {
      tmp *= A;
      tmp %= MOD;
    }
    return tmp;
  }
  long long val[26];
  long long num[100000 + 20], inv[100000 + 20];
  void init() {
    for (int i = 0; i < 100000; ++i) inv[i] = quick(quick(MUL, i), MOD - 2);
    for (int i = 0; i < 26; ++i) {
      val[i] = rng() % 1000000000 + 1;
    }
  }
  void hash_work(string s) {
    long long alr = 1;
    for (int i = 0; i < s.length(); ++i) {
      num[i + 1] = num[i] + val[s[i] - 'a'] * alr % MOD;
      num[i + 1] %= MOD;
      alr *= MUL;
      alr %= MOD;
    }
  }
  long long cut(int l, int r) {
    return (num[r] - num[l - 1] + MOD) % MOD * inv[l - 1] % MOD;
  }
} hs, hs_rev;
const int N = 1 << 17;
pair<int, int> segtree[N * 2];
void change(int index, int val) {
  index += N - 1;
  segtree[index] = max(segtree[index], make_pair(val, index - (N - 1)));
  index >>= 1;
  while (index) {
    segtree[index] = max(segtree[index << 1], segtree[index << 1 | 1]);
    index >>= 1;
  }
}
pair<int, int> query(int a, int b, int now = 1, int l = 1, int r = N + 1) {
  if (r <= a || l >= b) {
    return make_pair(0, 1);
  }
  if (r <= b && l >= a) {
    return segtree[now];
  }
  int mid = (l + r) >> 1;
  return max(query(a, b, now << 1, l, mid), query(a, b, now << 1 | 1, mid, r));
}
bool comp(pair<int, int> A, pair<int, int> B) { return A.second > B.second; }
int nxt[200000 + 20];
int main() {
  ios::sync_with_stdio(false);
  string s;
  cin >> s;
  hs.init();
  hs_rev.init();
  for (int i = 0; i < 26; ++i) hs_rev.val[i] = hs.val[i];
  hs.hash_work(s);
  string ss;
  ss = s;
  reverse(s.begin(), s.end());
  ss = s + '#' + ss;
  int j_ = 0;
  for (int i = 0; i < ss.length(); ++i) {
    if (!i) continue;
    if (ss[i] == ss[j_]) {
      nxt[i] = ++j_;
    } else {
      while (j_ && ss[i] != ss[j_]) {
        j_ = nxt[j_ - 1];
      }
      if (ss[i] == ss[j_]) {
        nxt[i] = ++j_;
      } else {
        nxt[i] = 0;
      }
    }
  }
  hs_rev.hash_work(s);
  vector<pair<int, int> > can;
  int len = s.length();
  s = '#' + s;
  for (int i = 1; i <= len; ++i) {
    can.push_back(make_pair(nxt[i + len], i));
  }
  sort(can.begin(), can.end());
  vector<pair<int, int> > queries;
  for (int i = 1; i <= len; ++i) {
    int l = 1, r = min(len - i + 1, i) + 1;
    while (l < r - 1) {
      int mid = (l + r) >> 1;
      if (hs.cut(i, mid + i - 1) ==
          hs_rev.cut(len - i + 1, len - i + 1 + mid - 1)) {
        l = mid;
      } else {
        r = mid;
      }
    }
    queries.push_back(make_pair(i - l + 1, i + l - 1));
  }
  sort(queries.begin(), queries.end(), comp);
  pair<int, pair<pair<int, int>, pair<int, int> > > rest =
      make_pair(-1, make_pair(make_pair(-1, -1), make_pair(-1, -1)));
  int zz = 0;
  for (auto it : queries) {
    while (zz < can.size() && can[zz].first <= len - it.second) {
      change(can[zz].second, can[zz].first);
      zz++;
    }
    pair<int, int> qq = query(1, it.first);
    if (it.second - it.first + 1 + qq.first * 2 > rest.first)
      rest =
          make_pair(qq.first * 2 + it.second - it.first + 1, make_pair(it, qq));
  }
  if (rest.second.second.first) {
    cout << 3 << endl;
    cout << rest.second.second.second - rest.second.second.first + 1 << " "
         << rest.second.second.first << endl;
    cout << rest.second.first.first << " "
         << rest.second.first.second - rest.second.first.first + 1 << endl;
    cout << len - rest.second.second.first + 1 << " "
         << rest.second.second.first << endl;
  } else {
    cout << 1 << endl;
    cout << rest.second.first.first << " "
         << rest.second.first.second - rest.second.first.first + 1 << endl;
  }
  return 0;
}
