#include <bits/stdc++.h>
using namespace std;
int n, m;
vector<vector<int>> adj;
const int nax = 2e5 + 5;
int dep[nax], par[nax];
struct Answer {
  int a, b, c;
  Answer(int x, int y, int z) {
    a = x;
    b = y;
    c = z;
  }
};
vector<Answer> ans;
map<pair<int, int>, bool> avail;
void dfs(int v) {
  stack<int> st;
  for (auto &c : adj[v]) {
    if (dep[c] == 0) {
      dep[c] = dep[v] + 1;
      par[c] = v;
      dfs(c);
    }
    if (dep[c] > dep[v] && avail[{min(c, v), max(c, v)}]) {
      st.push(c);
    }
  }
  while ((int)st.size() > 1) {
    int fi = st.top();
    st.pop();
    int se = st.top();
    st.pop();
    ans.emplace_back(fi, v, se);
    avail[{min(fi, v), max(fi, v)}] = false;
    avail[{min(se, v), max(se, v)}] = false;
  }
  if ((int)st.size() == 1) {
    int fi = st.top();
    st.pop();
    if (avail[{min(fi, v), max(fi, v)}] &&
        avail[{min(par[v], v), max(par[v], v)}]) {
      avail[{min(fi, v), max(fi, v)}] = false;
      avail[{min(par[v], v), max(par[v], v)}] = false;
      ans.emplace_back(fi, v, par[v]);
    }
  }
}
void solve() {
  cin >> n >> m;
  adj.resize(n + 1);
  for (int i = 1; i <= m; ++i) {
    int u, v;
    cin >> u >> v;
    avail[{min(u, v), max(u, v)}] = true;
    adj[u].push_back(v);
    adj[v].push_back(u);
  }
  for (int i = 1; i <= n; ++i) {
    if (dep[i] == 0) {
      dep[i] = 1;
      dfs(i);
    }
  }
  cout << (int)ans.size() << '\n';
  for (auto p : ans) {
    cout << p.a << ' ' << p.b << ' ' << p.c << '\n';
  }
}
signed main() {
  ios_base::sync_with_stdio(false);
  cin.tie(0);
  int t = 1;
  while (t--) solve();
  return 0;
}
