import std.algorithm;
import std.array;
import std.ascii;
import std.container;
import std.conv;
import std.math;
import std.numeric;
import std.range;
import std.stdio;
import std.string;
import std.typecons;

void log(A...)(A arg) {
    stderr.writeln(arg);
}
int size(T)(in T s) {
    return cast(int)s.length;
}

const real EPS = 1e-8;

void main() {
    int N, M; scanf("%d %d\n", &N, &M);
    auto S = new int[][N];
    auto H = new int[][N];
    foreach (i; 0 .. N) {
        int k; scanf("%d", &k);
        S[i] = new int[k];
        H[i] = new int[k];
        foreach (j; 0 .. k) {
            scanf("%d %d", &S[i][j], &H[i][j]);
        }
    }

    real height(int i, real m) {
        real h = 0;
        int k = 0;
        while (m > 0 && k < S[i].size) {
            real d = min(H[i][k], m / S[i][k]);
            m -= d * S[i][k];
            assert(m >= -EPS);
            h += d;
            k++;
        }
        return h;
    }

    real ans = -1e8;
    foreach (int i; 0 .. N) {
        auto dp = new int[][](N + 1, M + 1);
        foreach (int n; 0 .. N) {
            dp[n + 1] = dp[n].dup;
            if (i == n) continue;
            int x = 0, h = 0;
            foreach (int k; 0 .. S[n].size) {
                x += S[n][k] * H[n][k];
                h += H[n][k];
                foreach (int m; 0 .. M + 1) {
                    if (m + x <= M) {
                        dp[n + 1][m + x] = max(dp[n + 1][m + x], dp[n][m] + h);
                    }
                }
            }
        }
        foreach (m; 0 .. M + 1) {
            int r = M - m;
            ans = max(ans, dp[N][m] + height(i, r));
        }
    }
    writefln("%.12f", ans);
}