From feb6da8db91b6ceaac61d703fb2d392aae8d77d7 Mon Sep 17 00:00:00 2001 From: Joseph Southan Date: Mon, 4 May 2020 16:18:46 +0100 Subject: [PATCH 1/7] Remove bundled calendars --- lib/business/calendar.rb | 5 +- lib/business/data/achus.yml | 58 ------- lib/business/data/bacs.yml | 129 --------------- lib/business/data/bankgirot.yml | 208 ------------------------- lib/business/data/becs.yml | 36 ----- lib/business/data/becsnz.yml | 50 ------ lib/business/data/betalingsservice.yml | 56 ------- lib/business/data/padca.yml | 35 ----- lib/business/data/target.yml | 101 ------------ lib/business/data/targetfrance.yml | 130 ---------------- lib/business/data/weekdays.yml | 6 - spec/calendar_spec.rb | 33 +--- 12 files changed, 6 insertions(+), 841 deletions(-) delete mode 100644 lib/business/data/achus.yml delete mode 100644 lib/business/data/bacs.yml delete mode 100644 lib/business/data/bankgirot.yml delete mode 100644 lib/business/data/becs.yml delete mode 100644 lib/business/data/becsnz.yml delete mode 100644 lib/business/data/betalingsservice.yml delete mode 100644 lib/business/data/padca.yml delete mode 100644 lib/business/data/target.yml delete mode 100644 lib/business/data/targetfrance.yml delete mode 100644 lib/business/data/weekdays.yml diff --git a/lib/business/calendar.rb b/lib/business/calendar.rb index 4dc1c70..c45aa5d 100644 --- a/lib/business/calendar.rb +++ b/lib/business/calendar.rb @@ -3,12 +3,11 @@ module Business class Calendar class << self - attr_accessor :additional_load_paths + attr_accessor :load_paths end def self.calendar_directories - directories = @additional_load_paths || [] - directories + [File.join(File.dirname(__FILE__), 'data')] + @load_paths end private_class_method :calendar_directories diff --git a/lib/business/data/achus.yml b/lib/business/data/achus.yml deleted file mode 100644 index 9e26612..0000000 --- a/lib/business/data/achus.yml +++ /dev/null @@ -1,58 +0,0 @@ -working_days: - - monday - - tuesday - - wednesday - - thursday - - friday - -holidays: - - January 1st, 2019 - - January 21st, 2019 - - February 18th, 2019 - - May 27th, 2019 - - July 4th, 2019 - - September 2nd, 2019 - - October 14th, 2019 - - November 11th, 2019 - - November 28th, 2019 - - December 25th, 2019 - - January 1st, 2020 - - January 20th, 2020 - - February 17th, 2020 - - May 25th, 2020 - - July 4th, 2020 - - September 7th, 2020 - - October 12th, 2020 - - November 11th, 2020 - - November 26th, 2020 - - December 25th, 2020 - - January 1st, 2021 - - January 18th, 2021 - - February 15th, 2021 - - May 31st, 2021 - - July 5th, 2021 - - September 6th, 2021 - - October 11th, 2021 - - November 11th, 2021 - - November 25th, 2021 - - December 25th, 2021 - - January 1st, 2022 - - January 17th, 2022 - - February 21st, 2022 - - May 30th, 2022 - - July 4th, 2022 - - September 5th, 2022 - - October 10th, 2022 - - November 11th, 2022 - - November 24th, 2022 - - December 26th, 2022 - - January 2nd, 2023 - - January 16th, 2023 - - February 20th, 2023 - - May 29th, 2023 - - July 4th, 2023 - - September 4th, 2023 - - October 9th, 2023 - - November 11th, 2023 - - November 23rd, 2023 - - December 25th, 2023 diff --git a/lib/business/data/bacs.yml b/lib/business/data/bacs.yml deleted file mode 100644 index 7215c92..0000000 --- a/lib/business/data/bacs.yml +++ /dev/null @@ -1,129 +0,0 @@ -working_days: - - monday - - tuesday - - wednesday - - thursday - - friday - -holidays: - - January 1st, 2013 - - March 29th, 2013 - - April 1st, 2013 - - May 6th, 2013 - - May 27th, 2013 - - August 26th, 2013 - - December 25th, 2013 - - December 26th, 2013 - - January 1st, 2014 - - April 18th, 2014 - - April 21st, 2014 - - May 5th, 2014 - - May 26th, 2014 - - August 25th, 2014 - - December 25th, 2014 - - December 26th, 2014 - - January 1st, 2015 - - April 3rd, 2015 - - April 6th, 2015 - - May 4th, 2015 - - May 25th, 2015 - - August 31st, 2015 - - December 25th, 2015 - - December 28th, 2015 - - January 1st, 2016 - - March 25th, 2016 - - March 28th, 2016 - - May 2nd, 2016 - - May 30th, 2016 - - August 29th, 2016 - - December 26th, 2016 - - December 27th, 2016 - - January 2nd, 2017 - - April 14th, 2017 - - April 17th, 2017 - - May 1st, 2017 - - May 29th, 2017 - - August 28th, 2017 - - December 25th, 2017 - - December 26th, 2017 - - January 1st, 2018 - - March 30th, 2018 - - April 2nd, 2018 - - May 7th, 2018 - - May 28th, 2018 - - August 27th, 2018 - - December 25th, 2018 - - December 26th, 2018 - - January 1st, 2019 - - April 19th, 2019 - - April 22nd, 2019 - - May 6th, 2019 - - May 27th, 2019 - - August 26th, 2019 - - December 25th, 2019 - - December 26th, 2019 - - January 1st, 2020 - - April 10th, 2020 - - April 13th, 2020 - - May 8th, 2020 - - May 25th, 2020 - - August 31st, 2020 - - December 25th, 2020 - - December 26th, 2020 - - December 28th, 2020 - - January 1st, 2021 - - April 2nd, 2021 - - April 5th, 2021 - - May 3rd, 2021 - - May 31st, 2021 - - August 30th, 2021 - - December 27th, 2021 - - December 28th, 2021 - - January 3rd, 2022 - - April 15th, 2022 - - April 18th, 2022 - - May 2nd, 2022 - - May 30th, 2022 - - August 29th, 2022 - - December 26th, 2022 - - December 27th, 2022 - - January 2nd, 2023 - - April 7th, 2023 - - April 10th, 2023 - - May 1st, 2023 - - May 29th, 2023 - - August 28th, 2023 - - December 25th, 2023 - - December 26th, 2023 - - January 1st, 2024 - - March 29th, 2024 - - April 1st, 2024 - - May 6th, 2024 - - May 27th, 2024 - - August 26th, 2024 - - December 25th, 2024 - - December 26th, 2024 - - January 1st, 2025 - - April 18th, 2025 - - April 21st, 2025 - - May 5th, 2025 - - May 26th, 2025 - - August 25th, 2025 - - December 25th, 2025 - - December 26th, 2025 - - January 1st, 2026 - - April 3rd, 2026 - - April 6th, 2026 - - May 4th, 2026 - - May 25th, 2026 - - August 31st, 2026 - - December 25th, 2026 - - December 28th, 2026 - - January 1st, 2027 - - March 26th, 2027 - - March 29th, 2027 - - May 3rd, 2027 - - May 31st, 2027 - - August 30th, 2027 - - December 27th, 2027 - - December 28th, 2027 diff --git a/lib/business/data/bankgirot.yml b/lib/business/data/bankgirot.yml deleted file mode 100644 index 1831710..0000000 --- a/lib/business/data/bankgirot.yml +++ /dev/null @@ -1,208 +0,0 @@ -working_days: - - monday - - tuesday - - wednesday - - thursday - - friday - -holidays: - - January 1st, 2015 - - January 6th, 2015 - - April 3rd, 2015 - - April 6th, 2015 - - May 1st, 2015 - - May 14th, 2015 - - June 6th, 2015 - - June 19th, 2015 - - December 24th, 2015 - - December 25th, 2015 - - December 26th, 2015 - - December 31st, 2015 - - January 1st, 2016 - - January 6th, 2016 - - March 25th, 2016 - - March 28th, 2016 - - May 1st, 2016 - - May 5th, 2016 - - June 6th, 2016 - - June 24th, 2016 - - December 24th, 2016 - - December 25th, 2016 - - December 26th, 2016 - - December 31st, 2016 - - January 1st, 2017 - - January 6th, 2017 - - April 14th, 2017 - - April 16th, 2017 - - April 17th, 2017 - - May 1st, 2017 - - May 25th, 2017 - - June 4th, 2017 - - June 6th, 2017 - - June 23rd, 2017 - - June 24th, 2017 - - November 4th, 2017 - - December 24th, 2017 - - December 25th, 2017 - - December 26th, 2017 - - December 31st, 2017 - - January 1st, 2018 - - January 6th, 2018 - - March 30th, 2018 - - April 1st, 2018 - - April 2nd, 2018 - - May 1st, 2018 - - May 10th, 2018 - - May 20th, 2018 - - June 6th, 2018 - - June 22rd, 2018 - - June 23rd, 2018 - - November 3rd, 2018 - - December 24th, 2018 - - December 25th, 2018 - - December 26th, 2018 - - December 31st, 2018 - - January 1st, 2019 - - January 6th, 2019 - - April 19th, 2019 - - April 21st, 2019 - - April 22nd, 2019 - - May 1st, 2019 - - May 30th, 2019 - - June 6th, 2019 - - June 9th, 2019 - - June 21st, 2019 - - June 22nd, 2019 - - November 2nd, 2019 - - December 24th, 2019 - - December 25th, 2019 - - December 26th, 2019 - - December 31st, 2019 - - January 1st, 2020 - - January 6th, 2020 - - April 10th, 2020 - - April 12th, 2020 - - April 13th, 2020 - - May 1st, 2020 - - May 21st, 2020 - - May 31st, 2020 - - June 6th, 2020 - - June 19th, 2020 - - June 20th, 2020 - - October 31st, 2020 - - December 24th, 2020 - - December 25th, 2020 - - December 26th, 2020 - - December 31st, 2020 - - January 1st, 2021 - - January 6th, 2021 - - April 2nd, 2021 - - April 4th, 2021 - - April 5th, 2021 - - May 1st, 2021 - - May 13th, 2021 - - May 23rd, 2021 - - June 6th, 2021 - - June 25th, 2021 - - June 26th, 2021 - - November 6th, 2021 - - December 24th, 2021 - - December 25th, 2021 - - December 26th, 2021 - - December 31st, 2021 - - January 1st, 2022 - - January 6th, 2022 - - April 15th, 2022 - - April 17th, 2022 - - April 18th, 2022 - - May 1st, 2022 - - May 26th, 2022 - - June 5th, 2022 - - June 6th, 2022 - - June 24th, 2022 - - June 25th, 2022 - - November 5th, 2022 - - December 24th, 2022 - - December 25th, 2022 - - December 26th, 2022 - - December 31st, 2022 - - January 1st, 2023 - - January 6th, 2023 - - April 7th, 2023 - - April 9th, 2023 - - April 10th, 2023 - - May 1st, 2023 - - May 18th, 2023 - - May 28th, 2023 - - June 6th, 2023 - - June 23rd, 2023 - - June 24th, 2023 - - November 4th, 2023 - - December 24th, 2023 - - December 25th, 2023 - - December 26th, 2023 - - December 31st, 2023 - - January 1st, 2024 - - January 6th, 2024 - - March 29th, 2024 - - March 31st, 2024 - - April 1st, 2024 - - May 1st, 2024 - - May 9th, 2024 - - May 19th, 2024 - - June 6th, 2024 - - June 21st, 2023 - - June 22nd, 2023 - - November 2nd, 2024 - - December 24th, 2024 - - December 25th, 2024 - - December 26th, 2024 - - December 31st, 2024 - - January 1st, 2025 - - January 6th, 2025 - - April 18th, 2025 - - April 20th, 2025 - - April 21st, 2025 - - May 1st, 2025 - - May 29th, 2025 - - June 6th, 2025 - - June 8th, 2025 - - June 20th, 2025 - - June 21st, 2025 - - November 1st, 2025 - - December 24th, 2025 - - December 25th, 2025 - - December 26th, 2025 - - December 31st, 2025 - - January 1st, 2026 - - January 6th, 2026 - - April 3rd, 2026 - - April 5th, 2026 - - April 6th, 2026 - - May 1st, 2026 - - May 14th, 2026 - - May 24th, 2026 - - June 6th, 2026 - - June 19th, 2026 - - June 20th, 2026 - - October 31st, 2026 - - December 24th, 2026 - - December 25th, 2026 - - December 26th, 2026 - - December 31st, 2026 - - January 1st, 2027 - - January 6th, 2027 - - March 26th, 2027 - - March 28th, 2027 - - March 29th, 2027 - - May 1st, 2027 - - May 6th, 2027 - - May 16th, 2027 - - June 6th, 2027 - - June 25th, 2027 - - June 26th, 2027 - - November 6th, 2027 - - December 24th, 2027 - - December 25th, 2027 - - December 26th, 2027 - - December 31st, 2027 diff --git a/lib/business/data/becs.yml b/lib/business/data/becs.yml deleted file mode 100644 index 5315fee..0000000 --- a/lib/business/data/becs.yml +++ /dev/null @@ -1,36 +0,0 @@ -working_days: - - monday - - tuesday - - wednesday - - thursday - - friday - -holidays: - - January 1st, 2017 - - January 26th, 2017 - - April 14th, 2017 - - April 17th, 2017 - - April 25th, 2017 - - December 25th, 2017 - - December 26th, 2017 - - January 1st, 2018 - - January 26th, 2018 - - March 30th, 2018 - - April 2nd, 2018 - - April 25th, 2018 - - December 25th, 2018 - - December 26th, 2018 - - January 1st, 2019 - - January 28th, 2019 - - April 19th, 2019 - - April 22nd, 2019 - - April 25th, 2019 - - December 25th, 2019 - - December 26th, 2019 - - January 1st, 2020 - - January 27th, 2020 - - April 10th, 2020 - - April 13nd, 2020 - - April 25th, 2020 - - December 25th, 2020 - - December 28th, 2020 diff --git a/lib/business/data/becsnz.yml b/lib/business/data/becsnz.yml deleted file mode 100644 index 572cdb4..0000000 --- a/lib/business/data/becsnz.yml +++ /dev/null @@ -1,50 +0,0 @@ -working_days: - - monday - - tuesday - - wednesday - - thursday - - friday - -holidays: - - January 2nd, 2017 - - January 3rd, 2017 - - February 6th, 2017 - - April 14th, 2017 - - April 17th, 2017 - - April 25th, 2017 - - June 5th, 2017 - - October 23rd, 2017 - - December 25th, 2017 - - December 26th, 2017 - - January 1st, 2018 - - January 2nd, 2018 - - February 6th, 2018 - - March 30th, 2018 - - April 2nd, 2018 - - April 25th, 2018 - - June 4th, 2018 - - October 22nd, 2018 - - December 25th, 2018 - - December 26th, 2018 - - January 1st, 2019 - - January 2nd, 2019 - - February 6th, 2019 - - April 19th, 2019 - - April 22nd, 2019 - - April 25th, 2019 - - June 3rd, 2019 - - October 28th, 2019 - - December 25th, 2019 - - December 26th, 2019 - - January 1st, 2020 - - January 2nd, 2020 - - February 6th, 2020 - - April 10th, 2020 - - April 13th, 2020 - - April 27th, 2020 - - June 1st, 2020 - - October 26th, 2020 - - December 25th, 2020 - - December 28th, 2020 - - diff --git a/lib/business/data/betalingsservice.yml b/lib/business/data/betalingsservice.yml deleted file mode 100644 index e593dd0..0000000 --- a/lib/business/data/betalingsservice.yml +++ /dev/null @@ -1,56 +0,0 @@ -working_days: - - monday - - tuesday - - wednesday - - thursday - - friday - -holidays: - - January 1st, 2017 - - April 13th, 2017 - - April 14th, 2017 - - April 16th, 2017 - - April 17th, 2017 - - May 12th, 2017 - - May 25th, 2017 - - May 26th, 2017 - - June 5th, 2017 - - December 25th, 2017 - - December 26th, 2017 - - January 1st, 2018 - - March 29th, 2018 - - March 30th, 2018 - - April 2nd, 2018 - - April 27th, 2018 - - May 10th, 2018 - - May 11th, 2018 - - May 21st, 2018 - - June 5th, 2018 - - December 25th, 2018 - - December 26th, 2018 - - December 31st, 2018 - - January 1st, 2019 - - April 18th, 2019 - - April 19th, 2019 - - April 22nd, 2019 - - May 17th, 2019 - - May 30th, 2019 - - May 31st, 2019 - - June 5th, 2019 - - June 10th, 2019 - - December 25th, 2019 - - December 26th, 2019 - - December 31st, 2019 - - January 1st, 2020 - - April 9th, 2020 - - April 10th, 2020 - - April 13th, 2020 - - May 8th, 2020 - - May 21st, 2020 - - May 22nd, 2020 - - June 1st, 2020 - - June 5th, 2020 - - December 24th, 2020 - - December 25th, 2020 - - December 26th, 2020 - - December 31st, 2020 diff --git a/lib/business/data/padca.yml b/lib/business/data/padca.yml deleted file mode 100644 index eb40440..0000000 --- a/lib/business/data/padca.yml +++ /dev/null @@ -1,35 +0,0 @@ -working_days: - - monday - - tuesday - - wednesday - - thursday - - friday - -holidays: - - January 1st, 2018 - - March 30th, 2018 - - May 21st, 2018 - - July 2nd, 2018 - - September 3rd, 2018 - - October 8th, 2018 - - November 12th, 2018 - - December 25th, 2018 - - December 26th, 2018 - - January 1st, 2019 - - April 19th, 2019 - - May 20th, 2019 - - July 1st, 2019 - - September 2nd, 2019 - - October 14th, 2019 - - November 11th, 2019 - - December 25th, 2019 - - December 26th, 2019 - - January 1st, 2020 - - April 10th, 2020 - - May 18th, 2020 - - July 1st, 2020 - - September 7th, 2020 - - October 12th, 2020 - - November 11th, 2020 - - December 25th, 2020 - - December 28th, 2020 diff --git a/lib/business/data/target.yml b/lib/business/data/target.yml deleted file mode 100644 index 8efb809..0000000 --- a/lib/business/data/target.yml +++ /dev/null @@ -1,101 +0,0 @@ -# Any changes made to this file should also be made to targetfrance.yml, -# as that file also contains Target(SEPA) holidays. - -working_days: - - monday - - tuesday - - wednesday - - thursday - - friday - -holidays: - - January 1st, 2013 - - March 29th, 2013 - - April 1st, 2013 - - May 1st, 2013 - - December 25th, 2013 - - December 26th, 2013 - - January 1st, 2014 - - April 18th, 2014 - - April 21st, 2014 - - May 1st, 2014 - - December 25th, 2014 - - December 26th, 2014 - - January 1st, 2015 - - April 3rd, 2015 - - April 6th, 2015 - - May 1st, 2015 - - December 25th, 2015 - - December 26th, 2015 - - January 1st, 2016 - - March 25th, 2016 - - March 28th, 2016 - - May 1st, 2016 - - December 25th, 2016 - - December 26th, 2016 - - January 1st, 2017 - - April 14th, 2017 - - April 17th, 2017 - - May 1st, 2017 - - December 25th, 2017 - - December 26th, 2017 - - January 1st, 2018 - - March 30th, 2018 - - April 2nd, 2018 - - May 1st, 2018 - - December 25th, 2018 - - December 26th, 2018 - - January 1st, 2019 - - April 19th, 2019 - - April 22nd, 2019 - - May 1st, 2019 - - December 25th, 2019 - - December 26th, 2019 - - January 1st, 2020 - - April 10th, 2020 - - April 13th, 2020 - - May 1st, 2020 - - December 25th, 2020 - - December 26th, 2020 - - January 1st, 2021 - - April 2nd, 2021 - - April 5th, 2021 - - May 1st, 2021 - - December 25th, 2021 - - December 26th, 2021 - - January 1st, 2022 - - April 15th, 2022 - - April 18th, 2022 - - May 1st, 2022 - - December 25th, 2022 - - December 26th, 2022 - - January 1st, 2023 - - April 7th, 2023 - - April 10th, 2023 - - May 1st, 2023 - - December 25th, 2023 - - December 26th, 2023 - - January 1st, 2024 - - March 29th, 2024 - - April 1st, 2024 - - May 1st, 2024 - - December 25th, 2024 - - December 26th, 2024 - - January 1st, 2025 - - April 18th, 2025 - - April 21st, 2025 - - May 1st, 2025 - - December 25th, 2025 - - December 26th, 2025 - - January 1st, 2026 - - April 3rd, 2026 - - April 6th, 2026 - - May 1st, 2026 - - December 25th, 2026 - - December 26th, 2026 - - January 1st, 2027 - - March 26th, 2027 - - March 29th, 2027 - - May 1st, 2027 - - December 25th, 2027 - - December 26th, 2027 diff --git a/lib/business/data/targetfrance.yml b/lib/business/data/targetfrance.yml deleted file mode 100644 index e67ec73..0000000 --- a/lib/business/data/targetfrance.yml +++ /dev/null @@ -1,130 +0,0 @@ -# The dates for Ascension Day and Whit Monday change each year. At the time of writing this comment (29/10/2019), -# the dates for these holidays have only been published up till the year 2021. -# In this file, dates from the year 2022 onwards only consist of fixed/known bank holidays. - -working_days: - - monday - - tuesday - - wednesday - - thursday - - friday - -holidays: - - January 1st, 2018 - - March 30th, 2018 - - April 2nd, 2018 - - May 1st, 2018 - - May 8th, 2018 - - May 10th, 2018 - - May 21st, 2018 - - July 14th, 2018 - - August 15th, 2018 - - November 1st, 2018 - - November 11th, 2018 - - December 25th, 2018 - - December 26th, 2018 - - January 1st, 2019 - - April 19th, 2019 - - April 22nd, 2019 - - May 1st, 2019 - - May 8th, 2019 - - May 30th, 2019 - - June 10th, 2019 - - July 14th, 2019 - - August 15th, 2019 - - November 1st, 2019 - - November 11th, 2019 - - December 25th, 2019 - - December 26th, 2019 - - January 1st, 2020 - - April 10th, 2020 - - April 13th, 2020 - - May 1st, 2020 - - May 8th, 2020 - - May 21st, 2020 - - June 1st, 2020 - - July 14th, 2020 - - August 15th, 2020 - - November 1st, 2020 - - November 11th, 2020 - - December 25th, 2020 - - December 26th, 2020 - - January 1st, 2021 - - April 2nd, 2021 - - April 5th, 2021 - - May 1st, 2021 - - May 8th, 2021 - - May 13th, 2021 - - May 24th, 2021 - - July 14th, 2021 - - August 15th, 2021 - - November 1st, 2021 - - November 11th, 2021 - - December 25th, 2021 - - December 26th, 2021 - - January 1st, 2022 - - April 15th, 2022 - - April 18th, 2022 - - May 1st, 2022 - - May 8th, 2022 - - July 14th, 2022 - - August 15th, 2022 - - November 1st, 2022 - - November 11th, 2022 - - December 25th, 2022 - - December 26th, 2022 - - January 1st, 2023 - - April 7th, 2023 - - April 10th, 2023 - - May 1st, 2023 - - May 8th, 2023 - - July 14th, 2023 - - August 15th, 2023 - - November 1st, 2023 - - November 11th, 2023 - - December 25th, 2023 - - December 26th, 2023 - - January 1st, 2024 - - March 29th, 2024 - - April 1st, 2024 - - May 1st, 2024 - - May 8th, 2024 - - July 14th, 2024 - - August 15th, 2024 - - November 1st, 2024 - - November 11th, 2024 - - December 25th, 2024 - - December 26th, 2024 - - January 1st, 2025 - - April 18th, 2025 - - April 21st, 2025 - - May 1st, 2025 - - May 8th, 2025 - - July 14th, 2025 - - August 15th, 2025 - - November 1st, 2025 - - November 11th, 2025 - - December 25th, 2025 - - December 26th, 2025 - - January 1st, 2026 - - April 3rd, 2026 - - April 6th, 2026 - - May 1st, 2026 - - May 8th, 2026 - - July 14th, 2026 - - August 15th, 2026 - - November 1st, 2026 - - November 11th, 2026 - - December 25th, 2026 - - December 26th, 2026 - - January 1st, 2027 - - March 26th, 2027 - - March 29th, 2027 - - May 1st, 2027 - - May 8th, 2027 - - July 14th, 2027 - - August 15th, 2027 - - November 1st, 2027 - - November 11th, 2027 - - December 25th, 2027 - - December 26th, 2027 diff --git a/lib/business/data/weekdays.yml b/lib/business/data/weekdays.yml deleted file mode 100644 index 286a831..0000000 --- a/lib/business/data/weekdays.yml +++ /dev/null @@ -1,6 +0,0 @@ -working_days: - - monday - - tuesday - - wednesday - - thursday - - friday diff --git a/spec/calendar_spec.rb b/spec/calendar_spec.rb index d7e23e8..1819969 100644 --- a/spec/calendar_spec.rb +++ b/spec/calendar_spec.rb @@ -10,25 +10,13 @@ describe ".load" do before do fixture_path = File.join(File.dirname(__FILE__), 'fixtures', 'calendars') - Business::Calendar.additional_load_paths = [fixture_path] - end - - context "when given a valid calendar" do - subject { Business::Calendar.load("weekdays") } - - it "loads the yaml file" do - expect(YAML).to receive(:load_file) { |path| - expect(path).to match(/weekdays\.yml$/) - }.and_return({}) - subject - end - - it { is_expected.to be_a Business::Calendar } + described_class.load_paths = [fixture_path] end context "when given a calendar from a custom directory" do - after { Business::Calendar.additional_load_paths = nil } - subject { Business::Calendar.load("ecb") } + subject { described_class.load("ecb") } + + after { described_class.load_paths = nil } it "loads the yaml file" do expect(YAML).to receive(:load_file) { |path| @@ -72,19 +60,6 @@ end end - describe "bundled calendars" do - calendars = Dir.glob("../lib/business/data*.yml") - .map { |f| File.basename(f, ".yml") } - - calendars.each do |calendar| - describe calendar do - it "should load without issues" do - expect { Business::Calendar.load(calendar) }.not_to raise_error - end - end - end - end - describe "#set_working_days" do let(:calendar) { Business::Calendar.new({}) } let(:working_days) { [] } From 396f5c62123ba1f6f83dc6584996e8cf15634c26 Mon Sep 17 00:00:00 2001 From: Joseph Southan Date: Mon, 4 May 2020 16:19:12 +0100 Subject: [PATCH 2/7] Update readme to detail how to load calendars --- README.md | 119 +++++++++++++++++++++--------------------------------- 1 file changed, 46 insertions(+), 73 deletions(-) diff --git a/README.md b/README.md index 6c0a0e6..a887393 100644 --- a/README.md +++ b/README.md @@ -15,70 +15,73 @@ $ gem install business ### Getting started -Get started with business by creating an instance of the calendar class, -passing in a hash that specifies with days of the week are considered working -days, and which days are holidays. +Get started with business by creating an instance of the calendar class, passing in a hash that specifies with days of the week are considered working days, and which days are holidays. ```ruby calendar = Business::Calendar.new( working_days: %w( mon tue wed thu fri ), holidays: ["01/01/2014", "03/01/2014"] # array items are either parseable date strings, or real Date objects + extra_working_dates: [nil], # Makes the calendar to consider a weekend day as a working day. ) ``` -`extra_working_dates` key makes the calendar to consider a weekend day as a working day. +### Load a calendar from a file -A few calendar configs are bundled with the gem (see [lib/business/data]((lib/business/data)) for -details). Load them by calling the `load` class method on `Calendar`. The -`load_cached` variant of this method caches the calendars by name after loading -them, to avoid reading and parsing the config file multiple times. +#### Calendar file definition -```ruby -calendar = Business::Calendar.load("weekdays") -calendar = Business::Calendar.load_cached("weekdays") -``` +Defining a calendar as a Ruby object may not be convient, to load it from a YAML file follow and customise the example below. All keys are optional and will default to the following: + +- If `working_days` is missing, then common default is used (mon-fri). +- If `holidays` is missing, "no holidays" assumed. +- If `extra_working_dates` is missing, then no changes in `working_days` will happen. -If `working_days` is missing, then common default is used (mon-fri). -If `holidays` is missing, "no holidays" assumed. -If `extra_working_dates` is missing, then no changes in `working_days` will happen. +> Note: Elements of `holidays` and `extra_working_dates` may be eiter strings that `Date.parse()` can understand, or YYYY-MM-DD (which is considered as a Date by Ruby YAML itself). -Elements of `holidays` and `extra_working_dates` may be -eiter strings that `Date.parse()` can understand, -or YYYY-MM-DD (which is considered as a Date by Ruby YAML itself). +#### Example ```yaml +working_days: + - Monday + - Wednesday + - Friday holidays: - - 2017-01-08 # Same as January 8th, 2017 + - 1st April 2020 + - 2021-04-01 +extra_working_dates: + - 9th March 2020 # A Saturday ``` -### Checking for business days +#### Using the calendar -To check whether a given date is a business day (falls on one of the specified -working days or working dates, and is not a holiday), use the `business_day?` -method on `Calendar`. +Ensure the calendar file is saved to a directory that will hold all your calendars, eg; `path/to/your/calendar/directory` then add this directory to your code before you call your calendar: ```ruby -calendar.business_day?(Date.parse("Monday, 9 June 2014")) -# => true -calendar.business_day?(Date.parse("Sunday, 8 June 2014")) -# => false +Business::Calendar.load_paths = ["path/to/your/calendar/directory"] ``` -### Custom calendars - -To use a calendar you've written yourself, you need to add the directory it's -stored in as an additional calendar load path: +Now you can load the calendar by calling the `load` class method on `Business::Calendar`. The +`load_cached` variant of this method caches the calendars by name after loading them, to avoid reading and parsing the config file multiple times. ```ruby -Business::Calendar.additional_load_paths = ['path/to/your/calendar/directory'] +calendar = Business::Calendar.load("my_calendars") +# or +calendar = Business::Calendar.load_cached("my_calendars") ``` -You can then load the calendar as normal. +### Checking for business days + +To check whether a given date is a business day (falls on one of the specified working days or working dates, and is not a holiday), use the `business_day?` method on `Business::Calendar`. + +```ruby +calendar.business_day?(Date.parse("Monday, 9 June 2014")) +# => true +calendar.business_day?(Date.parse("Sunday, 8 June 2014")) +# => false +``` ### Business day arithmetic -The `add_business_days` and `subtract_business_days` are used to perform -business day arithmetic on dates. +The `add_business_days` and `subtract_business_days` are used to perform business day arithmetic on dates. ```ruby date = Date.parse("Thursday, 12 June 2014") @@ -88,10 +91,7 @@ calendar.subtract_business_days(date, 4).strftime("%A, %d %B %Y") # => "Friday, 06 June 2014" ``` -The `roll_forward` and `roll_backward` methods snap a date to a nearby business -day. If provided with a business day, they will return that date. Otherwise, -they will advance (forward for `roll_forward` and backward for `roll_backward`) -until a business day is found. +The `roll_forward` and `roll_backward` methods snap a date to a nearby business day. If provided with a business day, they will return that date. Otherwise, they will advance (forward for `roll_forward` and backward for `roll_backward`) until a business day is found. ```ruby date = Date.parse("Saturday, 14 June 2014") @@ -101,10 +101,7 @@ calendar.roll_backward(date).strftime("%A, %d %B %Y") # => "Friday, 13 June 2014" ``` -To count the number of business days between two dates, pass the dates to -`business_days_between`. This method counts from start of the first date to -start of the second date. So, assuming no holidays, there would be two business -days between a Monday and a Wednesday. +To count the number of business days between two dates, pass the dates to `business_days_between`. This method counts from start of the first date to start of the second date. So, assuming no holidays, there would be two business days between a Monday and a Wednesday. ```ruby date = Date.parse("Saturday, 14 June 2014") @@ -112,40 +109,16 @@ calendar.business_days_between(date, date + 7) # => 5 ``` -### Included Calendars +## But other libraries already do this -We include some calendar data with this Gem but give no guarantees of its -accuracy. -The calendars that we include are: +Another gem, [business_time](https://github.com/bokmann/business_time), also exists for this purpose. We previously used business_time, but encountered several issues that prompted us to start business. -* Bacs -* Bankgirot -* BECS (Australia) -* BECSNZ (New Zealand) -* PAD (Canada) -* Betalingsservice -* Target (SEPA) -* TargetFrance (SEPA + French bank holidays) -* US Banking (ACH) +Firstly, business_time works by monkey-patching `Date`, `Time`, and `FixNum`. While this enables syntax like `Time.now + 1.business_day`, it means that all configuration has to be global. GoCardless handles payments across several geographies, so being able to work with multiple working-day calendars is +essential for us. Business provides a simple `Calendar` class, that is initialized with a configuration that specifies which days of the week are considered to be working days, and which dates are holidays. -## But other libraries already do this +Secondly, business_time supports calculations on times as well as dates. For our purposes, date-based calculations are sufficient. Supporting time-based calculations as well makes the code significantly more complex. We chose to avoid this extra complexity by sticking solely to date-based mathematics. -Another gem, [business_time](https://github.com/bokmann/business_time), also -exists for this purpose. We previously used business_time, but encountered -several issues that prompted us to start business. - -Firstly, business_time works by monkey-patching `Date`, `Time`, and `FixNum`. -While this enables syntax like `Time.now + 1.business_day`, it means that all -configuration has to be global. GoCardless handles payments across several -geographies, so being able to work with multiple working-day calendars is -essential for us. Business provides a simple `Calendar` class, that is -initialized with a configuration that specifies which days of the week are -considered to be working days, and which dates are holidays. - -Secondly, business_time supports calculations on times as well as dates. For -our purposes, date-based calculations are sufficient. Supporting time-based -calculations as well makes the code significantly more complex. We chose to -avoid this extra complexity by sticking solely to date-based mathematics. +--- ![I'm late for business](http://3.bp.blogspot.com/-aq4iOz2OZzs/Ty8xaQwMhtI/AAAAAAAABrM/-vn4tcRA9-4/s1600/daily-morning-awesomeness-243.jpeg) From c40b3dcbc53cb1dead22867bfd57b26ff56c6f18 Mon Sep 17 00:00:00 2001 From: Joseph Southan Date: Mon, 4 May 2020 16:30:59 +0100 Subject: [PATCH 3/7] Add note to changelog re calendars --- CHANGELOG.md | 7 +++++++ README.md | 13 +++++++++++++ 2 files changed, 20 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92eda99..fdbcdf8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## 2.0.0 - May 4, 2020 + +**BREAKING CHANGES** 🚨 + +- Remove bundled calendars see [this pr](https://github.com/gocardless/business/pull/54) for more context. If you need to use any of the previously bundled calendars, [see here](https://github.com/gocardless/business/tree/b12c186ca6fd4ffdac85175742ff7e4d0a705ef4/lib/business/data) +- `Business::Calendar.load_paths=` is now required + ## 1.18.0 - April 30, 2020 ### Note we have dropped support for Ruby < 2.4.x diff --git a/README.md b/README.md index a887393..9dfcb51 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,19 @@ To get business, simply: $ gem install business ``` +## Important: 2.0.0 breaking changes + +We have removed the bundled calendars as of version 2.0.0, if you need the calendars that were included: + +Download the calendars you wish to use from [before version 2](https://github.com/gocardless/business/tree/b12c186ca6fd4ffdac85175742ff7e4d0a705ef4/lib/business/data) and place them in a suitable place in your project. + +Then, add the directory to where you placed the yml files before you load the calendar: + +```ruby +Calendar::Business.load_paths("lib/calendars") # your_project/lib/calendars/ contains bacs.yml +Calendar::Business.load("bacs") +``` + ### Getting started Get started with business by creating an instance of the calendar class, passing in a hash that specifies with days of the week are considered working days, and which days are holidays. From 6d6311266d11e6103bd4964041a98d9224642781 Mon Sep 17 00:00:00 2001 From: Joseph Southan Date: Tue, 5 May 2020 00:24:26 +0100 Subject: [PATCH 4/7] Allow hashes to be passed into load_path --- README.md | 13 +++++++++++++ lib/business/calendar.rb | 25 +++++++++++++++++-------- spec/calendar_spec.rb | 10 +++++++++- 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 9dfcb51..c69a007 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,19 @@ calendar = Business::Calendar.load("my_calendars") calendar = Business::Calendar.load_cached("my_calendars") ``` +#### New in version 2.0.0: + +Add a hash to the `load_path` array to use already loaded data. This can be useful if loading calendar data from an external source. + +```ruby +Business::Calendar.load_paths = [ + "path/to/your/calendar/directory", + { "foo_calendar" => { "working_days" => ["monday"] } } +] + +Business::Calendar.load("foo_calendar") +``` + ### Checking for business days To check whether a given date is a business day (falls on one of the specified working days or working dates, and is not a holiday), use the `business_day?` method on `Business::Calendar`. diff --git a/lib/business/calendar.rb b/lib/business/calendar.rb index c45aa5d..80ed39c 100644 --- a/lib/business/calendar.rb +++ b/lib/business/calendar.rb @@ -11,21 +11,30 @@ def self.calendar_directories end private_class_method :calendar_directories - def self.load(calendar) - directory = calendar_directories.find do |dir| - File.exists?(File.join(dir, "#{calendar}.yml")) + def self.load(calendar_name) + data = calendar_directories.detect do |path| + if path.is_a?(Hash) + break path[calendar_name] if path[calendar_name] + else + next unless File.exists?(File.join(path, "#{calendar_name}.yml")) + + break YAML.load_file(File.join(path, "#{calendar_name}.yml")) + end end - raise "No such calendar '#{calendar}'" unless directory - yaml = YAML.load_file(File.join(directory, "#{calendar}.yml")) + raise "No such calendar '#{calendar_name}'" unless data + valid_keys = %w(holidays working_days extra_working_dates) - unless (yaml.keys - valid_keys).empty? + unless (data.keys - valid_keys).empty? raise "Only valid keys are: #{valid_keys.join(', ')}" end - self.new(holidays: yaml['holidays'], working_days: yaml['working_days'], - extra_working_dates: yaml['extra_working_dates']) + self.new( + holidays: data['holidays'], + working_days: data['working_days'], + extra_working_dates: data['extra_working_dates'], + ) end @lock = Mutex.new diff --git a/spec/calendar_spec.rb b/spec/calendar_spec.rb index 1819969..10509ed 100644 --- a/spec/calendar_spec.rb +++ b/spec/calendar_spec.rb @@ -8,9 +8,11 @@ describe Business::Calendar do describe ".load" do + let(:dummy_calendar) { { "working_days" => ["monday"] } } + before do fixture_path = File.join(File.dirname(__FILE__), 'fixtures', 'calendars') - described_class.load_paths = [fixture_path] + described_class.load_paths = [fixture_path, { "foobar" => dummy_calendar }] end context "when given a calendar from a custom directory" do @@ -37,6 +39,12 @@ end end + context "when loading a calendar as a hash" do + subject { described_class.load("foobar") } + + it { is_expected.to be_a Business::Calendar } + end + context "when given a calendar that does not exist" do subject { Business::Calendar.load("invalid-calendar") } specify { expect { subject }.to raise_error(/No such calendar/) } From ef00e10f16887eb9cc255a8b98096bd005a473a6 Mon Sep 17 00:00:00 2001 From: Joseph Southan Date: Tue, 5 May 2020 10:26:36 +0100 Subject: [PATCH 5/7] Update and clarify readme --- CHANGELOG.md | 4 +- README.md | 111 ++++++++++++++++++++++++++++++++------------------- 2 files changed, 73 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fdbcdf8..9d925b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ ## 2.0.0 - May 4, 2020 -**BREAKING CHANGES** 🚨 +🚨 **BREAKING CHANGES** 🚨 + +For more on the breaking changes that have been introduced in v2.0.0 please [see the readme](README.md#v200-breaking-changes). - Remove bundled calendars see [this pr](https://github.com/gocardless/business/pull/54) for more context. If you need to use any of the previously bundled calendars, [see here](https://github.com/gocardless/business/tree/b12c186ca6fd4ffdac85175742ff7e4d0a705ef4/lib/business/data) - `Business::Calendar.load_paths=` is now required diff --git a/README.md b/README.md index c69a007..36b75eb 100644 --- a/README.md +++ b/README.md @@ -5,30 +5,52 @@ Date calculations based on business calendars. -## Documentation +- [v2.0.0 breaking changes](#v200-breaking-changes) +- [Getting Started](#getting-started) + - [Creating a calendar](#creating-a-calendar) + - [Using a calendar file](#use-a-calendar-file) +- [Checking for business days](#checking-for-business-days) +- [Business day arithmetic](#business-day-arithmetic) +- [But other libraries already do this](#but-other-libraries-already-do-this) +- [License & Contributing](#license--contributing) -To get business, simply: +## v2.0.0 breaking changes -```bash -$ gem install business +We have removed the bundled calendars as of version 2.0.0, if you need the calendars that were included: + +- Download the calendars you wish to use from [v1.18.0](https://github.com/gocardless/business/tree/b12c186ca6fd4ffdac85175742ff7e4d0a705ef4/lib/business/data) +- Place them in a suitable directory in your project, typically `lib/calendars` +- Add this directory path to your instance of `Business::Calendar` using the `load_paths` method.dd the directory to where you placed the yml files before you load the calendar + +```ruby +Business::Calendar.load_paths("lib/calendars") # your_project/lib/calendars/ contains bacs.yml +Business::Calendar.load("bacs") ``` -## Important: 2.0.0 breaking changes +If you wish to stay on the last version that contained bundled calendars, pin `business` to `v1.18.0` -We have removed the bundled calendars as of version 2.0.0, if you need the calendars that were included: +```ruby +# Gemfile +gem "business", "v1.18.0" +``` + +## Getting started -Download the calendars you wish to use from [before version 2](https://github.com/gocardless/business/tree/b12c186ca6fd4ffdac85175742ff7e4d0a705ef4/lib/business/data) and place them in a suitable place in your project. +To install business, simply: -Then, add the directory to where you placed the yml files before you load the calendar: +```bash +gem install business +``` + +If you are using a Gemfile: ```ruby -Calendar::Business.load_paths("lib/calendars") # your_project/lib/calendars/ contains bacs.yml -Calendar::Business.load("bacs") +gem "business", "~> 2.0" ``` -### Getting started +### Creating a calendar -Get started with business by creating an instance of the calendar class, passing in a hash that specifies with days of the week are considered working days, and which days are holidays. +Get started with business by creating an instance of the calendar class, that accepts a hash that specifies which days of the week are considered working days, which days are holidays and which are extra working dates. ```ruby calendar = Business::Calendar.new( @@ -38,21 +60,27 @@ calendar = Business::Calendar.new( ) ``` -### Load a calendar from a file +### Use a calendar file -#### Calendar file definition +Defining a calendar as a Ruby object may not be convenient, so we provide a way of defining these calendars as YAML. Below we will walk through the necessary [steps](#example-calendar) to build your first calendar. All keys are optional and will default to the following: -Defining a calendar as a Ruby object may not be convient, to load it from a YAML file follow and customise the example below. All keys are optional and will default to the following: +Note: Elements of `holidays` and `extra_working_dates` may be either strings that `Date.parse()` [can understand](https://ruby-doc.org/stdlib-2.7.1/libdoc/date/rdoc/Date.html#method-c-parse), or `YYYY-MM-DD` (which is considered as a Date by Ruby YAML itself)[https://github.com/ruby/psych/blob/6ec6e475e8afcf7868b0407fc08014aed886ecf1/lib/psych/scalar_scanner.rb#L60]. -- If `working_days` is missing, then common default is used (mon-fri). -- If `holidays` is missing, "no holidays" assumed. -- If `extra_working_dates` is missing, then no changes in `working_days` will happen. +#### YAML file Structure -> Note: Elements of `holidays` and `extra_working_dates` may be eiter strings that `Date.parse()` can understand, or YYYY-MM-DD (which is considered as a Date by Ruby YAML itself). +```yml +working_days: # Optional, default [Monday-Friday] + - +holidays: # Optional, default: [] ie: "no holidays" assumed + - +extra_working_dates: # Optional, default: [], ie: no changes in `working_days` will happen + - +``` -#### Example +#### Example calendar ```yaml +# lib/calendars/my_calendar.yml working_days: - Monday - Wednesday @@ -64,37 +92,35 @@ extra_working_dates: - 9th March 2020 # A Saturday ``` -#### Using the calendar +Ensure the calendar file is saved to a directory that will hold all your calendars, typically `lib/calendars`, then add this directory to your instance of `Business::Calendar` using the `load_paths` method before you call your calendar. -Ensure the calendar file is saved to a directory that will hold all your calendars, eg; `path/to/your/calendar/directory` then add this directory to your code before you call your calendar: +`load_paths` also accepts an array of plain Ruby hashes with the format: ```ruby -Business::Calendar.load_paths = ["path/to/your/calendar/directory"] + { "calendar_name" => { "working_days" => [] } ``` -Now you can load the calendar by calling the `load` class method on `Business::Calendar`. The -`load_cached` variant of this method caches the calendars by name after loading them, to avoid reading and parsing the config file multiple times. +#### Example loading both a path and ruby hashes ```ruby -calendar = Business::Calendar.load("my_calendars") -# or -calendar = Business::Calendar.load_cached("my_calendars") +Business::Calendar.load_paths = [ + "lib/calendars", + { "foo_calendar" => { "working_days" => ["monday"] } }, + { "bar_calendar" => { "working_days" => ["sunday"] } }, +] ``` -#### New in version 2.0.0: - -Add a hash to the `load_path` array to use already loaded data. This can be useful if loading calendar data from an external source. +Now you can load the calendar by calling the `Business::Calendar.load(calendar_name)`. In order to avoid parsing the calendar file multiple times, there is a `Business::Calendar.load_cached(calendar_name)` method that caches the calendars by name after loading them. ```ruby -Business::Calendar.load_paths = [ - "path/to/your/calendar/directory", - { "foo_calendar" => { "working_days" => ["monday"] } } -] - -Business::Calendar.load("foo_calendar") +calendar = Business::Calendar.load("my_calendar") # lib/calendars/my_calendar.yml +calendar = Business::Calendar.load("foo_calendar") +# or +calendar = Business::Calendar.load_cached("my_calendar") +calendar = Business::Calendar.load_cached("foo_calendar") ``` -### Checking for business days +## Checking for business days To check whether a given date is a business day (falls on one of the specified working days or working dates, and is not a holiday), use the `business_day?` method on `Business::Calendar`. @@ -105,7 +131,7 @@ calendar.business_day?(Date.parse("Sunday, 8 June 2014")) # => false ``` -### Business day arithmetic +## Business day arithmetic The `add_business_days` and `subtract_business_days` are used to perform business day arithmetic on dates. @@ -144,7 +170,10 @@ essential for us. Business provides a simple `Calendar` class, that is initializ Secondly, business_time supports calculations on times as well as dates. For our purposes, date-based calculations are sufficient. Supporting time-based calculations as well makes the code significantly more complex. We chose to avoid this extra complexity by sticking solely to date-based mathematics. ---- +

