#include <bits/stdc++.h>
using namespace std;
struct Edge {
  int u, v;
  bool used;
  Edge(int _u, int _v) : u(_u), v(_v), used(false) {}
  Edge(){};
  void swap() {
    int temp = u;
    u = v;
    v = temp;
  }
  void show() { printf("%d %d\n", u + 1, v + 1); }
};
const int N = (int)2e5 + 5;
vector<Edge> edges;
vector<int> g[N];
vector<int> incid[N];
int par[N];
bool used[N];
int getOther(int v, int i) { return edges[i].u ^ edges[i].v ^ v; }
vector<pair<int, int>> out;
void push(int a, int b) {
  edges[a].used = true;
  edges[b].used = true;
  out.push_back({a, b});
}
void dfs(int v, int p = -1) {
  used[v] = true;
  int deg = 1;
  for (int i : g[v]) {
    int u = getOther(v, i);
    if (u == p) continue;
    if (!used[u]) {
      par[u] = i;
      dfs(u, v);
      if (!edges[i].used) incid[v].push_back(i);
      ++deg;
    } else {
      incid[u].push_back(i);
    }
  }
  if (deg == 1) return;
  if (p != -1) incid[v].push_back(par[v]);
  int sz = (int)incid[v].size();
  for (int i = 0; i + 1 < sz; i += 2) push(incid[v][i], incid[v][i + 1]);
}
int main() {
  int n, m;
  scanf("%d %d", &n, &m);
  for (int i = 0; i < m; ++i) {
    int u, v;
    scanf("%d %d", &u, &v);
    --u;
    --v;
    edges.push_back(Edge(u, v));
    g[u].push_back(i);
    g[v].push_back(i);
  }
  for (int v = 0; v < n; ++v) {
    if (!used[v]) dfs(v);
  }
  printf("%d\n", (int)(out).size());
  srand(time(0));
  for (auto& [a, b] : out) {
    while (edges[a].v != edges[b].u) {
      if (rand() & 1)
        edges[a].swap();
      else
        edges[b].swap();
    }
    printf("%d %d %d\n", edges[a].u + 1, edges[a].v + 1, edges[b].v + 1);
  }
}
