#include <bits/stdc++.h>
using namespace std;
template <class T>
T inf() {
  return numeric_limits<T>::has_infinity ? numeric_limits<T>::infinity()
                                         : (numeric_limits<T>::max() / 2);
}
FILE *file_in = stdin, *file_out = stdout;
struct NORMAL_IN {
  bool cnt;
  NORMAL_IN() : cnt(true) {}
  operator int() const { return cnt; }
  NORMAL_IN &operator>>(int &n) {
    cnt = fscanf(file_in, "%d", &n) != EOF;
    return *this;
  }
  NORMAL_IN &operator>>(unsigned int &n) {
    cnt = fscanf(file_in, "%u", &n) != EOF;
    return *this;
  }
  NORMAL_IN &operator>>(long long &n) {
    cnt = fscanf(file_in, "%lld", &n) != EOF;
    return *this;
  }
  NORMAL_IN &operator>>(unsigned long long &n) {
    cnt = fscanf(file_in, "%llu", &n) != EOF;
    return *this;
  }
  NORMAL_IN &operator>>(double &n) {
    cnt = fscanf(file_in, "%lf", &n) != EOF;
    return *this;
  }
  NORMAL_IN &operator>>(long double &n) {
    cnt = fscanf(file_in, "%Lf", &n) != EOF;
    return *this;
  }
  NORMAL_IN &operator>>(char *c) {
    cnt = fscanf(file_in, "%s", c) != EOF;
    return *this;
  }
  NORMAL_IN &operator>>(string &s) {
    s.clear();
    for (bool r = false;;) {
      const char c = getchar();
      if (c == EOF) {
        cnt = false;
        break;
      }
      const int t = isspace(c);
      if (!r and !t) r = true;
      if (r) {
        if (!t)
          s.push_back(c);
        else
          break;
      }
    }
    return *this;
  }
  template <class T>
  NORMAL_IN &operator>>(vector<T> &v) {
    int n;
    fscanf(file_in, "%d", &n);
    for (int i = 0; i < (int)(n); ++i) {
      T t;
      *this >> t;
      v.push_back(t);
    }
    return *this;
  }
} normal_in;
struct NORMAL_OUT {
  NORMAL_OUT &operator<<(const int &n) {
    fprintf(file_out, "%d", n);
    return *this;
  }
  NORMAL_OUT &operator<<(const unsigned int &n) {
    fprintf(file_out, "%u", n);
    return *this;
  }
  NORMAL_OUT &operator<<(const long long &n) {
    fprintf(file_out, "%lld", n);
    return *this;
  }
  NORMAL_OUT &operator<<(const unsigned long long &n) {
    fprintf(file_out, "%llu", n);
    return *this;
  }
  NORMAL_OUT &operator<<(const double &n) {
    fprintf(file_out, "%lf", n);
    return *this;
  }
  NORMAL_OUT &operator<<(const long double &n) {
    fprintf(file_out, "%Lf", n);
    return *this;
  }
  NORMAL_OUT &operator<<(const char c[]) {
    fprintf(file_out, "%s", c);
    return *this;
  }
  NORMAL_OUT &operator<<(const string &s) {
    fprintf(file_out, "%s", s.c_str());
    return *this;
  }
} normal_out;
struct ERR_OUT {
  template <class T>
  ERR_OUT &operator<<(const T &a) {
    cerr << "\x1b[7m" << a << "\x1b[m";
    return *this;
  }
} ferr;
template <class Weight>
struct edge {
  int src, dst;
  Weight weight;
  int rev;
  edge(int src, int dst, Weight weight = 1, int rev = -1)
      : src(src), dst(dst), weight(weight), rev(rev) {}
};
template <class Weight>
bool operator<(const edge<Weight> &e, const edge<Weight> &f) {
  return e.weight != f.weight ? e.weight > f.weight
         : e.src != f.src     ? e.src < f.src
                              : e.dst < f.dst;
}
template <class Weight>
struct matrix : vector<vector<Weight> > {
  matrix(const array<int, 2> &a, Weight w = 0)
      : vector<vector<Weight> >(a[0], vector<Weight>(a[1], w)) {}
  matrix(const array<int, 1> &a, Weight w = 0)
      : vector<vector<Weight> >(a[0], vector<Weight>(a[0], 0)) {}
  matrix() {}
};
template <class Weight>
struct graph : vector<vector<edge<Weight> > > {
  Weight inf{::inf<Weight>()};
  graph() {}
  graph(const int &n) : vector<vector<edge<Weight> > >(n) {}
  void _add_edge(int from, int to, Weight w, int rev = -1) {
    if ((int)this->size() < from + 1) this->resize(from + 1);
    this->at(from).push_back(edge<Weight>(from, to, w, rev));
  }
};
template <class Weight>
void addBiEdge(graph<Weight> &g, const pair<int, int> &e, Weight w = 1) {
  const int &from = e.first, &to = e.second;
  g._add_edge(from, to, w, g[to].size());
  g._add_edge(to, from, w, g[from].size() - 1);
}
template <class Weight>
void addEdge(graph<Weight> &g, const pair<int, int> &e, Weight w = 1) {
  const int &from = e.first, &to = e.second;
  g._add_edge(from, to, w);
}
template <class T>
void matrix_out(const vector<vector<T> > &x) {
  for (int i = 0; i < (int)(x.size()); ++i) {
    for (int j = 0; j < (int)(x[0].size()); ++j) {
      cout << x[i][j] << "\t";
    }
    cout << "\n";
  }
}
template <class U, class S, class T>
U &operator<<(U &os, const pair<S, T> &p) {
  os << "(" << p.first << ", " << p.second << ")";
  return os;
}
void printBit(int b, int k = -1) {
  if (k == -1) {
    int bb = 1, i = 0;
    while (bb) {
      if (b & bb) k = i;
      bb <<= 1;
      i++;
    }
  }
  for (int ct = 0; ct < (int)(k); ++ct) {
    cout << b % 2;
    b >>= 1;
  }
  cout << "\n";
}
template <typename U, template <typename... Args> class Container,
          typename... Types>
U &operator<<(U &os, const Container<Types...> &x) {
  os << "{";
  for (const auto &e : x) os << " " << e << " ";
  os << "}";
  return os;
}
int main() {
  int n, m;
  normal_in >> n >> m;
  graph<int> g(n);
  unordered_map<int, unordered_map<int, int> > mp;
  vector<pair<int, int> > query(m);
  for (int i = 0; i < (int)(m); ++i) {
    int a, b, c;
    normal_in >> a >> b >> c;
    a--;
    b--;
    mp[a][b] = mp[b][a] = i;
    query[i] = {a, b};
    addBiEdge(g, {a, b}, c);
  }
  vector<int> ans(m, -1), flow(n, 0);
  for (int u = 1; u < n - 1; u++) {
    for (int i = 0; i < (int)(g[u].size()); ++i) {
      flow[u] += g[u][i].weight;
    }
    flow[u] /= 2;
  }
  queue<int> q;
  q.push(0);
  while (!q.empty()) {
    int u = q.front();
    q.pop();
    for (auto &&e : g[u]) {
      int v = e.dst;
      int i = mp[u][v];
      if (ans[i] != -1) continue;
      if (query[i].first == u)
        ans[i] = 0;
      else
        ans[i] = 1;
      flow[v] -= e.weight;
      if (v != n - 1 and flow[v] == 0) {
        q.push(v);
      }
    }
  }
  for (int i = 0; i < (int)(ans.size()); ++i) {
    normal_out << ans[i] << "\n";
  }
}
