#include <algorithm>
#include <cstring>
#include <deque>
#include <functional>
#include <iostream>
#include <map>
#include <numeric>
#include <queue>
#include <set>
#include <vector>
using namespace std;
using ll = long long;
const int INF = 1 << 29;

template <class T, class Compare = less<T>>
class SlideRangeQuery {
 private:
  const vector<T>& vs;

  Compare comp;
  int x = 0;
  deque<int> deq;

 public:
  SlideRangeQuery(const vector<T>& vs_) : vs(vs_) {}

  // [a, b)
  int query(int a, int b) {
    while (!deq.empty() && deq.front() < a) {
      deq.pop_front();
    }
    for (x = max(a, x); x < b; x++) {
      while (!deq.empty() && not comp(vs[deq.back()], vs[x])) {
        deq.pop_back();
      }
      deq.push_back(x);
    }
    return deq.empty() ? -1 : deq.front();
  }
};

template <class T>
using SlideMinimum = SlideRangeQuery<T, less<T>>;

template <class T>
using SlideMaximum = SlideRangeQuery<T, greater<T>>;

int main() {
  int N, W;
  while (cin >> N >> W) {
    vector<int> v(N), w(N), m(N);
    for (int i = 0; i < N; i++) cin >> v[i] >> w[i] >> m[i];
    vector<int> dp(W + 1);
    for (int i = 0; i < N; i++) {
      for (int r = 0; r < w[i]; r++) {
        vector<int> b;
        for (int j = 0; w[i] * j + r <= W; j++)
          b.push_back(dp[w[i] * j + r] - v[i] * j);
        SlideMaximum<int> sm(b);
        for (int j = 0; w[i] * j + r <= W; j++)
          dp[w[i] * j + r] = b[sm.query(max(0, j - m[i]), j + 1)] + j * v[i];
      }
    }
    int res = *max_element(dp.begin(), dp.end());
    cout << res << endl;
  }
  return 0;
}

