anchor.diff:    y += tableTextSize + verticalPadding * 2.0;
     for (int index = 0; index < kTrainData.length; index += 1) {
       final Train train = kTrainData[index];
  -    y += verticalPadding;
  +    train.yTop = y;
       x = window.padding.left;
       path.moveTo(x, y);
  -    train.code.paint(c, new Rect.fromLTWH(x + horizontalPadding, y + verticalPadding, columnWidths[0] - horizontalPadding * 2.0, tableTextSize));
  -    final double rowHeight = math.max(train.description.actualHeight(columnWidths[2] - horizontalPadding * 2.0), tableTextSize);
  +    y += verticalPadding;
  +    train.code.paint(c, new Rect.fromLTWH(x + horizontalPadding, y, columnWidths[0] - horizontalPadding * 2.0, tableTextSize));
  +    final double codeHeight = train.code.actualHeight(columnWidths[0] - horizontalPadding * 2.0);
  +    if (train.checked) {
  +      Paint paint = new Paint();
  +      paint.color = const Color(0xFF43A047);
  +      c.drawCircle(new Point(x + columnWidths[0] / 2.0, y + codeHeight + verticalPadding + iconSize / 2.0), iconSize / 2.0, paint);
  +    }
  +    final double rowHeight = math.max(
  +      codeHeight + horizontalPadding + iconSize,
  +      train.description.actualHeight(columnWidths[2] - horizontalPadding * 2.0)
  +    );
       x += columnWidths[0];
       if (train.image != null) {
  -      final Rect destRect = new Rect.fromLTWH(x, y, columnWidths[1], rowHeight + verticalPadding * 2.0);
  +      final Rect destRect = new Rect.fromLTWH(x, y - verticalPadding, columnWidths[1], rowHeight + verticalPadding * 2.0);
         final double sourceHeight = train.image.width.toDouble() * destRect.height / destRect.width;
         final Rect sourceRect = new Rect.fromLTWH(
           0.0,
  
positive.code:     captionSize
    ));
  
    final List<double> columnWidths = captions.map/*<double>*/((Text caption) => caption.naturalMaxWidth).toList();
    for (int index = 0; index < kTrainData.length; index += 1) {
      Train train = kTrainData[index];
      columnWidths[0] = math.max(columnWidths[0], train.code.naturalMaxWidth + horizontalPadding * 2.0);
      columnWidths[1] = math.max(columnWidths[1], (train.image?.width ?? 0.0) + horizontalPadding * 2.0);
      columnWidths[2] = math.max(columnWidths[2], train.description.naturalMaxWidth + horizontalPadding * 2.0);
    }
    // make the image column max 40% (and take into account the device pixel ratio)
    columnWidths[1] = math.min(columnWidths[1] / window.devicePixelRatio, width * 0.4);
    columnWidths[2] = width - (columnWidths[0] + columnWidths[1]);
  
    final Path path = new Path();
  
negative.code:   window.render(scene);
  }
  
  void handlePointerPacket(ByteData serializedPacket) {
    final mojo.Message message = new mojo.Message(
      serializedPacket,
      const <mojo.MojoHandle>[],
      serializedPacket.lengthInBytes,
      0
    );
    final mojom.PointerPacket packet = mojom.PointerPacket.deserialize(message);
    for (mojom.Pointer event in packet.pointers) {
      if (event.type == mojom.PointerType.down) {
        double y = event.y;
        for (int index = 0; index < kTrainData.length; index += 1) {
          final Train train = kTrainData[index];
          if (train.yTop < y && train.yBottom > y) {
            train.checked = !train.checked;
            window.scheduleFrame();
            break;
          }
        }
      }
    }
  }
  
  void main() { 
    window.onBeginFrame = render;
    window.onMetricsChanged = window.scheduleFrame;
    window.onPointerPacket = handlePointerPacket;
    window.scheduleFrame();
  }
  