#include <bits/stdc++.h>
using namespace std;
template <class c>
struct rge {
  c b, e;
};
template <class c>
rge<c> range(c i, c j) {
  return rge<c>{i, j};
}
template <class c>
auto dud(c* x) -> decltype(cerr << *x, 0);
template <class c>
char dud(...);
struct debug {
  template <class c>
  debug& operator<<(const c&) {
    return *this;
  }
};
using ll = long long;
using ld = long double;
constexpr int nax = 1000 * 1000 + 105;
constexpr int infty = 1000 * 1000 * 1000 + 5;
constexpr int mod = 1000 * 1000 * 1000 + 7;
int n, m;
vector<int> graf[nax];
vector<tuple<int, int, int>> result;
bool odw[nax];
bool stos[nax];
bool dfs(int w, int o) {
  vector<int> konce;
  if (o != -1) {
    konce.push_back(o);
  }
  odw[w] = true;
  stos[w] = true;
  for (int d : graf[w]) {
    if (d == o)
      continue;
    else if (stos[d])
      konce.push_back(d);
    else if (odw[d])
      continue;
    else {
      if (dfs(d, w)) konce.push_back(d);
    }
  }
  stos[w] = false;
  while (konce.size() > 1) {
    const int a = konce.back();
    konce.pop_back();
    const int b = konce.back();
    konce.pop_back();
    result.emplace_back(a, w, b);
  }
  return !konce.empty();
}
int fut[nax];
int fuf(int w) {
  if (fut[w] == w) return w;
  return fut[w] = fuf(fut[w]);
}
void fuu(int u, int v) { fut[fuf(u)] = fuf(v); }
int main() {
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= n; i++) fut[i] = i;
  while (m--) {
    int a, b;
    scanf("%d%d", &a, &b);
    graf[a].push_back(b);
    graf[b].push_back(a);
    fuu(a, b);
  }
  for (int i = 1; i <= n; i++) {
    if (i == fuf(i)) dfs(i, -1);
  }
  printf("%d\n", (int)result.size());
  for (const auto& r : result) {
    printf("%d %d %d\n", get<0>(r), get<1>(r), get<2>(r));
  }
  return 0;
}
