#include <bits/stdc++.h>
using namespace std;
const long long nax = 200005;
vector<long long> g_orig[nax], g_tree[nax], g_back[nax];
long long vis[nax] = {0}, dep[nax] = {0};
vector<long long> roots;
void make_tree(long long u, long long p, long long d = 0) {
  vis[u] = 1;
  dep[u] = d;
  for (auto &k : g_orig[u])
    if (k == p)
      continue;
    else if (vis[k] == 0)
      g_tree[u].push_back(k), make_tree(k, u, d + 1);
    else if (dep[u] > dep[k])
      g_back[u].push_back(k);
}
vector<pair<pair<long long, long long>, long long>> ans;
bool dfs(long long u, long long p) {
  for (auto &k : g_tree[u])
    if (k != p && dfs(k, u)) g_back[u].push_back(k);
  while (((long long)g_back[u].size()) > 1) {
    long long a = g_back[u][((long long)g_back[u].size()) - 1], b = u,
              c = g_back[u][((long long)g_back[u].size()) - 2];
    ans.push_back({{a, b}, c});
    g_back[u].pop_back();
    g_back[u].pop_back();
  }
  if (((long long)g_back[u].size()) == 0) return true;
  if (u != p) ans.push_back({{p, u}, g_back[u][0]});
  return false;
}
int32_t main() {
  ios::sync_with_stdio(false);
  cin.tie(0);
  long long n, m;
  cin >> n >> m;
  for (long long i = 0; i < m; i++) {
    long long a, b;
    cin >> a >> b;
    g_orig[a].push_back(b);
    g_orig[b].push_back(a);
  }
  for (long long i = 1; i <= n; i++)
    if (vis[i] == 0) make_tree(i, i), roots.push_back(i);
  for (auto &k : roots) dfs(k, k);
  cout << ((long long)ans.size()) << "\n";
  for (auto &k : ans)
    cout << k.first.first << " " << k.first.second << " " << k.second << "\n";
}
