#include <bits/stdc++.h>
using namespace std;
inline long long mod(long long n, long long m) {
  long long ret = n % m;
  if (ret < 0) ret += m;
  return ret;
}
long long gcd(long long a, long long b) {
  return (b == 0LL ? a : gcd(b, a % b));
}
long long exp(long long a, long long b, long long m) {
  if (b == 0LL) return 1LL;
  if (b == 1LL) return mod(a, m);
  long long k = mod(exp(a, b / 2, m), m);
  if (b & 1LL) {
    return mod(a * mod(k * k, m), m);
  } else
    return mod(k * k, m);
}
const int N = 2e5 + 100;
struct coisa {
  int a, b, c;
  coisa() {}
  coisa(int a, int b, int c) : a(a), b(b), c(c) {}
};
vector<coisa> res;
int vis[N];
int H[N];
int t = 0;
vector<int> g[N];
map<int, int> used[N];
void pre(int v) {
  vis[v] = 1;
  for (int to : g[v])
    if (!vis[to]) {
      H[to] = H[v] + 1;
      pre(to);
    }
}
void dfs(int v, int p = -1) {
  vis[v] = 2;
  for (int to : g[v]) {
    if (vis[to] != 2) {
      dfs(to, v);
    }
  }
  vector<int> here;
  for (int to : g[v]) {
    if (H[v] < H[to] and !used[v][to]) {
      here.push_back(to);
      used[v][to] = used[to][v] = 1;
    }
  }
  for (int i = 0; i < (int)here.size() - 1; i += 2) {
    res.push_back(coisa(here[i], v, here[i + 1]));
  }
  if ((int)here.size() % 2 == 1 and p != -1 and !used[v][p]) {
    used[v][p] = used[p][v] = 1;
    res.push_back(coisa(p, v, here.back()));
  }
}
void solve(int root) {
  pre(root);
  dfs(root);
}
int32_t main() {
  ios_base::sync_with_stdio(0);
  cin.tie(0);
  cout.tie(0);
  ;
  int n, m;
  cin >> n >> m;
  for (int i = 0; i < m; i++) {
    int a, b;
    cin >> a >> b;
    g[a].push_back(b);
    g[b].push_back(a);
  }
  for (int i = 1; i <= n; i++) {
    if (!vis[i]) {
      solve(i);
    }
  }
  cout << (int)res.size() << "\n";
  for (auto c : res) {
    cout << c.a << " " << c.b << " " << c.c << "\n";
  }
}
