#include <bits/stdc++.h>
using namespace std;
void fre() {
  freopen("c://test//input.in", "r", stdin);
  freopen("c://test//output.out", "w", stdout);
}
template <class T1, class T2>
inline void gmax(T1 &a, T2 b) {
  if (b > a) a = b;
}
template <class T1, class T2>
inline void gmin(T1 &a, T2 b) {
  if (b < a) a = b;
}
const int TOP = 1e5, N = TOP + 10;
char s[N];
int n;
struct Hash {
  int Z;
  int V;
  long long v[N];
  long long u[N];
  void init(int zz, int vv) {
    Z = zz;
    V = vv;
    v[0] = 1;
    for (int i = 1; i <= n; ++i) v[i] = v[i - 1] * V % Z;
    u[0] = 0;
    for (int i = 1; i <= n; ++i) u[i] = (u[i - 1] * V + s[i] - 'a' + 1) % Z;
  }
  long long hashvalue(int l, int r) {
    return (u[r] - u[l - 1] * v[r - (l - 1)] % Z + Z) % Z;
  }
} a, b;
int nxt[N];
int match[N];
void getnxt(char s[]) {
  int m = n;
  nxt[0] = m;
  int i;
  for (i = 0; i + 1 < m && s[i] == s[i + 1]; i++)
    ;
  nxt[1] = i;
  int st = 1;
  for (i = 2; i < m; i++) {
    if (i + nxt[i - st] < st + nxt[st])
      nxt[i] = nxt[i - st];
    else {
      int j = max(0, st + nxt[st] - i);
      for (; i + j < m && s[i + j] == s[j]; j++)
        ;
      nxt[i] = j;
      st = i;
    }
    ++match[nxt[i]];
  }
  ++match[nxt[0]];
  ++match[nxt[1]];
  for (int i = n; i > 1; --i) match[i - 1] += match[i];
}
vector<pair<int, int> > ans;
int main() {
  scanf("%s", s + 1);
  n = strlen(s + 1);
  a.init(1e9 + 7, 33);
  b.init(1e9 + 9, 37);
  getnxt(s + 1);
  ans.clear();
  for (int i = 1; i <= n; ++i) {
    if (a.hashvalue(1, i) == a.hashvalue(n - i + 1, n) &&
        b.hashvalue(1, i) == b.hashvalue(n - i + 1, n)) {
      ans.push_back({i, match[i]});
    }
  }
  printf("%d\n", ans.size());
  for (int i = 0; i < ans.size(); ++i)
    printf("%d %d\n", ans[i].first, ans[i].second);
  return 0;
}
