#include <bits/stdc++.h>
using namespace std;
struct Runs {
int l, r, p;
};
const int maxn = 1e6 + 5;
char t[maxn];
int m;
namespace getRuns {
struct Hash {
int p[maxn], h[maxn];
int mod, buf;
Hash(int _buf, int _mod) {
buf = _buf;
mod = _mod;
}
void Init(char *s, int n) {
p[0] = 1;
h[0] = 0;
for (int i = 1; i <= n; i++) {
p[i] = 1ll * p[i - 1] * buf % mod;
h[i] = (1ll * h[i - 1] * buf % mod + s[i] - 'a' + 1) % mod;
}
}
bool tl(int u, int v, int len) {
return (h[u] - h[v] + mod + 1ll * (h[v - len] - h[u - len] + mod) % mod * p[len] % mod) % mod == 0;
}
bool tr(int u, int v, int len) {
return (h[u + len - 1] - h[v + len - 1] + mod + 1ll * (h[v - 1] - h[u - 1] + mod) % mod * p[len] % mod) % mod == 0;
}
long long get(int l, int r) {
return (h[r] - 1ll * h[l - 1] * p[r - l + 1] % mod + mod) % mod;
}
} h1(31, 19260817);
int extl(int u, int v) {
if (t[u] != t[v])
return 0;
int l = 1, r = min(u, v), mid;
while (l < r) {
mid = (l + r + 1) >> 1;
if (h1.tl(u, v, mid))
l = mid;
else
r = mid - 1;
}
return l;
}
int extr(int u, int v) {
if (t[u] != t[v])
return 0;
int l = 1, r = m - max(u, v) + 1, mid;
while (l < r) {
mid = (l + r + 1) >> 1;
if (h1.tr(u, v, mid))
l = mid;
else
r = mid - 1;
}
return l;
}
vector<Runs> raw_runs(0);
int chk(int u, int v) {
int tl = extl(u, v), tr = extr(u, v);
if (tl + tr >= v - u + 1) {
raw_runs.push_back({u - tl + 1, v + tr - 1, v - u});
return v + tr - 1;
}
return 0;
}
vector<Runs> init() {
vector<Runs> b(0);
for (int p = 1; p <= m; p++)
for (int k = p, mx = 0; k + p <= m; k += p)
if (mx < k)
mx = max(mx, chk(k, k + p) - p);
sort(raw_runs.begin(), raw_runs.end(), [](const Runs &A, const Runs &B) { return A.l == B.l ? (A.r == B.r ? A.p < B.p : A.r < B.r) : A.l < B.l; });
for (const Runs &r : raw_runs)
if (b.empty() || r.l != b.back().l || r.r != b.back().r)
b.push_back(r);
return b;
}
} // namespace getRuns
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> (t + 1);
m = strlen(t + 1);
getRuns::h1.Init(t, m);
getRuns::h2.Init(t, m);
vector<Runs>
ans = getRuns::init();
cout << (int)ans.size() << endl;
for (auto [l, r, p] : ans) cout << l << " " << r << " " << p << endl;
}