+ ($v, my $patch) = split /_/, $v, 2;
+ if (defined $patch) {
+ $patch =~ s/_//g;
+ $v .= "_p$patch";
+ }
+
+ return $v;
+};
+
+my $insert_dot_at = sub {
+ my ($v, $pos, $all) = @_;
+
+ my ($int, $frac) = split /\./, $v, 2;
+ return $v unless defined $frac;
+
+ my @p;
+ push @p, $-[0] while $frac =~ /[0-9]/g;
+ my %digit = map { $_ => 1 } @p;
+
+ my $shift = 0;
+ for (my $i = $pos; $i < @p; $i += $pos) {
+ if ($digit{$i}) {
+ substr($frac, $i + $shift, 0) = '.';
+ ++$shift;
+ }
+ last unless $all;
+ }
+
+ "$int.$frac";
+};
+
+my $insert_dot_at_1 = sub { $insert_dot_at->($_[0], 1, 0) },
+my $insert_dot_at_all_1 = sub { $insert_dot_at->($_[0], 1, 1) },
+my $insert_dot_at_2 = sub { $insert_dot_at->($_[0], 2, 0) },
+my $insert_dot_at_all_2 = sub { $insert_dot_at->($_[0], 2, 1) },
+my $insert_dot_at_all_3 = sub { $insert_dot_at->($_[0], 3, 1) },
+
+my $pad_decimals_to = sub {
+ my ($v, $n) = @_;
+
+ my ($int, $frac) = split /\./, $v, 2;
+ return $v unless defined $v;
+
+ my $l = length $frac;
+ if ($l < $n) {
+ $frac .= '0' x ($n - $l);
+ }
+
+ "$int.$frac";
+};
+
+my $pad_decimals_to_2 = sub { $pad_decimals_to->($_[0], 2) };
+my $pad_decimals_to_4 = sub { $pad_decimals_to->($_[0], 4) };
+
+my $correct_suffixes = sub {
+ my ($v) = @_;
+
+ $v = $default_mapping->($v);
+ $v =~ s/(?<!_)((?:alpha|beta|pre|rc|p)\d*)\b/_$1/g;