#include <bits/stdc++.h>
using namespace std;
long long INF = 0x3f3f3f3f;
struct Edge {
  int from, to;
  long long cap, flow;
  Edge(int u = 0, int v = 0, long long c = 0)
      : from(u), to(v), cap(c), flow(0) {}
};
struct Dinic {
  int number, N;
  vector<Edge> edges;
  vector<vector<int> > adj;
  vector<int> d, cur;
  Dinic(int Num)
      : number(Num),
        N(Num + 20),
        edges(0),
        adj(Num + 20),
        d(Num + 20),
        cur(Num + 20) {}
  void addEdge(int u, int v, long long cap) {
    if (u == v) return;
    edges.emplace_back(u, v, cap);
    adj[u].emplace_back(edges.size() - 1);
    edges.emplace_back(v, u, 0);
    adj[v].emplace_back(edges.size() - 1);
  }
  bool reach(int v) { return d[v] != N + 1; }
  bool bfs(int S, int T) {
    queue<int> q({S});
    fill(d.begin(), d.end(), N + 1);
    d[S] = 0;
    while (!q.empty()) {
      int u = q.front();
      q.pop();
      if (u == T) break;
      for (int k : adj[u]) {
        Edge &e = edges[k];
        if (e.flow < e.cap && d[e.to] > d[e.from] + 1) {
          d[e.to] = d[e.from] + 1;
          q.emplace(e.to);
        }
      }
    }
    return d[T] != N + 1;
  }
  long long dfs(int u, int T, long long flow = -1) {
    if (u == T || flow == 0) return flow;
    for (int &i = cur[u]; i < int(adj[u].size()); ++i) {
      Edge &e = edges[adj[u][i]];
      Edge &re = edges[adj[u][i] ^ 1];
      if (d[e.to] == d[e.from] + 1) {
        long long rem = e.cap - e.flow;
        if (flow != -1 && rem > flow) rem = flow;
        long long pushed = dfs(e.to, T, rem);
        if (pushed > 0) {
          e.flow += pushed;
          re.flow -= pushed;
          return pushed;
        }
      }
    }
    return 0;
  }
  long long maxFlow(int S, int T) {
    long long total = 0, flow;
    while (bfs(S, T)) {
      fill(cur.begin(), cur.end(), 0);
      while ((flow = dfs(S, T)) > 0) total += flow;
    }
    return total;
  }
};
struct LowBoundFeasibleFlow : Dinic {
  int ss, tt;
  vector<long long> outFlow, lowBound, flows;
  LowBoundFeasibleFlow(int sz)
      : Dinic(sz + 2), ss(sz + 1), tt(sz + 2), outFlow(sz + 3) {}
  void addEdge(int from, int to, long long low, long long high) {
    Dinic::addEdge(from, to, high - low);
    outFlow[from] += low;
    outFlow[to] -= low;
    lowBound.push_back(low);
    flows.push_back(low);
  }
  bool feasibleFlow() {
    long long sum = 0;
    for (int i = 0; i <= number; ++i) {
      if (outFlow[i] > 0)
        Dinic::addEdge(i, tt, outFlow[i]), sum += outFlow[i];
      else if (outFlow[i] < 0)
        Dinic::addEdge(ss, i, -outFlow[i]);
    }
    if (Dinic::maxFlow(ss, tt) != sum) return false;
    for (int i = 0; i < (int)lowBound.size(); ++i)
      flows[i] += Dinic::edges[2 * i].flow;
    return true;
  }
};
struct LowBoundMinFlow : LowBoundFeasibleFlow {
  LowBoundMinFlow(int Num) : LowBoundFeasibleFlow(Num) {}
  long long minBoundedFlow(int S, int T) {
    LowBoundFeasibleFlow::addEdge(T, S, 0, INF);
    int id = Dinic::edges.size() - 2;
    if (!LowBoundFeasibleFlow::feasibleFlow()) return -1;
    Dinic::edges[id].flow = Dinic::edges[id ^ 1].flow = Dinic::edges[id].cap;
    return flows.back() - Dinic::maxFlow(T, S);
  }
};
struct LowBoundMaxFlow : LowBoundFeasibleFlow {
  LowBoundMaxFlow(int Num) : LowBoundFeasibleFlow(Num) {}
  long long maxBoundedFlow(int S, int T) {
    LowBoundFeasibleFlow::addEdge(T, S, 0, INF);
    int id = Dinic::edges.size() - 2;
    if (!LowBoundFeasibleFlow::feasibleFlow()) return -1;
    Dinic::edges[id].flow = Dinic::edges[id ^ 1].flow = Dinic::edges[id].cap;
    return flows.back() + Dinic::maxFlow(S, T);
  }
};
int u[23333], v[23333], g[23333], inCut[23333];
int main() {
  int n, m, s, t;
  scanf("%d%d%d%d", &n, &m, &s, &t);
  Dinic Din(n);
  for (int i = 1; i <= m; ++i) {
    scanf("%d%d%d", &u[i], &v[i], &g[i]);
    if (g[i]) {
      Din.addEdge(u[i], v[i], 1);
      Din.addEdge(v[i], u[i], INF);
    } else
      Din.addEdge(u[i], v[i], INF);
  }
  long long ans = Din.maxFlow(s, t);
  printf("%lld\n", ans);
  LowBoundFeasibleFlow lbff(n);
  lbff.addEdge(t, s, 0, INF);
  for (int i = 1; i <= m; ++i)
    if (g[i]) {
      lbff.addEdge(u[i], v[i], 1, INF);
      inCut[i] = Din.reach(u[i]) ^ Din.reach(v[i]);
    }
  assert(lbff.feasibleFlow());
  int cc = 0;
  for (int i = 1; i <= m; ++i) {
    if (!g[i])
      puts("0 1");
    else {
      ++cc;
      printf("%lld %lld\n", lbff.flows[cc] + 1,
             lbff.flows[cc] + 1 + (1 - inCut[i]));
    }
  }
  return 0;
}
