diff --git a/challenge-313/jo-37/blog.txt b/challenge-313/jo-37/blog.txt
new file mode 100644
index 0000000000..eb7adbdb33
--- /dev/null
+++ b/challenge-313/jo-37/blog.txt
@@ -0,0 +1 @@
+https://github.sommrey.de/the-bears-den/2025/03/21/ch-313.html
diff --git a/challenge-313/jo-37/perl/ch-1.pl b/challenge-313/jo-37/perl/ch-1.pl
new file mode 100755
index 0000000000..5b0aa1117d
--- /dev/null
+++ b/challenge-313/jo-37/perl/ch-1.pl
@@ -0,0 +1,93 @@
+#!/usr/bin/perl
+
+use v5.26;
+use Test2::V0 -no_srand;
+use Test2::Tools::Subtest 'subtest_streamed';
+use Getopt::Long;
+use experimental 'signatures';
+
+### Options and Arguments
+
+my ($tests, $examples, $verbose);
+GetOptions(
+    'examples!' => \$examples,
+    'tests!'    => \$tests,
+    'verbose!'  => \$verbose,
+) or usage();
+
+run_tests($examples, $tests);	# tests do not return
+
+usage() unless @ARGV == 2;
+
+sub usage {
+    die <<~EOS;
+    $0 - check broken keys
+
+    usage: $0 [-examples] [-tests] [--] [NAME TYPED]
+
+    -examples
+        run the examples from the challenge
+     
+    -tests
+        run some tests
+
+    NAME
+        the original string
+
+    TYPED
+        the typed string
+
+    EOS
+}
+
+
+### Input and Output
+
+say +(qw(true false))[!broken_keys(@ARGV)];
+
+
+### Implementation
+#
+# For details see:
+# https://github.sommrey.de/the-bears-den/2025/03/21/ch-313.html#task-1
+
+
+sub broken_keys ($name, $typed) {
+    $typed =~ /^(??{$name =~ s#.#\Q$&\E+#gr})$/;
+}
+
+
+### Examples and Tests
+
+sub run_tests ($examples, $tests) {
+    return unless $examples || $tests;
+
+    state sub run_example ($args, $expected, $name) {
+        my $result = broken_keys(@$args);
+        is $result, $expected,
+            "$name: (@$args) -> " . $expected->name;
+    }
+
+    plan 2;
+
+    $examples ? subtest_streamed(examples => sub {
+        my @examples = (
+            [['perl', 'perrrl'], T(), 'example 1'],
+            [['raku', 'rrakuuuu'], T(), 'example 2'],
+            [['python', 'perl'], F(), 'example 3'],
+            [['coffeescript', 'cofffeescccript'], T(), 'example 4'],
+        );
+        plan scalar @examples;
+        for (@examples) {
+            run_example @$_;
+        }
+    }) : pass 'skip examples';
+
+    $tests ? subtest_streamed(tests => sub {
+        plan 2;
+        is broken_keys('.', 'abc'), F(), 'ignore regex meta';
+        is broken_keys('+*', '++**'), T(), 'match regex meta';
+    }) : pass 'skip tests';
+
+    exit;
+}
diff --git a/challenge-313/jo-37/perl/ch-2.pl b/challenge-313/jo-37/perl/ch-2.pl
new file mode 100755
index 0000000000..cf73e74c6c
--- /dev/null
+++ b/challenge-313/jo-37/perl/ch-2.pl
@@ -0,0 +1,94 @@
+#!/usr/bin/perl
+
+use v5.26;
+use Test2::V0 -no_srand;
+use Test2::Tools::Subtest 'subtest_streamed';
+use Getopt::Long;
+use experimental 'signatures';
+
+use List::MoreUtils 'indexes';
+
+### Options and Arguments
+
+my ($tests, $examples, $verbose);
+GetOptions(
+    'examples!' => \$examples,
+    'tests!'    => \$tests,
+    'verbose!'  => \$verbose,
+) or usage();
+
+run_tests($examples, $tests);	# tests do not return
+
+usage() unless @ARGV == 1;
+
+sub usage {
+    die <<~EOS;
+    $0 - Task Title
+
+    usage: $0 [-examples] [-tests] [STR]
+
+    -examples
+        run the examples from the challenge
+     
+    -tests
+        run some tests
+
+    STR
+        a string
+
+    EOS
+}
+
+
+### Input and Output
+
+say reverse_letters(shift);
+
+
+### Implementation
+#
+# For details see:
+# https://github.sommrey.de/the-bears-den/2025/03/21/ch-313.html#task-2
+
+
+sub reverse_letters {
+    my @s = shift =~ /\X/g;
+    my @li = indexes {/\p{L}/} @s;
+    @s[@li] = @s[reverse @li];
+    join '', @s;
+}
+
+
+### Examples and Tests
+
+sub run_tests ($examples, $tests) {
+    return unless $examples || $tests;
+
+    state sub run_example ($args, $expected, $name) {
+        my $result = reverse_letters(@$args);
+        is $result, $expected,
+            "$name: (@$args) -> $expected";
+    }
+
+    plan 2;
+
+    $examples ? subtest_streamed(examples => sub {
+        my @examples = (
+            [["p-er?l"], "l-re?p", 'example 1'],
+            [["wee-k!L-y"], "yLk-e!e-w", 'example 2'],
+            [["_c-!h_all-en!g_e"], "_e-!g_nel-la!h_c", 'example 3'],
+        );
+        plan scalar @examples;
+        for (@examples) {
+            run_example @$_;
+        }
+    }) : pass 'skip examples';
+
+    $tests ? subtest_streamed(tests => sub {
+        plan 1;
+        is reverse_letters("a\N{COMBINING DIAERESIS},o&u"),
+            "u,o&a\N{COMBINING DIAERESIS}", 'operate on grapheme clusters';
+    }) : pass 'skip tests';
+
+    exit;
+}