#include <bits/stdc++.h>
using namespace std;
const int maxn = 2005;
const long long INF = 0x3f3f3f3f3f3f3f3fll;
const long long MOD = 1e9 + 7;
int n, k, L;
long long ans;
class Candy {
 public:
  int x, y, c;
  inline bool operator<(const Candy &oth) const { return x < oth.x; }
} a[maxn];
inline bool cmp(const Candy &a, const Candy &b) { return a.y < b.y; }
int val[maxn], cnt[maxn];
vector<int> vx, vy;
multiset<int> ms[maxn];
inline int pos(vector<int> &vec, int x) {
  return lower_bound(vec.begin(), vec.end(), x) - vec.begin();
}
class Node {
 public:
  long long mn1, mn2, cnt, sum, tag;
  inline Node() {
    mn1 = mn2 = INF;
    cnt = sum = 0;
    tag = -1;
  }
  inline Node(long long mn1_, long long mn2_, long long cnt_, long long sum_,
              long long tag_)
      : mn1(mn1_), mn2(mn2_), cnt(cnt_), sum(sum_), tag(tag_) {}
  inline Node operator+(const Node &oth) const {
    Node ret;
    if (mn1 == oth.mn1)
      ret = Node(mn1, min(mn2, oth.mn2), cnt + oth.cnt, sum + oth.sum, -1);
    else if (mn1 < oth.mn1)
      ret = Node(mn1, min(mn2, oth.mn1), cnt, sum + oth.sum, -1);
    else
      ret = Node(oth.mn1, min(mn1, oth.mn2), oth.cnt, sum + oth.sum, -1);
    return ret;
  }
};
class Segbeat {
 private:
  static const int siz = 2048;
  Node dat[siz << 1];
  inline void apply(int x, int k) {
    if (dat[x].mn1 >= k) return;
    if (dat[x].mn2 > k) {
      dat[x].tag = max(dat[x].tag, 1ll * k);
      dat[x].sum += 1ll * (k - dat[x].mn1) * dat[x].cnt;
      dat[x].mn1 = k;
      return;
    }
    apply(x << 1, k);
    apply(x << 1 | 1, k);
    dat[x] = dat[x << 1] + dat[x << 1 | 1];
    return;
  }
  inline void pushDown(int x) {
    if (dat[x].tag != -1) {
      apply(x << 1, dat[x].tag);
      apply(x << 1 | 1, dat[x].tag);
      dat[x].tag = -1;
    }
    dat[x] = dat[x << 1] + dat[x << 1 | 1];
    return;
  }

 public:
  inline int size() { return siz; }
  inline void build(int x, int l, int r) {
    if (l == r) {
      if (l >= vy.size())
        dat[x] = Node();
      else {
        dat[x].mn1 = val[l];
        dat[x].mn2 = INF;
        dat[x].sum = dat[x].mn1 * (!l ? 1 : vy[l] - vy[l - 1]);
        dat[x].cnt = (!l ? 1 : vy[l] - vy[l - 1]);
      }
      return;
    }
    int md = l + r >> 1;
    build(x << 1, l, md);
    build(x << 1 | 1, md + 1, r);
    dat[x] = dat[x << 1] + dat[x << 1 | 1];
    return;
  }
  inline void update(int x, int l, int r, int s, int t, int k) {
    if (s > t) return;
    if (l >= s && r <= t) {
      apply(x, k);
      return;
    }
    int md = l + r >> 1;
    pushDown(x);
    if (s <= md) update(x << 1, l, md, s, t, k);
    if (t > md) update(x << 1 | 1, md + 1, r, s, t, k);
    dat[x] = dat[x << 1] + dat[x << 1 | 1];
    return;
  }
  inline long long query() { return dat[1].sum; }
} seg;
int main() {
  scanf("%d%d%d", &n, &k, &L);
  for (int i = (0); i < (n); ++i) {
    scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].c);
    --a[i].c;
    vx.push_back(a[i].x);
    vy.push_back(a[i].y);
  }
  vx.push_back(0);
  vx.push_back(L - 1);
  vy.push_back(0);
  vy.push_back(L - 1);
  sort(a, a + n);
  sort(vx.begin(), vx.end());
  vx.erase(unique(vx.begin(), vx.end()), vx.end());
  sort(vy.begin(), vy.end());
  vy.erase(unique(vy.begin(), vy.end()), vy.end());
  for (int i = (0); i < (n); ++i) {
    a[i].x = lower_bound(vx.begin(), vx.end(), a[i].x) - vx.begin();
    a[i].y = lower_bound(vy.begin(), vy.end(), a[i].y) - vy.begin();
  }
  for (int i = (0); i < (vx.size()); ++i) {
    for (int j = (0); j < (k); ++j) ms[j].clear();
    int tot = 0;
    memset(cnt, 0, sizeof(cnt));
    vector<Candy> all;
    all.clear();
    for (int j = (0); j < (n); ++j)
      if (a[j].x >= i) {
        ms[a[j].c].insert(a[j].y);
        all.push_back(a[j]);
      }
    sort(all.begin(), all.end(), cmp);
    for (int j = vy.size() - 1, l = all.size(), r = all.size(); j >= 0; --j) {
      for (; l && all[l - 1].y >= j; --l) {
        if (!cnt[all[l - 1].c]) ++tot;
        ++cnt[all[l - 1].c];
      }
      if (tot == k) {
        for (; cnt[all[r - 1].c] > 1; --r) --cnt[all[r - 1].c];
        val[j] = vy[all[r - 1].y];
      } else
        val[j] = L;
    }
    seg.build(1, 0, seg.size() - 1);
    for (int j = vx.size() - 1, it = n - 1; j >= i; --j) {
      for (; it >= 0 && a[it].x > j; --it) {
        int c = a[it].c;
        ms[c].erase(ms[c].find(a[it].y));
        if (ms[c].count(a[it].y)) continue;
        multiset<int>::iterator pos = ms[c].lower_bound(a[it].y);
        int val = (pos == ms[a[it].c].end() ? L : vy[*pos]),
            l = (pos == ms[c].begin() ? 0 : *(--pos) + 1);
        seg.update(1, 0, seg.size() - 1, l, a[it].y, val);
      }
      long long res = seg.query();
      res = (1ll * L * L - res) % MOD;
      res = 1ll * res * (i ? vx[i] - vx[i - 1] : 1) % MOD *
            (j == vx.size() - 1 ? 1 : vx[j + 1] - vx[j]) % MOD;
      (ans += res) %= MOD;
    }
  }
  printf("%lld\n", ans);
  return 0;
}
