#include <bits/stdc++.h>
const int MAXN = 2E5 + 5;
int depth[MAXN]{};
std::pair<int, int> edges[MAXN]{};
std::vector<std::pair<int, int> > graph[MAXN]{};
std::vector<std::pair<int, int> > final;
int M, N;
bool dfs(int cur) {
  std::vector<int> use;
  int src = 0, upp = -1;
  for (auto nxt : graph[cur])
    if (!depth[nxt.first]) {
      depth[nxt.first] = depth[cur] + 1;
      if (dfs(nxt.first)) use.push_back(nxt.second);
    } else if (depth[nxt.first] == depth[cur] - 1)
      upp = nxt.second;
    else if (depth[nxt.first] > depth[cur])
      use.push_back(nxt.second);
  bool res = true;
  if (use.size() & 1U) {
    if (upp != -1) final.emplace_back(upp, use[0]);
    res = false;
    src = 1;
  }
  for (int i = src; i < (int)use.size(); i += 2)
    final.emplace_back(use[i], use[i + 1]);
  return res;
}
int main() {
  scanf(" %d%d", &N, &M);
  for (int i = 0; i < M; ++i) {
    int u, v;
    scanf(" %d%d", &u, &v);
    graph[u].emplace_back(v, i);
    graph[v].emplace_back(u, i);
    edges[i] = {u, v};
  }
  for (int i = 1; i <= N; ++i)
    if (!depth[i]) {
      depth[i] = 1;
      dfs(i);
    }
  printf("%u\n", final.size());
  for (auto itr : final) {
    std::pair<int, int> A = edges[itr.first], B = edges[itr.second];
    if (A.first == B.first)
      std::swap(A.first, A.second);
    else if (A.first == B.second)
      std::swap(A, B);
    else if (A.second == B.second)
      std::swap(B.first, B.second);
    printf("%d %d %d\n", A.first, A.second, B.second);
  }
  return 0;
}