I'm late for business

+## License & Contributing +- business is available as open source under the terms of the [MIT License](LICENSE). +- Bug reports and pull requests are welcome on GitHub at https://github.com/gocardless/business. -![I'm late for business](http://3.bp.blogspot.com/-aq4iOz2OZzs/Ty8xaQwMhtI/AAAAAAAABrM/-vn4tcRA9-4/s1600/daily-morning-awesomeness-243.jpeg) +GoCardless ♥ open source. If you do too, come [join us](https://gocardless.com/about/jobs). From 49238d9cd822284b1066484be996243cb66b8b56 Mon Sep 17 00:00:00 2001 From: Joseph Southan Date: Tue, 5 May 2020 13:46:19 +0100 Subject: [PATCH 6/7] Add missing date require --- lib/business/calendar.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/business/calendar.rb b/lib/business/calendar.rb index 80ed39c..3231922 100644 --- a/lib/business/calendar.rb +++ b/lib/business/calendar.rb @@ -1,4 +1,5 @@ require 'yaml' +require 'date' module Business class Calendar From 5e2aaef766c96702f8b7a2b07064dba4c0fa5099 Mon Sep 17 00:00:00 2001 From: Joseph Southan Date: Thu, 7 May 2020 15:19:09 +0100 Subject: [PATCH 7/7] Bump gem to v2.0.0 --- lib/business/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/business/version.rb b/lib/business/version.rb index 81b7d1d..2f78dfc 100644 --- a/lib/business/version.rb +++ b/lib/business/version.rb @@ -1,3 +1,3 @@ module Business - VERSION = "1.18.0" + VERSION = "2.0.0" end