#include <bits/stdc++.h>
using namespace std;
const int maxn = 200005;
struct edge {
  int to, next, num;
} lst[maxn << 1];
int len = 1, first[maxn];
void addedge(int a, int b, int w) {
  lst[len].to = b;
  lst[len].next = first[a];
  lst[len].num = w;
  first[a] = len++;
}
int u[maxn], v[maxn], typ[maxn];
int sum[maxn];
int ufs[maxn];
int find(int x) { return x == ufs[x] ? x : ufs[x] = find(ufs[x]); }
bool ontree[maxn];
void dfs(int x, int p) {
  for (int pt = first[x]; pt; pt = lst[pt].next) {
    if (lst[pt].to != p) {
      dfs(lst[pt].to, x);
      if (sum[lst[pt].to] == 0) {
        typ[lst[pt].num] = (v[lst[pt].num] == x);
        sum[x] ^= 1;
      } else {
        typ[lst[pt].num] = (u[lst[pt].num] == x);
        sum[lst[pt].to] = 0;
      }
    }
  }
}
vector<int> P[maxn];
int main() {
  int n, m;
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= m; ++i) scanf("%d%d", u + i, v + i);
  for (int i = 1; i <= n; ++i) ufs[i] = i;
  for (int i = 1; i <= m; ++i) {
    if (find(u[i]) == find(v[i])) {
      typ[i] = 0;
      sum[u[i]] ^= 1;
    } else {
      ufs[find(u[i])] = find(v[i]);
      addedge(u[i], v[i], i);
      addedge(v[i], u[i], i);
    }
  }
  for (int i = 1; i <= n; ++i) {
    if (ufs[i] == i) dfs(i, 0);
  }
  for (int i = 1; i <= m; ++i) {
    if (typ[i] == 0)
      P[u[i]].push_back(v[i]);
    else
      P[v[i]].push_back(u[i]);
  }
  int ans = 0;
  for (int i = 1; i <= n; ++i) {
    ans = ans + P[i].size() / 2;
  }
  printf("%d\n", ans);
  for (int i = 1; i <= n; ++i) {
    int sz = P[i].size();
    for (int j = 0; j + 1 < sz; j += 2) {
      printf("%d %d %d\n", P[i][j], i, P[i][j + 1]);
    }
  }
  return 0;
}
