import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.io.IOException;
import java.util.InputMismatchException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.io.BufferedOutputStream;
import java.util.StringTokenizer;
import java.io.Closeable;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.Flushable;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
	static class TaskAdapter implements Runnable {
		@Override
		public void run() {
			InputStream inputStream = System.in;
			OutputStream outputStream = System.out;
			Input in = new Input(inputStream);
			Output out = new Output(outputStream);
			FDestroyIt solver = new FDestroyIt();
			solver.solve(1, in, out);
			out.close();
		}
	}

	public static void main(String[] args) throws Exception {
		Thread thread = new Thread(null, new TaskAdapter(), "", 1<<29);
		thread.start();
		thread.join();
	}
	static class FDestroyIt {
		int n;
		int m;
		boolean[] turn;
		int[][] cards;
		int[][][] memo;

		public FDestroyIt() {
		}

		public int dp(int card, int used, int cost) {
			if(card==m) {
				return 0;
			}
			if(turn[card]) {
				cost = 3;
			}
			if(memo[card][used][cost]!=-1) {
				return memo[card][used][cost];
			}
			if(cost==0) {
				return memo[card][used][cost] = dp(card+1, used, cost);
			}
			int ans = dp(card+1, used, cost);
			if(cards[card][0]<=cost) {
				int cur = 0;
				if(used==9) {
					cur = (cards[card][1]<<1)+dp(card+1, 0, cost-cards[card][0]);
				}else {
					cur = cards[card][1]+dp(card+1, used+1, cost-cards[card][0]);
				}
				ans = Math.max(ans, cur);
			}
			return memo[card][used][cost] = ans;
		}

		public void solve(int kase, Input in, Output pw) {
			n = in.nextInt();
			ArrayList<int[]> card = new ArrayList<>();
			int cnt = 0;
			turn = new boolean[200000];
			for(int i = 0; i<n; i++) {
				int k = in.nextInt();
				turn[cnt] = true;
				cnt += k;
				for(int j = 0; j<k; j++) {
					card.add(new int[] {in.nextInt(), in.nextInt()});
				}
			}
			m = cnt;
			cards = new int[cnt][2];
			for(int i = 0; i<cnt; i++) {
				cards[i] = card.get(i);
			}
			memo = new int[m][10][4];
			for(int i = 0; i<m; i++) {
				for(int j = 0; j<10; j++) {
					Arrays.fill(memo[i][j], -1);
				}
			}
			pw.println(dp(0, 0, 3));
		}

	}

	static class Output implements Closeable, Flushable {
		public StringBuilder sb;
		public OutputStream os;
		public int BUFFER_SIZE;
		public boolean autoFlush;
		public String LineSeparator;

		public Output(OutputStream os) {
			this(os, 1<<16);
		}

		public Output(OutputStream os, int bs) {
			BUFFER_SIZE = bs;
			sb = new StringBuilder(BUFFER_SIZE);
			this.os = new BufferedOutputStream(os, 1<<17);
			autoFlush = false;
			LineSeparator = System.lineSeparator();
		}

		public void println(int i) {
			println(String.valueOf(i));
		}

		public void println(String s) {
			sb.append(s);
			println();
			if(autoFlush) {
				flush();
			}else if(sb.length()>BUFFER_SIZE >> 1) {
				flushToBuffer();
			}
		}

		public void println() {
			sb.append(LineSeparator);
		}

		private void flushToBuffer() {
			try {
				os.write(sb.toString().getBytes());
			}catch(IOException e) {
				e.printStackTrace();
			}
			sb = new StringBuilder(BUFFER_SIZE);
		}

		public void flush() {
			try {
				flushToBuffer();
				os.flush();
			}catch(IOException e) {
				e.printStackTrace();
			}
		}

		public void close() {
			flush();
			try {
				os.close();
			}catch(IOException e) {
				e.printStackTrace();
			}
		}

	}

	static class Input {
		BufferedReader br;
		StringTokenizer st;

		public Input(InputStream is) {
			this(is, 1<<20);
		}

		public Input(InputStream is, int bs) {
			br = new BufferedReader(new InputStreamReader(is), bs);
			st = null;
		}

		public boolean hasNext() {
			try {
				while(st==null||!st.hasMoreTokens()) {
					String s = br.readLine();
					if(s==null) {
						return false;
					}
					st = new StringTokenizer(s);
				}
				return true;
			}catch(Exception e) {
				return false;
			}
		}

		public String next() {
			if(!hasNext()) {
				throw new InputMismatchException();
			}
			return st.nextToken();
		}

		public int nextInt() {
			return Integer.parseInt(next());
		}

	}
}

