#include <bits/stdc++.h>
using namespace std;
const long long maxn = 2e3 + 10;
const long long Mod = 1e9 + 7;
long long n, N1, N2, k, L, lst, p1[maxn], p2[maxn], ans;
struct node {
  long long x, y, c;
} a[maxn];
struct Node {
  long long len, sum, lazy, val;
} Tree[maxn << 2];
vector<pair<long long, long long> > p, b[maxn];
multiset<long long> Col[maxn];
inline void PushTag(long long root, long long val) {
  Tree[root].sum = val * Tree[root].len;
  Tree[root].lazy = Tree[root].val = val;
}
inline void PushUp(long long root) {
  Tree[root].sum = Tree[root << 1].sum + Tree[root << 1 | 1].sum;
  Tree[root].val = Tree[root << 1].val;
}
inline void PushDown(long long root) {
  if (!Tree[root].lazy) return;
  PushTag(root << 1, Tree[root].lazy);
  PushTag(root << 1 | 1, Tree[root].lazy);
  Tree[root].lazy = 0;
}
inline void Build(long long root, long long l, long long r) {
  Tree[root].len = p1[r] - p1[l - 1];
  Tree[root].sum = Tree[root].len * (L + 1);
  Tree[root].lazy = 0;
  if (l == r) {
    Tree[root].val = Tree[root].sum;
    return;
  }
  long long Mid = l + r >> 1;
  Build(root << 1, l, Mid);
  Build(root << 1 | 1, Mid + 1, r);
  PushUp(root);
}
inline void Modify(long long root, long long l, long long r, long long L,
                   long long R, long long val) {
  if (L > R) return;
  if (L <= l && r <= R) {
    PushTag(root, val);
    return;
  }
  long long Mid = l + r >> 1;
  PushDown(root);
  if (L <= Mid) Modify(root << 1, l, Mid, L, R, val);
  if (Mid < R) Modify(root << 1 | 1, Mid + 1, r, L, R, val);
  PushUp(root);
}
inline long long Query(long long root, long long l, long long r, long long L,
                       long long R) {
  if (L <= l && r <= R) return Tree[root].sum;
  long long Mid = l + r >> 1, ret = 0;
  PushDown(root);
  if (L <= Mid) ret += Query(root << 1, l, Mid, L, R);
  if (Mid < R) ret += Query(root << 1 | 1, Mid + 1, r, L, R);
  return ret;
}
inline long long Find(long long root, long long l, long long r, long long val) {
  if (l == r) return Tree[root].val <= val ? l : 0;
  long long Mid = l + r >> 1;
  PushDown(root);
  if (Tree[root << 1 | 1].val > val) return Find(root << 1, l, Mid, val);
  return Find(root << 1 | 1, Mid + 1, r, val);
}
signed main() {
  scanf("%lld%lld%lld", &n, &k, &L);
  for (long long i = (1), _end_ = (n); i <= _end_; ++i) {
    scanf("%lld%lld%lld", &a[i].x, &a[i].y, &a[i].c);
    ++a[i].x;
    ++a[i].y;
  }
  sort(a + 1, a + n + 1, [](node &a, node &b) { return a.x < b.x; });
  lst = 0;
  for (long long i = (1), _end_ = (n); i <= _end_; ++i)
    if (a[i].x != lst) {
      lst = p1[++N1] = a[i].x;
      a[i].x = N1;
    } else
      a[i].x = N1;
  sort(a + 1, a + n + 1, [](node &a, node &b) { return a.y < b.y; });
  lst = 0;
  for (long long i = (1), _end_ = (n); i <= _end_; ++i)
    if (a[i].y != lst) {
      lst = p2[++N2] = a[i].y;
      a[i].y = N2;
    } else
      a[i].y = N2;
  for (long long i = (1), _end_ = (n); i <= _end_; ++i)
    b[a[i].y].push_back(pair<long long, long long>(a[i].x, a[i].c));
  for (long long o = (1), _end_ = (N2); o <= _end_; ++o)
    sort(b[o].begin(), b[o].end());
  p1[N1 + 1] = p2[N2 + 1] = L + 1;
  for (long long i = (1), _end_ = (N2); i <= _end_; ++i) {
    p.clear();
    for (long long o = (1), _end_ = (k); o <= _end_; ++o) {
      Col[o].clear();
      Col[o].insert(0);
    }
    Build(1, 1, N1);
    for (long long k = (1), _end_ = (n); k <= _end_; ++k)
      if (a[k].y >= i) p.push_back(pair<long long, long long>(a[k].x, a[k].c));
    sort(p.begin(), p.end());
    for (auto k : p) {
      auto it = --Col[k.second].end();
      Modify(1, 1, N1, *it + 1, k.first, p1[k.first]);
      Col[k.second].insert(k.first);
    }
    for (long long o = (1), _end_ = (k); o <= _end_; ++o) {
      auto it = --Col[o].end();
      Modify(1, 1, N1, *it + 1, N1, L + 1);
      Col[o].insert(N1 + 1);
    }
    long long ret = ((L + 1) * p1[N1] - Tree[1].sum) % Mod;
    ret = ret * (p2[i] - p2[i - 1]) % Mod;
    ret = ret * (p2[N2 + 1] - p2[N2]) % Mod;
    ans = (ans + ret) % Mod;
    for (long long j = N2 - 1; j >= i; --j) {
      for (auto it : b[j + 1]) {
        auto pos = Col[it.second].lower_bound(it.first);
        auto l = pos, r = pos;
        --l;
        ++r;
        Modify(1, 1, N1, *l + 1, Find(1, 1, N1, p1[*r]), p1[*r]);
        Col[it.second].erase(pos);
      }
      ret = ((L + 1) * p1[N1] - Tree[1].sum) % Mod;
      ret = ret * (p2[i] - p2[i - 1]) % Mod;
      ret = ret * (p2[j + 1] - p2[j]) % Mod;
      ans = (ans + ret) % Mod;
    }
  }
  printf("%lld\n", (ans + Mod) % Mod);
  return 0;
}
