aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad S Anwar <mohammad.anwar@yahoo.com>2024-03-04 17:24:02 +0000
committerMohammad S Anwar <mohammad.anwar@yahoo.com>2024-03-04 17:24:02 +0000
commit58d2a420a8de4551ea694c94ab1088cd795dad7d (patch)
treed9ef49892910b3051d7c084c93fec202bcb6647e
parent93e897d94b55160397eff52df0d0b59f1b00a861 (diff)
parent074cecb5fed0a7961ba5c5f4b2605676fe589f25 (diff)
downloadperlweeklychallenge-club-58d2a420a8de4551ea694c94ab1088cd795dad7d.tar.gz
perlweeklychallenge-club-58d2a420a8de4551ea694c94ab1088cd795dad7d.tar.bz2
perlweeklychallenge-club-58d2a420a8de4551ea694c94ab1088cd795dad7d.zip
Merge branch 'master' of https://github.com/manwar/perlweeklychallenge-club
-rwxr-xr-xchallenge-259/e-choroba/perl/ch-1.pl155
-rwxr-xr-xchallenge-259/e-choroba/perl/ch-2.pl109
-rw-r--r--challenge-259/luca-ferrari/blog-1.txt1
-rw-r--r--challenge-259/luca-ferrari/blog-10.txt1
-rw-r--r--challenge-259/luca-ferrari/blog-2.txt1
-rw-r--r--challenge-259/luca-ferrari/blog-3.txt1
-rw-r--r--challenge-259/luca-ferrari/blog-4.txt1
-rw-r--r--challenge-259/luca-ferrari/blog-5.txt1
-rw-r--r--challenge-259/luca-ferrari/blog-6.txt1
-rw-r--r--challenge-259/luca-ferrari/blog-7.txt1
-rw-r--r--challenge-259/luca-ferrari/blog-8.txt1
-rw-r--r--challenge-259/luca-ferrari/blog-9.txt1
-rw-r--r--challenge-259/luca-ferrari/pljava/pom.xml6
-rw-r--r--challenge-259/luca-ferrari/pljava/src/main/java/Task1.java73
-rw-r--r--challenge-259/luca-ferrari/pljava/src/main/java/Task2.java107
-rw-r--r--challenge-259/luca-ferrari/plperl/ch-1.plperl41
-rw-r--r--challenge-259/luca-ferrari/plperl/ch-2.plperl58
-rw-r--r--challenge-259/luca-ferrari/plpgsql/ch-1.sql36
-rw-r--r--challenge-259/luca-ferrari/plpgsql/ch-2.sql15
-rw-r--r--challenge-259/luca-ferrari/python/ch-1.py37
-rw-r--r--challenge-259/luca-ferrari/python/ch-2.py69
-rw-r--r--challenge-259/luca-ferrari/raku/ch-1.raku36
-rw-r--r--challenge-259/luca-ferrari/raku/ch-2.raku45
-rw-r--r--challenge-259/zapwai/c/259.txt8
-rw-r--r--challenge-259/zapwai/c/ch-1.c123
-rw-r--r--challenge-259/zapwai/c/ch-2.c140
-rw-r--r--challenge-259/zapwai/javascript/ch-1.js134
-rw-r--r--challenge-259/zapwai/javascript/ch-2.js100
-rw-r--r--challenge-259/zapwai/perl/ch-1.pl65
-rw-r--r--challenge-259/zapwai/perl/ch-2.pl67
-rw-r--r--challenge-259/zapwai/python/ch-1.py72
-rw-r--r--challenge-259/zapwai/python/ch-2.py38
-rw-r--r--challenge-259/zapwai/rust/259.txt8
-rw-r--r--challenge-259/zapwai/rust/ch-1.rs111
-rw-r--r--challenge-259/zapwai/rust/ch-2.rs106
35 files changed, 1766 insertions, 3 deletions
diff --git a/challenge-259/e-choroba/perl/ch-1.pl b/challenge-259/e-choroba/perl/ch-1.pl
new file mode 100755
index 0000000000..ec52ff9e59
--- /dev/null
+++ b/challenge-259/e-choroba/perl/ch-1.pl
@@ -0,0 +1,155 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+use experimental qw{ signatures };
+
+use Time::Piece ();
+use Time::Seconds qw( ONE_DAY );
+
+use constant DATE_FORMAT => '%Y-%m-%d';
+
+sub banking_day_offset($start, $offset, $holidays=[]) {
+ my %H;
+ @H{@$holidays} = ();
+ my $tp = 'Time::Piece'->strptime($start, DATE_FORMAT);
+ my $add = 0;
+ # Start date is weekend, move to Monday.
+ $add += $tp->wday % 5 if $tp->wday % 6 == 1;
+
+ # How many weeks to move forward.
+ $add += 7 * int($offset / 5);
+
+ # Remaining non-week days.
+ $add += $offset % 5;
+
+ # Add a weekend if we went over it in the remaining non-week days.
+ $add += 2 if 1 != $tp->wday % 6 && $tp->wday + $offset % 5 > 6;
+
+ my $date = $tp + ONE_DAY * $add;
+
+ # Now handle the holidays.
+ for my $h (sort keys %H) {
+ my $holiday = 'Time::Piece'->strptime($h, DATE_FORMAT);
+ next if $holiday < $tp || $holiday->wday % 6 == 1;
+ if ($holiday <= $date) {
+ $date += ONE_DAY;
+ $date += 2 * ONE_DAY if $date->wday == 7;
+ }
+ }
+
+ # We might still land on a weekend or holiday.
+ $date += ONE_DAY while $date->wday % 6 == 1
+ || exists $H{ $date->strftime(DATE_FORMAT) };
+
+ return $date->strftime(DATE_FORMAT)
+}
+
+sub banking_day_offset_slow($start, $offset, $holidays=[]) {
+ my %H;
+ @H{@$holidays} = ();
+ my $tp = 'Time::Piece'->strptime($start, DATE_FORMAT);
+ $tp += ONE_DAY while $tp->wday % 6 == 1
+ || exists $H{ $tp->strftime(DATE_FORMAT) };
+ for (1 .. $offset) {
+ $tp += ONE_DAY;
+ $tp += ONE_DAY while $tp->wday % 6 == 1
+ || exists $H{ $tp->strftime(DATE_FORMAT) };
+ }
+ return $tp->strftime(DATE_FORMAT)
+}
+
+use Test::More tests => 2 + 1;
+
+my %DISPATCH = (slow => \&banking_day_offset_slow,
+ fast => \&banking_day_offset);
+
+for my $how (qw( slow fast )) {
+ my $banking_day_offset = $DISPATCH{$how};
+
+ subtest $how => sub {
+ is $banking_day_offset->('2018-06-28', 3, ['2018-07-03']),
+ '2018-07-04',
+ 'Example 1';
+
+ is $banking_day_offset->('2018-06-28', 3),
+ '2018-07-03',
+ 'Example 2';
+
+ is $banking_day_offset->('2018-06-28', 2, ['2018-07-02', '2018-07-03']),
+ '2018-07-04',
+ 'Land in the middle of holidays';
+
+ is $banking_day_offset->('2018-06-28', 2, ['2018-07-01', '2018-06-30']),
+ '2018-07-02',
+ 'Holidays on a weekend';
+
+ is $banking_day_offset->('2024-01-01', 262),
+ '2025-01-01',
+ 'Whole year';
+
+ is $banking_day_offset->('2018-06-28', 101, [qw[ 2018-11-16 2018-11-19]]),
+ '2018-11-20',
+ 'Holidays wrap a weekend';
+
+ is $banking_day_offset->('2012-05-22', 161, ['2012-05-22']),
+ '2013-01-03',
+ 'Start on a holiday';
+ }, 2 + 5;
+}
+
+use Benchmark qw{ cmpthese };
+
+my $start = '2003-04-20';
+my $offset = 731;
+my @h = qw[ 2001-10-08 2005-02-20 2000-01-07 2003-09-26 2000-08-14
+ 2008-09-22 2003-05-10 2004-05-12 2004-10-12 2008-06-12
+ 2003-06-15 2003-09-20 2006-08-01 2009-02-18 2006-07-11
+ 2008-04-01 2003-10-03 2008-08-07 2008-11-17 2009-02-03
+ 2004-08-18 2005-04-23 2003-08-15 2007-03-22 2004-11-07
+ 2004-08-13 2008-09-04 2003-06-27 2006-07-12 2003-11-06
+ 2000-01-30 2006-11-26 2004-07-05 2007-03-07 2000-12-11
+ 2001-01-17 2007-01-18 2002-05-01 2000-01-06 2000-03-03
+ 2005-09-05 2001-01-03 2005-06-02 2003-08-15 2002-09-13
+ 2006-07-15 2005-06-22 2001-10-27 2005-07-14 2004-09-19
+ 2008-02-10 2003-05-10 2007-08-11 2000-02-05 2002-01-25
+ 2002-03-28 2003-07-26 2007-08-13 2002-03-21 2003-03-09
+ 2006-03-11 2004-03-05 2004-05-08 2006-09-24 2000-10-03
+ 2001-12-19 2003-02-26 2005-10-06 2001-08-23 2004-09-25
+ 2009-12-20 2004-10-10 2005-08-15 2001-11-25 2002-03-11
+ 2007-10-22 2000-10-30 2009-04-14 2009-10-30 2004-09-01
+ 2004-04-11 2000-04-04 2003-11-14 2004-11-16 2001-06-28
+ 2008-11-18 2009-11-16 2006-01-27 2007-08-06 2009-09-14
+ 2000-10-25 2001-09-14 2000-09-17 2007-01-07 2005-02-05
+ 2000-09-20 2002-02-01 2003-05-08 2002-06-03 2006-12-02
+ 2009-08-15 2008-11-22 2002-12-23 2002-06-08 2003-09-27
+ 2004-10-08 2007-12-16 2005-12-19 2003-05-15 2007-10-30
+ 2006-11-13 2005-12-04 2006-09-06 2005-05-08 2007-10-23
+ 2006-05-31 2005-01-16 2009-02-15 2000-05-08 2002-04-13
+ 2000-07-11 2005-05-25 2004-07-03 2007-12-03 2008-07-19
+ 2009-08-27 2004-08-27 2002-03-14 2007-03-29 2005-02-03
+ 2004-10-30 2000-07-14 2004-01-27 2004-12-18 2004-12-08
+ 2005-11-23 2008-04-18 2000-03-06 2009-05-31 2002-08-13
+ 2000-12-25 2008-09-17 2004-06-10 2003-04-29 2003-04-28
+ 2000-04-30 2005-04-18 2003-08-01 2000-05-22 2009-03-18
+ 2002-08-08 2008-11-15 2006-03-17 2003-07-17 2006-10-02
+ 2007-01-17 2009-09-04 2000-04-22 2007-04-23 2006-01-08
+ 2003-08-01 2003-08-11 2003-02-10 2007-04-08 2003-02-26
+ 2002-05-16 2002-11-04 2004-01-07 2001-09-28 2001-11-29
+ 2002-03-19 2009-10-08 2002-08-25 2004-08-22 2003-06-23
+ 2001-05-23 2000-12-02 2000-04-26 2000-05-25 2006-05-15
+ 2006-08-18 2009-12-26 2008-07-31 2009-10-02 2002-07-19
+ 2006-08-01 2000-06-09 2006-04-10 ];
+
+is banking_day_offset($start, $offset, [@h]),
+ banking_day_offset_slow($start, $offset, [@h]),
+ 'long';
+
+cmpthese(-3, {
+ slow => sub { banking_day_offset_slow($start, $offset, [@h]) },
+ fast => sub { banking_day_offset($start, $offset, [@h]) },
+})
+
+__END__
+ Rate slow fast
+slow 84.1/s -- -80%
+fast 431/s 412% --
diff --git a/challenge-259/e-choroba/perl/ch-2.pl b/challenge-259/e-choroba/perl/ch-2.pl
new file mode 100755
index 0000000000..cb76a4af8f
--- /dev/null
+++ b/challenge-259/e-choroba/perl/ch-2.pl
@@ -0,0 +1,109 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+
+use Marpa::R2 ();
+
+my $dsl = << '__DSL__';
+lexeme default = latm => 1
+:default ::= action => ::first
+
+BonusStruct ::= Struct
+ | Struct (nl) Lines (End) action => bonus
+End ::= (begin ws) (Endid) (ws end) action => []
+Endid ::= ('end') Id action => check_id
+Struct ::= (begin) (ws) Id (ws) Fields (ws) (end) action => struct
+Id ::= word
+Lines ::= char Lines action => concat
+ | char
+Fields ::= Field (ws) Fields action => merge
+ | Field
+Field ::= Name (eq) Value action => name_val
+Name ::= word
+Value ::= Number
+ | (qq) Quoted (qq)
+Number ::= digit
+ | nonz Digits action => concat
+Digits ::= digit Digits action => concat
+ | digit
+Quoted ::= Char Quoted action => concat
+ | Char
+Char ::= bs action => bs
+ | dq action => dq
+ || char
+
+begin ~ '{%'
+end ~ '%}'
+qq ~ '"'
+word ~ [\w]+
+bs ~ '\\'
+dq ~ '\"'
+char ~ [\s\S]
+eq ~ '='
+digit ~ [0-9]
+nonz ~ [1-9]
+ws ~ [\s]+
+nl ~ [\n]
+__DSL__
+
+sub concat { $_[1] . $_[2] }
+sub name_val { +{$_[1] => $_[2]} }
+sub merge { +{%{ $_[1] }, %{ $_[2] }} }
+sub struct { $_[0] = $_[1]; {name => $_[1], fields => $_[2]} }
+sub bonus { +{%{ $_[1] }, text => $_[2]} }
+sub check_id { $_[0] eq $_[1] or die "Invalid id" }
+sub bs { '\\' }
+sub dq { '"' }
+
+my $grammar = 'Marpa::R2::Scanless::G'->new({source => \$dsl});
+use experimental qw{ signatures };
+sub line_parser($input) {
+ my $value_ref = $grammar->parse(\$input, 'main');
+ return $$value_ref
+}
+
+use Test2::V0;
+plan 5;
+
+is line_parser('{% id field1="value1" field2="value2" field3=42 %}'),
+ {
+ name => 'id',
+ fields => {
+ field1 => 'value1',
+ field2 => 'value2',
+ field3 => 42,
+ }
+ }, 'Example 1';
+
+is line_parser('{% youtube title="Title \"quoted\" done" %}'),
+ { name => 'youtube', fields => {title => 'Title "quoted" done'}},
+ 'Double quotes';
+
+is line_parser('{% youtube title="Title with escaped backslash \\\\" %}'),
+ {
+ name => 'youtube',
+ fields => {
+ title => 'Title with escaped backslash \\'
+ }
+ },
+ 'Backslash';
+
+is line_parser('{% id filed1="value1" %}
+LINES
+{% endid %}'),
+ {
+ name => 'id',
+ fields => {
+ filed1 => 'value1'
+ },
+ text => "LINES\n"
+ },
+ 'bonus';
+
+my $e = dies {
+ line_parser(join "\n",
+ '{% id filed1="value1" %}',
+ 'LINES',
+ '{% endOTHERID %}'
+ ) };
+like $e, qr/Invalid id/, 'Fails';
diff --git a/challenge-259/luca-ferrari/blog-1.txt b/challenge-259/luca-ferrari/blog-1.txt
new file mode 100644
index 0000000000..f59eee9b34
--- /dev/null
+++ b/challenge-259/luca-ferrari/blog-1.txt
@@ -0,0 +1 @@
+https://fluca1978.github.io/2024/03/04/PerlWeeklyChallenge259.html#task1
diff --git a/challenge-259/luca-ferrari/blog-10.txt b/challenge-259/luca-ferrari/blog-10.txt
new file mode 100644
index 0000000000..3a8f05e0f8
--- /dev/null
+++ b/challenge-259/luca-ferrari/blog-10.txt
@@ -0,0 +1 @@
+https://fluca1978.github.io/[= date -%]/PerlWeeklyChallenge259.html#task2pljava
diff --git a/challenge-259/luca-ferrari/blog-2.txt b/challenge-259/luca-ferrari/blog-2.txt
new file mode 100644
index 0000000000..9fa1af6ea8
--- /dev/null
+++ b/challenge-259/luca-ferrari/blog-2.txt
@@ -0,0 +1 @@
+https://fluca1978.github.io/2024/03/04/PerlWeeklyChallenge259.html#task2
diff --git a/challenge-259/luca-ferrari/blog-3.txt b/challenge-259/luca-ferrari/blog-3.txt
new file mode 100644
index 0000000000..26ad2f3825
--- /dev/null
+++ b/challenge-259/luca-ferrari/blog-3.txt
@@ -0,0 +1 @@
+https://fluca1978.github.io/2024/03/04/PerlWeeklyChallenge259.html#task1plperl
diff --git a/challenge-259/luca-ferrari/blog-4.txt b/challenge-259/luca-ferrari/blog-4.txt
new file mode 100644
index 0000000000..a1c1a8df1d
--- /dev/null
+++ b/challenge-259/luca-ferrari/blog-4.txt
@@ -0,0 +1 @@
+https://fluca1978.github.io/2024/03/04/PerlWeeklyChallenge259.html#task2plperl
diff --git a/challenge-259/luca-ferrari/blog-5.txt b/challenge-259/luca-ferrari/blog-5.txt
new file mode 100644
index 0000000000..8f99d56a78
--- /dev/null
+++ b/challenge-259/luca-ferrari/blog-5.txt
@@ -0,0 +1 @@
+https://fluca1978.github.io/2024/03/04/PerlWeeklyChallenge259.html#task1plpgsql
diff --git a/challenge-259/luca-ferrari/blog-6.txt b/challenge-259/luca-ferrari/blog-6.txt
new file mode 100644
index 0000000000..2956e4b204
--- /dev/null
+++ b/challenge-259/luca-ferrari/blog-6.txt
@@ -0,0 +1 @@
+https://fluca1978.github.io/2024/03/04/PerlWeeklyChallenge259.html#task2plpgsql
diff --git a/challenge-259/luca-ferrari/blog-7.txt b/challenge-259/luca-ferrari/blog-7.txt
new file mode 100644
index 0000000000..ae78544493
--- /dev/null
+++ b/challenge-259/luca-ferrari/blog-7.txt
@@ -0,0 +1 @@
+https://fluca1978.github.io/2024/03/04/PerlWeeklyChallenge259.html#task1python
diff --git a/challenge-259/luca-ferrari/blog-8.txt b/challenge-259/luca-ferrari/blog-8.txt
new file mode 100644
index 0000000000..0374c2d0a7
--- /dev/null
+++ b/challenge-259/luca-ferrari/blog-8.txt
@@ -0,0 +1 @@
+https://fluca1978.github.io/2024/03/04/PerlWeeklyChallenge259.html#task2python
diff --git a/challenge-259/luca-ferrari/blog-9.txt b/challenge-259/luca-ferrari/blog-9.txt
new file mode 100644
index 0000000000..7521039415
--- /dev/null
+++ b/challenge-259/luca-ferrari/blog-9.txt
@@ -0,0 +1 @@
+https://fluca1978.github.io/2024/03/04/PerlWeeklyChallenge259.html#task1pljava
diff --git a/challenge-259/luca-ferrari/pljava/pom.xml b/challenge-259/luca-ferrari/pljava/pom.xml
index 1a0d8dbf4d..30b7a337f3 100644
--- a/challenge-259/luca-ferrari/pljava/pom.xml
+++ b/challenge-259/luca-ferrari/pljava/pom.xml
@@ -5,11 +5,11 @@
<modelVersion>4.0.0</modelVersion>
<groupId>PWC</groupId>
- <artifactId>PWC258</artifactId>
+ <artifactId>PWC259</artifactId>
<version>1</version>
- <name>Perl Weekly Challenge 258</name>
- <description>Implementation of the tasks in PL/Java for PWC 258</description>
+ <name>Perl Weekly Challenge 259</name>
+ <description>Implementation of the tasks in PL/Java for PWC 259</description>
<properties>
<project.build.sourceEncoding>US-ASCII</project.build.sourceEncoding>
diff --git a/challenge-259/luca-ferrari/pljava/src/main/java/Task1.java b/challenge-259/luca-ferrari/pljava/src/main/java/Task1.java
new file mode 100644
index 0000000000..de464e56c0
--- /dev/null
+++ b/challenge-259/luca-ferrari/pljava/src/main/java/Task1.java
@@ -0,0 +1,73 @@
+
+
+
+package PWC259;
+
+/**
+ * PL/Java implementation for PWC 259
+ * Task 1
+ * See <https://perlweeklychallenge.org/blog/perl-weekly-challenge-259>
+ *
+ *
+ * To compile on the local machine:
+
+ $ export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64/ # if not already set
+ $ mvn clean build
+ $ scp target/PWC259-1.jar luca@rachel:/tmp
+
+
+ * To install into PostgreSQL execute:
+
+ select sqlj.install_jar( 'file:///tmp/PWC259-1.jar', 'PWC259', true );
+
+ select pwc259.task2_pljava();
+
+ and then to redeploy:
+
+ select sqlj.replace_jar( 'file:///tmp/PWC259-1.jar', 'PWC259', true );
+
+*/
+
+import org.postgresql.pljava.*;
+import org.postgresql.pljava.annotation.Function;
+import static org.postgresql.pljava.annotation.Function.Effects.IMMUTABLE;
+import static org.postgresql.pljava.annotation.Function.OnNullInput.RETURNS_NULL;
+
+import java.util.*;
+import java.util.stream.*;
+import java.sql.SQLException;
+import java.util.logging.*;
+import java.sql.ResultSet;
+import java.sql.Date;
+
+public class Task1 {
+
+ private final static Logger logger = Logger.getAnonymousLogger();
+
+ @Function( schema = "pwc259",
+ onNullInput = RETURNS_NULL,
+ effects = IMMUTABLE )
+ public static final java.sql.Date task1_pljava( Date startDay, int how_many, Date[] holidays ) throws SQLException {
+ logger.log( Level.INFO, "Entering pwc259.task1_pljava" );
+
+ Calendar day = Calendar.getInstance();
+ day.setTime( startDay );
+
+ while ( how_many > 0 ) {
+ day.add( Calendar.DAY_OF_YEAR, 1 );
+
+ while ( day.get( Calendar.DAY_OF_MONTH ) == Calendar.SUNDAY
+ || day.get( Calendar.DAY_OF_MONTH ) == Calendar.SATURDAY )
+ day.add( Calendar.DAY_OF_YEAR, 1 );
+
+ if ( holidays != null )
+ for ( Date skip : holidays )
+ if ( skip.equals( day.getTime() ) )
+ day.add( Calendar.DAY_OF_YEAR, 1 );
+
+ how_many--;
+ }
+
+ return new java.sql.Date( day.getTimeInMillis() );
+ }
+}
diff --git a/challenge-259/luca-ferrari/pljava/src/main/java/Task2.java b/challenge-259/luca-ferrari/pljava/src/main/java/Task2.java
new file mode 100644
index 0000000000..1a33f13bea
--- /dev/null
+++ b/challenge-259/luca-ferrari/pljava/src/main/java/Task2.java
@@ -0,0 +1,107 @@
+
+
+
+package PWC259;
+
+/**
+ * PL/Java implementation for PWC 259
+ * Task 2
+ * See <https://perlweeklychallenge.org/blog/perl-weekly-challenge-259>
+ *
+ *
+ * To compile on the local machine:
+
+ $ export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64/ # if not already set
+ $ mvn clean build
+ $ scp target/PWC259-1.jar luca@rachel:/tmp
+
+
+ * To install into PostgreSQL execute:
+
+ select sqlj.install_jar( 'file:///tmp/PWC259-1.jar', 'PWC259', true );
+
+ select pwc259.task2_pljava();
+
+ and then to redeploy:
+
+ select sqlj.replace_jar( 'file:///tmp/PWC259-1.jar', 'PWC259', true );
+
+*/
+
+import org.postgresql.pljava.*;
+import org.postgresql.pljava.annotation.Function;
+import static org.postgresql.pljava.annotation.Function.Effects.IMMUTABLE;
+import static org.postgresql.pljava.annotation.Function.OnNullInput.RETURNS_NULL;
+
+import java.util.*;
+import java.util.regex.*;
+import java.util.stream.*;
+import java.sql.SQLException;
+import java.util.logging.*;
+import java.sql.ResultSet;
+import java.sql.Date;
+
+public class Task2 implements ResultSetProvider {
+
+ private final static Logger logger = Logger.getAnonymousLogger();
+
+ @Function( schema = "pwc259",
+ onNullInput = RETURNS_NULL,
+ effects = IMMUTABLE )
+ public static final ResultSetProvider task2_pljava( String line ) throws SQLException {
+ logger.log( Level.INFO, "Entering pwc259.task2_pljava : " + line );
+ return new Task2( line );
+ }
+
+
+ public Task2( String line ) throws SQLException {
+ params = new LinkedList< List<String> >();
+ parse( line );
+ }
+
+
+ private final void parse( String line ) throws SQLException {
+ Pattern pattern = Pattern.compile( "[{][%] (\\w+)\\s*(.*)\\s* [%][}]" );
+ Matcher matcher = pattern.matcher( line );
+
+ if ( matcher.find() ) {
+ id = matcher.group( 1 );
+
+ Pattern subPattern = Pattern.compile( "(\\w+)[=](\\w+)\\s*" );
+ Matcher subMatch = subPattern.matcher( matcher.group( 2 ) );
+
+ while ( subMatch.find() ) {
+ List<String> current = new LinkedList<String>();
+ current.add( subMatch.group( 1 ) );
+ current.add( subMatch.group( 2 ) );
+ params.add( current );
+
+ }
+ }
+ else
+ throw new SQLException( "Cannot parse " + line );
+
+ }
+
+ private List< List<String> > params;
+ private String id;
+
+ @Override
+ public boolean assignRowValues(ResultSet rs, int row)
+ throws SQLException {
+
+ // stop the result set
+ if ( row >= params.size() )
+ return false;
+
+ rs.updateInt( 1, row );
+ rs.updateString( 2, id );
+ rs.updateString( 3, params.get( row ).get( 0 ) );
+ rs.updateString( 4, params.get( row ).get( 1 ) );
+ return true;
+ }
+
+ @Override
+ public void close() {
+ }
+}
diff --git a/challenge-259/luca-ferrari/plperl/ch-1.plperl b/challenge-259/luca-ferrari/plperl/ch-1.plperl
new file mode 100644
index 0000000000..bd7a6e6a27
--- /dev/null
+++ b/challenge-259/luca-ferrari/plperl/ch-1.plperl
@@ -0,0 +1,41 @@
+--
+-- Perl Weekly Challenge 259
+-- Task 1
+-- See <https://perlweeklychallenge.org/blog/perl-weekly-challenge-259>
+--
+
+CREATE SCHEMA IF NOT EXISTS pwc259;
+
+CREATE OR REPLACE FUNCTION
+pwc259.task1_plperl( date, int, date[] )
+RETURNS date
+AS $CODE$
+
+use DateTime;
+
+ my ( $when, $offset, $holidays ) = @_;
+
+ $when =~ / ^ (?<year>\d{4}) [-] (?<month>\d{2}) [-] (?<day>\d{2}) $ /x;
+
+ my $day = DateTime->new( year => $+{ year}, month => $+{ month }, day => $+{ day } );
+
+ while ( $offset > 0 ) {
+ $day->add( days => 1 );
+ $offset--;
+
+ # skip weekends
+ while ( $day->day_of_week == 6 || $day->day_of_week == 7 ) {
+ $day->add( days => 1 );
+ }
+
+ if ( $holidays->@* ) {
+ while( grep { $_ eq $day->ymd } $holidays->@* ) {
+ $day->add( days => 1 );
+ }
+ }
+ }
+
+ return $day->ymd;
+
+$CODE$
+LANGUAGE plperlu;
diff --git a/challenge-259/luca-ferrari/plperl/ch-2.plperl b/challenge-259/luca-ferrari/plperl/ch-2.plperl
new file mode 100644
index 0000000000..b3500be853
--- /dev/null
+++ b/challenge-259/luca-ferrari/plperl/ch-2.plperl
@@ -0,0 +1,58 @@
+--
+-- Perl Weekly Challenge 259
+-- Task 2
+-- See <https://perlweeklychallenge.org/blog/perl-weekly-challenge-259>
+--
+
+CREATE SCHEMA IF NOT EXISTS pwc259;
+
+CREATE OR REPLACE FUNCTION
+pwc259.task2_plperl( text)
+RETURNS TABLE( id text, field_name text, field_value text )
+AS $CODE$
+
+ my ( $line ) = @_;
+
+ if ( $line =~ / ^ [{] [%] \s* (?<id>\w+) \s* (?<options>.*) \s* [%] [}] $ /x ) {
+ my $id = $+{ id };
+ my ( $name, $value ) = ( '', '' );
+ if ( $+{ options } ) {
+ my $is_value = 0;
+ my $allowed_spaces = 0;
+ my $previous = '';
+
+ for ( split //, $+{ options } ) {
+
+
+ $is_value = 1 and $previous = $_ and next if ( $_ eq '=' );
+ $allowed_spaces = 1 and $previous = $_ and next if ( $_ eq '"' and $previous eq '=' );
+
+ $name .= $_ if ( ! $is_value );
+ $value .= $_ if ( $is_value );
+
+ if ( $is_value
+ && ( ( $_ eq ' ' && ! $allowed_spaces )
+ || ( $_ eq '"' && $previous ne '\\' && $allowed_spaces ) )
+ ) {
+ # stop here!
+ $value =~ s/^\s*|\s*$//g;
+ $value =~ s/^["]|["]$//g;
+ $value =~ s/\\"/"/g;
+ return_next( { id => $id ,
+ field_name => $name,
+ field_value => $value } );
+
+ ( $name, $value, $is_value, $allowed_spaces ) = ( '', '', 0, 0 );
+ }
+
+ $previous = $_;
+ }
+
+
+ }
+ }
+
+ return undef;
+
+$CODE$
+LANGUAGE plperl;
diff --git a/challenge-259/luca-ferrari/plpgsql/ch-1.sql b/challenge-259/luca-ferrari/plpgsql/ch-1.sql
new file mode 100644
index 0000000000..4b8f2eff5a
--- /dev/null
+++ b/challenge-259/luca-ferrari/plpgsql/ch-1.sql
@@ -0,0 +1,36 @@
+--
+-- Perl Weekly Challenge 259
+-- Task 1
+-- See <https://perlweeklychallenge.org/blog/perl-weekly-challenge-259>
+--
+
+CREATE SCHEMA IF NOT EXISTS pwc259;
+
+CREATE OR REPLACE FUNCTION
+pwc259.task1_plpgsql( day date, how_many_days int, holidays date[] )
+RETURNS date
+AS $CODE$
+DECLARE
+ current_holiday date;
+BEGIN
+
+ WHILE how_many_days > 0 LOOP
+ day := day + 1;
+
+ WHILE extract( dow from day ) IN ( 0, 6 ) LOOP
+ day := day + 1;
+ END LOOP;
+
+ FOREACH current_holiday IN ARRAY holidays LOOP
+ IF current_holiday = day THEN
+ day := day + 1;
+ END IF;
+ END LOOP;
+
+ how_many_days := how_many_days - 1;
+ END LOOP;
+
+ RETURN day;
+END
+$CODE$
+LANGUAGE plpgsql;
diff --git a/challenge-259/luca-ferrari/plpgsql/ch-2.sql b/challenge-259/luca-ferrari/plpgsql/ch-2.sql
new file mode 100644
index 0000000000..15c2f30024
--- /dev/null
+++ b/challenge-259/luca-ferrari/plpgsql/ch-2.sql
@@ -0,0 +1,15 @@
+--
+-- Perl Weekly Challenge 259
+-- Task 2
+-- See <https://perlweeklychallenge.org/blog/perl-weekly-challenge-259>
+--
+
+CREATE SCHEMA IF NOT EXISTS pwc259;
+
+CREATE OR REPLACE FUNCTION
+pwc259.task2_plpgsql( line text )
+RETURNS TABLE( id text, field_name text, field_value text )
+AS $CODE$
+ SELECT pwc259.task2_plperl( line );
+$CODE$
+LANGUAGE sql;
diff --git a/challenge-259/luca-ferrari/python/ch-1.py b/challenge-259/luca-ferrari/python/ch-1.py
new file mode 100644
index 0000000000..9b3a0fd121
--- /dev/null
+++ b/challenge-259/luca-ferrari/python/ch-1.py
@@ -0,0 +1,37 @@
+#!python
+
+#
+# Perl Weekly Challenge 259
+# Task 1
+#
+# See <https://perlweeklychallenge.org/blog/perl-weekly-challenge-259>
+#
+
+import sys
+from datetime import date, timedelta
+
+# task implementation
+# the return value will be printed
+def task_1( args ):
+ day = date.fromisoformat( args[ 0 ] )
+ offset = int( args[ 1 ] )
+ holidays = list( map( lambda x: date.fromisoformat( x ), args[ 2: ] ) )
+ one_day = timedelta( days=1 )
+</