+
+ while (my ($browser, $vercols) = each %versions) {
+ my $div = 0; # multiplier exponent (decreased to lower value)
+ my @vers = map { $row->{$browser}->{$_} } @$vercols;
+ if (my $current = $caniuse->{agents}->{$browser}->{versions}->[-3]) {
+ my @future; # find upcoming releases (after current)
+ for (reverse @$vercols) {
+ last if $_ eq $current;
+ push @future, pop @vers;
+ $_ eq 'u' and $_ = $vers[-1] for $future[-1]; # inherit latest value if unknown
+ }
+ splice @vers, -1, 0, @future; # move ahead to decrease precedence
+ }
+ $rank += $statspts->{$_} * 2**($div--) for reverse @vers;
+ }
+ }
+ return $rank;
+}
+
+sub saytitlecol {
+ my ($id) = @_;
+ my $row = $caniuse->{data}->{$id};
+
+ for ($row->{categories}) {
+ my $cell = $_ ? lc $_->[0] : '-';
+ $cell =~ s/ api$//; # trim unessential fluff in 'js api'
+ printf '<th title="%s">%s', join(' + ', @$_), $cell;
+ }
+
+ print '<td>', map {
+ sprintf('<a href="%s" onclick="%s">%s</a>',
+ "#$id",
+ sprintf("try { %s; return false } catch(err) { return true }",
+ "document.getElementById('$id').classList.toggle('target')",
+ ),
+ Entity($_),
+ );
+ } $row->{title};
+ print '<div class=aside>';
+ s/\.?$/./, print "<p>$_</p>" for map { ref $_ ? @$_ : $_ || () }
+ Entity($row->{description}),
+ map { s/\s*\n/\n<br>/g; $_ } $row->{notes};
+ printf 'Resources: %s.', join(', ', map {
+ sprintf '<a href="%s">%s</a>', EscapeHTML($_->{url}), $_->{title}
+ } @$_) for grep { @$_ } $row->{links} // ();
+ printf '<br>Parent feature: %s.', join(', ', map {
+ sprintf '<a href="%s">%s</a>', EscapeHTML("#$_"), $caniuse->{data}->{$_}->{title}
+ } $_) for $row->{parent} || ();
+ print '</div>';
+}
+
+sub saystatuscol {
+ my ($id) = @_;
+ my $row = $caniuse->{data}->{$id};
+
+ for ($row->{status}) {
+ my $cell = $_ // '-';
+ $cell = sprintf '<a href="%s">%s</a>', $_, $cell for $row->{spec} // ();
+ printf '<td title="%s" class="l %s">%s',
+ $caniuse->{statuses}->{$_}, $CSTATUS{$_} // '', $cell;
+ }
+}
+
+sub saybrowsercols {
+ my ($id, $browser) = @_;
+ my $feature = $caniuse->{data}->{$id};
+ my $data = $feature->{stats}->{$browser};
+ if (ref $data eq 'ARRAY') {
+ # special case for unsupported
+ my $release = $caniuse->{agents}->{$browser}->{verrelease};
+ $data = {
+ map { $_ => defined $release->{$_} ? 'u' : 'n' } keys %$release
+ };