#include <bits/stdc++.h>
using std::string;
inline void setIO(string file) {
  string in = file + ".in", out = file + ".out";
  freopen(in.c_str(), "r", stdin);
  freopen(out.c_str(), "w", stdout);
}
template <typename type>
inline void read(type &x) {
  int pm = 1;
  char c;
  do {
    c = getchar();
    if (c == '-') pm = -1;
  } while (!isdigit(c));
  x = c ^ '0';
  while (c = getchar(), isdigit(c)) x = x * 10 + (c ^ '0');
  x *= pm;
}
template <typename type>
void write(type x, char c = 0) {
  if (x < 0) putchar('-'), x = -x;
  if (x > 9) write(x / 10);
  putchar(x % 10 | '0');
  if (c) putchar(c);
}
using std::vector;
const int MAXN = 200005, MAXM = 200005;
int n, cnt;
int he[MAXN], deg[MAXN], de[MAXN];
bool vis[MAXN];
vector<int> ans[MAXN];
struct line {
  int to, nex;
} ed[MAXM << 1];
inline void addE(int u, int v) {
  static int cnt;
  ed[++cnt] = (line){v, he[u]};
  he[u] = cnt;
}
void DFS(int u, int fa) {
  vis[u] = true;
  for (int i = he[u], v; i; i = ed[i].nex) {
    v = ed[i].to;
    if (v == fa) continue;
    if (!vis[v]) {
      de[v] = de[u] + 1;
      DFS(v, u);
    } else if (de[v] > de[u]) {
      ++deg[u];
      ans[u].push_back(v);
    }
  }
  if (fa) {
    if (deg[u] & 1)
      ans[u].push_back(fa);
    else {
      ++deg[fa];
      ans[fa].push_back(u);
    }
  }
}
inline void solve() {
  for (int i = 1; i <= n; ++i) {
    if (!vis[i]) DFS(i, 0);
  }
  for (int i = 1; i <= n; ++i) cnt += ans[i].size() >> 1;
}
int main() {
  int m;
  read(n), read(m);
  for (int i = 1, u, v; i <= m; ++i) {
    read(u), read(v);
    addE(u, v), addE(v, u);
  }
  solve();
  write(cnt, '\n');
  for (int i = 1; i <= n; ++i) {
    for (int j = 0; j + 1 < ans[i].size(); j += 2) {
      write(ans[i][j], ' ');
      write(i, ' ');
      write(ans[i][j + 1], '\n');
    }
  }
  return 0;
}
