From 23b8eb94370595b777728759d3254eea08a64de3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 23 May 2023 03:56:27 +0000 Subject: [PATCH 01/90] Bump requests from 2.27.1 to 2.31.0 Bumps [requests](https://github.com/psf/requests) from 2.27.1 to 2.31.0. - [Release notes](https://github.com/psf/requests/releases) - [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md) - [Commits](https://github.com/psf/requests/compare/v2.27.1...v2.31.0) --- updated-dependencies: - dependency-name: requests dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b7af566f..f04fd6fb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -67,7 +67,7 @@ python-dateutil==2.8.2 # via matplotlib pytz==2022.1 # via babel -requests==2.27.1 +requests==2.31.0 # via sphinx scipy==1.8.0 # via -r requirements.in From 6fcb275587f55d50577cdce276b1d056ccdeaddc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gr=C3=BCning?= Date: Fri, 16 Jun 2023 22:57:14 +0200 Subject: [PATCH 02/90] stricter label checks --- galaxy/wrapper/deepTools_macros.xml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/galaxy/wrapper/deepTools_macros.xml b/galaxy/wrapper/deepTools_macros.xml index 0f16a03e..312b040a 100755 --- a/galaxy/wrapper/deepTools_macros.xml +++ b/galaxy/wrapper/deepTools_macros.xml @@ -441,12 +441,14 @@ is vital to you, select Yes below."> - - - - - - + + + + + + + + From 9d75226a122c47aad029186fd9f49db3a7b04756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gr=C3=BCning?= Date: Sat, 17 Jun 2023 15:14:40 +0200 Subject: [PATCH 03/90] add validator --- galaxy/wrapper/deepTools_macros.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/galaxy/wrapper/deepTools_macros.xml b/galaxy/wrapper/deepTools_macros.xml index 312b040a..0e63e48f 100755 --- a/galaxy/wrapper/deepTools_macros.xml +++ b/galaxy/wrapper/deepTools_macros.xml @@ -122,6 +122,7 @@ + [A-Za-z0-9 =-_/+]+ From 252920ba8af1f6c65e723d717a933228fba01be4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gr=C3=BCning?= Date: Sat, 17 Jun 2023 15:15:41 +0200 Subject: [PATCH 04/90] add validator --- galaxy/wrapper/deepTools_macros.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy/wrapper/deepTools_macros.xml b/galaxy/wrapper/deepTools_macros.xml index 0e63e48f..7846e9ae 100755 --- a/galaxy/wrapper/deepTools_macros.xml +++ b/galaxy/wrapper/deepTools_macros.xml @@ -122,7 +122,6 @@ - [A-Za-z0-9 =-_/+]+ @@ -449,6 +448,7 @@ is vital to you, select Yes below."> + [A-Za-z0-9 =-_/+]+ From 87d2284d14ad6fa06ae62bf572d172e4ab428eb5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Jul 2023 23:13:54 +0000 Subject: [PATCH 05/90] Bump scipy from 1.8.0 to 1.10.0 Bumps [scipy](https://github.com/scipy/scipy) from 1.8.0 to 1.10.0. - [Release notes](https://github.com/scipy/scipy/releases) - [Commits](https://github.com/scipy/scipy/compare/v1.8.0...v1.10.0) --- updated-dependencies: - dependency-name: scipy dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b7af566f..c4f741d3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -69,7 +69,7 @@ pytz==2022.1 # via babel requests==2.27.1 # via sphinx -scipy==1.8.0 +scipy==1.10.0 # via -r requirements.in six==1.16.0 # via From ae0e77a218cf2b0a9b73639053a24474be0e7f94 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 20 Jul 2023 11:42:21 +0000 Subject: [PATCH 06/90] Bump pygments from 2.12.0 to 2.15.0 Bumps [pygments](https://github.com/pygments/pygments) from 2.12.0 to 2.15.0. - [Release notes](https://github.com/pygments/pygments/releases) - [Changelog](https://github.com/pygments/pygments/blob/master/CHANGES) - [Commits](https://github.com/pygments/pygments/compare/2.12.0...2.15.0) --- updated-dependencies: - dependency-name: pygments dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b7af566f..6305d79a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -55,7 +55,7 @@ py2bit==0.3.0 # via -r requirements.in pybigwig==0.3.18 # via -r requirements.in -pygments==2.12.0 +pygments==2.15.0 # via sphinx pyparsing==3.0.8 # via From b7f0ac65a76979e90174dca31fce1f7e5496b9c4 Mon Sep 17 00:00:00 2001 From: Garrett Graham Date: Fri, 21 Jul 2023 17:21:12 +0000 Subject: [PATCH 07/90] np.{type} to {type} --- deeptools/heatmapper.py | 6 +++--- deeptools/plotFingerprint.py | 6 +++--- deeptools/plotHeatmap.py | 10 +++++----- deeptools/plotProfile.py | 10 +++++----- deeptools/sumCoveragePerBin.py | 2 +- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/deeptools/heatmapper.py b/deeptools/heatmapper.py index 1a2e5f03..08efea13 100644 --- a/deeptools/heatmapper.py +++ b/deeptools/heatmapper.py @@ -777,7 +777,7 @@ def read_matrix_file(self, matrix_file): # split the line into bed interval and matrix values region = line.split('\t') chrom, start, end, name, score, strand = region[0:6] - matrix_row = np.ma.masked_invalid(np.fromiter(region[6:], np.float64)) + matrix_row = np.ma.masked_invalid(np.fromiter(region[6:], float64)) matrix_rows.append(matrix_row) starts = start.split(",") ends = end.split(",") @@ -852,7 +852,7 @@ def save_matrix(self, file_name): # join np_array values # keeping nans while converting them to strings if not np.ma.is_masked(score_list[idx]): - np.float64(score_list[idx]) + float64(score_list[idx]) matrix_values = "\t".join( np.char.mod('%f', self.matrix.matrix[idx, :])) starts = ["{0}".format(x[0]) for x in region[1]] @@ -1345,7 +1345,7 @@ def removeempty(self): to_keep = [] score_list = np.ma.masked_invalid(np.mean(self.matrix, axis=1)) for idx, region in enumerate(self.regions): - if np.ma.is_masked(score_list[idx]) or np.float64(score_list[idx]) == 0: + if np.ma.is_masked(score_list[idx]) or float64(score_list[idx]) == 0: continue else: to_keep.append(idx) diff --git a/deeptools/plotFingerprint.py b/deeptools/plotFingerprint.py index 4aee5b47..4ea0b50a 100755 --- a/deeptools/plotFingerprint.py +++ b/deeptools/plotFingerprint.py @@ -240,7 +240,7 @@ def getSyntheticJSD(vec): lamb = np.mean(vec) # Average coverage coverage = np.sum(vec) - chip = np.zeros(MAXLEN, dtype=np.int) + chip = np.zeros(MAXLEN, dtype=int) for val in vec: # N.B., we need to clip past the end of the array if val >= MAXLEN: @@ -277,8 +277,8 @@ def getJSD(args, idx, mat): return np.NAN # These will hold the coverage histograms - chip = np.zeros(MAXLEN, dtype=np.int) - input = np.zeros(MAXLEN, dtype=np.int) + chip = np.zeros(MAXLEN, dtype=int) + input = np.zeros(MAXLEN, dtype=int) for row in mat: # ChIP val = row[idx] diff --git a/deeptools/plotHeatmap.py b/deeptools/plotHeatmap.py index bc4bbcc2..97a198f2 100755 --- a/deeptools/plotHeatmap.py +++ b/deeptools/plotHeatmap.py @@ -180,21 +180,21 @@ def addProfilePlot(hm, plt, fig, grids, iterNum, iterNum2, perGroup, averageType ticks[0].label1.set_horizontalalignment('left') ticks[-1].label1.set_horizontalalignment('right') - globalYmin = min(np.float64(globalYmin), ax_profile.get_ylim()[0]) + globalYmin = min(float64(globalYmin), ax_profile.get_ylim()[0]) globalYmax = max(globalYmax, ax_profile.get_ylim()[1]) - # It turns out that set_ylim only takes np.float64s + # It turns out that set_ylim only takes float64s for sample_id, subplot in enumerate(ax_list): localYMin = yMin[sample_id % len(yMin)] localYMax = yMax[sample_id % len(yMax)] lims = [globalYmin, globalYmax] if localYMin: if localYMax: - lims = (np.float64(localYMin), np.float64(localYMax)) + lims = (float64(localYMin), float64(localYMax)) else: - lims = (np.float64(localYMin), lims[1]) + lims = (float64(localYMin), lims[1]) elif localYMax: - lims = (lims[0], np.float64(localYMax)) + lims = (lims[0], float64(localYMax)) if lims[0] >= lims[1]: lims = (lims[0], lims[0] + 1) ax_list[sample_id].set_ylim(lims) diff --git a/deeptools/plotProfile.py b/deeptools/plotProfile.py index 087b4f02..5abf40a3 100755 --- a/deeptools/plotProfile.py +++ b/deeptools/plotProfile.py @@ -750,7 +750,7 @@ def plot_profile(self): self.color_list[coloridx], label, plot_type=self.plot_type) - globalYmin = min(np.float64(globalYmin), ax.get_ylim()[0]) + globalYmin = min(float64(globalYmin), ax.get_ylim()[0]) globalYmax = max(globalYmax, ax.get_ylim()[1]) # Exclude ticks from all but one subplot by default @@ -783,18 +783,18 @@ def plot_profile(self): first = False ax_list.append(ax) - # It turns out that set_ylim only takes np.float64s + # It turns out that set_ylim only takes float64s for sample_id, subplot in enumerate(ax_list): localYMin = self.y_min[sample_id % len(self.y_min)] localYMax = self.y_max[sample_id % len(self.y_max)] lims = [globalYmin, globalYmax] if localYMin is not None: if localYMax is not None: - lims = (np.float64(localYMin), np.float64(localYMax)) + lims = (float64(localYMin), float64(localYMax)) else: - lims = (np.float64(localYMin), lims[1]) + lims = (float64(localYMin), lims[1]) elif localYMax is not None: - lims = (lims[0], np.float64(localYMax)) + lims = (lims[0], float64(localYMax)) if lims[0] >= lims[1]: lims = (lims[0], lims[0] + 1) ax_list[sample_id].set_ylim(lims) diff --git a/deeptools/sumCoveragePerBin.py b/deeptools/sumCoveragePerBin.py index b6a722a2..69e76d99 100644 --- a/deeptools/sumCoveragePerBin.py +++ b/deeptools/sumCoveragePerBin.py @@ -90,7 +90,7 @@ def get_coverage_of_region(self, bamHandle, chrom, regions, except: # bigWig input, as used by plotFingerprint if bamHandle.chroms(chrom): - _ = np.array(bamHandle.stats(chrom, regStart, regEnd, type="mean", nBins=nRegBins), dtype=np.float64) + _ = np.array(bamHandle.stats(chrom, regStart, regEnd, type="mean", nBins=nRegBins), dtype=float64) _[np.isnan(_)] = 0.0 _ = _ * tileSize coverages += _ From 6cfc6d3190277b76996935082cc4d2733cbc8b33 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Jul 2023 21:27:39 +0000 Subject: [PATCH 08/90] Bump certifi from 2022.12.7 to 2023.7.22 Bumps [certifi](https://github.com/certifi/python-certifi) from 2022.12.7 to 2023.7.22. - [Commits](https://github.com/certifi/python-certifi/compare/2022.12.07...2023.07.22) --- updated-dependencies: - dependency-name: certifi dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index b7af566f..13a19be2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,7 +8,7 @@ alabaster==0.7.12 # via sphinx babel==2.10.1 # via sphinx -certifi==2022.12.7 +certifi==2023.7.22 # via requests charset-normalizer==2.0.12 # via requests From 5e9603e1c72f3c241b8e01183fa21d435400e8cf Mon Sep 17 00:00:00 2001 From: WardDeb Date: Thu, 10 Aug 2023 16:59:46 +0200 Subject: [PATCH 09/90] float64 to float --- deeptools/heatmapper.py | 10 +++++----- deeptools/plotHeatmap.py | 8 ++++---- deeptools/plotProfile.py | 8 ++++---- deeptools/sumCoveragePerBin.py | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/deeptools/heatmapper.py b/deeptools/heatmapper.py index 08efea13..f67afaf4 100644 --- a/deeptools/heatmapper.py +++ b/deeptools/heatmapper.py @@ -777,7 +777,7 @@ def read_matrix_file(self, matrix_file): # split the line into bed interval and matrix values region = line.split('\t') chrom, start, end, name, score, strand = region[0:6] - matrix_row = np.ma.masked_invalid(np.fromiter(region[6:], float64)) + matrix_row = np.ma.masked_invalid(np.fromiter(region[6:], float)) matrix_rows.append(matrix_row) starts = start.split(",") ends = end.split(",") @@ -852,7 +852,7 @@ def save_matrix(self, file_name): # join np_array values # keeping nans while converting them to strings if not np.ma.is_masked(score_list[idx]): - float64(score_list[idx]) + float(score_list[idx]) matrix_values = "\t".join( np.char.mod('%f', self.matrix.matrix[idx, :])) starts = ["{0}".format(x[0]) for x in region[1]] @@ -1253,10 +1253,10 @@ def hmcluster(self, k, evaluate_silhouette=True, method='kmeans', clustering_sam matrix = np.asarray(self.matrix) matrix_to_cluster = matrix if clustering_samples is not None: - assert all(i > 0 for i in clustering_samples),\ + assert all(i > 0 for i in clustering_samples), \ "all indices should be bigger than or equal to 1." assert all(i <= len(self.sample_labels) for i in - clustering_samples),\ + clustering_samples), \ "each index should be smaller than or equal to {}(total "\ "number of samples.)".format(len(self.sample_labels)) @@ -1345,7 +1345,7 @@ def removeempty(self): to_keep = [] score_list = np.ma.masked_invalid(np.mean(self.matrix, axis=1)) for idx, region in enumerate(self.regions): - if np.ma.is_masked(score_list[idx]) or float64(score_list[idx]) == 0: + if np.ma.is_masked(score_list[idx]) or float(score_list[idx]) == 0: continue else: to_keep.append(idx) diff --git a/deeptools/plotHeatmap.py b/deeptools/plotHeatmap.py index 97a198f2..6b0f2133 100755 --- a/deeptools/plotHeatmap.py +++ b/deeptools/plotHeatmap.py @@ -180,7 +180,7 @@ def addProfilePlot(hm, plt, fig, grids, iterNum, iterNum2, perGroup, averageType ticks[0].label1.set_horizontalalignment('left') ticks[-1].label1.set_horizontalalignment('right') - globalYmin = min(float64(globalYmin), ax_profile.get_ylim()[0]) + globalYmin = min(float(globalYmin), ax_profile.get_ylim()[0]) globalYmax = max(globalYmax, ax_profile.get_ylim()[1]) # It turns out that set_ylim only takes float64s @@ -190,11 +190,11 @@ def addProfilePlot(hm, plt, fig, grids, iterNum, iterNum2, perGroup, averageType lims = [globalYmin, globalYmax] if localYMin: if localYMax: - lims = (float64(localYMin), float64(localYMax)) + lims = (float(localYMin), float(localYMax)) else: - lims = (float64(localYMin), lims[1]) + lims = (float(localYMin), lims[1]) elif localYMax: - lims = (lims[0], float64(localYMax)) + lims = (lims[0], float(localYMax)) if lims[0] >= lims[1]: lims = (lims[0], lims[0] + 1) ax_list[sample_id].set_ylim(lims) diff --git a/deeptools/plotProfile.py b/deeptools/plotProfile.py index 5abf40a3..415a487c 100755 --- a/deeptools/plotProfile.py +++ b/deeptools/plotProfile.py @@ -750,7 +750,7 @@ def plot_profile(self): self.color_list[coloridx], label, plot_type=self.plot_type) - globalYmin = min(float64(globalYmin), ax.get_ylim()[0]) + globalYmin = min(float(globalYmin), ax.get_ylim()[0]) globalYmax = max(globalYmax, ax.get_ylim()[1]) # Exclude ticks from all but one subplot by default @@ -790,11 +790,11 @@ def plot_profile(self): lims = [globalYmin, globalYmax] if localYMin is not None: if localYMax is not None: - lims = (float64(localYMin), float64(localYMax)) + lims = (float(localYMin), float(localYMax)) else: - lims = (float64(localYMin), lims[1]) + lims = (float(localYMin), lims[1]) elif localYMax is not None: - lims = (lims[0], float64(localYMax)) + lims = (lims[0], float(localYMax)) if lims[0] >= lims[1]: lims = (lims[0], lims[0] + 1) ax_list[sample_id].set_ylim(lims) diff --git a/deeptools/sumCoveragePerBin.py b/deeptools/sumCoveragePerBin.py index 69e76d99..9cde4555 100644 --- a/deeptools/sumCoveragePerBin.py +++ b/deeptools/sumCoveragePerBin.py @@ -90,7 +90,7 @@ def get_coverage_of_region(self, bamHandle, chrom, regions, except: # bigWig input, as used by plotFingerprint if bamHandle.chroms(chrom): - _ = np.array(bamHandle.stats(chrom, regStart, regEnd, type="mean", nBins=nRegBins), dtype=float64) + _ = np.array(bamHandle.stats(chrom, regStart, regEnd, type="mean", nBins=nRegBins), dtype=float) _[np.isnan(_)] = 0.0 _ = _ * tileSize coverages += _ From 4826ebd86b6fc851e184cc50ad2cf4600e194c34 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Wed, 16 Aug 2023 14:08:47 +0200 Subject: [PATCH 10/90] bin execs replaced by toml scripts --- bin/alignmentSieve | 12 ---- bin/bamCompare | 12 ---- bin/bamCoverage | 12 ---- bin/bamPEFragmentSize | 12 ---- bin/bigwigAverage | 12 ---- bin/bigwigCompare | 12 ---- bin/computeGCBias | 12 ---- bin/computeMatrix | 14 ----- bin/computeMatrixOperations | 12 ---- bin/correctGCBias | 12 ---- bin/deeptools | 12 ---- bin/estimateReadFiltering | 12 ---- bin/estimateScaleFactor | 115 ------------------------------------ bin/multiBamSummary | 14 ----- bin/multiBigwigSummary | 14 ----- bin/plotCorrelation | 12 ---- bin/plotCoverage | 12 ---- bin/plotEnrichment | 12 ---- bin/plotFingerprint | 12 ---- bin/plotHeatmap | 12 ---- bin/plotPCA | 12 ---- bin/plotProfile | 12 ---- 22 files changed, 373 deletions(-) delete mode 100755 bin/alignmentSieve delete mode 100755 bin/bamCompare delete mode 100755 bin/bamCoverage delete mode 100755 bin/bamPEFragmentSize delete mode 100755 bin/bigwigAverage delete mode 100755 bin/bigwigCompare delete mode 100755 bin/computeGCBias delete mode 100755 bin/computeMatrix delete mode 100755 bin/computeMatrixOperations delete mode 100755 bin/correctGCBias delete mode 100755 bin/deeptools delete mode 100755 bin/estimateReadFiltering delete mode 100755 bin/estimateScaleFactor delete mode 100755 bin/multiBamSummary delete mode 100755 bin/multiBigwigSummary delete mode 100755 bin/plotCorrelation delete mode 100755 bin/plotCoverage delete mode 100755 bin/plotEnrichment delete mode 100755 bin/plotFingerprint delete mode 100755 bin/plotHeatmap delete mode 100755 bin/plotPCA delete mode 100755 bin/plotProfile diff --git a/bin/alignmentSieve b/bin/alignmentSieve deleted file mode 100755 index 6d35603c..00000000 --- a/bin/alignmentSieve +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python -#-*- coding: utf-8 -*- - -import deeptools.misc -from deeptools.alignmentSieve import main -import sys - -if __name__ == "__main__": - args = None - if len(sys.argv) == 1: - args = ["--help"] - main(args) diff --git a/bin/bamCompare b/bin/bamCompare deleted file mode 100755 index 18cc2c12..00000000 --- a/bin/bamCompare +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python -#-*- coding: utf-8 -*- - -import deeptools.misc -from deeptools.bamCompare import main -import sys - -if __name__ == "__main__": - args = None - if len(sys.argv) == 1: - args = ["--help"] - main(args) diff --git a/bin/bamCoverage b/bin/bamCoverage deleted file mode 100755 index 75fde989..00000000 --- a/bin/bamCoverage +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python -#-*- coding: utf-8 -*- - -import deeptools.misc -from deeptools.bamCoverage import main -import sys - -if __name__ == "__main__": - args = None - if len(sys.argv) == 1: - args = ["--help"] - main(args) diff --git a/bin/bamPEFragmentSize b/bin/bamPEFragmentSize deleted file mode 100755 index f38d51fa..00000000 --- a/bin/bamPEFragmentSize +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python -#-*- coding: utf-8 -*- - -import deeptools.misc -from deeptools.bamPEFragmentSize import main -import sys - -if __name__ == "__main__": - args = None - if len(sys.argv) == 1: - args = ["--help"] - main(args) diff --git a/bin/bigwigAverage b/bin/bigwigAverage deleted file mode 100755 index 3c01a85e..00000000 --- a/bin/bigwigAverage +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python -#-*- coding: utf-8 -*- - -import deeptools.misc -from deeptools.bigwigAverage import main -import sys - -if __name__ == "__main__": - args = None - if len(sys.argv) == 1: - args = ["--help"] - main(args) diff --git a/bin/bigwigCompare b/bin/bigwigCompare deleted file mode 100755 index 61d0ce11..00000000 --- a/bin/bigwigCompare +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python -#-*- coding: utf-8 -*- - -import deeptools.misc -from deeptools.bigwigCompare import main -import sys - -if __name__ == "__main__": - args = None - if len(sys.argv) == 1: - args = ["--help"] - main(args) diff --git a/bin/computeGCBias b/bin/computeGCBias deleted file mode 100755 index bd1726bd..00000000 --- a/bin/computeGCBias +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python -#-*- coding: utf-8 -*- - -import deeptools.misc -from deeptools.computeGCBias import main -import sys - -if __name__ == "__main__": - args = None - if len(sys.argv) == 1: - args = ["--help"] - main(args) diff --git a/bin/computeMatrix b/bin/computeMatrix deleted file mode 100755 index 0e4ed909..00000000 --- a/bin/computeMatrix +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env python -#-*- coding: utf-8 -*- - -import deeptools.misc -from deeptools.computeMatrix import main -import sys - -if __name__ == "__main__": - args = None - if len(sys.argv) == 1: - args = ["--help"] - elif len(sys.argv) == 2 and sys.argv[1] != '--version': - sys.argv.append("--help") - main(args) diff --git a/bin/computeMatrixOperations b/bin/computeMatrixOperations deleted file mode 100755 index 4e72fbea..00000000 --- a/bin/computeMatrixOperations +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python -#-*- coding: utf-8 -*- - -import deeptools.misc -from deeptools.computeMatrixOperations import main -import sys - -if __name__ == "__main__": - args = None - if len(sys.argv) == 1: - args = ["--help"] - main(args) diff --git a/bin/correctGCBias b/bin/correctGCBias deleted file mode 100755 index 2906632c..00000000 --- a/bin/correctGCBias +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python -#-*- coding: utf-8 -*- - -import deeptools.misc -from deeptools.correctGCBias import main -import sys - -if __name__ == "__main__": - args = None - if len(sys.argv) == 1: - args = ["--help"] - main(args) diff --git a/bin/deeptools b/bin/deeptools deleted file mode 100755 index f5cd8a02..00000000 --- a/bin/deeptools +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python -#-*- coding: utf-8 -*- - -import deeptools.misc -from deeptools.deeptools_list_tools import main -import sys - -if __name__ == "__main__": - args = None - if len(sys.argv) == 1: - args = ["--help"] - main(args) diff --git a/bin/estimateReadFiltering b/bin/estimateReadFiltering deleted file mode 100755 index 4948d489..00000000 --- a/bin/estimateReadFiltering +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import deeptools.misc -from deeptools.estimateReadFiltering import main -import sys - -if __name__ == "__main__": - args = None - if len(sys.argv) == 1: - args = ["--help"] - main(args) diff --git a/bin/estimateScaleFactor b/bin/estimateScaleFactor deleted file mode 100755 index 58b6e4ed..00000000 --- a/bin/estimateScaleFactor +++ /dev/null @@ -1,115 +0,0 @@ -#!/usr/bin/env python -#-*- coding: utf-8 -*- - -import deeptools.misc -import argparse -import sys - -from deeptools.SES_scaleFactor import estimateScaleFactor -from deeptools.parserCommon import numberOfProcessors -from deeptools._version import __version__ - -debug = 0 - - -def parseArguments(args=None): - parser = argparse.ArgumentParser( - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - description='Given two BAM files, this estimates scaling factors ' - '(bigger to smaller).') - - # define the arguments - parser.add_argument('--bamfiles', '-b', - metavar='list of bam files', - help='List of indexed BAM files, space delineated', - nargs='+', - required=True) - - - parser.add_argument('--ignoreForNormalization', '-ignore', - help='A comma-separated list of chromosome names, ' - 'limited by quotes, ' - 'containing those ' - 'chromosomes that should be excluded ' - 'during normalization computations. For example, ' - '--ignoreForNormalization "chrX, chrM" ') - - parser.add_argument('--sampleWindowLength', '-l', - help='Length in bases for a window used to ' - 'sample the genome and compute the size or scaling ' - 'factors', - default=1000, - type=int) - - parser.add_argument('--numberOfSamples', '-n', - help='Number of samplings taken from the genome ' - 'to compute the scaling factors', - default=100000, - type=int) - - parser.add_argument('--normalizationLength', '-nl', - help='By default, data is normalized to 1 ' - 'fragment per 100 bases. The expected value is an ' - 'integer. For example, if normalizationLength ' - 'is 1000, then the resulting scaling factor ' - 'will cause the average coverage of the BAM file to ' - 'have on average 1 fragment per kilobase', - type=int, - default=10) - - parser.add_argument('--skipZeros', - help='If set, then zero counts that happen for *all* ' - 'BAM files given are ignored. This will result in a ' - 'reduced number of read counts than that specified ' - 'in --numberOfSamples', - action='store_true', - required=False) - - parser.add_argument('--numberOfProcessors', '-p', - help='Number of processors to use. The default is ' - 'to use half the maximum number of processors.', - metavar="INT", - type=numberOfProcessors, - default="max/2", - required=False) - - parser.add_argument('--verbose', '-v', - help='Set to see processing messages.', - action='store_true') - - parser.add_argument('--version', action='version', - version='%(prog)s {}'.format(__version__)) - - args=parser.parse_args(args) - if args.ignoreForNormalization: - args.ignoreForNormalization=[x.strip() for x in args.ignoreForNormalization.split(',')] - else: - args.ignoreForNormalization = [] - return args - -def main(args): - """ - The algorithm samples the genome a number of times as specified - by the --numberOfSamples parameter to estimate scaling factors of - betweeen to samples - - """ - if len(args.bamfiles) > 2: - print("SES method to stimate scale factors only works for two samples") - exit(0) - - sys.stderr.write("{:,} number of samples will be computed.\n".format(args.numberOfSamples)) - sizeFactorsDict = estimateScaleFactor(args.bamfiles, args.sampleWindowLength, - args.numberOfSamples, - args.normalizationLength, - numberOfProcessors=args.numberOfProcessors, - chrsToSkip=args.ignoreForNormalization, - verbose=args.verbose) - - for k, v in sizeFactorsDict.items(): - print("{}: {}".format(k, v)) - - -if __name__ == "__main__": - args = parseArguments() - main(args) diff --git a/bin/multiBamSummary b/bin/multiBamSummary deleted file mode 100755 index 1dc376ea..00000000 --- a/bin/multiBamSummary +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env python -#-*- coding: utf-8 -*- - -import deeptools.misc -from deeptools.multiBamSummary import main -import sys - -if __name__ == "__main__": - args = None - if len(sys.argv) == 1: - args = ["--help"] - if len(sys.argv) == 2 and sys.argv[1] != "--version": - sys.argv.append("--help") - main(args) diff --git a/bin/multiBigwigSummary b/bin/multiBigwigSummary deleted file mode 100755 index 37108ed9..00000000 --- a/bin/multiBigwigSummary +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env python -#-*- coding: utf-8 -*- - -import deeptools.misc -from deeptools.multiBigwigSummary import main -import sys - -if __name__ == "__main__": - args = None - if len(sys.argv) == 1: - args = ["--help"] - if len(sys.argv) == 2 and sys.argv[1] != "--version": - sys.argv.append("--help") - main(args) diff --git a/bin/plotCorrelation b/bin/plotCorrelation deleted file mode 100755 index 560c15b7..00000000 --- a/bin/plotCorrelation +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python -#-*- coding: utf-8 -*- - -import deeptools.misc -from deeptools.plotCorrelation import main -import sys - -if __name__ == "__main__": - args = None - if len(sys.argv) == 1: - args = ["--help"] - main(args) diff --git a/bin/plotCoverage b/bin/plotCoverage deleted file mode 100755 index 6957ff57..00000000 --- a/bin/plotCoverage +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import deeptools.misc -from deeptools.plotCoverage import main -import sys - -if __name__ == "__main__": - args = None - if len(sys.argv) == 1: - args = ["--help"] - main(args) diff --git a/bin/plotEnrichment b/bin/plotEnrichment deleted file mode 100755 index c1debcb7..00000000 --- a/bin/plotEnrichment +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import deeptools.misc -from deeptools.plotEnrichment import main -import sys - -if __name__ == "__main__": - args = None - if len(sys.argv) == 1: - args = ["--help"] - main(args) diff --git a/bin/plotFingerprint b/bin/plotFingerprint deleted file mode 100755 index c170dc00..00000000 --- a/bin/plotFingerprint +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python -#-*- coding: utf-8 -*- - -import deeptools.misc -from deeptools.plotFingerprint import main -import sys - -if __name__ == "__main__": - args = None - if len(sys.argv) == 1: - args = ["--help"] - main(args) diff --git a/bin/plotHeatmap b/bin/plotHeatmap deleted file mode 100755 index cb38dff7..00000000 --- a/bin/plotHeatmap +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python -#-*- coding: utf-8 -*- - -import deeptools.misc -from deeptools.plotHeatmap import main -import sys - -if __name__ == "__main__": - args = None - if len(sys.argv) == 1: - args = ["--help"] - main(args) diff --git a/bin/plotPCA b/bin/plotPCA deleted file mode 100755 index 636dbcbb..00000000 --- a/bin/plotPCA +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python -#-*- coding: utf-8 -*- - -import deeptools.misc -from deeptools.plotPCA import main -import sys - -if __name__ == "__main__": - args = None - if len(sys.argv) == 1: - args = ["--help"] - main(args) diff --git a/bin/plotProfile b/bin/plotProfile deleted file mode 100755 index b39f5261..00000000 --- a/bin/plotProfile +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env python -#-*- coding: utf-8 -*- - -import deeptools.misc -from deeptools.plotProfile import main -import sys - -if __name__ == "__main__": - args = None - if len(sys.argv) == 1: - args = ["--help"] - main(args) From 0c609ded838130093bf37199ca6c193b11cab768 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Wed, 16 Aug 2023 14:09:14 +0200 Subject: [PATCH 11/90] replace version check for tests with toml version definition --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d35d5517..d83fb359 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,9 +8,9 @@ jobs: steps: - uses: actions/checkout@v1 - name: Check path - run: find /home/runner/work/deepTools/deepTools -name "_version.py" + run: find /home/runner/work/deepTools/deepTools -name "pyproject.toml" - name: Get Version of Deeptools - run: echo "deeptools_version=$(grep "__version__" /home/runner/work/deepTools/deepTools/deeptools/_version.py | awk '{print substr($NF, 2, length($NF) - 2)}')" >> $GITHUB_ENV + run: echo "deeptools_version=$(grep "version" /home/runner/work/deepTools/deepTools/pyproject.toml | awk '{print substr($NF, 2, length($NF) - 2)}')" >> $GITHUB_ENV - name: Get Version of Galaxy tools run: echo "galaxy_deeptools_version=$(grep "token.*TOOL_VERSION" /home/runner/work/deepTools/deepTools/galaxy/wrapper/deepTools_macros.xml | awk -F '>|<' '{print $3}')" >> $GITHUB_ENV - name: Versions From 288ba70d68cfa61f6cba0f47ec962c95d869aa1c Mon Sep 17 00:00:00 2001 From: WardDeb Date: Wed, 16 Aug 2023 14:09:33 +0200 Subject: [PATCH 12/90] remove _version file --- deeptools/_version.py | 5 ----- 1 file changed, 5 deletions(-) delete mode 100755 deeptools/_version.py diff --git a/deeptools/_version.py b/deeptools/_version.py deleted file mode 100755 index cb8316dc..00000000 --- a/deeptools/_version.py +++ /dev/null @@ -1,5 +0,0 @@ - -# This file is originally generated from Git information by running 'setup.py -# version'. Distribution tarballs contain a pre-generated copy of this file. - -__version__ = '3.5.2' From fb0a242a698fb729f1f5de9a62fcdb7fee36fdc6 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Wed, 16 Aug 2023 14:09:57 +0200 Subject: [PATCH 13/90] version checks with importlib --- deeptools/alignmentSieve.py | 4 ++-- deeptools/bamPEFragmentSize.py | 4 ++-- deeptools/computeMatrix.py | 6 +++--- deeptools/computeMatrixOperations.py | 4 ++-- deeptools/deeptools_list_tools.py | 4 ++-- deeptools/estimateReadFiltering.py | 4 ++-- deeptools/multiBamSummary.py | 4 ++-- deeptools/multiBigwigSummary.py | 4 ++-- deeptools/parserCommon.py | 6 +++--- deeptools/plotCorrelation.py | 4 ++-- deeptools/plotCoverage.py | 4 ++-- deeptools/plotPCA.py | 5 ++--- 12 files changed, 26 insertions(+), 27 deletions(-) diff --git a/deeptools/alignmentSieve.py b/deeptools/alignmentSieve.py index 5e28b2ce..9e1d621b 100644 --- a/deeptools/alignmentSieve.py +++ b/deeptools/alignmentSieve.py @@ -7,7 +7,7 @@ from deeptools import parserCommon from deeptools.bamHandler import openBam from deeptools.mapReduce import mapReduce -from deeptools._version import __version__ +from importlib.metadata import version from deeptools.utilities import getTLen, smartLabels, getTempFileName @@ -60,7 +60,7 @@ def parseArguments(): action='store_true') general.add_argument('--version', action='version', - version='%(prog)s {}'.format(__version__)) + version='%(prog)s {}'.format(version('deeptools'))) general.add_argument('--shift', nargs='+', diff --git a/deeptools/bamPEFragmentSize.py b/deeptools/bamPEFragmentSize.py index 646b51ca..35cedfa4 100755 --- a/deeptools/bamPEFragmentSize.py +++ b/deeptools/bamPEFragmentSize.py @@ -18,7 +18,7 @@ # own tools from deeptools.parserCommon import writableFile from deeptools.getFragmentAndReadSize import get_read_and_fragment_length -from deeptools._version import __version__ +from importlib.metadata import version def parse_arguments(): @@ -109,7 +109,7 @@ def parse_arguments(): action='store_true', required=False) parser.add_argument('--version', action='version', - version='%(prog)s {}'.format(__version__)) + version='%(prog)s {}'.format(version('deeptools'))) return parser diff --git a/deeptools/computeMatrix.py b/deeptools/computeMatrix.py index 99c12832..25cf9521 100644 --- a/deeptools/computeMatrix.py +++ b/deeptools/computeMatrix.py @@ -7,7 +7,7 @@ import multiprocessing from deeptools.parserCommon import writableFile, numberOfProcessors -from deeptools._version import __version__ +from importlib.metadata import version from deeptools import parserCommon from deeptools import heatmapper import deeptools.computeMatrixOperations as cmo @@ -37,7 +37,7 @@ def parse_arguments(args=None): ' -R -b 1000\n \n') parser.add_argument('--version', action='version', - version='%(prog)s {}'.format(__version__)) + version='%(prog)s {}'.format(version('deeptools'))) subparsers = parser.add_subparsers( title='Commands', @@ -137,7 +137,7 @@ def computeMatrixOptArgs(case=['scale-regions', 'reference-point'][0]): parser = argparse.ArgumentParser(add_help=False) optional = parser.add_argument_group('Optional arguments') optional.add_argument('--version', action='version', - version='%(prog)s {}'.format(__version__)) + version='%(prog)s {}'.format(version('deeptools'))) if case == 'scale-regions': optional.add_argument('--regionBodyLength', '-m', diff --git a/deeptools/computeMatrixOperations.py b/deeptools/computeMatrixOperations.py index deb62076..0abf4b7e 100755 --- a/deeptools/computeMatrixOperations.py +++ b/deeptools/computeMatrixOperations.py @@ -6,7 +6,7 @@ import sys import os import csv -from deeptools._version import __version__ +from importlib.metadata import version def parse_arguments(): @@ -138,7 +138,7 @@ def parse_arguments(): usage='Example usage:\n computeMatrixOperations dataRange -m input.mat.gz\n\n') parser.add_argument('--version', action='version', - version='%(prog)s {}'.format(__version__)) + version='%(prog)s {}'.format(version('deeptools'))) return parser diff --git a/deeptools/deeptools_list_tools.py b/deeptools/deeptools_list_tools.py index 15b0e6a8..32dcf702 100644 --- a/deeptools/deeptools_list_tools.py +++ b/deeptools/deeptools_list_tools.py @@ -3,7 +3,7 @@ import argparse import sys -from deeptools._version import __version__ +from importlib.metadata import version def parse_arguments(args=None): @@ -61,7 +61,7 @@ def parse_arguments(args=None): """) parser.add_argument('--version', action='version', - version='%(prog)s {}'.format(__version__)) + version='%(prog)s {}'.format(version('deeptools'))) return parser diff --git a/deeptools/estimateReadFiltering.py b/deeptools/estimateReadFiltering.py index 464fe099..63b02327 100644 --- a/deeptools/estimateReadFiltering.py +++ b/deeptools/estimateReadFiltering.py @@ -5,7 +5,7 @@ from deeptools import parserCommon, bamHandler, utilities from deeptools.mapReduce import mapReduce from deeptools.utilities import smartLabels -from deeptools._version import __version__ +from importlib.metadata import version def parseArguments(): @@ -92,7 +92,7 @@ def parseArguments(): action='store_true') general.add_argument('--version', action='version', - version='%(prog)s {}'.format(__version__)) + version='%(prog)s {}'.format(version('deeptools'))) filtering = parser.add_argument_group('Optional arguments') diff --git a/deeptools/multiBamSummary.py b/deeptools/multiBamSummary.py index a588c09c..433adb4e 100644 --- a/deeptools/multiBamSummary.py +++ b/deeptools/multiBamSummary.py @@ -9,7 +9,7 @@ import deeptools.countReadsPerBin as countR from deeptools import parserCommon from deeptools.utilities import smartLabels -from deeptools._version import __version__ +from importlib.metadata import version old_settings = np.seterr(all='ignore') @@ -44,7 +44,7 @@ def parse_arguments(args=None): conflict_handler='resolve') parser.add_argument('--version', action='version', - version='%(prog)s {}'.format(__version__)) + version='%(prog)s {}'.format(version('deeptools'))) subparsers = parser.add_subparsers( title="commands", dest='command', diff --git a/deeptools/multiBigwigSummary.py b/deeptools/multiBigwigSummary.py index 8d89421f..ad616090 100644 --- a/deeptools/multiBigwigSummary.py +++ b/deeptools/multiBigwigSummary.py @@ -7,7 +7,7 @@ import numpy as np import multiprocessing from deeptools import parserCommon -from deeptools._version import __version__ +from importlib.metadata import version from deeptools.utilities import smartLabels import deeptools.getScorePerBigWigBin as score_bw import deeptools.deepBlue as db @@ -43,7 +43,7 @@ def parse_arguments(args=None): conflict_handler='resolve') parser.add_argument('--version', action='version', - version='multiBigwigSummary {}'.format(__version__)) + version='multiBigwigSummary {}'.format(version('deeptools'))) subparsers = parser.add_subparsers( title="commands", dest='command', diff --git a/deeptools/parserCommon.py b/deeptools/parserCommon.py index ef4f4d07..8e726ea0 100755 --- a/deeptools/parserCommon.py +++ b/deeptools/parserCommon.py @@ -1,6 +1,6 @@ import argparse import os -from deeptools._version import __version__ +from importlib.metadata import version def check_float_0_1(value): @@ -297,7 +297,7 @@ def getParentArgParse(args=None, binSize=True, blackList=True): optional = parser.add_argument_group('Optional arguments') optional.add_argument('--version', action='version', - version='%(prog)s {}'.format(__version__)) + version='%(prog)s {}'.format(version('deeptools'))) if binSize: optional.add_argument('--binSize', '-bs', @@ -521,7 +521,7 @@ def heatmapperOptionalArgs(mode=['heatmap', 'profile'][0]): optional.add_argument("--help", "-h", action="help", help="show this help message and exit") optional.add_argument('--version', action='version', - version='%(prog)s {}'.format(__version__)) + version='%(prog)s {}'.format(version('deeptools'))) if mode == 'profile': optional.add_argument( '--averageType', diff --git a/deeptools/plotCorrelation.py b/deeptools/plotCorrelation.py index a03839ba..e3a553f5 100644 --- a/deeptools/plotCorrelation.py +++ b/deeptools/plotCorrelation.py @@ -13,7 +13,7 @@ from deeptools.correlation import Correlation from deeptools.parserCommon import writableFile -from deeptools._version import __version__ +from importlib.metadata import version old_settings = np.seterr(all='ignore') @@ -117,7 +117,7 @@ def plot_correlation_args(): action='store_true') optional.add_argument('--version', action='version', - version='%(prog)s {}'.format(__version__)) + version='%(prog)s {}'.format(version('deeptools'))) group = parser.add_argument_group('Output optional options') diff --git a/deeptools/plotCoverage.py b/deeptools/plotCoverage.py index 02ce25da..d0b8613b 100755 --- a/deeptools/plotCoverage.py +++ b/deeptools/plotCoverage.py @@ -18,7 +18,7 @@ import deeptools.countReadsPerBin as countR from deeptools import parserCommon from deeptools.utilities import smartLabels -from deeptools._version import __version__ +from importlib.metadata import version old_settings = np.seterr(all='ignore') @@ -49,7 +49,7 @@ def parse_arguments(args=None): conflict_handler='resolve') parser.add_argument('--version', action='version', - version='plotCoverage {}'.format(__version__)) + version='plotCoverage {}'.format(version('deeptools'))) return parser diff --git a/deeptools/plotPCA.py b/deeptools/plotPCA.py index d12eac8d..75dc8a4b 100644 --- a/deeptools/plotPCA.py +++ b/deeptools/plotPCA.py @@ -11,8 +11,7 @@ from deeptools.correlation import Correlation from deeptools.parserCommon import writableFile -from deeptools._version import __version__ - +from importlib.metadata import version def parse_arguments(args=None): basic_args = plotCorrelationArgs() @@ -133,7 +132,7 @@ def plotCorrelationArgs(): help="A list of markers for the symbols. (e.g., '<','>','o') are accepted. The marker values should be space separated. For example, --markers 's' 'o' 's' 'o'. If not specified, the symbols will be given automatic shapes.") optional.add_argument('--version', action='version', - version='%(prog)s {}'.format(__version__)) + version='%(prog)s {}'.format(version('deeptools'))) optionalEx = optional.add_mutually_exclusive_group() optionalEx.add_argument('--transpose', From 45dea0000ac85478347bef903e1bb3f471ab97bc Mon Sep 17 00:00:00 2001 From: WardDeb Date: Wed, 16 Aug 2023 14:10:24 +0200 Subject: [PATCH 14/90] version check docs update to importlib --- docs/conf.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index f88dd260..cd8b3abc 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -14,6 +14,7 @@ import sys import os +import tomllib # to allow readthedocs to compile without installing some dependencies import mock @@ -81,18 +82,12 @@ def get_version(): - import re + with open('../pyproject.toml', 'rb') as f: + d = tomllib.load(f) try: - f = open("../deeptools/_version.py") - except EnvironmentError: + return d['project']['version'] + except: return None - for line in f.readlines(): - mo = re.match("__version__ = '([^']+)'", line) - if mo: - ver = mo.group(1) - return ver - return None - version = get_version() # The full version, including alpha/beta/rc tags. From 6ca54b0bbb9976da20e91e5f8f20be2f0714b729 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Wed, 16 Aug 2023 14:11:44 +0200 Subject: [PATCH 15/90] purge reqs & setup.py --- requirements.txt | 99 ------------------------------------------------ setup.py | 97 ----------------------------------------------- 2 files changed, 196 deletions(-) delete mode 100644 requirements.txt delete mode 100755 setup.py diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index bdca3431..00000000 --- a/requirements.txt +++ /dev/null @@ -1,99 +0,0 @@ -# -# This file is autogenerated by pip-compile with python 3.9 -# To update, run: -# -# pip-compile -# -alabaster==0.7.12 - # via sphinx -babel==2.10.1 - # via sphinx -certifi==2023.7.22 - # via requests -charset-normalizer==2.0.12 - # via requests -cycler==0.11.0 - # via matplotlib -deeptoolsintervals==0.1.9 - # via -r requirements.in -docutils==0.17.1 - # via sphinx -fonttools==4.33.3 - # via matplotlib -idna==3.3 - # via requests -imagesize==1.3.0 - # via sphinx -importlib-metadata==4.11.3 - # via sphinx -jinja2==3.1.2 - # via - # numpydoc - # sphinx -kiwisolver==1.4.2 - # via matplotlib -markupsafe==2.1.1 - # via jinja2 -matplotlib>=3.5<3.6 - # We're manually setting matplitlib <3.6 to avoide issue #1172 -numpy==1.22.3 - # via - # -r requirements.in - # matplotlib - # scipy -numpydoc==1.3.1 - # via -r requirements.in -packaging==21.3 - # via - # matplotlib - # sphinx -pillow==9.3.0 - # via matplotlib -plotly==5.7.0 - # via -r requirements.in -py2bit==0.3.0 - # via -r requirements.in -pybigwig==0.3.18 - # via -r requirements.in -pygments==2.15.0 - # via sphinx -pyparsing==3.0.8 - # via - # matplotlib - # packaging -pysam==0.19.0 - # via -r requirements.in -python-dateutil==2.8.2 - # via matplotlib -pytz==2022.1 - # via babel -requests==2.31.0 - # via sphinx -scipy==1.10.0 - # via -r requirements.in -six==1.16.0 - # via - # plotly - # python-dateutil -snowballstemmer==2.2.0 - # via sphinx -sphinx==4.5.0 - # via numpydoc -sphinxcontrib-applehelp==1.0.2 - # via sphinx -sphinxcontrib-devhelp==1.0.2 - # via sphinx -sphinxcontrib-htmlhelp==2.0.0 - # via sphinx -sphinxcontrib-jsmath==1.0.1 - # via sphinx -sphinxcontrib-qthelp==1.0.3 - # via sphinx -sphinxcontrib-serializinghtml==1.1.5 - # via sphinx -tenacity==8.0.1 - # via plotly -urllib3==1.26.9 - # via requests -zipp==3.8.0 - # via importlib-metadata \ No newline at end of file diff --git a/setup.py b/setup.py deleted file mode 100755 index 76514364..00000000 --- a/setup.py +++ /dev/null @@ -1,97 +0,0 @@ -# -*- coding: utf-8 -*- - -import re - -from setuptools import setup, find_packages -from setuptools.command.sdist import sdist as _sdist -from setuptools.command.install import install as _install - -VERSION_PY = """ -# This file is originally generated from Git information by running 'setup.py -# version'. Distribution tarballs contain a pre-generated copy of this file. - -__version__ = '%s' -""" - - -def get_version(): - try: - f = open("deeptools/_version.py") - except EnvironmentError: - return None - for line in f.readlines(): - mo = re.match("__version__ = '([^']+)'", line) - if mo: - ver = mo.group(1) - return ver - return None - - -class sdist(_sdist): - - def run(self): - self.distribution.metadata.version = get_version() - return _sdist.run(self) - - -class install(_install): - - def run(self): - self.distribution.metadata.version = get_version() - _install.run(self) - return - - -def openREADME(): - """ - This is only needed because README.rst is UTF-8 encoded and that won't work - under python3 iff sys.getfilesystemencoding() returns 'ascii' - - Since open() doesn't accept an encoding in python2... - """ - try: - f = open("README.rst", encoding="utf-8") - except: - f = open("README.rst") - - foo = f.read() - f.close() - return foo - - -setup( - name='deepTools', - version=get_version(), - author='Fidel Ramirez, Devon P Ryan, Björn Grüning, Friederike Dündar, Sarah Diehl,' - ' Vivek Bhardwaj, Fabian Kilpert, Andreas S Richter, Steffen Heyne, Thomas Manke', - author_email='dpryan79@gmail.com', - packages=find_packages(), - scripts=['bin/bamCompare', 'bin/bamCoverage', 'bin/multiBamSummary', - 'bin/plotHeatmap', 'bin/plotFingerprint', 'bin/estimateScaleFactor', - 'bin/bamPEFragmentSize', 'bin/computeMatrix', 'bin/plotProfile', - 'bin/computeGCBias', 'bin/correctGCBias', 'bin/multiBigwigSummary', - 'bin/bigwigCompare', 'bin/plotCoverage', 'bin/plotPCA', 'bin/plotCorrelation', - 'bin/plotEnrichment', 'bin/deeptools', 'bin/computeMatrixOperations', - 'bin/estimateReadFiltering', 'bin/alignmentSieve', 'bin/bigwigAverage'], - include_package_data=True, - url='http://pypi.python.org/pypi/deepTools/', - license='LICENSE.txt', - description='Useful tools for exploring deep sequencing data ', - long_description=openREADME(), - classifiers=[ - 'Intended Audience :: Science/Research', - 'Topic :: Scientific/Engineering :: Bio-Informatics'], - install_requires=[ - "numpy >= 1.9.0", - "scipy >= 0.17.0", - "matplotlib >= 3.3.0", - "pysam >= 0.14.0", - "numpydoc >= 0.5", - "pyBigWig >= 0.2.1", - "py2bit >= 0.2.0", - "plotly >= 4.9", - "deeptoolsintervals >= 0.1.8" - ], - zip_safe=True, - cmdclass={'sdist': sdist, 'install': install} -) From c986db967e429bf9d3fff5c4c286c6b6fc889d1f Mon Sep 17 00:00:00 2001 From: WardDeb Date: Wed, 16 Aug 2023 14:11:54 +0200 Subject: [PATCH 16/90] init toml --- pyproject.toml | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..c5dfe3e8 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,72 @@ +[build-system] +requires = [ + "setuptools" +] + +[project] +name = "deepTools" +version = "3.5.3.dev1" +authors = [ + {name="Fidel Ramirez"}, + {name="Devon P Ryan"}, + {name="Björn Grüning"}, + {name="Friederike Dündar"}, + {name="Sarah Diehl"}, + {name="Vivek Bhardwaj"}, + {name="Fabian Kilpert"}, + {name="Andreas S Richter"}, + {name="Steffen Heyne"}, + {name="Thomas Manke"}, + {email="bioinfo-core@ie-freiburg.mpg.de"} +] +requires-python = ">=3.7" +dependencies = [ + "numpy >= 1.9.0", + "scipy >= 0.17.0", + "matplotlib >= 3.3.0", + "pysam >= 0.14.0", + "numpydoc >= 0.5", + "pyBigWig >= 0.2.1", + "py2bit >= 0.2.0", + "plotly >= 4.9", + "deeptoolsintervals >= 0.1.8" +] +description = "Useful tools for exploring deep sequencing data." +license = {file = "LICENSE.txt"} +classifiers = [ + "Intended Audience :: Science/Research", + "Topic :: Scientific/Engineering :: Bio-Informatics" +] +readme = "README.rst" + +[project.urls] +homepage = "https://pypi.python.org/pypi/deepTools/" +documentation = "https://deeptools.readthedocs.io/en/latest/" +repository = "https://github.com/deeptools/deepTools" + +[tool.setuptools] +packages = ["deeptools"] + +[project.scripts] +alignmentSieve = "deeptools.alignmentSieve:main" +bamCompare = "deeptools.bamCompare:main" +bamCoverage = "deeptools.bamCoverage:main" +bamPEFragmentSize = "deeptools.bamPEFragmentSize:main" +bigwigAverage = "deeptools.bigwigAverage:main" +bigwigCompare = "deeptools.bigwigCompare:main" +computeGCBias = "deeptools.computeGCBias:main" +computeMatrix = "deeptools.computeMatrix:main" +computeMatrixOperations = "deeptools.computeMatrixOperations:main" +correctGCBias = "deeptools.correctGCBias:main" +deeptools = "deeptools.deeptools_list_tools:main" +estimateReadFiltering = "deeptools.estimateReadFiltering:main" +estimateScaleFactor = "deeptools.estimateScaleFactor:main" +multiBamSummary = "deeptools.multiBamSummary:main" +multiBigwigSummary = "deeptools.multiBigwigSummary:main" +plotCorrelation = "deeptools.plotCorrelation:main" +plotCoverage = "deeptools.plotCoverage:main" +plotEnrichment = "deeptools.plotEnrichment:main" +plotFingerprint = "deeptools.plotFingerPrint:main" +plotHeatmap = "deeptools.plotHeatmap:main" +plotPCA = "deeptools.plotPCA:main" +plotProfile = "deeptools.plotProfile:main" From ce327bcdfa80fbdc7bd82b39e424bb03f3f15450 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Wed, 16 Aug 2023 14:26:39 +0200 Subject: [PATCH 17/90] update cm for mpl > 3.7 --- deeptools/cm.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deeptools/cm.py b/deeptools/cm.py index fcb7c20f..47bcf162 100644 --- a/deeptools/cm.py +++ b/deeptools/cm.py @@ -30,7 +30,7 @@ # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -from matplotlib import colors, cm as mpl_cm +from matplotlib import colors, colormaps as mpl_cm _rocket_lut = [ @@ -1084,5 +1084,5 @@ _cmap_r = colors.ListedColormap(_lut[::-1], _name + "_r") locals()[_name + "_r"] = _cmap_r - mpl_cm.register_cmap(_name, _cmap) - mpl_cm.register_cmap(_name + "_r", _cmap_r) + mpl_cm.register(_cmap, name=_name) + mpl_cm.register(_cmap_r, name=_name + "_r") From 63526573ae9d6f38acd77c6b365d068ff25aa3e4 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Wed, 16 Aug 2023 16:27:17 +0200 Subject: [PATCH 18/90] port nosetests to pytest --- .../test/test_bamCoverage_and_bamCompare.py | 31 ++- .../test/test_computeMatrixOperations.py | 18 +- deeptools/test/test_countReadsPerBin.py | 217 ++++++++---------- ...er_images.py => test_heatmapper_images.py} | 5 - deeptools/test/test_readFiltering.py | 11 +- deeptools/test/test_writeBedGraph.py | 151 +++++------- 6 files changed, 181 insertions(+), 252 deletions(-) rename deeptools/test/{testskip_heatmapper_images.py => test_heatmapper_images.py} (98%) diff --git a/deeptools/test/test_bamCoverage_and_bamCompare.py b/deeptools/test/test_bamCoverage_and_bamCompare.py index fbc8b9fd..a7e5e4ad 100644 --- a/deeptools/test/test_bamCoverage_and_bamCompare.py +++ b/deeptools/test/test_bamCoverage_and_bamCompare.py @@ -1,4 +1,3 @@ -from nose.tools import assert_equal import deeptools.bamCoverage as bam_cov import deeptools.bamCompare as bam_comp import deeptools.getScaleFactor as gs @@ -46,7 +45,7 @@ def test_bam_coverage_arguments(): resp = _foo.readlines() _foo.close() expected = ['3R\t0\t50\t0\n', '3R\t50\t150\t1\n', '3R\t150\t200\t2\n'] - assert_equal(resp, expected) + assert resp == expected, "{} != {}".format(resp, expected) unlink(outfile) @@ -59,7 +58,7 @@ def test_bam_coverage_extend(): resp = _foo.readlines() _foo.close() expected = ['3R\t0\t150\t1\n', '3R\t150\t200\t3\n'] - assert_equal(resp, expected) + assert resp == expected, "{} != {}".format(resp, expected) unlink(outfile) @@ -76,7 +75,7 @@ def test_bam_coverage_extend_and_normalizeUsingRPGC(): # the scale factor should be 0.5, thus the result is similar to # that of the previous test divided by 0.5 expected = ['3R\t0\t150\t0.5\n', '3R\t150\t200\t1.5\n'] - assert_equal(resp, expected) + assert resp == expected, "{} != {}".format(resp, expected) unlink(outfile) @@ -90,7 +89,7 @@ def test_bam_coverage_skipnas(): resp = _foo.readlines() _foo.close() expected = ['3R\t50\t150\t1\n', '3R\t150\t200\t2\n'] - assert_equal(resp, expected) + assert resp == expected, "{} != {}".format(resp, expected) unlink(outfile) @@ -104,7 +103,7 @@ def test_bam_coverage_filtering(): resp = _foo.readlines() _foo.close() expected = ['3R\t0\t50\t0\n', '3R\t50\t200\t1\n'] - assert_equal(resp, expected) + assert resp == expected, "{} != {}".format(resp, expected) unlink(outfile) @@ -124,7 +123,7 @@ def test_bam_compare_arguments(): resp = _foo.readlines() _foo.close() expected = ['3R\t0\t200\t1\n'] - assert_equal(resp, expected) + assert resp == expected, "{} != {}".format(resp, expected) unlink(outfile) @@ -142,7 +141,7 @@ def test_bam_compare_diff_files(): resp = _foo.readlines() _foo.close() expected = ['3R\t0\t50\t0\n', '3R\t50\t100\t-1\n', '3R\t100\t150\t0\n', '3R\t150\t200\t-1\n'] - assert_equal(resp, expected) + assert resp == expected, "{} != {}".format(resp, expected) unlink(outfile) @@ -159,7 +158,7 @@ def test_bam_compare_pseudocounts(): resp = _foo.readlines() _foo.close() expected = ['3R\t0\t50\tinf\n', '3R\t50\t100\t0\n', '3R\t100\t150\t1\n', '3R\t150\t200\t0\n'] - assert_equal(resp, expected) + assert resp == expected, "{} != {}".format(resp, expected) unlink(outfile) @@ -176,7 +175,7 @@ def test_bam_compare_ZoverZ(): resp = _foo.readlines() _foo.close() expected = ['3R\t50\t100\t-1\n', '3R\t100\t150\t0\n', '3R\t150\t200\t-0.584963\n'] - assert_equal(resp, expected) + assert resp == expected, "{} != {}".format(resp, expected) unlink(outfile) @@ -228,7 +227,7 @@ def test_bam_compare_diff_files_skipnas(): resp = _foo.readlines() _foo.close() expected = ['3R\t100\t150\t0\n', '3R\t150\t200\t-1\n'] - assert_equal(resp, expected) + assert resp == expected, "{} != {}".format(resp, expected) unlink(outfile) @@ -246,7 +245,7 @@ def test_bam_compare_extend(): resp = _foo.readlines() _foo.close() expected = ['3R\t0\t100\t-1\n', '3R\t100\t150\t1\n', '3R\t150\t200\t-1\n'] - assert_equal(resp, expected) + assert resp == expected, "{} != {}".format(resp, expected) unlink(outfile) @@ -286,7 +285,7 @@ def test_bam_compare_scale_factors_ratio(): """ expected = ['3R\t0\t50\t1\n', '3R\t50\t100\t0.666667\n', '3R\t100\t150\t1.33333\n', '3R\t150\t200\t1\n'] - assert_equal(resp, expected) + assert resp == expected, "{} != {}".format(resp, expected) unlink(outfile) @@ -328,7 +327,7 @@ def test_bam_compare_scale_factors_subtract(): """ expected = ['3R\t0\t50\t0\n', '3R\t50\t100\t-250000\n', '3R\t100\t150\t250000\n', '3R\t150\t200\t0\n'] - assert_equal(resp, expected) + assert resp == expected, "{} != {}".format(resp, expected) unlink(outfile) @@ -358,7 +357,7 @@ def test_bam_coverage_filter_blacklist(): '3R\t950\t1000\t1.62672\n', '3R\t1000\t1050\t0.813362\n', '3R\t1050\t1500\t0\n'] - assert_equal(resp, expected) + assert resp == expected, "{} != {}".format(resp, expected) unlink(outfile) @@ -459,5 +458,5 @@ def test_bam_compare_filter_blacklist(): '3R\t750\t800\t-0.123451\n', '3R\t900\t950\t0.212545\n', '3R\t950\t1000\t0.199309\n', '3R\t1000\t1050\t0.167945\n', '3R\t1050\t1500\t0\n'] - assert_equal(resp, expected) + assert resp == expected, "{} != {}".format(resp, expected) unlink(outfile) diff --git a/deeptools/test/test_computeMatrixOperations.py b/deeptools/test/test_computeMatrixOperations.py index 27f2e633..df81d545 100644 --- a/deeptools/test/test_computeMatrixOperations.py +++ b/deeptools/test/test_computeMatrixOperations.py @@ -8,9 +8,6 @@ __author__ = 'Devon' -ROOT = os.path.dirname(os.path.abspath(__file__)) + "/test_data/" - - def getHeader(fp): s = fp.readline() if isinstance(s, bytes): @@ -20,20 +17,21 @@ def getHeader(fp): class TestComputeMatrixOperations(object): - def setUp(self): - self.root = ROOT - self.matrix = self.root + "computeMatrixOperations.mat.gz" - self.bed = self.root + "computeMatrixOperations.bed" - self.rbindMatrix1 = self.root + "somegenes.txt.gz" - self.rbindMatrix2 = self.root + "othergenes.txt.gz" + root = os.path.dirname(os.path.abspath(__file__)) + "/test_data/" + matrix = root + "computeMatrixOperations.mat.gz" + bed = root + "computeMatrixOperations.bed" + rbindMatrix1 = root + "somegenes.txt.gz" + rbindMatrix2 = root + "othergenes.txt.gz" def testSubset(self): """ computeMatrixOperations subset """ + dCorrect = {"verbose": True, "scale": 1, "skip zeros": False, "nan after end": False, "sort using": "mean", "unscaled 5 prime": [0, 0, 0, 0], "body": [1000, 1000, 1000, 1000], "sample_labels": ["SRR648667.forward", "SRR648668.forward", "SRR648669.forward", "SRR648670.forward"], "downstream": [0, 0, 0, 0], "unscaled 3 prime": [0, 0, 0, 0], "group_labels": ["genes"], "bin size": [10, 10, 10, 10], "upstream": [0, 0, 0, 0], "group_boundaries": [0, 196], "sample_boundaries": [0, 100, 200, 300, 400], "max threshold": None, "ref point": [None, None, None, None], "min threshold": None, "sort regions": "no", "proc number": 20, "bin avg type": "mean", "missing data as zero": False} oname = "/tmp/subset.mat.gz" args = "subset -m {} --sample SRR648667.forward SRR648668.forward SRR648669.forward SRR648670.forward -o {}".format(self.matrix, oname) + print(args) args = args.split() cmo.main(args) f = gzip.GzipFile(oname) @@ -68,7 +66,7 @@ def testfilterStrand(self): dCorrect = {"verbose": True, "scale": 1, "skip zeros": False, "nan after end": False, "sort using": "mean", "unscaled 5 prime": [0, 0, 0, 0, 0, 0, 0, 0], "body": [1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000], "sample_labels": ["SRR648667.forward", "SRR648668.forward", "SRR648669.forward", "SRR648670.forward", "SRR648667.reverse", "SRR648668.reverse", "SRR648669.reverse", "SRR648670.reverse"], "downstream": [0, 0, 0, 0, 0, 0, 0, 0], "unscaled 3 prime": [0, 0, 0, 0, 0, 0, 0, 0], "group_labels": ["genes"], "bin size": [10, 10, 10, 10, 10, 10, 10, 10], "upstream": [0, 0, 0, 0, 0, 0, 0, 0], "group_boundaries": [0, 107], "sample_boundaries": [0, 100, 200, 300, 400, 500, 600, 700, 800], "max threshold": None, "ref point": [None, None, None, None, None, None, None, None], "min threshold": None, "sort regions": "no", "proc number": 20, "bin avg type": "mean", "missing data as zero": False} oname = "/tmp/filterStrand1.mat.gz" args = "filterStrand -m {} -o {} --strand +".format(self.matrix, oname) - args = args.split() + args = args.split(' ') cmo.main(args) f = gzip.GzipFile(oname) d = getHeader(f) # Skip the header, which can be in a different order diff --git a/deeptools/test/test_countReadsPerBin.py b/deeptools/test/test_countReadsPerBin.py index 52941071..882ca603 100644 --- a/deeptools/test/test_countReadsPerBin.py +++ b/deeptools/test/test_countReadsPerBin.py @@ -4,157 +4,163 @@ import numpy as np import numpy.testing as nt import os.path +import pytest __author__ = 'Fidel' -ROOT = os.path.dirname(os.path.abspath(__file__)) + "/test_data/" +@pytest.mark.parametrize("bc", ["bam", 'cram']) +class TestCountReadsPerBin(): - -class TestCountReadsPerBin(object): - - def setUp(self): - """ - The distribution of reads between the two bam files is as follows. - - They cover 200 bp:: - - 0 100 200 - |------------------------------------------------------------| - A ==============> - <============== - - - B <============== ==============> - ==============> - ==============> - """ - self.root = ROOT - self.bamFile1 = self.root + "testA.bam" - self.bamFile2 = self.root + "testB.bam" - self.bamFile_PE = self.root + "test_paired2.bam" - self.chrom = '3R' + def ifiles(self, ext='bam'): + root = os.path.dirname(os.path.abspath(__file__)) + "/test_data/" + bamFile1 = root + "testA." + ext + bamFile2 = root + "testB." + ext + bamFile_PE = root + "test_paired2." + ext + chrom = '3R' step_size = 50 bin_length = 25 - - self.c = cr.CountReadsPerBin([self.bamFile1, self.bamFile2], - binLength=bin_length, - stepSize=step_size) - - def test_count_reads_in_region(self): - self.c.skipZeros = False - resp, _ = self.c.count_reads_in_region(self.chrom, 0, 200) + c = cr.CountReadsPerBin([bamFile1, bamFile2], + binLength=bin_length, + stepSize=step_size) + return c, bamFile1, bamFile2, bamFile_PE, chrom, step_size, bin_length + """ + The distribution of reads between the two bam files is as follows. + + They cover 200 bp:: + + 0 100 200 + |------------------------------------------------------------| + A ==============> + <============== + + + B <============== ==============> + ==============> + ==============> + """ + + def test_count_reads_in_region(self, bc): + c, bamFile1, bamFile2, bamFile_PE, chrom, step_size, bin_length = self.ifiles(bc) + c.skipZeros = False + resp, _ = c.count_reads_in_region(chrom, 0, 200) nt.assert_equal(resp, np.array([[0, 0.], [0, 1.], [1, 1.], [1, 2.]])) - def test_count_reads_in_region_extension_1(self): + def test_count_reads_in_region_extension_1(self, bc): """ In this case when read extension is smaller than read length extension is turned off and a warning is printed. """ - self.c = cr.CountReadsPerBin([self.bamFile1, self.bamFile2], + c, bamFile1, bamFile2, bamFile_PE, chrom, step_size, bin_length = self.ifiles(bc) + c = cr.CountReadsPerBin([bamFile1, bamFile2], binLength=1, stepSize=50, extendReads=25) - resp, _ = self.c.count_reads_in_region(self.chrom, 0, 200) + resp, _ = c.count_reads_in_region(chrom, 0, 200) nt.assert_equal(resp, np.array([[0, 0.], [0, 1.], [1, 1.], [1, 2.]])) - def test_count_reads_in_region_total(self): + def test_count_reads_in_region_total(self, bc): """ count the reads over the whole region 2 for the first case, and 4 for the second """ - self.c.skipZeros = False - self.c.stepSize = 200 - self.c.binLength = 200 - resp, _ = self.c.count_reads_in_region(self.chrom, 0, 200) + c, bamFile1, bamFile2, bamFile_PE, chrom, step_size, bin_length = self.ifiles(bc) + c.skipZeros = False + c.stepSize = 200 + c.binLength = 200 + resp, _ = c.count_reads_in_region(chrom, 0, 200) nt.assert_equal(resp, np.array([[2, 4.]])) - def test_countReadsInRegions_min_mapping_quality(self): + def test_countReadsInRegions_min_mapping_quality(self, bc): + c, bamFile1, bamFile2, bamFile_PE, chrom, step_size, bin_length = self.ifiles(bc) # Test min mapping quality. - self.c.minMappingQuality = 40 - self.c.skipZeros = False + c.minMappingQuality = 40 + c.skipZeros = False - resp, _ = self.c.count_reads_in_region(self. chrom, 0, 200) + resp, _ = c.count_reads_in_region(chrom, 0, 200) nt.assert_equal(resp, np.array([[0, 0, 0, 1.], [0, 0, 0, 1.]]).T) - def test_count_reads_in_region_ignore_duplicates(self): - + def test_count_reads_in_region_ignore_duplicates(self, bc): + c, bamFile1, bamFile2, bamFile_PE, chrom, step_size, bin_length = self.ifiles(bc) # Test ignore duplicates - self.c.skipZeros = False - self.c.ignoreDuplicates = True - resp, _ = self.c.count_reads_in_region(self.chrom, 0, 200) + c.skipZeros = False + c.ignoreDuplicates = True + resp, _ = c.count_reads_in_region(chrom, 0, 200) nt.assert_equal(resp, np.array([[0, 0, 1, 1.], [0, 1, 1, 1.]]).T) - def test_count_reads_in_region_ignore_bed_regions(self): + def test_count_reads_in_region_ignore_bed_regions(self, bc): + c, bamFile1, bamFile2, bamFile_PE, chrom, step_size, bin_length = self.ifiles(bc) # Test bed regions: - bed_regions = [[self.chrom, [(10, 20)], "."], [self.chrom, [(150, 160)], "."]] - self.c.skipZeros = False - self.c.binLength = 10 - resp, _ = self.c.count_reads_in_region(self.chrom, 0, 200, bed_regions_list=bed_regions) + bed_regions = [[chrom, [(10, 20)], "."], [chrom, [(150, 160)], "."]] + c.skipZeros = False + c.binLength = 10 + resp, _ = c.count_reads_in_region(chrom, 0, 200, bed_regions_list=bed_regions) nt.assert_equal(resp, np.array([[0, 1.], [0, 2.]]).T) - def test_get_coverage_of_region_sam_flag_include(self): - - self.c.samFlag_include = 16 # include reverse reads only - self.c.bamFilesList = [self.bamFile1] - resp, _ = self.c.count_reads_in_region('3R', 0, 200) + def test_get_coverage_of_region_sam_flag_include(self, bc): + c, bamFile1, bamFile2, bamFile_PE, chrom, step_size, bin_length = self.ifiles(bc) + c.samFlag_include = 16 # include reverse reads only + c.bamFilesList = [bamFile1] + resp, _ = c.count_reads_in_region(chrom, 0, 200) nt.assert_array_equal(resp, np.array([[0], [0], [0], [1]])) - def test_get_coverage_of_region_sam_flag_exclude(self): - - self.c.samFlag_exclude = 16 # exclude reverse reads - self.c.bamFilesList = [self.bamFile1] - resp, _ = self.c.count_reads_in_region('3R', 0, 200) + def test_get_coverage_of_region_sam_flag_exclude(self, bc): + c, bamFile1, bamFile2, bamFile_PE, chrom, step_size, bin_length = self.ifiles(bc) + c.samFlag_exclude = 16 # exclude reverse reads + c.bamFilesList = [bamFile1] + resp, _ = c.count_reads_in_region(chrom, 0, 200) nt.assert_array_equal(resp, np.array([[0], [0], [1], [0]])) - def test_get_coverage_of_region_large_bin(self): - self.c.bamFilesList = [self.bamFile2] - self.c.binLength = 200 - self.c.stepSize = 200 - resp, _ = self.c.count_reads_in_region('3R', 0, 200) + def test_get_coverage_of_region_large_bin(self, bc): + c, bamFile1, bamFile2, bamFile_PE, chrom, step_size, bin_length = self.ifiles(bc) + c.bamFilesList = [bamFile2] + c.binLength = 200 + c.stepSize = 200 + resp, _ = c.count_reads_in_region(chrom, 0, 200) nt.assert_array_equal(resp, np.array([[4]])) - def test_get_coverage_of_region_ignore_duplicates(self): - self.c.ignoreDuplicates = True - self.c.bamFilesList = [self.bamFile2] - resp, _ = self.c.count_reads_in_region('3R', 0, 200) + def test_get_coverage_of_region_ignore_duplicates(self, bc): + c, bamFile1, bamFile2, bamFile_PE, chrom, step_size, bin_length = self.ifiles(bc) + c.ignoreDuplicates = True + c.bamFilesList = [bamFile2] + resp, _ = c.count_reads_in_region(chrom, 0, 200) nt.assert_array_equal(resp, np.array([[0.], [1.], [1.], [1.]])) # check zero to nans - self.c.zerosToNans = True - resp, _ = self.c.count_reads_in_region('3R', 0, 200) + c.zerosToNans = True + resp, _ = c.count_reads_in_region(chrom, 0, 200) nt.assert_array_equal(resp, np.array([[np.nan], [1.], [1.], [1.]])) - def test_get_coverage_of_region_split_read(self): + def test_get_coverage_of_region_split_read(self, bc): """ The bamFile1 contains a read at position 10 with the following CIGAR: 10S20M10N10M10S that maps to a chromosome named chr_cigar. """ - + c, bamFile1, bamFile2, bamFile_PE, chrom, step_size, bin_length = self.ifiles(bc) # turn of read extension - self.c.extendPairedEnds = False - self.c.bamFilesList = [self.bamFile1] - self.c.binLength = 10 - self.c.stepSize = 10 - resp, _ = self.c.count_reads_in_region('chr_cigar', 0, 100) + c.extendPairedEnds = False + c.bamFilesList = [bamFile1] + c.binLength = 10 + c.stepSize = 10 + resp, _ = c.count_reads_in_region('chr_cigar', 0, 100) nt.assert_array_equal(resp, np.array([[0.], [1.], [1.], @@ -166,60 +172,31 @@ def test_get_coverage_of_region_split_read(self): [0.], [0.]])) - def test_get_coverage_of_region_zeros_to_nan(self): - self.c.zerosToNans = True - resp, _ = self.c.count_reads_in_region(self.chrom, 0, 200) + def test_get_coverage_of_region_zeros_to_nan(self, bc): + c, bamFile1, bamFile2, bamFile_PE, chrom, step_size, bin_length = self.ifiles(bc) + c.zerosToNans = True + resp, _ = c.count_reads_in_region(chrom, 0, 200) nt.assert_equal(resp, np.array([[np.nan, np.nan], [np.nan, 1], [1, 1], [1, 2]])) - def test_bed_file(self): + def test_bed_file(self, bc): + c, bamFile1, bamFile2, bamFile_PE, chrom, step_size, bin_length = self.ifiles(bc) bed = "chr3R\t0\t10\nchr3R\t110\t120\nchr3R\t160\t180" import tempfile bed_file = tempfile.NamedTemporaryFile(suffix=".bed", delete=False, mode="w") bed_file.write(bed) bed_file.close() - self.c = cr.CountReadsPerBin([self.bamFile2], + c = cr.CountReadsPerBin([bamFile2], bedFile=[bed_file.name]) - resp = self.c.run() + resp = c.run() nt.assert_equal(resp, np.array([[0.], [1.], [2.]])) import os os.unlink(bed_file.name) - - -class TestCountReadsPerBinCRAM(TestCountReadsPerBin): - def setUp(self): - """ - As above, but using CRAM rather than BAM - The distribution of reads between the two bam files is as follows. - - They cover 200 bp:: - - 0 100 200 - |------------------------------------------------------------| - A ==============> - <============== - - - B <============== ==============> - ==============> - ==============> - """ - self.root = ROOT - self.bamFile1 = self.root + "testA.cram" - self.bamFile2 = self.root + "testB.cram" - self.bamFile_PE = self.root + "test_paired2.cram" - self.chrom = '3R' - step_size = 50 - bin_length = 25 - - self.c = cr.CountReadsPerBin([self.bamFile1, self.bamFile2], - binLength=bin_length, - stepSize=step_size) diff --git a/deeptools/test/testskip_heatmapper_images.py b/deeptools/test/test_heatmapper_images.py similarity index 98% rename from deeptools/test/testskip_heatmapper_images.py rename to deeptools/test/test_heatmapper_images.py index 8c8d56e9..7f5d5255 100644 --- a/deeptools/test/testskip_heatmapper_images.py +++ b/deeptools/test/test_heatmapper_images.py @@ -14,11 +14,6 @@ ROOT = os.path.dirname(os.path.abspath(__file__)) + "/test_heatmapper/" tolerance = 30 -skip = False -if matplotlib.__version__ != "3.1.1": - skip = True - - def test_plotHeatmap_simple_plot(): """ Test a simple plot generated using a matrix from diff --git a/deeptools/test/test_readFiltering.py b/deeptools/test/test_readFiltering.py index 6e0b0e81..07f19b32 100644 --- a/deeptools/test/test_readFiltering.py +++ b/deeptools/test/test_readFiltering.py @@ -1,4 +1,3 @@ -from nose.tools import assert_equal import deeptools.estimateReadFiltering as est import deeptools.alignmentSieve as sieve import os.path @@ -30,7 +29,7 @@ def test_estimate_read_filtering_minimal(): _ = resp[1].split("\t") _[0] = os.path.basename(_[0]) resp[1] = "\t".join(_) - assert_equal(resp, expected) + assert resp == expected unlink(outfile) @@ -51,7 +50,7 @@ def test_estimate_read_filtering_params(): resp[1] = "\t".join(_) expected = ['Sample\tTotal Reads\tMapped Reads\tAlignments in blacklisted regions\tEstimated mapped reads filtered\tBelow MAPQ\tMissing Flags\tExcluded Flags\tInternally-determined Duplicates\tMarked Duplicates\tSingletons\tWrong strand\n', 'test_filtering.bam\t193\t193\t7\t193\t41.4\t0.0\t186.5\t31.6\t0.0\t0.0\t0.0\n'] - assert_equal(resp, expected) + assert resp == expected unlink(outfile) @@ -72,7 +71,7 @@ def test_sieve(): expected = ['#bamFilterReads --filterMetrics\n', '#File\tReads Remaining\tTotal Initial Reads\n', 'test_filtering\t5\t193\n'] - assert_equal(resp, expected) + assert resp == expected unlink(outlog) h = hashlib.md5(pysam.view(outfile).encode('utf-8')).hexdigest() assert h == "acbc4443fb0387bfd6c412af9d4fc414" @@ -121,7 +120,7 @@ def test_sieve_BED(): 'chr2\t5001491\t5001527\n', 'chr2\t5001700\t5001736\n'] - assert_equal(resp, expected) + assert resp == expected unlink(outfile) @@ -161,5 +160,5 @@ def test_sieve_BED_shift(): 'chr2\t5001119\t5001266\n', 'chr2\t5001230\t5001600\n'] - assert_equal(resp, expected) + assert resp == expected unlink(outfile) diff --git a/deeptools/test/test_writeBedGraph.py b/deeptools/test/test_writeBedGraph.py index c419684f..97e9ba07 100644 --- a/deeptools/test/test_writeBedGraph.py +++ b/deeptools/test/test_writeBedGraph.py @@ -1,143 +1,104 @@ from unittest import TestCase -from nose.tools import * import os - +import pytest import deeptools.writeBedGraph as wr from deeptools.writeBedGraph import scaleCoverage -ROOT = os.path.dirname(os.path.abspath(__file__)) + "/test_data/" - -__author__ = 'fidel' - - -class TestWriteBedGraph(TestCase): - - def setUp(self): - """ - The distribution of reads between the two bam files is as follows. - - They cover 200 bp:: - - 0 100 200 - |------------------------------------------------------------| - A ==============> - <============== - - - B <============== ==============> - ==============> - ==============> - """ - - self.root = ROOT - self.bamFile1 = self.root + "testA.bam" - self.bamFile2 = self.root + "testB.bam" - self.bamFile_PE = self.root + "test_paired2.bam" - self.chrom = '3R' - - self.step_size = 50 - self.bin_length = 50 - self.func_args = {'scaleFactor': 1.0} - - self.c = wr.WriteBedGraph([self.bamFile1], - binLength=self.bin_length, - stepSize=self.step_size) - - def test_writeBedGraph_worker(self): - self.c.zerosToNans = False - self.c.skipZeros = False - - tempFile = self.c.writeBedGraph_worker('3R', 0, 200, scaleCoverage, self.func_args) +@pytest.mark.parametrize("bc", ["bam", 'cram']) +class TestWriteBedGraph(): + def ifiles(self, ext='bam'): + root = os.path.dirname(os.path.abspath(__file__)) + "/test_data/" + bamFile1 = root + "testA." + ext + bamFile2 = root + "testB." + ext + bamFile_PE = root + "test_paired2." + ext + chrom = '3R' + step_size = 50 + bin_length = 50 + func_args = {'scaleFactor': 1.0} + c = wr.WriteBedGraph([bamFile1], + binLength=bin_length, + stepSize=step_size) + return c, bamFile1, bamFile2, bamFile_PE, chrom, step_size, bin_length, func_args + + def test_writeBedGraph_worker(self, bc): + c, bamFile1, bamFile2, bamFile_PE, chrom, step_size, bin_length, func_args = self.ifiles(bc) + c.zerosToNans = False + c.skipZeros = False + + tempFile = c.writeBedGraph_worker(chrom, 0, 200, scaleCoverage, func_args) _foo = open(tempFile[3], 'r') res = _foo.readlines() _foo.close() - assert_equal(res, ['3R\t0\t100\t0\n', '3R\t100\t200\t1\n']) + assert res == ['3R\t0\t100\t0\n', '3R\t100\t200\t1\n'] os.remove(tempFile[3]) - def test_writeBedGraph_worker_zerotonan(self): + def test_writeBedGraph_worker_zerotonan(self, bc): + c, bamFile1, bamFile2, bamFile_PE, chrom, step_size, bin_length, func_args = self.ifiles(bc) # turn on zeroToNan - self.c.zerosToNans = True - tempFile2 = self.c.writeBedGraph_worker('3R', 0, 200, scaleCoverage, self.func_args) + c.zerosToNans = True + tempFile2 = c.writeBedGraph_worker(chrom, 0, 200, scaleCoverage, func_args) _foo = open(tempFile2[3], 'r') res = _foo.readlines() _foo.close() - assert_equal(res, ['3R\t100\t200\t1\n']) + assert res == ['3R\t100\t200\t1\n'] os.remove(tempFile2[3]) - def test_writeBedGraph_worker_scaling(self): + def test_writeBedGraph_worker_scaling(self, bc): + c, bamFile1, bamFile2, bamFile_PE, chrom, step_size, bin_length, func_args = self.ifiles(bc) func_args = {'scaleFactor': 3.0} - tempFile = self.c.writeBedGraph_worker('3R', 0, 200, scaleCoverage, func_args) + tempFile = c.writeBedGraph_worker(chrom, 0, 200, scaleCoverage, func_args) _foo = open(tempFile[3], 'r') res = _foo.readlines() _foo.close() - assert_equal(res, ['3R\t0\t100\t0\n', '3R\t100\t200\t3\n']) + assert res == ['3R\t0\t100\t0\n', '3R\t100\t200\t3\n'] os.remove(tempFile[3]) - def test_writeBedGraph_worker_ignore_duplicates(self): - self.c = wr.WriteBedGraph([self.bamFile2], - binLength=self.bin_length, - stepSize=self.step_size, ignoreDuplicates=True) - self.c.zerosToNans = True + def test_writeBedGraph_worker_ignore_duplicates(self, bc): + c, bamFile1, bamFile2, bamFile_PE, chrom, step_size, bin_length, func_args = self.ifiles(bc) + c = wr.WriteBedGraph([bamFile2], + binLength=bin_length, + stepSize=step_size, ignoreDuplicates=True) + c.zerosToNans = True - tempFile = self.c.writeBedGraph_worker('3R', 0, 200, scaleCoverage, self.func_args) + tempFile = c.writeBedGraph_worker(chrom, 0, 200, scaleCoverage, func_args) _foo = open(tempFile[3], 'r') res = _foo.readlines() _foo.close() - assert_equal(res, ['3R\t50\t200\t1\n']) + assert res == ['3R\t50\t200\t1\n'] os.remove(tempFile[3]) - def test_writeBedGraph_worker_smoothing(self): - self.c.binLength = 20 - self.c.stepSize = 20 - self.c.smoothLength = 60 - tempFile = self.c.writeBedGraph_worker('3R', 100, 200, scaleCoverage, self.func_args) + def test_writeBedGraph_worker_smoothing(self, bc): + c, bamFile1, bamFile2, bamFile_PE, chrom, step_size, bin_length, func_args = self.ifiles(bc) + c.binLength = 20 + c.stepSize = 20 + c.smoothLength = 60 + tempFile = c.writeBedGraph_worker(chrom, 100, 200, scaleCoverage, func_args) _foo = open(tempFile[3], 'r') res = _foo.readlines() _foo.close() - assert_equal(res, ['3R\t100\t120\t1\n', '3R\t120\t180\t1.33333\n', '3R\t180\t200\t1\n']) + assert res == ['3R\t100\t120\t1\n', '3R\t120\t180\t1.33333\n', '3R\t180\t200\t1\n'] os.remove(tempFile[3]) - def test_writeBedGraph_cigar(self): + def test_writeBedGraph_cigar(self, bc): """ The bamFile1 contains a read at position 10 with the following CIGAR: 10S20M10N10M10S that maps to a chromosome named chr_cigar. """ - + c, bamFile1, bamFile2, bamFile_PE, chrom, step_size, bin_length, func_args = self.ifiles(bc) # turn of read extension - self.c.extendPairedEnds = False - self.c.binLength = 10 - self.c.stepSize = 10 - tempFile = self.c.writeBedGraph_worker('chr_cigar', 0, 100, scaleCoverage, self.func_args) + c.extendPairedEnds = False + c.binLength = 10 + c.stepSize = 10 + tempFile = c.writeBedGraph_worker('chr_cigar', 0, 100, scaleCoverage, func_args) _foo = open(tempFile[3], 'r') res = _foo.readlines() _foo.close() # the sigle read is split into bin 10-30, and then 40-50 - assert_equal(res, ['chr_cigar\t0\t10\t0\n', + assert res == ['chr_cigar\t0\t10\t0\n', 'chr_cigar\t10\t30\t1\n', 'chr_cigar\t30\t40\t0\n', 'chr_cigar\t40\t50\t1\n', - 'chr_cigar\t50\t100\t0\n']) + 'chr_cigar\t50\t100\t0\n'] os.remove(tempFile[3]) - - -class TestWriteBedGraphCRAM(TestWriteBedGraph): - def setUp(self): - """ - As above, but for CRAM files - """ - - self.root = ROOT - self.bamFile1 = self.root + "testA.cram" - self.bamFile2 = self.root + "testB.cram" - self.bamFile_PE = self.root + "test_paired2.cram" - self.chrom = '3R' - - self.step_size = 50 - self.bin_length = 50 - self.func_args = {'scaleFactor': 1.0} - - self.c = wr.WriteBedGraph([self.bamFile1], - binLength=self.bin_length, - stepSize=self.step_size) From 2e7e4ac1048ac6ea161f3b35487963f6420ae2c9 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Wed, 16 Aug 2023 16:55:07 +0200 Subject: [PATCH 19/90] escape sysargv check in case of pytests --- deeptools/computeMatrixOperations.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/deeptools/computeMatrixOperations.py b/deeptools/computeMatrixOperations.py index 0abf4b7e..d3014973 100755 --- a/deeptools/computeMatrixOperations.py +++ b/deeptools/computeMatrixOperations.py @@ -786,10 +786,13 @@ def sortMatrix(hm, regionsFileName, transcriptID, transcript_id_designator, verb def main(args=None): - if len(sys.argv) == 1: - args = ["-h"] - if len(sys.argv) == 2: - args = [sys.argv[1], "-h"] + # if args none is need since otherwise pytest passes 'pytest' as sys.argv + if args == None: + if len(sys.argv) == 1: + args = ["-h"] + if len(sys.argv) == 2: + args = [sys.argv[1], "-h"] + args = parse_arguments().parse_args(args) hm = heatmapper.heatmapper() From 4b8d38cc0d6acead2564848dc69687d3a244dcb0 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Wed, 16 Aug 2023 16:56:28 +0200 Subject: [PATCH 20/90] deprecate nosetest in favor of pytest --- .github/workflows/test.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d83fb359..e819d6f0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -36,7 +36,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - - uses: "dpryan79/github-actions/@master" + - uses: "deeptools/github-actions/@master" - name: PEP8 run: | source activate foo @@ -44,7 +44,7 @@ jobs: - name: Test deepTools run: | source activate foo - nosetests --with-doctest -sv deeptools + pytest - name: make an artifact run: | source activate foo @@ -59,8 +59,8 @@ jobs: runs-on: macOS-latest steps: - uses: actions/checkout@v1 - - uses: "dpryan79/github-actions/@master" + - uses: "deeptools/github-actions/@master" - name: Test deepTools run: | source activate foo - nosetests --with-doctest -sv deeptools + pytest From 2cc7977fc9db85ff17648f1b6abde09e7938ea17 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Wed, 16 Aug 2023 16:57:30 +0200 Subject: [PATCH 21/90] rollback heatmapperr imgs test until later --- ...mages.py => skiptest_heatmapper_images.py} | 24 ------------------- 1 file changed, 24 deletions(-) rename deeptools/test/{test_heatmapper_images.py => skiptest_heatmapper_images.py} (94%) diff --git a/deeptools/test/test_heatmapper_images.py b/deeptools/test/skiptest_heatmapper_images.py similarity index 94% rename from deeptools/test/test_heatmapper_images.py rename to deeptools/test/skiptest_heatmapper_images.py index 7f5d5255..c4891aa9 100644 --- a/deeptools/test/test_heatmapper_images.py +++ b/deeptools/test/skiptest_heatmapper_images.py @@ -23,8 +23,6 @@ def test_plotHeatmap_simple_plot(): -R {test_path}/test.bed -o /tmp/mat.gz -bs 25 """ - if skip: - return outfile = NamedTemporaryFile(suffix='.png', prefix='plotHeatmap_test_', delete=False) args = "-m {}/master.mat.gz --outFileName {}".format(ROOT, outfile.name).split() deeptools.plotHeatmap.main(args) @@ -34,8 +32,6 @@ def test_plotHeatmap_simple_plot(): def test_plotHeatmap_rename_labels(): - if skip: - return outfile = NamedTemporaryFile(suffix='.png', prefix='plotHeatmap_test_', delete=False) args = "-m {}/master.mat.gz --outFileName {} --regionsLabel uno dos".format(ROOT, outfile.name).split() @@ -46,8 +42,6 @@ def test_plotHeatmap_rename_labels(): def test_plotHeatmap_scale_regions(): - if skip: - return outfile = NamedTemporaryFile(suffix='.png', prefix='plotHeatmap_test_', delete=False) args = "-m {}/master_scale_reg.mat.gz --outFileName {}".format(ROOT, outfile.name).split() deeptools.plotHeatmap.main(args) @@ -57,8 +51,6 @@ def test_plotHeatmap_scale_regions(): def test_plotHeatmap_multi_bigwig_pergroup(): - if skip: - return outfile = NamedTemporaryFile(suffix='.png', prefix='plotHeatmap_test_', delete=False) args = "-m {}/master_multi.mat.gz --perGroup --samplesLabel file1 file2 file3 file4 " \ "--outFileName {}".format(ROOT, outfile.name).split() @@ -69,8 +61,6 @@ def test_plotHeatmap_multi_bigwig_pergroup(): def test_plotHeatmap_multiple_colors_muti_scales(): - if skip: - return outfile = NamedTemporaryFile(suffix='.png', prefix='plotHeatmap_test_', delete=False) args = "-m {}/master_multi.mat.gz --colorList white,blue white,red --zMin 1 0 --zMax 4 5 " \ "--outFileName {}".format(ROOT, outfile.name).split() @@ -81,8 +71,6 @@ def test_plotHeatmap_multiple_colors_muti_scales(): def test_plotHeatmap_multiple_colormap_no_boxes(): - if skip: - return outfile = NamedTemporaryFile(suffix='.png', prefix='plotHeatmap_test_', delete=False) args = "-m {}/master_multi.mat.gz --colorMap Reds binary terrain --boxAroundHeatmaps no " \ "--outFileName {}".format(ROOT, outfile.name).split() @@ -93,8 +81,6 @@ def test_plotHeatmap_multiple_colormap_no_boxes(): def test_plotHeatmap_interpolation(): - if skip: - return outfile = NamedTemporaryFile(suffix='.png', prefix='plotHeatmap_test_', delete=False) args = "-m {}/large_matrix.mat.gz --interpolation bilinear " \ "--outFileName {}".format(ROOT, outfile.name).split() @@ -105,8 +91,6 @@ def test_plotHeatmap_interpolation(): def test_plotProfiler(): - if skip: - return outfile = NamedTemporaryFile(suffix='.png', prefix='plotHeatmap_test_', delete=False) args = "-m {}/master.mat.gz --outFileName {} --regionsLabel uno dos " \ "--plotType std".format(ROOT, outfile.name).split() @@ -117,8 +101,6 @@ def test_plotProfiler(): def test_plotProfiler_heatmap(): - if skip: - return outfile = NamedTemporaryFile(suffix='.png', prefix='plotHeatmap_test_', delete=False) args = "-m {}/master.mat.gz --outFileName {} --plotType heatmap".format(ROOT, outfile.name).split() deeptools.plotProfile.main(args) @@ -128,8 +110,6 @@ def test_plotProfiler_heatmap(): def test_plotProfiler_overlapped_lines(): - if skip: - return outfile = NamedTemporaryFile(suffix='.png', prefix='plotHeatmap_test_', delete=False) args = "-m {}/master.mat.gz --outFileName {} " \ "--plotType overlapped_lines --yMin -1".format(ROOT, outfile.name).split() @@ -140,8 +120,6 @@ def test_plotProfiler_overlapped_lines(): def test_plotProfiler_multibigwig(): - if skip: - return outfile = NamedTemporaryFile(suffix='.png', prefix='plotHeatmap_test_', delete=False) args = "-m {}/master_multi.mat.gz --outFileName {} " \ "--numPlotsPerRow 2 --yMax 1.5".format(ROOT, outfile.name).split() @@ -152,8 +130,6 @@ def test_plotProfiler_multibigwig(): def test_plotProfiler_multibigwig_pergroup(): - if skip: - return outfile = NamedTemporaryFile(suffix='.png', prefix='plotHeatmap_test_', delete=False) args = "-m {}/master_multi.mat.gz --outFileName {} " \ "--perGroup --yMax 1.5".format(ROOT, outfile.name).split() From df18b1d833a07f5ab4dfcfb98ea6f82c94166cea Mon Sep 17 00:00:00 2001 From: WardDeb Date: Wed, 16 Aug 2023 17:24:10 +0200 Subject: [PATCH 22/90] flake8 --- deeptools/computeMatrixOperations.py | 2 +- deeptools/plotPCA.py | 1 + deeptools/test/skiptest_heatmapper_images.py | 1 + .../test/test_computeMatrixOperations.py | 1 + deeptools/test/test_countReadsPerBin.py | 27 ++++++++++------ deeptools/test/test_writeBedGraph.py | 31 ++++++++++++------- docs/conf.py | 1 + 7 files changed, 41 insertions(+), 23 deletions(-) diff --git a/deeptools/computeMatrixOperations.py b/deeptools/computeMatrixOperations.py index d3014973..6b3272d4 100755 --- a/deeptools/computeMatrixOperations.py +++ b/deeptools/computeMatrixOperations.py @@ -787,7 +787,7 @@ def sortMatrix(hm, regionsFileName, transcriptID, transcript_id_designator, verb def main(args=None): # if args none is need since otherwise pytest passes 'pytest' as sys.argv - if args == None: + if args is None: if len(sys.argv) == 1: args = ["-h"] if len(sys.argv) == 2: diff --git a/deeptools/plotPCA.py b/deeptools/plotPCA.py index 75dc8a4b..394dcfba 100644 --- a/deeptools/plotPCA.py +++ b/deeptools/plotPCA.py @@ -13,6 +13,7 @@ from deeptools.parserCommon import writableFile from importlib.metadata import version + def parse_arguments(args=None): basic_args = plotCorrelationArgs() parser = argparse.ArgumentParser( diff --git a/deeptools/test/skiptest_heatmapper_images.py b/deeptools/test/skiptest_heatmapper_images.py index c4891aa9..1e102650 100644 --- a/deeptools/test/skiptest_heatmapper_images.py +++ b/deeptools/test/skiptest_heatmapper_images.py @@ -14,6 +14,7 @@ ROOT = os.path.dirname(os.path.abspath(__file__)) + "/test_heatmapper/" tolerance = 30 + def test_plotHeatmap_simple_plot(): """ Test a simple plot generated using a matrix from diff --git a/deeptools/test/test_computeMatrixOperations.py b/deeptools/test/test_computeMatrixOperations.py index df81d545..433e25bd 100644 --- a/deeptools/test/test_computeMatrixOperations.py +++ b/deeptools/test/test_computeMatrixOperations.py @@ -8,6 +8,7 @@ __author__ = 'Devon' + def getHeader(fp): s = fp.readline() if isinstance(s, bytes): diff --git a/deeptools/test/test_countReadsPerBin.py b/deeptools/test/test_countReadsPerBin.py index 882ca603..eb09a968 100644 --- a/deeptools/test/test_countReadsPerBin.py +++ b/deeptools/test/test_countReadsPerBin.py @@ -8,6 +8,7 @@ __author__ = 'Fidel' + @pytest.mark.parametrize("bc", ["bam", 'cram']) class TestCountReadsPerBin(): @@ -19,9 +20,11 @@ def ifiles(self, ext='bam'): chrom = '3R' step_size = 50 bin_length = 25 - c = cr.CountReadsPerBin([bamFile1, bamFile2], - binLength=bin_length, - stepSize=step_size) + c = cr.CountReadsPerBin( + [bamFile1, bamFile2], + binLength=bin_length, + stepSize=step_size + ) return c, bamFile1, bamFile2, bamFile_PE, chrom, step_size, bin_length """ The distribution of reads between the two bam files is as follows. @@ -38,7 +41,7 @@ def ifiles(self, ext='bam'): ==============> ==============> """ - + def test_count_reads_in_region(self, bc): c, bamFile1, bamFile2, bamFile_PE, chrom, step_size, bin_length = self.ifiles(bc) c.skipZeros = False @@ -55,10 +58,12 @@ def test_count_reads_in_region_extension_1(self, bc): extension is turned off and a warning is printed. """ c, bamFile1, bamFile2, bamFile_PE, chrom, step_size, bin_length = self.ifiles(bc) - c = cr.CountReadsPerBin([bamFile1, bamFile2], - binLength=1, - stepSize=50, - extendReads=25) + c = cr.CountReadsPerBin( + [bamFile1, bamFile2], + binLength=1, + stepSize=50, + extendReads=25 + ) resp, _ = c.count_reads_in_region(chrom, 0, 200) @@ -190,8 +195,10 @@ def test_bed_file(self, bc): bed_file.write(bed) bed_file.close() - c = cr.CountReadsPerBin([bamFile2], - bedFile=[bed_file.name]) + c = cr.CountReadsPerBin( + [bamFile2], + bedFile=[bed_file.name] + ) resp = c.run() nt.assert_equal(resp, np.array([[0.], diff --git a/deeptools/test/test_writeBedGraph.py b/deeptools/test/test_writeBedGraph.py index 97e9ba07..bdf0bca1 100644 --- a/deeptools/test/test_writeBedGraph.py +++ b/deeptools/test/test_writeBedGraph.py @@ -1,9 +1,9 @@ -from unittest import TestCase import os import pytest import deeptools.writeBedGraph as wr from deeptools.writeBedGraph import scaleCoverage + @pytest.mark.parametrize("bc", ["bam", 'cram']) class TestWriteBedGraph(): def ifiles(self, ext='bam'): @@ -15,9 +15,11 @@ def ifiles(self, ext='bam'): step_size = 50 bin_length = 50 func_args = {'scaleFactor': 1.0} - c = wr.WriteBedGraph([bamFile1], - binLength=bin_length, - stepSize=step_size) + c = wr.WriteBedGraph( + [bamFile1], + binLength=bin_length, + stepSize=step_size + ) return c, bamFile1, bamFile2, bamFile_PE, chrom, step_size, bin_length, func_args def test_writeBedGraph_worker(self, bc): @@ -55,9 +57,12 @@ def test_writeBedGraph_worker_scaling(self, bc): def test_writeBedGraph_worker_ignore_duplicates(self, bc): c, bamFile1, bamFile2, bamFile_PE, chrom, step_size, bin_length, func_args = self.ifiles(bc) - c = wr.WriteBedGraph([bamFile2], - binLength=bin_length, - stepSize=step_size, ignoreDuplicates=True) + c = wr.WriteBedGraph( + [bamFile2], + binLength=bin_length, + stepSize=step_size, + ignoreDuplicates=True + ) c.zerosToNans = True tempFile = c.writeBedGraph_worker(chrom, 0, 200, scaleCoverage, func_args) @@ -96,9 +101,11 @@ def test_writeBedGraph_cigar(self, bc): _foo.close() # the sigle read is split into bin 10-30, and then 40-50 - assert res == ['chr_cigar\t0\t10\t0\n', - 'chr_cigar\t10\t30\t1\n', - 'chr_cigar\t30\t40\t0\n', - 'chr_cigar\t40\t50\t1\n', - 'chr_cigar\t50\t100\t0\n'] + assert res == [ + 'chr_cigar\t0\t10\t0\n', + 'chr_cigar\t10\t30\t1\n', + 'chr_cigar\t30\t40\t0\n', + 'chr_cigar\t40\t50\t1\n', + 'chr_cigar\t50\t100\t0\n' + ] os.remove(tempFile[3]) diff --git a/docs/conf.py b/docs/conf.py index cd8b3abc..8e647cfc 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -89,6 +89,7 @@ def get_version(): except: return None + version = get_version() # The full version, including alpha/beta/rc tags. release = version From 4294a3b4717ccb6fc384ee5eaace1c8ebb65fedd Mon Sep 17 00:00:00 2001 From: WardDeb Date: Thu, 17 Aug 2023 08:26:04 +0200 Subject: [PATCH 23/90] add conda env for workflows --- .github/env.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .github/env.yml diff --git a/.github/env.yml b/.github/env.yml new file mode 100644 index 00000000..c9e1a63a --- /dev/null +++ b/.github/env.yml @@ -0,0 +1,8 @@ +channels: + - conda-forge + - bioconda +dependencies: + - python = 3.11 + - flake8 + - pytest + - planemo \ No newline at end of file From 70004ab1cba65014380559771d9ec56d09ec756c Mon Sep 17 00:00:00 2001 From: WardDeb Date: Thu, 17 Aug 2023 08:26:20 +0200 Subject: [PATCH 24/90] switch test to micromamba --- .github/workflows/test.yml | 55 ++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e819d6f0..01974c2a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,12 +1,17 @@ name: Test on: [push, pull_request] + +defaults: + run: + shell: bash -l {0} + jobs: check_versions_matches: name: Check deeptools version matches galaxy tools runs-on: ubuntu-latest if: github.base_ref == 'master' steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v3 - name: Check path run: find /home/runner/work/deepTools/deepTools -name "pyproject.toml" - name: Get Version of Deeptools @@ -35,32 +40,48 @@ jobs: name: Test on Linux runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - uses: "deeptools/github-actions/@master" + - uses: actions/checkout@v3 + - uses: mamba-org/setup-micromamba@main + with: + environment-file: .github/env.yml + cache-downloads: true + environment-name: foo + - name: pip install + run: | + micromamba activate foo + pip install . - name: PEP8 run: | - source activate foo + micromamba activate foo flake8 . --exclude=.venv,.build,build --ignore=E501,F403,E402,F999,F405,E722,W504,W605 - name: Test deepTools run: | - source activate foo + mamba activate foo pytest - - name: make an artifact - run: | - source activate foo - rm -f dist/* - python setup.py sdist - - uses: actions/upload-artifact@master - with: - name: "Dist files" - path: "dist" + #- name: make an artifact + # run: | + # source activate foo + # rm -f dist/* + # python setup.py sdist + #- uses: actions/upload-artifact@master + # with: + # name: "Dist files" + # path: "dist" build-osx: name: Test on OSX runs-on: macOS-latest steps: - - uses: actions/checkout@v1 - - uses: "deeptools/github-actions/@master" + - uses: actions/checkout@v3 + - uses: mamba-org/setup-micromamba@main + with: + environment-file: .github/env.yml + cache-downloads: true + environment-name: foo + - name: pip install + run: | + micromamba activate foo + pip install . - name: Test deepTools run: | - source activate foo + micromamba activate foo pytest From 427b0afbf64636dc0945249955c6c11798fd25b6 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Thu, 17 Aug 2023 08:38:29 +0200 Subject: [PATCH 25/90] planemo tests to python 3.11, include samtools in test env --- .github/env.yml | 3 ++- .github/workflows/planemo.yml | 13 ++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/env.yml b/.github/env.yml index c9e1a63a..896bed27 100644 --- a/.github/env.yml +++ b/.github/env.yml @@ -5,4 +5,5 @@ dependencies: - python = 3.11 - flake8 - pytest - - planemo \ No newline at end of file + - planemo + - samtools \ No newline at end of file diff --git a/.github/workflows/planemo.yml b/.github/workflows/planemo.yml index 44baae70..04e82d56 100644 --- a/.github/workflows/planemo.yml +++ b/.github/workflows/planemo.yml @@ -10,12 +10,15 @@ jobs: matrix: chunk: [1, 2, 3] steps: - - uses: actions/checkout@v1 - - uses: "dpryan79/github-actions/@master" + - uses: actions/checkout@v3 + - uses: mamba-org/setup-micromamba@main + with: + environment-file: .github/env.yml + cache-downloads: true + environment-name: foo - name: planemo run: | - source activate foo - conda update -c conda-forge -c bioconda samtools + micromamba activate foo ./.planemo.sh ${{ matrix.chunk }} ${{ env.GALAXY_BRANCH }} - uses: actions/upload-artifact@v3 with: @@ -27,7 +30,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.7'] + python-version: ['3.11'] steps: - uses: actions/download-artifact@v3 with: From e355cb1ade4f02a244652d55ea14ad694fe8fe54 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Thu, 17 Aug 2023 08:47:08 +0200 Subject: [PATCH 26/90] shell defaults planemo test --- .github/workflows/planemo.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/planemo.yml b/.github/workflows/planemo.yml index 04e82d56..11040879 100644 --- a/.github/workflows/planemo.yml +++ b/.github/workflows/planemo.yml @@ -1,7 +1,13 @@ name: Planemo on: [push, pull_request] + env: GALAXY_BRANCH: release_22.05 + +defaults: + run: + shell: bash -l {0} + jobs: planemo_test: name: Planemo test From c273c83a538c4cd35a08742db091875897a49986 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Thu, 17 Aug 2023 09:04:01 +0200 Subject: [PATCH 27/90] pin allure version for planemo tests --- .github/env.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/env.yml b/.github/env.yml index 896bed27..fdbb7a06 100644 --- a/.github/env.yml +++ b/.github/env.yml @@ -6,4 +6,5 @@ dependencies: - flake8 - pytest - planemo - - samtools \ No newline at end of file + - samtools + - allure-python-commons==2.12.0 \ No newline at end of file From c9fc79d2179643dfeea7f0d972fbfb2913929a7f Mon Sep 17 00:00:00 2001 From: WardDeb Date: Thu, 17 Aug 2023 10:14:53 +0200 Subject: [PATCH 28/90] pin python to 3.10 in test env --- .github/env.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/env.yml b/.github/env.yml index fdbb7a06..80cabc10 100644 --- a/.github/env.yml +++ b/.github/env.yml @@ -2,9 +2,11 @@ channels: - conda-forge - bioconda dependencies: - - python = 3.11 + - python = 3.10 - flake8 - pytest - planemo - samtools - - allure-python-commons==2.12.0 \ No newline at end of file + - allure-python-commons==2.12.0 # pinned for planemo + - pycryptodome # pinned for galaxy-util + - rich # pinned for ephemeris \ No newline at end of file From f6e76d9654bf5907324b048a87c081c4443db272 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Thu, 17 Aug 2023 10:29:16 +0200 Subject: [PATCH 29/90] pin 3.10 in planemo wf as well --- .github/workflows/planemo.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/planemo.yml b/.github/workflows/planemo.yml index 11040879..925d9b43 100644 --- a/.github/workflows/planemo.yml +++ b/.github/workflows/planemo.yml @@ -36,7 +36,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.11'] + python-version: ['3.10'] steps: - uses: actions/download-artifact@v3 with: From 15aeb57b8206820441c7ded6e011c973a3dc2c2e Mon Sep 17 00:00:00 2001 From: WardDeb Date: Thu, 17 Aug 2023 11:32:30 +0200 Subject: [PATCH 30/90] test env channel priority into condarc --- .github/env.yml | 3 --- .github/workflows/planemo.yml | 4 ++++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/env.yml b/.github/env.yml index 80cabc10..617db68d 100644 --- a/.github/env.yml +++ b/.github/env.yml @@ -1,6 +1,3 @@ -channels: - - conda-forge - - bioconda dependencies: - python = 3.10 - flake8 diff --git a/.github/workflows/planemo.yml b/.github/workflows/planemo.yml index 925d9b43..edc1b9c2 100644 --- a/.github/workflows/planemo.yml +++ b/.github/workflows/planemo.yml @@ -22,6 +22,10 @@ jobs: environment-file: .github/env.yml cache-downloads: true environment-name: foo + condarc: | + channels: + - conda-forge + - bioconda - name: planemo run: | micromamba activate foo From 1ce04249ca0fa402b1d414ec1f4a76fe9a6d1242 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Thu, 17 Aug 2023 11:59:51 +0200 Subject: [PATCH 31/90] planemo on 3.9, test on 3.11 --- .github/env.yml | 9 ++------- .github/planemo.yml | 12 ++++++++++++ .github/workflows/planemo.yml | 8 ++------ .github/workflows/test.yml | 8 ++++++++ 4 files changed, 24 insertions(+), 13 deletions(-) create mode 100644 .github/planemo.yml diff --git a/.github/env.yml b/.github/env.yml index 617db68d..a226adc8 100644 --- a/.github/env.yml +++ b/.github/env.yml @@ -1,9 +1,4 @@ dependencies: - - python = 3.10 + - python = 3.11 - flake8 - - pytest - - planemo - - samtools - - allure-python-commons==2.12.0 # pinned for planemo - - pycryptodome # pinned for galaxy-util - - rich # pinned for ephemeris \ No newline at end of file + - pytest \ No newline at end of file diff --git a/.github/planemo.yml b/.github/planemo.yml new file mode 100644 index 00000000..a0ea025e --- /dev/null +++ b/.github/planemo.yml @@ -0,0 +1,12 @@ +channels: + - conda-forge + - bioconda +dependencies: + - python = 3.9 + - flake8 + - pytest + - planemo + - samtools + - allure-python-commons==2.12.0 # pinned for planemo + - pycryptodome # pinned for galaxy-util + - rich # pinned for ephemeris diff --git a/.github/workflows/planemo.yml b/.github/workflows/planemo.yml index edc1b9c2..3c706aa8 100644 --- a/.github/workflows/planemo.yml +++ b/.github/workflows/planemo.yml @@ -19,13 +19,9 @@ jobs: - uses: actions/checkout@v3 - uses: mamba-org/setup-micromamba@main with: - environment-file: .github/env.yml + environment-file: .github/planemo.yml cache-downloads: true environment-name: foo - condarc: | - channels: - - conda-forge - - bioconda - name: planemo run: | micromamba activate foo @@ -40,7 +36,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.10'] + python-version: ['3.9'] steps: - uses: actions/download-artifact@v3 with: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 01974c2a..1fb1c5b8 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -46,6 +46,10 @@ jobs: environment-file: .github/env.yml cache-downloads: true environment-name: foo + condarc: | + channels: + - conda-forge + - bioconda - name: pip install run: | micromamba activate foo @@ -77,6 +81,10 @@ jobs: environment-file: .github/env.yml cache-downloads: true environment-name: foo + condarc: | + channels: + - conda-forge + - bioconda - name: pip install run: | micromamba activate foo From e4af3cda4f828987784bd2b8aa01f3791b70448d Mon Sep 17 00:00:00 2001 From: WardDeb Date: Thu, 17 Aug 2023 12:28:51 +0200 Subject: [PATCH 32/90] complete rollback to 3.7 planemo with same deps as previous action --- .github/planemo.yml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/planemo.yml b/.github/planemo.yml index a0ea025e..cc151ff5 100644 --- a/.github/planemo.yml +++ b/.github/planemo.yml @@ -2,11 +2,15 @@ channels: - conda-forge - bioconda dependencies: - - python = 3.9 + - python = 3.7 + - numpy + - scipy - flake8 + - pysam + - piBigWig + - py2bit + - deeptoolsintervals - pytest - planemo - samtools - - allure-python-commons==2.12.0 # pinned for planemo - - pycryptodome # pinned for galaxy-util - - rich # pinned for ephemeris + - allure-python-commons==2.12.0 From 911875eee997e9de683b4fc90197ec20f208b417 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Thu, 17 Aug 2023 12:30:33 +0200 Subject: [PATCH 33/90] pybw typo --- .github/planemo.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/planemo.yml b/.github/planemo.yml index cc151ff5..5aab25d1 100644 --- a/.github/planemo.yml +++ b/.github/planemo.yml @@ -7,7 +7,7 @@ dependencies: - scipy - flake8 - pysam - - piBigWig + - pyBigWig - py2bit - deeptoolsintervals - pytest From 541e3bddc2df63a1878a7ce2b245ccd05463d460 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Thu, 17 Aug 2023 12:41:03 +0200 Subject: [PATCH 34/90] include pip install in planemo.. --- .github/env.yml | 3 +++ .github/workflows/planemo.yml | 6 +++++- .github/workflows/test.yml | 4 ---- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/env.yml b/.github/env.yml index a226adc8..d5c47454 100644 --- a/.github/env.yml +++ b/.github/env.yml @@ -1,3 +1,6 @@ +channels: + - conda-forge + - bioconda dependencies: - python = 3.11 - flake8 diff --git a/.github/workflows/planemo.yml b/.github/workflows/planemo.yml index 3c706aa8..f6b315c3 100644 --- a/.github/workflows/planemo.yml +++ b/.github/workflows/planemo.yml @@ -22,6 +22,10 @@ jobs: environment-file: .github/planemo.yml cache-downloads: true environment-name: foo + - name: pip install + run: | + micromamba activate foo + pip install . - name: planemo run: | micromamba activate foo @@ -36,7 +40,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.9'] + python-version: ['3.7'] steps: - uses: actions/download-artifact@v3 with: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1fb1c5b8..9bb7fcb0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -46,10 +46,6 @@ jobs: environment-file: .github/env.yml cache-downloads: true environment-name: foo - condarc: | - channels: - - conda-forge - - bioconda - name: pip install run: | micromamba activate foo From c9b4fdac88e08a67f6fef66042a6653e2ac2c828 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Thu, 17 Aug 2023 17:12:20 +0200 Subject: [PATCH 35/90] test with planemo test run python 3.10 --- .github/planemo.yml | 2 +- .github/workflows/planemo.yml | 2 +- .planemo.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/planemo.yml b/.github/planemo.yml index 5aab25d1..46deee95 100644 --- a/.github/planemo.yml +++ b/.github/planemo.yml @@ -2,7 +2,7 @@ channels: - conda-forge - bioconda dependencies: - - python = 3.7 + - python = 3.10 - numpy - scipy - flake8 diff --git a/.github/workflows/planemo.yml b/.github/workflows/planemo.yml index f6b315c3..c66fc228 100644 --- a/.github/workflows/planemo.yml +++ b/.github/workflows/planemo.yml @@ -40,7 +40,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.7'] + python-version: ['3.10'] steps: - uses: actions/download-artifact@v3 with: diff --git a/.planemo.sh b/.planemo.sh index 1dfc6722..6f9e0810 100755 --- a/.planemo.sh +++ b/.planemo.sh @@ -29,6 +29,6 @@ else fi planemo lint ${wrappers} -planemo test --no_dependency_resolution --galaxy_branch $2 --install_galaxy ${wrappers} 2>&1 +planemo test --no_dependency_resolution --galaxy_python_version 3.10 --galaxy_branch $2 --install_galaxy ${wrappers} 2>&1 mkdir upload mv tool_test_output* upload/ From 5232024f3ee53f77d72861c75eb08c2594cd317a Mon Sep 17 00:00:00 2001 From: WardDeb Date: Thu, 17 Aug 2023 17:29:03 +0200 Subject: [PATCH 36/90] planemo tests with python 3.11 under galaxy --- .github/planemo.yml | 2 +- .github/workflows/planemo.yml | 2 +- .planemo.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/planemo.yml b/.github/planemo.yml index 46deee95..eb0bf99d 100644 --- a/.github/planemo.yml +++ b/.github/planemo.yml @@ -2,7 +2,7 @@ channels: - conda-forge - bioconda dependencies: - - python = 3.10 + - python = 3.11 - numpy - scipy - flake8 diff --git a/.github/workflows/planemo.yml b/.github/workflows/planemo.yml index c66fc228..48cfc04b 100644 --- a/.github/workflows/planemo.yml +++ b/.github/workflows/planemo.yml @@ -40,7 +40,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.10'] + python-version: ['3.11'] steps: - uses: actions/download-artifact@v3 with: diff --git a/.planemo.sh b/.planemo.sh index 6f9e0810..a4e1bd2d 100755 --- a/.planemo.sh +++ b/.planemo.sh @@ -29,6 +29,6 @@ else fi planemo lint ${wrappers} -planemo test --no_dependency_resolution --galaxy_python_version 3.10 --galaxy_branch $2 --install_galaxy ${wrappers} 2>&1 +planemo test --no_dependency_resolution --galaxy_python_version 3.11 --galaxy_branch $2 --install_galaxy ${wrappers} 2>&1 mkdir upload mv tool_test_output* upload/ From d5fb5b6966fd7835f3690379740875a8e5351cdb Mon Sep 17 00:00:00 2001 From: WardDeb Date: Thu, 17 Aug 2023 17:36:44 +0200 Subject: [PATCH 37/90] py2bit as pip dep --- .github/planemo.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/planemo.yml b/.github/planemo.yml index eb0bf99d..78eaf258 100644 --- a/.github/planemo.yml +++ b/.github/planemo.yml @@ -7,10 +7,12 @@ dependencies: - scipy - flake8 - pysam - - pyBigWig - - py2bit - deeptoolsintervals - pytest - planemo - samtools - allure-python-commons==2.12.0 + - pip + - pip: + - py2bit + - pyBigWig From 7729d1540a93890220d6b0a7db1eb1ff707b8ae2 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Fri, 18 Aug 2023 08:01:25 +0200 Subject: [PATCH 38/90] python 3.10 for tests & planemo galaxy version --- .github/env.yml | 2 +- .github/planemo.yml | 8 +++----- .github/workflows/planemo.yml | 2 +- .planemo.sh | 2 +- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/.github/env.yml b/.github/env.yml index d5c47454..718f888d 100644 --- a/.github/env.yml +++ b/.github/env.yml @@ -2,6 +2,6 @@ channels: - conda-forge - bioconda dependencies: - - python = 3.11 + - python = 3.10 - flake8 - pytest \ No newline at end of file diff --git a/.github/planemo.yml b/.github/planemo.yml index 78eaf258..8716e588 100644 --- a/.github/planemo.yml +++ b/.github/planemo.yml @@ -2,7 +2,7 @@ channels: - conda-forge - bioconda dependencies: - - python = 3.11 + - python = 3.10 - numpy - scipy - flake8 @@ -12,7 +12,5 @@ dependencies: - planemo - samtools - allure-python-commons==2.12.0 - - pip - - pip: - - py2bit - - pyBigWig + - py2bit + - pyBigWig diff --git a/.github/workflows/planemo.yml b/.github/workflows/planemo.yml index 48cfc04b..c66fc228 100644 --- a/.github/workflows/planemo.yml +++ b/.github/workflows/planemo.yml @@ -40,7 +40,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.11'] + python-version: ['3.10'] steps: - uses: actions/download-artifact@v3 with: diff --git a/.planemo.sh b/.planemo.sh index a4e1bd2d..6f9e0810 100755 --- a/.planemo.sh +++ b/.planemo.sh @@ -29,6 +29,6 @@ else fi planemo lint ${wrappers} -planemo test --no_dependency_resolution --galaxy_python_version 3.11 --galaxy_branch $2 --install_galaxy ${wrappers} 2>&1 +planemo test --no_dependency_resolution --galaxy_python_version 3.10 --galaxy_branch $2 --install_galaxy ${wrappers} 2>&1 mkdir upload mv tool_test_output* upload/ From 65f4f11625cfff58f9cada7493dde67a21e5b122 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Fri, 18 Aug 2023 09:49:00 +0200 Subject: [PATCH 39/90] plotcorr - parsed labels changed slightly due to mpl versions (assumed) --- .../test-data/plotCorrelation_result2.png | Bin 12275 -> 11943 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/galaxy/wrapper/test-data/plotCorrelation_result2.png b/galaxy/wrapper/test-data/plotCorrelation_result2.png index 58ade4f24164b4243ea4894a31bf5660d3c7b7d2..c144cf38ab99b8069a2159c0d12971294a8d6728 100644 GIT binary patch literal 11943 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 Date: Fri, 18 Aug 2023 13:06:35 +0200 Subject: [PATCH 40/90] typo in pltfingerprint comment, typo in bin script, include 1 extra significant digit in synthetic JS distance test (np default changed?) --- deeptools/plotFingerprint.py | 2 +- .../wrapper/test-data/plotFingerprint_quality_metrics.tabular | 4 ++-- pyproject.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/deeptools/plotFingerprint.py b/deeptools/plotFingerprint.py index 4ea0b50a..f5e26072 100755 --- a/deeptools/plotFingerprint.py +++ b/deeptools/plotFingerprint.py @@ -393,7 +393,7 @@ def main(args=None): sys.stderr.write( "\nNo reads were found in {} regions sampled. Check that the\n" "min mapping quality is not overly high and that the \n" - "chromosome names between bam files are consistant.\n" + "chromosome names between bam files are consistent.\n" "For small genomes, decrease the --numberOfSamples.\n" "\n".format(num_reads_per_bin.shape[0])) exit(1) diff --git a/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular b/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular index f2e16088..6ca50181 100644 --- a/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular +++ b/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular @@ -1,3 +1,3 @@ Sample AUC Synthetic AUC X-intercept Synthetic X-intercept Elbow Point Synthetic Elbow Point JS Distance Synthetic JS Distance % genome enriched diff. enrichment CHANCE divergence -bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 nan 0.2690044980681214 nan nan nan -bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 0.0 0.2690044980681214 0 0 0 +bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 nan 0.26900449806812143 nan nan nan +bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 0.0 0.26900449806812143 0 0 0 diff --git a/pyproject.toml b/pyproject.toml index c5dfe3e8..7c3d2a0d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -66,7 +66,7 @@ multiBigwigSummary = "deeptools.multiBigwigSummary:main" plotCorrelation = "deeptools.plotCorrelation:main" plotCoverage = "deeptools.plotCoverage:main" plotEnrichment = "deeptools.plotEnrichment:main" -plotFingerprint = "deeptools.plotFingerPrint:main" +plotFingerprint = "deeptools.plotFingerprint:main" plotHeatmap = "deeptools.plotHeatmap:main" plotPCA = "deeptools.plotPCA:main" plotProfile = "deeptools.plotProfile:main" From 3973e28074d01051a8001768d95d965790a2e8ea Mon Sep 17 00:00:00 2001 From: WardDeb Date: Fri, 18 Aug 2023 13:24:08 +0200 Subject: [PATCH 41/90] replace both expected heatmaps in planemo tests (mpl version boost == size difference) --- .../wrapper/test-data/heatmapper_result1.png | Bin 71326 -> 53462 bytes .../wrapper/test-data/heatmapper_result2.png | Bin 56250 -> 39981 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/galaxy/wrapper/test-data/heatmapper_result1.png b/galaxy/wrapper/test-data/heatmapper_result1.png index 2ba154b086d919b60438be89653abbbcdfabe66b..fa3686351dc31c66c6c89118fc65396e0bbed693 100644 GIT binary patch literal 53462 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

Ewb4I- zJAs)L=xDN{klq42!r%SLiu`Y`9`;wX!~dxcg`W7_OWEJOU6QeD4Nm~~byd#e*84y6 zy(U7Pum)e-Vkqj?^H| zmQ$uPm4)V1s6`DBRm}dWlNdAAPtW9lXUH48lg6kc`fmsd{%JlY2?v~jedHXZy<8`4 z8N2*=jLoXd^Ld-#u!x&6i^BZ<0|Ii9QKcUK0teOtGz;T=7Js$jk-^PM$zZeJ5IfQ2 zlaE{}J&0V)5lF0r^M-}2hyW8gSj_`Llf1>?fPP6eh9K`uaY=_}Vcl~uLkh%WXpk*z z6qE#I4!=A7op4Pp4zF(Dh|=N zT>W|7VEuQTi5U1`3yB;HhB#QyLI!`Em$|EM(^oEjWd~z~1O(8Mn;Q{qu?;U<#y?kd)`i+8$?8muZ}(LzU-uX| zZ6V$ES_ty{#kMd6MR6^3>|4XT3&o0ZMDv+*@P>x9=sT8ITeVlLl6#+4l#76}wnINN zcG>g1UB`iu-`nZmAO`r-vEu8w_BH)ob@G&7E8sojYJ-qRkDy1-^?}VD^f-VGT!(>; zi4UHA$61U<+}_*ARDG2uGs5E@OrZ{NKF)lJYEvk-iUBtTJpaYmri*I}u(f~v(A%Vi z8K=rY8*z;d=F2x)h79R&Zl1yjkHOypgyq7z(FhBI?(rZ1V|iKxo0;Ycf4)TQspJy- zzBim>{kmh^Fc;a@I`lr_sq&$ASqa@&G(^2^$t-g*L2}+Ey=Uc__KRZQRy%^HO zKyj0Ow4Q+4;sd3v4e99vGlqOY179_Fq)O+|+{Y#cV@w5Kn3MgeuSb%vITlMUhHNZM zfFGD^+LCb;2l%gEm;KGLA8L7%`qsU{jYpQ5ha>_F9C;COM3L;h`ji!5b zOm#VX9Ty11+E6#^QSJb&y%$k>9Aq1qO>-&3qBbU*Z{s~)Jh`n|2-^}HtwE8l;2 zY!T1JAuXe0SapF?mim32FJwmhBIFezhi^M6$xu+x+NOHJeXqBHQd$MiTjx`nv3oIJ z&GS1R#?`sBQcu*FuqdNhb_Qc`2cGr@JpUfJ=8|(oboSP5n&eXCIb|X9DZ zTZT8%h2t|_5&rq@%z?&-Uvo$=C$VexoEjBz}?y_>ob?p zrh9rMS`Ux5C`5m@t>G8hKifm(Ze;cT9}ook?iik>;Z_yr=s)&|hM%U3xWRKG@6_#~ zn*$XhZ{0|zO-wTR8Q*5~KJ5lxugw1aIQRiLdA_9CL5Ftjy6S`J7?F^N1>wF{$Yo0W zb)0Im48!pl06EJ{nZ=h;d;2W#p^=fWGf?|2Z6p}&I3M^)GlJtWsK1oz`&?zpmE>W>`>^4aUvqbRI$E3-!X z_hKL?{%snc(!Utt5f9><%u2R?pSx4y1s5H1GnkS;a7e$o>b5sMCHqche_Sfe*^P*> zcSCiXqq><_y(o0DOUbi?N12G_dhVMzQRR#hoLfulM!d5h2g5A@SthrFZs%)r1IeDO{g$J zV`Epwm_Y5K2dzeT^J-_Q%nwhFE5Z3aQ1TsvCw0ouw^ivjU2iZ!;e4GJu-O;W9?en%uhT&Vh+nNT+w2U?Yd+3BssRw zMgOMpcB!%l9_k-3S^g=4p@sEuOnO7;En84f(0C)rG&kT8cd|~K2hloj&o0s%p z@)X53nu>WoO9b>HE}wA6?wE%iS2y+$E@P*+Ru7&gTa2R)#SL3%Qi(WNBvMxjjlE3J z%|dTWYd^8oY#h0~bP5Gq zK9y2EaNvN6^R-=WXeH#pMl~CkJ-T)jVfKmuA?{Lp7=jCCp5S%mA9=G`6n8%r_SGiX z*t}po)QIo+;rPppROqT%02;;MVc%f*tLkL!Pq?j#}ySXDO< zA;qvL_kHI3d-K;E-jV^gMzVAZB*(o~*xFdws6^qjl6-qJTMtbm^9PgX1Ew# zTw(Zb-sZ11>`!~;x1D`ffi=*04q<;+J~kXaWQ!gPM%HY1dfkXfy8{MX@1Xx#3=)kF zRyrIxITIlqlTkl=)-CytYU=AtM%VG=n!~7{KOHfaty8o3a23l=FW*_A{80j$ zrph$;G- zZf@io^D+@ikw;c&h|~G@2A-)5H#a0u8QEG9R4+%VChWF>@Xn{dihb`iR8yz% zTpY2zsrdX*biTA&Xi+IBfUvT^hezH3Bfij7Ygq0j=9(bHxa#eQKk@cgi`|zjgf!NG zRNR(E+)B&0IF!5L_N{#X&M?>WYlcG3ZWUQ>>{1D(a`ZUSS?ACqQ+EzNxjcALIU#QM z#wtiG*vW0A*4>|j26bi44ZTT}g=UiZ;~0V;83IV+>Y%|=T$rd!$-SUzc6&E5K#X^hD4xhsV;kSVaxMCRaq7upXL6fkE# zCQqEZ2J<@Z{;IV1ayc2RR6Cnt_1_oE?>;sOF#ep$r>;OIP{5IJ@P+bsi#86--tm;Q7K&*TkekCArG|x#16Vk?zJC&qeRG z$w+r-ABJWxwI6u90D&9s=pZi9FS^2eX5(Tuj>b$2wPqT^nG0Lze4M{AC!W$0Ty{}s zcHM`kHjU>uanQD_h<G9xTG7w zbU9*0>*wHP@y4plLx{>e=nZ{-QI=kD@=@!wqrv7%GazIX!P>NKi;B<#NGrzK6u9Qd zHnv;gJBAlg6*+e=XVBFZi>J-tGPEhE~Baw~d_Jmrjqebu?N0x!Re^Y^$)_1FD6i zk=$Z`kO2Srj_g{#Ky;EIZ`92RzOX=a`;~FI0RL&e?t3T3F-T84lkB56usJSpoL~O! zR!+rxtRq5ty4q95{W-sb5n7f1#e)3%0$A)|Y}+iv^}aJu@!p)43lBc`S|UD@yuW6I zXG?P|EBf3k+3$L7qE~YTH{|~lypMq_{SnIBNg{T*5K2NhMKDj3T~ zjN{%USBpZwqvL)scN$Y{MSkq6&;1rU{+~$GVYG4Ikf6SEnfrK;viC-zPLt#SR>h_9 zUwQ3ebD-i|qv?nK;k!l)xgQ3i2vzq`X*)T8?RO@3ljFMHCsDHC||9)QS8Dwt(TNFj|cNB;kJs$TtTuhIb>GT8I<1u~G)1p$B`QbgEjQgI~ zcD+hx%>^a+^SD=J&nt_Nw-)|kOB zw;t0CzJnp%3p(^%U>!mnQT!56v)9sC5S0G_!cJK9(n3kByDhXd%TmyO=Sj8I|%K&m^|cS@#S` zlnSF@r;n|PNTgDKZUf0zPGUaaLX>9-EZE2Ch^uU?B}OC|s-htC+aErC1vuoq0ASNzSM821&n;XpYnGcr?Sz!f5PK6E#u!)ZFE1T71aO)_JA?rSf z@5lv=nM)Q!xdGrM#J=E?v9Eu{olI`DfbD|K^A?DjH|FfSd`F!9BOv)P~2(EJXW8Kj;#4#Wv|FBm%Gw3vyN8*4$?i1^on|2a0l8QX) z>u^e#<2I;ks2hu*D)+=NW(*aXPAo!De{H)O{BYK9-zF7#qrtnDt_=ZAq*NIvy+@_Q z2SJvXTV!b)0?Qd~&k$0xP=4rn(RF}EVv_R_hSwez0=^TOTzfe|2w2bFA%x}$wwG&z zKGJ=s`G*&YfKmd3y6MC*c7+H?R9+xdhw=v*o(r1@L7gZhmV?+x1qJ5Gw~17eKI#3& zupTHl@@uN|he6kYLqSH09L7Z!@YIm-PXzXaf~?j1ZVMi8=*~6dAN82G+8ZpXh_Xz_ zZF)FB6fcn*9c&5|JF48Qrv~~@MF)ertouAGW-}RAIaVUEr>6*vlshD6xYj_8XDOHs#Pbd3mK`I; z5unM<%~r4L$Krd6FUrb(%Q7mBvv!XzJl<<_z3XRc{;*dH{4y_*84?3>+UI{NJ5uZ18qwqA2gop4xPlP=4&X&mEGV z-jdLUM^)wA-#&M}|Aa+Lxb1jd5A(WKuNmi}`}r2^4(r)dHX6x0{&$$@&uTXK#7mBM z%B@k`=Id^oU*PZ0s<<%j>D42MhOtLw`GwD30yf^W`<)ma{|hWu6yoaY49tCNwEdr8 z0)dpBgr!2y3lwEego%im|6tsWWKV&xrspZIF1GF^WC6}HCw6wDEvgDm{+nxAuMIpU&hp{E7jlU(Vo*;Tv z+NPK(qiTxAn8>Bp&2N1eN)AyR$dc``NqW$CQlATO&n57p@?T9Ac1((`}>~cKrc*h7jmFowPx<@UY89ZwRInV{&d)LZ9$LzsmQD~m2 zDa9)rnoI!aYxwWoAsNo0ZYiWpZs_dE&={IQq|PnC*XRmG>!};Os0b%WnI-)=AYDA3%)MzIgawDi|CqktJF_d!v^wB)I{=rHNW^u9q;qb%rIKMq9&5amMjUgnpV>tU>#6>}!6qC3!cK}&r`eL3p^-V1%GdQU) z>y^^_JgG&$wH+t^IdJtN0s&YYudwQ=56b57Ag| zbj_&kL!=*FFB+QdI4g>l^#+CY=$SpQTxcBqcbMxazxIEzRgQO0nYxUFxL(2LcU(aM z`v0Xw);3vlaC7r;o3#JLCe<#Z31W^WjuOyz6ZGqtJ&2Y&%0+vM6CB!pr z`thIyJP0n*R-I`rc|}eGNypGMpcav+!{ED}(kgguBdB{XH#ao0)2c_Q#{#-75vUuy zmAK>mg_ydsf%n6MSx(=|CQI%Kd~s1M=P8&sErzNFBd zguRIZ%4l^9u3qg!4>0sy679WvF9M!iSnH|{vM3C=RoVn+L%W^ z314aAUA{817{e`uHM{S|n`FJIjWm$;aXWi`tYtXFrP20ib6eHWugTlL&w}$MXivb+ z&aQ%s%DmjN)hSi6tlIN;E;!B}ab73(cc6^D1ydpay2J=1$`>7fjW|@FS5DwiU99Lo zFHu2FYJ48!k(o_l$#@LGvLyi#TNE>72=R@(y-(~NLwC6ea&>zLoY`1>w_0z!BV%Ik zxr7_sneF3(zt+Nkfx~}Zc~bM>zz_(ShcAG`{2y6|-w%yXhq)hm?Rx}YR!>`@m49tq zCh2gPK%GW<uOIM4+JiV`p&n&!_KDg zx^;5yAKbt{T@OFsX)Dw?yY@~<+_c7@bwO^tkLPV(p=JlV6;JHvkubqPrEO=noY^>@ zrim?o!iD8cinM90oydjdirST9Q7G^ia^xQ`fU01aAXlQot?@NjEB)l|J-)7;bc>K! zPN_;Py136aWbivx@bF-yCoUytR7T*Pa*=(S+B0+^Z~m;DD{Q0to*eD{^PuH9Gaj%8 z0(C!WGojy8;!CgGG7+vzNr>wXGbu7WMEhUk-P8q9>lKAo>q+TzPGlz#nlc7o>Bf{Uv4HaQB01qzUcbougRmXy^ z$ex^gXz4EwbGe64(_v*w~-=WuzT1BiamvkKs& zk(3#LN6Y7~KENd60;;67@Nq6A#$}GO5wcLMYSsMI?Y05<+72fsCgT z571ZCG^v59k_9%eJMOrnut?T$k7Sdlm|kPfxng8KOD`Zsh|Qh(rJX&ro2a?}AdTKa z%Vk|c(CFawXXvrN0hmIw47$OmAEEF+IDOZD5kM&n;$ooB5I}oh4=rBn3YyTo>=gul zZa~!p zV#vv!aE{i#Nkg_YcT2FP^7@g!(r#D`a^5~q!Za{->Tu7OIbpox(%Kc?(ruB_S^Q_I zG&l?%Dfxg&4>S%j-A^w_?r;~ps-?v)dOI7&ha zTm|km{K>4(6?~uqmMsbATEX3Qfe!j{d4px4Y=$0^xQc(?g&4Qk=Mef0j-RWbQNk?> zvSvaQ0_rH4dm6Q>#uxX7ZB!8LvbtQWkv{%6;KJ3?DwHud9sg~|`?4fiUc+u=oY|8x z0eSNpH6e)gf3YasCpI2yr7B2wsw!k6uf4`h>Km`~_Gp*4*2i)04x7}Op4)Ed@i$zN zrTJmrePHaHL*~UFNIG@lrrkaMx%Cl}a&BWIFH$QwzMS5gjs zXjy%)Pf6DMo2#7|b@0Q-fsUc5r`^uKbrq$+J^-TY(S{G^a5uNsAv)&r`FH#K*kGm99`A^}$?Uz{r2w%d9f8FdMPQ4xo<^c1knWj-aA}^)7%q=#&(3`)8{s1Pxj)rfroFiDXGg;Rn>A#|DZh$})iLqs0KtXOegE}9{8U@i29 z>+5bo`|~@;>ug~LV`0L;!Wn!URxKU$48m6u5*FT$S1Ch%bG&%~Lj@vm=T|E#z-qrS z?r9qA1-GAw*MzxkL75(P>o_cQD+JV_VJ|@%f%s#~K^w?yw{ZH352*A33Mg~>0u}l> z;Ym@i$wHul6)t=jq?*?Y21v4l!FGa*3Ll}iy#g9%_Yr41J3DFImfZ?r(9DNn&h7Dl zAuRboh*g6H1TI4$_PnSSqLghA4Q}J~1>zWuuo%MiD1p)je}x%L5gV`VYEG>iel3A- zhIFjx%e{~cZpAl2W&&v(4Tq4C2_qqZ3OOi_Aea1#dcH_GRI5syoQ=sPxfszEL{umY6(MzwUxVq1(g(CHaM#~t;nezey z9q1yqn}~te;o@wC7Cj-Q3%Z@C;rj=m*VG81R_m5Wpmq<;w+tE=Whu5ao*YTx$3gD;JTEjj4 zAzPt`Y>W)`hAK^dwA&|WZRe9_5}diYp>=3n(L~x=>WnS9{<_kdy2|iJvRxinkx$x^ z8rQ|OI*@1gQA{^8*={Du<7ih4XcBLBpcPCKeD=p!KtF#z=zoVp&}#E`??fF^u9 zSZVW=gx=7#8LfN$q?Pnr*wdHNMXNgG%1hY1yAH(*hQ9ginG$`8HVI-piHm0YbKYEY z%~PDWpNnLdEBD{M-IKhpuGc5>Mf=@OMX!Y?cUIbDlDw7J=RtIUXOqyF9yd{_-Mj{P zIid3&7C@A79=m&qh%@i+LmbvPjSbap#(qa)yeQH2lh(~)4(>ok@&Ahc4q>HU>(vNO z5^sr{jFzl0EHi+cO+8(v+5Jh>2-cK|hY^Ju&ADI+S!i~X zVJ46E4eavHqGZ-=Vi^Oav{KE zGq3d?PkwnhtnN9~updafdTkD~Ud$9DXuBcT&4pc}3Ho)P)ea5Q*;Wup#o4;~`;(^T z%yJ&gHq7q;uiA}Ol#kI}^Ra83K&M-dv;z=uqx%eUHiw4syp2dYfF0i(TfE}772bF@ z*!;IoTvV9#iw>9rp1qzgu=Za&+fFiWijsn!g+snPMHl5zfUb)1oA#gFCtoEiYI)sV zUAx$>jCK*BfRiupQt}B^6rQ{?kQi#j>ntFn!EpUlc{g;NbA8~Dl0=pa3kn2vZ=)j<#bV5(V|KO51T7L z_MvD#22isl#eJ!8DEZ-@`pP#*qV;&Jr(N7A;Crd@pn zAM)yw>UEo=*9!;`5lo_PH@ZOOwhnCmTmQXQ@d?W-NpiTH%VEHV5Sr(xNyX6@1+M*$ z&njQ9JBCqu&F<$z2G$`X*>XKp`H5K6IXL$9P`fR>x53hJNO6nZ`k-~@h9DAWZFwfz9-V%3g2pNiU)6Q%RaD>*9+BFdAVnEn(ualOK zK7?50P93|;@4Zka9%0e}Nh0gikJ5D0Zmc&Yq(L`9cKL|MDA#CT=@1T9etJ}w2z0IM zz&}ZkOq2vUy@>`t0Mk`}N>;iF3sIXz$q(^37%VsHa%BBk0Kx&>vT-_@{1xVx1>)-JSN8N!NV_qHpK!4R0Z!*7R*)@>$S^QN!^2=08xrJ3*I-?>AJcHECE`KUiHWky|Wui zUOeH;cU~$RlxASpsS+S-SOEWb*zc8fKbBlngY6oJFK|~F8Te%MS^Q5)-`za*1;Ca+ z;Y^qeWbo4<3Q@+^XM0&Tq_+ND?rNvRTQ5>-OoOQThCMcn4#nH$8rpa%p^&WM=G8Gw z8=O>{e3ke#tA~qS!vK`R;nM#B$v|-yy1A|vG$G)}sl5Kwgo3;Z2e21Y>efE9>SwMF z+g6M;%yMSG8K*CHzB^WBs++?h<`Gv^Xv1pvnskiSqJv|ZM^sP2-Hi=yNZf3pt7tZe z<+Xpo4*YO``pbeAvg??>TQ?9-o9M8Op0gCBb?W(8B* z$X{(6dGe~^cA?ozlzfF-(BV%j{00(KHDtQ-(M$mJd;angV$!{W5(*h3${zozJtNjAaP2F(1 zY=$?p>1H-Z%q>U9uI>A^(8Q(gAlgIbmqT1SzyAWY0%WTiPw zFmhN%?EaGuWa9nObE|^CnJVZ<9t}E?snh5<>xf4`&ZvAc$Ie;4gSu9g@68&6>W1~H zuoOka?_NwRa-20)eENe)?qRso)RH5HuympPQ z^23K9FB2i`QjmDXdGrGr8Ft!tqV?!VT1EO6q&GXwAuY&f_sX|FrS91}4ov&7VEf@P z_DK=nC=|$*YC<{%n^zcACR4egx3C}(219XIkbk#jf2!Fbwhal3SOMv{*U{<4 z5Z`q2O_2Mco93)Z=DAxcD%3);PR)BIJh|7g&dJP}ijt&qXqb=$6pSX2pf4ve09Kw4 z=-oU7*EM3jC3FX(NY| z4qYefJV={{9h0-hIB93FL(ijb9DC|U>77FqklOHCmR&DlNe z!r}gO6AQ!vjaA4~A`NGb8je-$&E%fM1n@A8q7m)7k0?I?R6=j#l189XmhOP25d*W7 zTJe~xaQb4qS8oo)DSyLl3$<%+jS!83l#%@?TYyp5It>r51%$Z`kjF06ux+K?>LA0B z6^d#66@1t`zYjLs*xUpIajdZo#@yjIBeiA=DwAzgr&J%$8c{>7i!YBnmL)Vnqx_1d z0$w%NGBzBtM?>R+k~i~L;&5*RjzqX^!K!cdaUNzRHv#PU4WL}$;$-it_$jS{EbpzP z4Xg&b+PyQ&khGHpm1Y2C27v1ZKug>4_fe=GS^+!b%1>H=62TXRnI+!bIk)H;_DtUs zz`kXuu-L~8%pf-~3>P1atrfz`KDB_R3dcGM3V|)=60q7Y?1K%KB#lv~JRnUwuXe7{ zJ8VdmZBjq3z!|X=1q=H}bNbTv*#p;FS{HJE5{7rhuaG2)T2X-q(2{abV%`o>8I0l) zJDCAC;(!`qr`F91JkUT=0(CQ$45>ZYeKEQthRNonXGIY@%jwyJ~b~ zxcw4jmiCYW$C&75*qTe%yL^os#CE5Sx+mH|av%$eM16pO$PP|l^1F4UBIQ^!Q(|n? z3D2VR3y?qRDI*|VQ2djspbvOh%ubZGqef}`5PCmfx!)50?d7^`Pg0gP4F8! z+5uLFZ{pgGn3{VD-93=@m-w83R*l^<=A7pkkg^xNKTD}WJ16cz3Q zcijq^Jj&2d7npEo z^#SRW(5Y&e53XzuJ{a4B_K_j#Ml4V>yoK5jBf~D1Vbi`1kQ5wog>F9R2sjbfb=ILX zWXR1Fy3&IFTixP-K! zHxF2!&Rz|Fuwgzeq=3aA$+wx<1sw$z6xn?SdQYh}^Gp?ggqsb+CbgFU#0`gVepm7M zq+=rhIS&`8*=>{#sMe31B`BTjNOd}`?&^Ue$4*O5&hpIAOl-{XQh{EGPD}tz!}k2) z&ai#RRr>o$)oj}0?fC6a}6hrkC%5lIe^L3 zj2o9ureq`Iq-!Ck*n2$`N#sB^u7n7OyoAXe7%z2>jx>Ra1G{(sfJ;*ek2=J4 zrMio%dveM>zEt*}F=%{A-q}eZ$9|p|GF3MbSU{Y>z9U1BXwBv1B=waJ#`rFLOZg1t zDM+hK&r2a+uUn)>k4AAF+I#Z=u65#uhHSdB#+;g`p2V?dXq=SU(ar`UL{hS?nO4t! zq}xHnDGN2CH|@#9GRO2P#@?&yfo;tV_Bp3}CUV2?vim!0s@gM5Q|<7m<5oh8t;LG5 zRiPTBV7h4K_bswfySkG!MDzNiQjgtP&fT>?x9I&{@*VIZ?zP{%-MbZ)bX9#-ebNTA z`rXf;tscEJz&-7Zn_Cq<%E3~5D{*dVm}rM8B?m2ydD8`u>yC5U^ri{uG(+poC*k0O z*wS&xtayRG*(3mgPGTdeHlTZXuR`+`KMpf?=}y8s5~!op5C!Uzb0F{r41O3evCprH(WU2@!;{_tJ%wxHCKrjOn+|5}IKit^^}D$QAeTzFuY+?MZ*9u;#& z?umqfL;G$~nZ#>;Io9gKGYEQ8ddL%TZy@I!WZE`i6jR;7^qKeMxre~QXqnU@C`}L3 zJJ&sxHhz=p7RfBl`%TzkZff4Cowu+OH!I|T;^e_Pib@$nH5%WYiW>%z7Nt%+8Q4F1 zc2D1X0&hvd2`GjL9KreuE2E*YB@SBS3r@s-6pZeYj7vkMLKV1HW7q%bL&4)Iw@pDzk~Vm5LHU0iFK66(H!H?8ihb| z8xADx<5K#H&uhSP>onb+&hOZ#N+YRCso+Rk72$XFdX}@iX0H8gB73|7NN~9&3t+tW zitV;mT-xZ^7rO7;hWyp;;^rFd_XhUTyn*|3Ezi6k4G$a$;H-u3VA^y$P!#T$VeBz2 zfKOz;nbUtSiL#WE6Jh$z$g30zzoeUOO~6Z0A-R_l7I3U#4w*)Hp=fw=b0GX7A<@R^ zDCLA7o6_TKID*T$d}oNWIq;x^hCH-OU1&_&rN`~J8?)4~9cc^ES<&1+dGYJfb0 zpxcZ+xsBUE%WkJ23u&O8QuI`IrKMJ&G7LgS$NuKPL)mB5Mdn+>YI_5YkhE=f$8zWM zfW}IjUyAKhxH74#_Q4_eehdJ25*$>J7sUPs17N26MHtp7&C~}ZU?}ecFCfb6*jH=- z;)e#7;aA`+PJWpHa#VbZH| z)H9Cb{8Fa;7fj|ds7A$J3OK$$O=%0b1EU!mR)nub*M{foZyhwy1rVaNBx#5()lgOK zrYYE1=YddahJ>SFzCqU*$hdqk>t;_+56xJ{JSnNA2$@^Q{zh2$sKAt4!+ufTW>agv zIbdw3^QHRpCDk`A(0>Uhlxq#XwdZSn+?>|fq^H&O(a!CbghTh+yjVw_MVhwkg~A4; zKkFWAzpfd1lS(0kxo~#I0>2b6(1f4L(3M+@Vz>{DwUj)qGo%znO415k6Il=kVbyjB zLAeXddkGfHCH(MT2zL-*?gJs_bULB@#uQh7wSA~r@3uw9lpqWv0LR0w4{SYjzeqtJ zLOa&+Vn3%@f0P?e;e6EgXa%*Qg7hBifodLZp}F%2H^g*kzjypVnT=XUF9#sC?;`5c z3mBq(i8_x$?YsBveeb9ZTK6M%&)_K>%s^_yfaDJ(zJ>~xe(xx~fMQw^$@U_n{LJz(WrzPU52;DKU+MZt+}kw3J>&ID~>D$gW>_MOFqJ&v71z>>+6AcP< z;te1^v^(VZ?xRc!BLYA%F@|0nAVA zxGrh8b2T%2xUZeM-VVUy06MZ?))V^S5v59hmm&eSRE(k-|4H5Ur{40f#L9%&7slbC bu}Su(u1bct+G-g1&sIfch4_sJfBOFbXig-X{+@>Y zLu(UzCj(n!%+kRA*;8x#r)Gv%9F1-5%&e`r**V!cZ(Mm|Z~sh?gX4c4XScRBm4J4WQMTMWtVP-dDHwgB*V%T_wrKNUl=hb4YNhCKB)6K7y@$Z_1 z>Nf=X1Qw%SaQDT|#%^d|qa&n)AM>TTtYHH5TL!iKt~dNVJwh&uK2v|Ge+M6%C2uZY zgOB;7|NkD&ji4maM8Vjcsg^7uYUwa#)O++L@UY|eTbar;G{r2s|{peeF z5=7jWW-@c>I5|59hUqgLDx4PING89KOul1lYa3u)^ZE1HZ0!=Yb>;4+=-zDC_t|86E=W7Lz@z`(%y zPn79W8{g>9udh!wcXUYE*l_M|&vML-R8jw(?2wX>IP!*sHn1gvL%X6yLXDh^j4(j* zm4Mx!A(h?A=YO9q43$OCho0tl-@YYiKjroO@1I|*)7?x=Ok!46?141GzSG^Q<2e-z zcU@e{iz;Mz{e5VM*CmdGFy8;l-68a8P)pa~fUH8jKm1|IRw6DMasaOHKW0`8% zUu$0w5n!VpJ8WlYMV?N?lj9Xr72>`IGsyj%m^f-}ZEfL{I?~+M*6{PoE1T&q2IxBd z30zpI{WMu{NJ!qZUw8Qh1;<*WxGxIYGs()yWe@A*E1&6Iz?6-{Z)m{S64$^)Rx+eKiga~@TcZ$r_y1_*udd%H$8TpLqkLLe|>$e@mZfBzn~y{ zINQZwd90z-d6^EzvU+b_J9%Z(bN?^x=FZOJp;8-umsO_TEX`M`@h&)*IEI)8ZV!9y zif6wFP1<8mVCX*KY}zcsM4c&e6!i4;i4Rj196IkM9h-=A8o6`#E@8RD?3)whj2acU z*Cfr%(pQeI?e8qAS25bo{mAq7_dkMF?krR|^b6A+C9gR)1|8+?=O?bOe0V-f5+4|HliemoMxXWjTwCgeNZ>d4WfcQWx``}!z^T~=$gt*c&J^yNeik3x?p zc0M@^gNsSa%6{Ek9`CGtZdY1bdga!wa~&c(S)D~UjE#*qM-TSjMn+!T+}{4$)^=K_ z-2Tfzkwx3WWOm8OONCS-EK4Jgu)V!q)kSz{cokZHQ6^}m;0eRQR zh+fxi`5wM6Gb`)VmoHzwKe=_0+eAKPhlbDU5_D(uEwiN6VI>2Dt0V3kI;*pNBpx0f z-_47b{{F3lM_q29&=ZqTDXB1Nqna>u#?XL&Qi${I&DO4KYis*Wcff7h{&THQPwHTQ zuQT6RuC%P|%kc1J%Yni#&<`2*Ey1tRtQW?xA5}QLEo# z$*(KufBpBw6MV*bc#vOz{=D(_J}w_8cs@NnJ#0N$kY(SBk&)35PC0(^$g8pic zo%xcB0=D!oU%mP@H+Krc(|)%1v>ydW@n(tAg9k53L^d(^?bSQujRC)=rjFCn(iU0` zQ;EMh^#xk;J}AiG+(Ud{_LyDzKYIas6dbxR#4rzW)vF|SeS0Y%Kk7p`J$v@7_ARZ4 zhS`C6R{%BNQX{o>qWIf0xYMLnE^A*QW>ot6YThU)D3p5am492AA1q<**l54Ks50F6 z^5{tz;h&R}rt6D28S9Iq?_la-wRI$-PaUh?(zqNK+Zz3MUzjfA;oY^aNY2McyjB;6 zwMDk4uH}`KP+*KC@FVc-rV~N6`cr}{Z83Zia6i9_ii#QD zyLa!>^YExz4V7Mn2jr~CEwh`IGP}YR;WI7g?X9TcxEr2~&S; ze%_MI_1D*@zeM?{6bFjA$RTSB(pR@bc(Gfu->=GGJvoYdo3~K}K01qSlO^&0A zo+_Ym&T(jH$ms8%Hj^D?oi{ZxdY*el5c839-AW1yfkUo~RTuO!mzJK%$jUx&4}k7f zo3^Mjs5_R-U$>E;(UFq0x#=9Tq4PW8@vD@kx&8vx4X1;>jgwfEh`<1Jb()%YxTGKu0Ay0?P zRiQ&zJomR!Z|Ib(z;hk(+T7f14r5jK9~*_hrsRK?=(hRmZNBG$N7=JqFLxp5tU#-9 zT`6)5Oia?4bcxll%0}*i*vjhaIfz~#U*F)xngd;QS%~_TUTtfiSFc`S@0(~`=J4_Hk=%im=DIBHai z`(QHme>QmasLb{ryG}WMrh2Ygusks_v4H*5d*wMu6=6S$Ec&8{n<(_$K4dw~{oqVC zhMU_qU3NN-oj88{z0;_>y2rtu(>EM0xWKdn2Pvq&zhCot8w;2Gg_kd1el+X;ly8n_ zk&%%Jf~(`!=LZ?CUzd`=g+w(sOGgRVecD~^RV6DA=!am~4+*>C^N4 zhR;+tp6$)X?JSOs(ZRX-oBOI^`%c|;b>dV!=Jb|>#bKwZd7CF%A|U)&S723Qoed8S zW%`yK5)#rH$tfOq`8H!zR8(+uGz&C1{L}rIf0Xv`r5WB8fzF-Sf-q~!8LnLucU&A{bKhB4?R`EGrY>Jhdf~z+p(fwe6J^QC$=J>3 zB))!r4S2jN*1WS=w@X`#5;sybl0xk4~K4+@Aqtwcw~*n!%oEZw|6I3oza)RKJ^C=90hNE)n zE8Aj3TDfz89?|C~ophxY6)}Yyi=(t8LQ5E?KR-|ePm;63OGHFON=|1rRUxnh1bfg zi<`Uq{oWHNPuBTUa${Ii;N`mI@uq-q(dBw_%k!_!gmrI7c%C-x{&e3WsY31Vm>kmo6!3Y58`D9t_d1`*BozDWtxNi@PlOj>fX^DGbV4(kHj5 zR%h@hp;0EZFf2!~OTsQaPen7ge^tUvguy!o#n7E($pC#*)6~kEZOf0TsnqUI2y5Y* zr!a3HpD&l4hCY;A!qV)w_x*ZkUS3|Q<9u}g6GUWWXZ^zq}z#%(=y$Auvu9*f>Y?YoUH1@-YoA(FP3T#h?k48s~l=DaKM?Ke69(s;|Ok{Ec$OyLaza?4V*w*(;Rr+<4^dT-sp$`|8!J&+P2# zAQj1f`m(aIA@%g>jbf`|Uq#Wqb5N=CXyw%0E>lbpVKntx{Z`?W z+VKvM;%e*a>gH_gIBsooNQW`AvWlyzg|E=GM{yI6y8S)9va)g$=B%@eOOkr7?$k)t z?d|n>KX}xkUfNYYtD)L@A94Z=VK%4>RJT7U?zj1Pd*77pStBGO>da7OjlJ!3W_fwJ z^k9F7U^k>^ZGMmfYW1n!Z0hy7{#TH@$A7)0m4vDrQu*=3KV+ir_>?i5EV{be@9``= z5=8-~yEA3DGnd}9teH9hp5ipDKmMrn8G)6RRiuC&Bf3av=s6=}j*WURXwCISPMQ>)@T<$RqoB*q?wgdf;L>( zc)YMy88vxQ!=oLq+Havk?tbd@=?0FP-IqoE7j>Qe!H838k9%>c8|4l3AT+W=l5x{ZmqMmq?Xfl*2G_fM?RM-+;UC&^D zcWVltNr4c;{QPMrCns2~)ywAxdXw&*oM@G8$hUBqPHk?0ih#8m2u?lfI5* z6~&#{^ZXBL#a*7yp1Zi*#aU-$tST?hNjmIq)EpdD(kqj6nPMHM|XAaKpfSw~1w7_P%=ibJ9= zVLC7LCJhwqvV8~mVhUa7JIv&YQCumwlv+5MGQf8fdL5f6xG}Yuqxu&X*XVkcj~pAH zK7BIWSQzF9los5Y9`>Ao$%&n)HbXTtWA&0%_^&7-yG0uq5|N!b?t(#B;|cVIsPEiM zNlB5M81r52*c!C1;VBp2aU`XrOn>BB?y@#RHR@4d(iY0xk)NOMFY87?K!EFjDnvD) zZ`%Gx-s7hGi+Y~(*(o)DVdTbuG`K*!T`egk#cB!kPWiM)`quVrZX5e;yFaG@!VqH_ zPP#igJFIg4~j`IrRBk_Z!YoYTmr z)buu&&pvZOyr}Wnr5dP~Guj#RU|!;Fc25ygs!=C%@bUFMIp4vkXjX`CYGq?tX#GG0p=IKI*I zP%+)=G0;I5nwD=v*_r>e`Tf-g8X8aXMtL~HqowhleE0lKwbP#7)QM9t<#Ls3xYNWM z&2N*0O%R1r?+5&unD9}{JdbfbUopb}0B()Ry&?))Ms!hh>vzb79gV1RswPEC{ng-L zvgy&9ntnKjRw_W<(LCf(DndoX_{wtj-L>sWqT0Du2|kNPe@ep8j&n)teAU2`7>}~5 z=VW!dldGO5uW`XW`*TK0O3EiNFdX2?H%MD-FoW`+_H#|t)r_@X77!2^o1SLI>PJWQ zMD{lympLydL4DBj<}~$3_yR%!sQO_etAUU=PE^AHfwRHt9lE!((E=2vXVCDa^2kOIE}D5Ym(yN^m?n?HfRtKD~=J3D(rCdS?a7U(pTH#g4+ zb`um7#MyNSU*FkSjHub)mgC~)o&fY8f#4L7bRQw9@(H&^crR1DVt)9kIsIWOJpdb^ z3bStbd3%43Ak>ltM8f{& zILWv6_HdvjTK4yLjA1NofgDOdsmX6fgb{O5m7%Iv3ujZ97D zY;E(O4i?|nb(v-`>&=S#cBPgoKoUjV!QP_h#8hW8E{h%tvJhw-OO4+(N&lPu8&DJH z(4T;L6%4sr4qy*d+|4kX!Z?`uVm9G6cDPYbH@8Y)Iivw60P!eoW@e_U*Dfft3&cu& zXQwh^cLkglVvS5pa6p@eQJP?DQMXsCw`W+B>A4sg8;#;#5tC45lT%S?B?E^`fBUvJ zWSy|bbyBqM^l&xX<*|F3g-?Ql=cMl4gLO(KU@;+$1+Wo{LFiLBQ&!&6q@eQ`6(krC(3FKAtGl zVvFXp4uqob7m&-PK*ZiRlnkJHE$q6k5Am_IzWzon^B%0{%iqOG3>HVKB88skpO5!3 z4!N$_`1&Np667?)sqY_fk*)xA01=f=#=9b>e+NP8*A`ehGIw`W+mSB#VH`G$DunT1szy`9r&NLr2XQ^<;BXs zXP}Nx5ghcr3Uvw+17K=Msi>TLq@x4vc~P-Yev(x!s}?xdu-OxB0THR4Pj1@%k*8;1 zFxXz5_V)Efvcuf`JUSV!^a~*FSID4Ycamqd0C#)_8f^}s74UTQT1DnZ;U@h2{Ix(# z>r^;406+IH1h65nUy^wUWkS0-pZydoG{^r#Lqqe--u~a38qtNS4PCd@PAPu3&Cd`7 z(2>&8(zQM54@qfg&Sa~d)YH>L9Nv%0=iDPMv)S4%y0CgRydWZ8f^qo(M3G6;VC7|y zAFf@!N?`Y=^$zgTK%D)A76WPc6R0^Ln%xX+q?zDKAg1VU)%;p>cR6$BjAY+@@9#DD zHv=Ws?*I=Nz)B|B!5}C|<#&PYE9Av2UR^p;?1==+sdz~Vm3s&K8#Q@`4gVlP=DK2h zp`(+xcN&?{xReB63NYZn&mYql3I+ahxH@u^G$;dA1ebn42NDGLUi6LKC34cvc|W@~ zvY-r@TJ;SL24nR;rNC$+rXQBzSYg)-wC<}xTy`?Kx>YyzYrUujtwF{C4kz>SByiEh z#57$qzTQJUb0X{O>tVWj=BH23Z=H>*v)J{P#>4X1S!QSIH)}ulgA~eQ9;)}7YHa{I za%=WoipJG)b#+o7R`-{K#FV^Mn3>_UIP#;))v3*C>H<&Uq`1+U8XEGT3>1q%Cf7r$ z`Y&Mmae#dw0(l|r$#Kpb770U8MS#QaU0@+4RVD4%B!!>;<0C_NBqSt^uEBF3erEK5 zj}p8ueQ4ohP=Njz2vGl|5;m1 zI`(^GlsjwqC|!8~CrFRxS3EYao^aoG^N-?o8XG7wv~YUsZ6%J>NGh+aENbB3i81}P z8S<&VMe<8Rk>(S+5C(6cW0Z+trYRU1JyPFK2oCmJT_t2)_x84uLSLOJqxF#fS~9wC z)x)bVc2a0bjGA=~4yqp>T~V0VqL)3Hj03A&mekwa zD$`7tlCZ!17k|;5Dj7IT=M2%|-~6?FAXMu##~6}i(Q{`=wT3xAr{Ew}Jqn$cf7{c8 z7A}$|i=qHe{zta*nq*s)F2hpy z3W5yQWI(y36clfP$dWC|^VoA4f|RqgvGFz}gdB+BXQS>L2KWqBlgDJ_n8T>*-c;(zGrE2%g6GQLb|*#4##g=4%`9;xDLJq zh44jTms@Zpw#M@pE*OFc3W4P1=Xa8d&&uDR?#(YK^)HM=W%(JVz5Ptj3BadI%gc8_ zkjeuY!OuoQrKT;q=p+#HZD|1vx^x-5=?u3W=gwk;VsmqIA5}Bey3!wBw{db(A24l; zPNCA)&|m_kN459l$&(>aOv?dh28E1_y?vqi5a11174Biupe-@5u*kw19cGC*cAf=D zP-Elc*RcBT?uU>^(SMkCZf-6;BV$HmN@}W{w6r&NR$W~k(fy49)F&|;8=D}=WND4( zq5go&V`sC~SmOj8f)f+35L|)vV+HDg%*JVZL7+z8uS7deeZPaK=rCBO@bed3k^A{he3GqUxcMFvHJcWE2$F`*L*1gI0b&t@kD+6a%UH3IHF* zJRsxFVqM8nBp?TzB@F^%GzyY6cGlC=lbMO>rcVs2(%-}4CJm*Yw|8iGI4^0Hq>cz=Hi9cKx;*Bi5HXB_0t}+aY+tT=`y6-&DA`(CTF4+P3iY-|&qyBtj$rg6K>a5iXK+wF;X@Js`T`^BfOOvjwsygcBw%%{bXamKAy1TIT zc@poU*>|G*@1e&2229{p0M=c3kENc2yme3FBZ&NjVnD3vpL?jL#t581+3Mn`o|~JS zL?&ML$&)nscp=TM?(X~Rq_ngg*hfeh545ycpn!+~4aUaSmP}Ms^!duS>l2V9Om-rH zCC{x~@s*I2^v%r7EUl=JgRw$tU51{wtgNij*2+W|Bq*2+6cCCq_qrhcJfAP>gR*v~ zSN9h6-&XF?nArK9nN0591+`aS$1n8~B)UOyy5OYfyBr8HO0P`Qq zcY)&|$5vKaIH-%>QSr!P%{BXL9QaZw>Oe#R;>v%(v^DZ7X7sc6MTX5u3ifjtx@+<} z$hcxMN_aOAp$Wxc$q5)Ju^eQ?>Ot=jh%tkzPMlB-77ux{AKJMBQ7T9wF`>B zoOA=O5Q zQjd>~h3*5!WsNWcYV;%~02YRTN{?c(?E0O0@*B&&w-`N) zOT;3=;_?A%xhLPRpsEiTTj0Z^Fb0;&Y<`2y%2GXK@Yt3*xN?My+)M_599slk6E6eN}rCq}v~ zOj&!5nXfNB`#RQ8=@;Q`6|efnj+FH2kIw{NHiWC7%HB=wz6vEfl#_Qs`u+@p=G;Kh zNtobYp}g(&cw`2fc^XWb^5}?(fH8NkA;9$uQ4#B$lAQwxjCd@Yy*NF zxKs?o#vutN;?3`GYiY&;3l~gJ)u_tI&;MggJmHE`+d#GZZG||&qp*;;0rZgVB1VY- zYLGXbi_{nri=DyWfQot0ZWLs;y;eAs5J*7AB2Zim0f8{?++b$@a(l7z@oIcA6zUvR zt7KT@5M?#AK33F|1}ReeiwFCPGTYb{Iy%Ax_jO7zdw?(GQ{k-VhGgI+v(QxnueWcB z<2|;`CN@HEJgo7Huv;eU%+8Y?+vt>{{RI>gl#tHQz%a+X{uIzl4WUTB$YpfAJzm%^ zDTxkhyNjU3mAY+l0gig}@+BbyI~0Oj{YykW@2iKO4TEYnktJ(v1LR|KOAB|usjbYir{TXcuE0$aU`U5o-T^Ha!=NB8oUwz2fe66+62uydY2cd7 zFa%jpSXc^`RM=qgJc-+0(Xv=uUfwTnzj3iP344o~%AOsN%zus^?DJvzKpY<@AyE(4 zsZiUWF9u5w__ltO+9W^dof|6SE`Hko5?l%(ut2$p2e8TI<%w&=LJN$~1C>L-#Njio zdcFP8)B8=Ty?rw<>O4I7F;MyK2hM}8dK>@} z2qwTEz6NsQ8Vidr1CB-CC&JtOVH~3e1^c5~aBV1SXm|q|aSp!9t+g;Wm$kdw%H0w9 zsHOL#3^^$9|DY)g$uG3N<7Q52>5r)c7hv5n|6Jy*i>Z>dsTW)U&&K!`6xQIjwT4S^ zX>kG>Y$GG=(0V*2 zxk?EYiXochaSEMzE>W#~NvbFtZxl8WGGMVyx##()DVj>2F ziKs$?NC3>H$H>PchxkQR_A|LRKK%2~KMw{#DLs4s{80>X;^wi{Re-EvtPlFs9zkWx z6)NX2hEn)~M^Dpb5w{<|trQb0FR81j9LZL*urIkj91jCa5IQQRyxdBIWoZ^PezXL? z0W3j4B++I#Os=5ws@->}*t$KXv*A`#Pp>F>tQ$22u2^@$ zQk-D}B_H1w*51*f{w6M6Bf6`}a}ZWB@@#_RQfPZBS@tP#fR4c*tTU(eFgz5@;+#(!EvNy!U{ z`|;Nlx=I7U484Uyky6K(00V!EMxNnOj7hI+iWb2;DM<}Lm_7RV-sbO6qJncG$A82V z3O$wv042yohP~hVJIVU+F4V$0KxPAi85|rm@=b>Yylg!1_KkLYCU46dh13wJ&C}pR z!iz*;jxruToK98e=2Op2NJ#iS8PlGco}kfQc1a|M3{-+6C(q z@KS!jmMDY6=VRe@Mn)D+_+lEeRblU;G>Ew&CodoR{ksyu6-P(ME}#>q2Z}O*ypoOb zNrn)_Z9~~m-1Qa^)$~wVL7_#T0+^4wKCM?+w&WLBOE(2J+ASAb?VXt%%N7@E4`NF% zs$VSV5P7)&9vD7mki;_(?HXP0u`%p~BYs^|Q)9m{q$vbK7D+R$=dQ9t0>YB;v;sBu&pEqcrjnQR2XFUARIGfPf~cnXJsr%AexF`4|GWHZb)?t_X5yd=}$bP+RiS zs93dI+uq*xg~Nz9LoQBI(g{ERfuUm1Y=a<(t@vaL3{V2pJ!n9>} zC2*d4kS3U5K+i*!1&ARS8b3W)k_+Cpo+q+pATuNOy1ubd7I<`I00UzRLcTy5cRY7d zg(~bqh*^JcuBhd_RsT7f$>#7Lt+5i9HS-CQZ(VgmZ`;0wTsQ7XQ^pZ%gBw5y>?@L{ zTs@%FY5|eU0G=J(?=_?qfS9f6F9%+-)C3PLD4-C)0d*Z%+3K!WVj$0hCsY;C@4ZaC zFGL)2jy=s!bK2W>fTcMQStJ1q)Pn=*%_&Mc(SzNB2L3pO>wtvR|Cp|=u7<*d$H5wA z&ADK*?Dga_B_$=HSY>5p*6{g^dxOO`>?4B&2q530<9UYX<vNPX)Pge?(Pgr@jHyY( zI{fp%L6)4iD{%y3u^}_J`X4OvmRWF7xm3{{Ufqe3!5v$KWH6vU`LLK&xeR=whz98p z`g;m!?=w&#?g9hQ+}e6X$wPhq{Z;X-A-RmxqI>o<)O=K<4TCkF7tzt^RyPBJ$ahBK<-rNl)c)T3cP+3Aylk+e8z(3vDTs3y@Iw)A5K%x&|u=iAeL|9}v~#Q2WToY1t4lNejr_ zpFxycbs<-4%(ClW#IW2(6qtGc`uyZFUcH90D6d{lqPG^&Sr;aLpEKOHhc8a8|K|_r zSP410Xc78u`S9WOjza3`ocBhA8JiO8a`pbUF#IJ*^^n#wFlQL?*!v3Ha*)~#DXFpm z`Zf;}U&&dHs=~Uo0944%BVJSaw99;v^X{7Z3uS63BJ3*=$*Ce6!+s14=!;5OCn;)qTgJcG{DK0NO_I?w7w8JV@1*fqqyH4CBp^ZB4B zw?@3$@DbE8B8G4?dvcSGkv4Ss!#>F{YYG$v#*8wV_wba%_M9#&dkuE03T5qNNtAK- z4m*YlwQn0d{G`g~)5Dy1R!=n4krY5@tr4NNu-sH1(8)= zie5yw$W>lSi}I$TK__*abObhqu|gvfuaKZ2NLxn_69X=yqtMLePlumWJSY|wB`psd z0oyRVpLWFxRKR`dV(QSR_8c7wm>a2wR41J_>h!1oK*t!hKz|0^SB5DNKO6%coPPpF zyxAlz%-MC#JWz_((mDm~Pk1)e5^`w$sEZ#&T+lokOx_pp1v+$uXlxwaix4iROr)+m z#uMikfi89rE|zx3b#HB0TCs!A9OOmRVqOUBq+_fi`-CC~LxuIXU2dV4#Go&~s)z6i zVuow>TtSn?2+_zq{1BY+!sret%ub_*OZ+*!NW&wa60?VJQSZZV=eas@p@SEoPm+#Z z<;XqGQT;@SA~y!j2#Gg`=iGE!pa~^C^*fX968g8l`OEli;lnBrHU>Ao#hDad2>e zgZjv^V|487$QzYm13D1wu*uuxcU{kt83H#VO8|J@V*2+#rKA`jzyFytZ-7yT18;z^ zpkrfe8~fY(?c0|^v+lDXJ3-EcI$s|+2%sSgFRBB|0dEBGGlW2)JsB$HM6eX7K23jC zR#vnJ;XBa0Xn#Ue6EVo=O;9zlHInk&f~Bn`{4@eh&8OZD3@ib~`@P1~6Y~O}pH|@$ z0zN)IB((v0`cY^`4%Xk-P-~?(5)%_ALm8gY0u*rDLSIJ*3D8C=I)CQpvj_IU-|+$5 z8_hV}%hc5CAc?*O0s1lUYyc&%A@2{AQjzsQQyv8`n3Sz87hD9qAU-`kDu^B21T#k- zusmQaY@uI(uTKqE@PQxWShkuU5L1t;T+Rc>ei@-r2zf)uu8cOo{aoaIdJ+Cc2yht+ zoipGI`%z|h9oYcEYJ^NSCVJFKZ;Td(giGC`AQqF%gS7I&Lu}TW^tuw1gJ3|(g%sz{ ze*-vt13TgccGP|*D=?c8ikWo8>tyd`gMN=S167f6KDB$Ao{sJ=CjID9?4t_D`w|j> z0*wB@V0@2w0YL_ac3+tx*hvvOAJ1=d*G#X(Dh^0^AIapPy0;|ivs>x_tyQ1rK6v=h z!hR537#j;G$Yhw$Ynj#4ZuD-yg22U4QR3W)`?vRq7rxJzI zi=RI-m%gd7kr0t$>e@PK!O#!_jK*c^DwwsKpJ)OZxCD8e5aWINL%;AT&}bMgL8>9R zu&PQJ%JyU`s8C1mq;`LRmV#xmLdG-RWri86Ro8Pj?x6wX0KgdS+xp!cWHRmno?+x6 zzj581=}#Ls+j8}`ImZ!VS1mNn*QBy_#?_+$D`6nC_|2@q<_ok@46p@KR-iOmswY=O zR?G_}J3yh00b$etP7@^OLdp9puZcz++?_Mq+cC_*SE@ub)z_m6L=2#8(Kz-K92iV& zY_F@T+>6G5C-;Y_KSE4Q-QY0Ybrkt)Y@k|x=IDt0kqWW=FMtiru&POti(uD$6dxb2 zn=*eE4-SCfJgc~AoyvEj?G>Yb%48>&61l_5sw@oTlxUP+(uY?U>bX znZR#DcwHe@Y5xE$dWHa*o%h!II6+BIc7Uf03Jxa3z^C|dIKEm~K!B2gfkCz_EHqRl zr4*!!N3ext%hTBA&K-nF!RRgd;6ZTkrs{>spFh2TeS{U_Dl>CB&L_cRN1~)+*X>M? zyo7yb7FXaXP%r-i*)N`nAA@3!PwT?jvtH`D&yPw4UbQPD?Za`(7@>%S0nEg|J`fEy&VTfJD%)zkuoq5?YZFMbysHVe8q*SOO zc?u|Tqt;AQ)&TR5JROLiPJSn%mCZQ`wAa-UfdQ7$2IB5>0juYU z)-b8Hc|e*=OPi+pKXAB=H}h{M`f+0tM}Yr3?B(=J@+zaPF(oM3Cs94P?xUxsb^(?M zoBiGAu+NK{n)j(v6?YNKs*PaWLijlJ7T38J5O&h3Qmsi&oZy@(@Nj&O8~cy*MR%eU z_H|5T#s4}*AJzaG+l1tKJMM_Hcs|z+-THx|M$?U!#j*J(hXsjsQT!$-i9bQiXoCGc z$Y}tPRHl_8Ee>d>)MbsuYlX~MH7q^924P2(k+eNLI+ z&BuV!`4?1Kfb;~=aX%oRf4lMxp9kxv_i;eY(5Ok4CU9&Wh$|?Z0n>^NY#q4BM$Kt> z1k(qak&%dYa&nTju3hEQElt{z!woJmx@Km~$Q_3-1p?vgmoEfhV&ZpRN;C&0j-9~&lr+zSt64g0;*~OoZbWYoI!Iln!D?qM;&2U2YF%Vj8 z2itu$zd_%ToChW0J>Q74I53k(yeh%cDA{6XXNSNmfMWfwx3I(^oQ=JQ?V@Sx1+YG6 z*sV1-G@QVY*>UDk)%G+VTwJr0lh+~lGTOk$QH_$yDb6gI!&BH#snxwLogT0Okj@eSJ_GKx@D0Qvn?R zLiLUnEP|xq?S3*?%m&+hmLQ0bLXUhb0(Hkj6J)@XTf!A?0Mr}oWb=i<1wCvWJa~=Z z&bvPbdp-b~zl7}crM>+OY?l$gbLWNa@F*ntn~xh$;rq5sz?xd+L@k{Zh6m#J~nPweLydex&Ij0^Tp#`?6Ar+B~ zii!ocHzwiDQ^0z}W&2yYAL4MP8q_~zH$*XjN*+jt-muB(mRXm?vC~xauo|X>hG~jC zd>|-+pdFfo~+l0Fb2s7&Zs5;S`p{sqXP836W@g^E`Qb7U|eNW=o`cLWl z7u*0JwYT$d>D%=hs-j_cr<<^uv0GLcUK_xMkcL9&Xv0pjGBvR|BVC5};a?(ImwBxh zjM3WHk6@w7EI>xOa$$4}trWE}2O9({o2d{w$wrJubi;o)K`U8pYea*3+2Qm~wuh|Cj7kAcKz(!92%5P zOGF4s0*Td6hOtkSG4stGfj(I+7Fz5|Ek22!B;#Ju_@Q#WMGidd3Vv>vq=L8oP916dr0bmB28^a=;VO1s# zVuOe_8b=SpuG`9Keu#e!APkJ^&d|s=WT-X;3G`aEzT)F=*ZZEII1i1e*H z#ED3i#p{!A2L%|S$V8+?{vE)dioz%|52=#o#?SDiMitJX*Ygjfsh=GlfEQ6?bc4_n z&5{uI)qA{X))c>#a;2lr(|_UO!*|0UouLg6)qL!dp#6!19ooZF0)1!?>4&|}L-P~e zV12TPGEs^C7ZLjF)Dh06t=@-|@Y2PUxw9RHOSc{h{Z--b{#hAti;r0}2Tq*1Hv$ z_5Z7v%o$$_E2vm{~z3At&NzNmKGJGd?c#8!FBrqa5z#(KmfbZ2;v-q zx*+1dEhyjyiy?9!fCo#G*(p(uFn;hm^ujsgu}= zGiSo#oelUV$oHxnu-$|m@F%zeda^B)o%m9)@gExT&%%aEbQJz0 zxB~l$f+Hi-sK61)ekh9oF@V^1FuUErkn;@Ccrul`lF}8xNQWD#kzfFH`4KNjwk@D} z=THGOHv;VpXEE?WocIK61JmsQ{GZl1>sq@M2rC)V; zmtmGVBE!Aqnam3RVDOWstnBYdWeu|>4buG22W)9;3xjBAv-YfWztPJx{=4Uv#bfbB;4f?=muBQxkN+zI;*(^sjGWxb9~)58@0h|S;T6Jl z=>yLs47C;X(h5Q!L^xrLcK&3%Oy0E?4%l$10?Ro;*N%B&+38aJF zUqzL$M=lzm9hHm;*y-*#fWbFXZ6Vs zj~mmV_9EDc=C#ZK$x<#Dkle-3XvcSOdrcs0`towOD$#}#(zCf7HnQL*|1!hQR={`e z-)8~#+BW}vRA3SSi1Y*8+YIWg^S$o7%S|}o*#_RpsT&yFQ(v~_(8a_OeM23N?1xcPe@cDz0TQyZ?W4W#ev(CFw4*fpRCRp)7!oQ}zdT3XTc>7EDsSKsvk$(OB> zcNfetnzifse#|VHz{>Vns9cu;>k$hx^YYuyXR~ONOIFqmhpF#Z6WM`s0x#bk2WaYw zOBD+XOBb4O)Yg@pzn5#K!H^cVAPUu{M$?_)6AtGgqphp=Aq>BlamA)aMw=zzGGgWC z=FTe5=fvGr@3+awU}b0Tg}rydZ$vj$RVm2HlR+nB0=EdD zJ_F*K{PARu?YRPRm+^qwOy`FW2ByCdm-$j)XR{P~U+k}@ikd;F!!=yy@|p|bB$5O$aeg?U+* z0lr>U;2XY2s^Z=4S~F%YH7SF$Dnm!zLvKs)QTbiAWfviZEO156~%zoS7Lr zf1nd7AMZL*rYq=dxreb4C+}xI@!1Gd*BCpBsj#!uFo4FF1FwB~0zi%GroI=NVk@|w zXQB8lH<5#4NKjiPi{Lyk(&=A^Jy=~eZR5+E+IcFf>K^_pP3al!%*QY5a{8i@!PD{kdvVVOxr-EJIwSUwilO5=^#9aMS2f%$NOUH_{ ztbkA7XN_!;lauR)+&QuAY~RMy_pcD|OwIk6d`)=59*yi{HPHFyKq^E0cJzQ_5#}ph znvAVO;w|#^=5?SBw)hX0MpbmtDl)wx9a`eiBsqjrSWf zmj!G;1{r}9RD2|}WNzL3{BUN8!)z}jIC;}@;Pb>HURz6Rre;32Z}xQg=~&K2A=tx~)M3$Mt!yWM-Fgsa?ncZ|Z~GfJIOhAGiLskx6~>rbydvV$xNh`OJq( zZGzi9|75}CuO>vifB!Q_@I!d=~q`Jn9| zsMZ;;85e<9y$fho@sX{^ux^!4e~Pgmt3SbGJ@QEXkoo=DM*8~?m5cEF46fa|^z?xRw@2x%CDC8ye0G1XM{{3i(;w{ca15b& z{?YpAc`W1AhQN=1dFX!96+gEthP04PF!n4q9z!zmSwl$JO{oNVZ{K&A&>B zp9O&~S5>{uvZTPKD0C;;1ZD#1u9u%u8pDW)I~iJ{9-Vzj`z*-7hXPa5-eeXQwGR{1xwc6_YU1BXu9)?}j9DG}g`Iu( z0wG?=c#U5h)tS3W5z4 z1hMOgA|OS2A|eV33XBL!i47~rD5400f|LOU1?f`MC@N9}hEcjAb)-qJ^R12MeUtO% zzj^w54KFa9(3>;Ip2!|1vuU`p<|{#4x3Cy_k|APd*0B}$cfb*_%;p^D zbEAFQy>s`B{_z?9{BWmDE-hg>PR7rNIKJ*2A|kT;Wceug0*yH-DI(%BXS5SOxjyqh ze-Qss3}K*KMF_S|mgB;-O=rqo&lN#|4F8rpAmR|^s=-k(2bPWjC^Hh3T!vGNib>Y5 zKl#WgGVy3VXF7JSk1wxIQnbmxRlV^CQLP@fb~z~j`+BRD`A8@3HcgGU?W?zP&O^M9 zGA}7P%i`Ve@p;qe)Ug`mLP5F5`z) ztCgRl2KUr+NBZLQiY4sr_(Bp4lHiT-*;I;Cyp1oYyaICDC{#FFoBQm9K)-D1z`0H2 z7e41H80{#PY)BP4&3;LOuys8soq3Ij7{@7175N zC$*pq`X-R(pO{q`>*XNqpZ{b6dhZvyL&nWU$HwD4g?-Qfo`?4l`!!BOb0F52mpsS7 z3ztB$fPX}|BGJr0IW7)X1J3(HUgLfAX7{|@>9hyY-qia-`c_iY;Usd%X^(1*!_jpU zOJ(FIBqry&K)hI?mbdi9qnR0~fuJ$M`Kf#Vm*1Rwkjhx%Try$YL_Fr|_{cj&S#wG+ z9<7&>ICGp+)0Rs-o;Z4Q(}v#_Kfjp0nVnF1UH@b|@`F-ksa?L)6Uk9v>r#}sKd){X z@o6;}8mcyDZ-;}&2tVbYrHac}Vg=8B2`zuTUb^h9%XPSDjM;6qm?F!h%&kjNqcf&( zrE~v@*)IWgbP1Pfd*UWek9ESJSE1xXj=dck#Mg*8PPs9ghOMty=5%hf$t5_9{>=17 z&Y07WwH=Bnj8X}oe$YB+9gBg)s3-{KCF6?3@5?S(qK;bU>kLOIg5{K0`42FtDr{~- zmA5F*5cz?1!ZE3ff$#+bzOzlE#;+QgYZ$;KB$E>a%UB*KoKXYv2IChd>`4{wLT2+2 z`o6wwVed}Q3Som?Y93y31ays|h^P`lJbT`}sau&a%uBR%5fHMQHx=*_zNDXiyJGvG zGaVoInxn6EwsZG2!>-vQW+0CN8ZvZX4M7{_BQ8N+R>o25W0_Q!xjdP?~UDa(MfC_wyIC?NVCA znYmQAb$R--%|c8_Edv9wqa`Rhki%w6bQ7Y)5S~rUrgz!9_UyR}+JF6;U<)U zx=sMT^6AHKA*E6!Cqm3BPZN;00#IQ&2;Rf+TFf)9FT&1!W#mMOa33Erh#4H0KG(Dt zE7w@pv|%G+vi0nIxcA7r{qR{HQk(I|EaTIqjgQ|+|NWU6)Iy2%u|*6fNaTEkkUW&* z!*odpg-bVJGe+Rs z%mn8Kw(R+W$4F`xo=^p|%wQt^$J#bck7!tOq#3K?4Jhz7c#75(T10wQtU~@?0AQx| zR$1?6$~r9L-;YFbzzAM{v%52%`r>kg!wDsph_?M-uV+j+cu4RDz?xlc@l1N zUoSoUQ#=oIP!*^Q$^{B2|G#=Qz%=7}E#Lr+?AuCnn2^Qu7sVBS5O&BkB7G>B=Xc^R zP96*BnjBzl-0RnaJ=V*aIr06))@&Pw+e(N6N?=t%KnW1JHaHt<%X4k}Th1Xp*!02? zI|Vxsrcq17O@??4Jt_HQ1)$oJ!%ruyn^>Egu^jdL;Y}?|-%Cq+>h#-BT_n`(xDnrp z;jX288h$0gh}LW1XY9eKe-|B`8y0s<&LRlFh`>y_=O%gYEP^AMjF$>F;XLS9?y|bQ zP9MI0B&;QR+W8Jwcwo>zfH33m-EGFa|_X1ml7RtyQUvx*c&oIr7*aqZc%8VH^)G#AA_I+68CUN}J65-T9 zUczTPjK8S7_1+jkQ<+~d@|~^|DOa*Xv$Bl>OC@n;UzaiDKt^K(6f+0ot5K;1ADo1# zrAEZNvjb7vq}?UzqB7#~#9vpVy5e~$Pf)_rrj}B~dYX7;bKL_aaz;Q0e zHwXY6Z~!6<1)TS1vX!xo!hCU>wJ}^r7`2=*E~jpeh}U?UKu5$%SbRfvAo%=|^<@aU z2$;r@PLN!q_^ARi^b$4|uZ}RhgKe+YYN`H;=u_Rn2Mg}~T)AO$*E@esU0_R@U0L`B z-mB}G_i~i8v2rzW_95e0ez-hsq5HJj4p+#LYjB_^vDs{7$g>=Kipsc$=c=<|$`a#$ z2#O0Z5qB81*Yzz!t+$u6)wkG`VDM2ASMG#zBK;99sU#1eIDL3pkppnmIma7_L= z>n?QsHN@kv)w`pJ2)vy;` zp5K5FD-RwC!b9RV*4Di}uPopF_`?q-$RVldx37mB^e_$fFm9sutH4>tWx{Bub0H`& zDvCFdnf;P-NeD@bAY2h;&P8!FwDbxgRq%!8wBGgx=DE};lD~B+B$o6cX~(uMMWVhG zdZW-voipAcs!dYIjS%?2Yj-J5in%a77bXMo%7l63usWKy&b}FyOKFlr|1JmL#`dzO z@9K|YbE;Yy)3sFg0NGRvEsF6BEfH3Z8A2;-6mE?wQSON0p%aNM~s>Y4M!%>0gGC# z^7UtC^wOJN(^)=j8LXc2fM@`4ngN{L1bOQ|9QmRx0g`<$V2mOg!u9u0lQvE%K7mtl zB>+`9fK^itj*1dq$AJFXH-X>W+|GP?}mD`&ju@)tmxifM33qxq=2E^OVM>>Hd@ zeoJ`H&LImsr<-iYnmJIC7=w7WO<;x{M*RC;K%|*gPAxO8`uH5gx=;8NmGK&IKqib* zI6ajjbxP?!HE1DI`em3*1JZ@RCQN@$HvW=Heai<1pOz^7p#}K=;bs4NsV^y=wx(tv zHs-BtxFJma;c47>7nO?u-jTmCYT>+doiB)JK0?v^*4uiQA08^Y-eInJu5rAkIkxF- zsJ9U0iMWJ7YI_wyyM90+G-!IDiq17n*MgGjx=d>C=fpJ=3<7u8ji3>t#E+1w>;PeE z954PEGS?ONUslD%^4b=pO|HJMvo@n7dd`THYQuA34vKen?~FbtCM8yVp{2F5VOqcn zi8|Snk_)x^ZGOJ2ZxA&1$f3HXgTMUX9&BppH&l8`X!i4G4&Kd5mo83LN&YwaTYUU5 z5tq?6Vq4rY&et7VyXr>s|4DWK<^?^p86q}H34gv0QZsH0H%h@$Ql!^*q=>xQ{ZyOVB$;7nzha-QU^d14|ROD zpFh6bCV+vyoaw76pfA=<5M8c@$PD)F90;7Y381J8MWz@6*d4LUwyj%pFcm$auRLIg zlftPh!44-m{Bx~1W~`qE^5=(GX|{zjZ41zHdZBpvba zwfGr^X{w0QCUSb9qGo~75g;I>s#J&ePobc47NK?umbY)92)E7Kv2p~@SKekbBxCS- z^~N4dKSie?3eWUXP9&7tSBqa3U%euP3;Qa#isitQz0x}2nvW04XitzJngU8VlFPw; z`-*Y(xM!D;?~l&dwNvRHl7KTOjw#-DsfNSgT0~Xa7yu*K@guZ5K+ef8UZ}we{2>Ah zCDcW&Gl3#kfch+TP%Y#{09YP;$_^Z$b+Dp?Y&;URRHJwZRrf>nuHe)gk4o-PWTo^| zkbEYB=_1nRctgS#WS8q=;INW|y~XzFgq8D`Ez2|RI3?M;7K1CgY~LjWia%&}U=JkA zvpVR7Q+hwE9D=zyz7AXDb%f|pMllAW(9GLP`cz2;4)!5RcBvW?R&o5^t`-bME40A- zQ4z}P3LZ0q5T1?27!FqZC*1*P0i<2!s_IBZ#4-V;Ct7weQH5b+i~Dy;1lwnbLmc0f z3urYQ(F0Qha`GRgcl(1yCjtl?|AY{7=YWZJ1Xxc1@cR8Xf5*JDfPNR*aUOEcJIG5S zhp`u;Ox;RV2~HhW)eX_uA)JE;j0io4mZKtfK3&%g^n zQZ0Hv5+tdplEXvB0YoW7dJyn1n4-8DX!(YrBsyN_VAd+G|%z>4Qa!)&%2@i8*>clfz5B&9LBwsR5gSY09J%x z6=wuU+j@!za}uHT6<0jAcz^GOI_xB}?&$&e7t_6aLjd;w%0u`||3T{tY^WtPKv%NE z7VN{TT6>RxG2^~E9oR1ku*jM`&qOwoeg(&{GF@)ZK_(CI=aB2$Z9>&`;;Xlx5D#vVg{0I^Ea#$iSHzSozNS zU8PP_c}DvUH^q2x2WZA=3kWlnnT3k~L@-|gORuL_ydeM(ZAG-Gu$g#rM4&)3w<)A5 z>Uj`n$p+a8a#UMKTfe`N7aDf(ky;E~s^vKNFHTlWBFp26hAhy^2T@XbVBun%g-%SN zAx9D6(iy*b<6}PRzKJr|Vxika$I2^QPFAILC}!F^6KyS>HwoIBW|x}FOam2Il^t5K zVg|eD27x5YTNkUJh+psQCL{XF_-0*87sEI8sjID1RUHz*S%O#V_q?;21CKD({tD0f ziNRnX|Amn3Jl=L@mzS?^y&q4?nX5IxWS&`ADfsyep{eEvLGAY|do5amQeY0!A9f(v zB-e1MA}6FHU2!x4AO_}frGy=Y98AqIHBvuW;zX?P)oHyRS%j!UIJW9D=CUpJCwoN+ zLz_&wS?-Rr2%hzSPUezK4J=?@isNx+b>#kJFqn*&&UP0+)8PZJrupa?fdw$}tsTVo zDr}rS({fhsR49`?3?!5th*IIR;l~lhpAsb~bxYvH*thJEDfXdOA}@Cgfs0_9zSNn#$KvTLX4$+OUb8W+O8c zTXQxfBJ8AZ2A$o&Lgh+29OR|j zR8u`AtdxPG{>-b_n*%sH12AATro>&j*@p#YFe`8l??r!ubJ z?7Cv<3+KhDKR??vuk~5*&TWbJ`QN`X?*BYZ_{k7K1CMLCnr<5XoV2mq0I`M_VFXke zBY9+?5{Y&?ArL9WptKrsMF9{w?CtXC5mVzQ>sZk2XrpA;7OzbX z9U1_Tyn6jw6QMJ*1!@p80Z4v`jIy#Z?IeH&KQ^@n^WDyLU!IPA@E=&Ouc^T5Y1l0@D;0$2s*bJwsZ$kn z(O*-kf0r`k8n}tY{lIH>IlQ>yTiB)j)k8(ro|c!{qB=!Ce4~wYzSXyJQ-ukj_`W{b zYOldQ8JzIbVQKYO5-y5!q$G%!KzrTDXisf7tMw-4$*GdzBH_M_CBzfGh5mVrAe zgE;j@#nF%P0dKSBTrj!gWb*t^D#}IP`v?y;l=5dFV63|=(&He%b_yg4^n+7?l-J~2AY2TIqv2Nuc z@AF7r)`)46gZrh8F#|&)GpOIHr=j#!nUcP~?>Qxg|B(px_Z>H|9~oF1yt$=+zG`wP!j{yYefmG9@?xs_HTdd@iXz!`l#yWDRR{f{YFZ^Ikeq9am|R`cgy#>9d$I~ zn+@4G>I>fT3zj_=bi&=@|7IJINualM))osF?~Lfy85^2mlY63xPlzVpJ`?X=CU) zUGBqi$O1&cuS#+F;%(cvk57mM@-r(gQa5@t0PZB@;B--_zRUssIMm+rdWfb^hu+>_ z2Uc_prwG0^$m%wWD?1q=FVR6%L(QR3Hn1PUVnm$2iFS<=njP?d6af6;1N#8=GP~{5 zyIlwh^$=BpE518bO1mcLmgQIux+Po!R_%{UHKYRcQ^XX3nTtWWRxOl< zQh6Kb9}d0_G_wln9N(!V#ApIolJmEO zV!RNq5FAe{dfauH{eajq9M@g|TG;qR^BLmoN9G@T7qy9?4E*YHhyg(OG1<6e8+ysm zHy}{v0YVyD=O!k97xdFMHo;0Pcto*#A0I;19ZWX!VVos!A+#X5^TS1UAh?W8;7UI? z;tPGKqn^q37nLnrXVIiwh&!)AHm(U5J}8YJ>P@Hq66~z(CkZ7DE{-5;3EyPY0zVn8 zOO&P@%~R*3_`B zWo~o&C)j4oP(n}3C&Mt#W1*i7RQ5VO@%WxRfV(jOlZ4w1v{L&l&<_syykO>M2Z@{{URQF{7z6eEGujJ;Z5vyV7 zPTW>>fGG=r&8*b3f2VDiCBA{e9`+B|epD0MlJfKO7y4OU3N2^`haN%rZcp48pqH5=eQLO*0I(?7?X7G)@R z!11&H;tB}t|3Sr`xOER587eP8%U*+5)`JQq7?Bnx*+n{mK5{)6F!>cOb1IfpuE0$B z5FEu|55wBpfi3fDi_m)~EH=9Q1kK0ROT;1NVh3W$3S;Z?wKQkcCVoL?He#WbPe#?T zT0nNw8I6MINT3?f-nq(l9&@Xxf$Liibn##U2jl?#Qu@h8kwSZ{lp)TtHb6F*8u+fh zq7>a}+jI>>3PEU!^0ZbMX;tf$;Qm9AeVlHE%`;N>+KJAcrwq6+Hl7XRCT_!&Vl(PX zlK82~cTIVp*DvyfC3LZ~r4}#2Kn9f+()*$5Pm$lJ#X>2A;bzV*==x1F9#0#Px~+%( z@hxP~RD6Tn)FmAq0p>9YOU4Ib@ZW+QC+eaUw9?M{Aj^A;sCix#_h1iT*4nbF=3~7P zyD|34o4YUzs`1z4?kAxcSy}Dbb)L$6P91(xxZd+K%Y#NoWGX5&-T>4+C1L8Pv)Zxy zAvz#)e0+TFyLBKn--4a|>Xf(Ib1`3_P4i$7bN>&L^!>Jm+HpYagi~KvVtLd8!3L6& zSmkZ8UZQ9H0NA@2fmL_F3Tj>P{KggcsH*3nUoKr*LR|UobaE9my`+u_cWU1l7`Iw7 zbD{VLVmkRg;j5r!*^J9#@=N!YU~iDj?_7n>k!3Djw{~33sMF>e)cPHe+NGg!7l+{L zy(JjIsVL)sZ|EWT*wn~fFX2_(sdujdCEe)7P#cvYL+DJV$QsQ+N*BB)r7z8tVoS%}lmuGHRatsyoZGFk)5K+F?%BQ|{T zVgtGidwG$!b9BRugQL+to8kQt_BtZdZ0YkqPLLa}A&|XsV%g5MY#-t$?{2 zXoZqgE1<*PIAAc3c0zD|I3-{1i59rGnR~Ez1S|KxpV*Cx5q}6Fh1HD!TKaxF2%@VS zG8r+=BG}0Hb!9sjz>B!GsH|Tb?}3ZZrf)!~e#NbemU|<_?0aX7B5<~98z%Ljf4fni^a)G;o#av;? z;%U`Eh5|Vb9oE3^lbfHr`?* zey7yn+zkLmwKvUfzX4#+gOIQfI9>rRM|Xu@&f5Uxq3v8bbXik!ki`Bn)%<<)GEE1P-8(ewKjBx3H60fPJrnz@2CqIBg7Q?;+_&U?>?yTQa0u zd5|7*@P9pwr50un5WPT5)-&UO_xO0Dt~73hHg%pAo(j$D?~pW?knA4y-MNQKNp2AF zrcE9(&*ow4yCv*E)LMylq)7>#?5p#}@j^BU&iR^Xja8M%Gj@{K%RQ4k(xCe~ zB*uRhJb#4_5)7;p?yiiRoC#>8*>~tSD1`q9!})I*=5!A!?|K6`)Iu-^4Wz9@t8Ym*@J*{zNC2bV{OiVKpOj(_x2_4{F|}*LX7XPK6!EK z{~^Tx0m;cYZ@qe&>rt7}69@5I-WhY!r#?#{#KPfn<8FYFlIb$g^dfFg{c9EDEp7&?t$N|B?)r{<@^mnm4DA$m`FrMg z4-zd50N|(n$Kv~@1;_8&vOIm*lgDvmza25M7E2JH$Eg_do)C@yyc>O8dXmUle|}xL zRYqrdPv@pX^Yd*6b)#NClpK|5wOM!L-!5)KVu~J?CfVBeL<+i>|8mhPjw4v+G6x!v zuzT4BZMq_F9)EcWbcvY*02U<~e=mvohaI58`lIzG>{34r5_3L10R0U1o!YE+1L*bO z!%^&1--KFr3g0EQ)P&S23WbsSW0*64ouEH-%q^A4xj*k6K4i!{+rvXf=$?K1DrnUq zf!N}uKDE;;Ln3CYtC^{)m;|gU`6Vvu;rN-$m+qf^as7x{TlWvEm1g|9le25 z%r489HPvDdy|C?7cFPe}-xVFDc8+U?xL5NU^*ao8D$9g@Wv05??)D8l41PBAlK$WvFSGaKgygH&oWR-OhQnIpqbQptQK7+mrnH$um6%P?2I0!iC ztD3dCF~q7Y<-(;)nz$>->E=_q+E&mtj80DFXkG0zFMo@!%@Ec1|^ z1cTb6XbeIYJ@mZ=QxyPm_jtr=NNcFbm3}YXT~Y^BUFG3br1dA}57BDhPv7St zn%7iQD_5s(ULZuNfC);B9H0@TBnRsDVqY|B7VSYU?%d!!m4AsC{S#3T-;yO^Q*0P_PxwI6E3sg((b@Wl5AI!OsF-9lL-alJEi*)619|u$f09 z6$&qK!V6LRZpnfQ_YIQ%Dd+$LuY_!+{XS<)+ii>8u3{>;8;z~I`eA7JKDS2P{SzVG7=(^ZNlzIAqQ&$t>1#P1bFX& z)1;V2NjBs{2f&qUknmyB?|^z{hbE4jHhJ=gqcUsO7(pV(W*|duaeVkfumBlL@DTPuk3^FP9 z@?%ZEMDp{+gn(NO(-%rfnZ^}GCaSUpzh0Q3WfoV2Wy4M6hJ?T)!fJ;hAgSd3=|O>k z^I;uI?-=Q>pe;FaS{ZMgNZQV=_|?HIZm`gp;e%V+DbmD$4H&s}Z?C(I&}#nZih56rg#%dp-iM$mhn zuIjY!o%Fkdzs-2Cho>h%DyoidK4ql@eY}Baq?Pt)Sc~mC#pl1SLF2Ko7H{+!VQOIU zZ83C=;p^+@M5GEt3kAG_t{(`D^Sc6_8>;DfvW;5Hq9ct{ow}=?`_25!sX>uenM6be z5ZyUUQtyO>g+}zX@bYJvi3z&LAQj(3QZlpk$_{P;LEj|p5UEWSY4MS zenN?ItF$nPs9#1&Q*sJ%#nIz^P#3Tn$W z^$ct%NlKDP43TeCF~r-ln4+?Q6~hndTQh+N(PF~Bwk{2vLN#@Dyi$t|EKF$bC@pjT zz<7w{zkGkV1}i}#(mOlMF#hm5DyBe6&(O*)65vZ2aNZU-DvPe_bQv|JaG6{u_+>)xXFoY_;$Y0={hz=gl+lJd5I+{dVkv49|GPUn$WTRv9m*?{?iYYac zdwLn5x~aUcDjCdjobHmC^*Vzer=K4Sc{*wXb_0INgBqeF>$0S>5u1SUxCDERwi9XD z%0dJ7@?W0}j~r0#rI(|7hX!AyN^;^3ZfFs7XkmHUPw_;kGHTUZi8JKP*|S((DmW!S zcZyp$HA*&;&477PYy`SyH!dkoI9dYaLa^jqq4B^iMp7v}My*!Xx$7cu5<|Z>bT7-p z9?f84YqMsJv`}oz-(_Bwl8lpjxm|;Sj!rlvuGqA-Oik~Rp)9Qb;}QYg&WEm;=mHeC zqiGX^nFvQ5LK;wbMu#WF@z!BzaFI&;&Z}43pbNy_wvlZMmm_R&Tfn@agg=0cP2&>5 zi;&8Py&R5zkU23q{RgSI1g^z*&z&0$*dc*;#?>{+EfXHNU_|VE^%Jb`(Vm+T)fxu* zo_T+K2NGLGno5Z4r%az-8)FIjfbeJ_a6e~6ff))VB@!g5IE|ZXCKqgl zfD4B*!MRY+EC4!*8y%o|AOXaSwvV`Y`7#u6JzG!eD6p zk0)n{<6so|deMQZ_P_hKuOHYTtZQ0!%k_r;mOPrBAupid%DTEgIA_{_%xj zP9v<9(x&x>5tQ|H-2Uck{yd<%QG27qUAUt6tH^3MgHUb$rr#8BAQZrL{wxm zB`v+3PypB?k{Ueh?%gK=WXKmK9ahSR+(Tfn43Qq#ctTP(Zaj_de)j;c_$nQbElvLM z#~1G#mnI@&NA|V@ItLB>7Rk#Y&<3I6AOK_7ma8HQ2!s*> z9f+vO0S)rmq|!tVXCX;l;G-1@Cjinz6W2thc*!jO#b5{UE6LQviwGnD98^e*KAA+x zgJ^{BwP80*B_b)F#WOXBT)ud57qB6I$00Z@^D7|c%|l1aNWc?Rg9bfr0iLj}>Xwx` ziY&=Y3<1+ebvsn|Qh@~e(rF{n@I-YLFcovE!Gh3+A}lz#9Lpz747~C+K`(*5y94)u zFo@GZCgy|5iUEBK94J4a0WIvw=;iv<`&K#vDII5*P%`_*+$5c9jEd&1u;OwablH=E9kcs6KqOaNfKv$J;-V z^BG!g$RH8ZLaso@UXKd0AfAFo-;?hZw|2Ll9tVX(KnS)|(Jb^$NRT~IdxA1`DO>~a zKr7veH<}+)6*|Ig>JyA>QJI#q(<4#?L9qpR#y(#a>?#EKi6}}y`AQ?_IEwBywY8~C zwHD7TLE<7GJT<8wFz8Y+c0fexfD$;Q;S_Ph9sXE8X|SLUK(=`m5{ie2`5=JV5BJlk zcLxblfW`#K-clt$8q(EyH zG0h9YZxW7zvMFCUKOjJ7g+VG(02McbNk|Zi3+FPq<>VNE2%eC%!(m||AvsXv%wYnn z(#9k;s3s{EL1?wMb;z_6xXS5?bh@RPAcVen{rOmuBoHGn3mBVxI&ui#gSX6}LVcq$EBp!m_9`lBE#fNVChp4DiQD^< zZNa(9NGg$WefoZEKuQ4`BZgw70K2thLE6<(KpXsDb6DJ5QQCV z%1Rs@Q@txtm%uf__rtlfBb2-EvUiSF3le(d{qtpIvrYOE>)<$Y7nR-gFRNDjVP+gaCff~k#W>CzYc0M%0erVnhnmf!_88PT*eE@Gqh_e3QrSD z9OqhL1xd6~%>kAH<@gb3CW~fAZ;*M;%-}dlCp>yo%sK>6fvO;qlFcNyzWA(L-U?PR7_Y>j#O?x% z{gFEQ)w0D@SIysxMwEpxox&LtV_U0%RJ}{nE@M$#2sV8-CByM zE3;~sZ{|LdxhNJK3~5LQJXCF~U|6=)T8lexN%Dfvj96B8X` zIsi&xB?#7e7P9)+6I05+H}?_myCZE~z+q7S%w#qMm;&fAH2D?EhW9bC1K3Zo8^8BN zKpkL#;x$jdKt6)=rG+ed!GbYWg;-hWNfV951@Qep7nRagN)#DN-kF?QTo{Me!dC8?j5bfS$%zMM-}`i83( zbpSg))IH=KUM1Gu^mJl!0l{Q9#N&Qqx8eog)FF2 zBGYG@J5!eGq5$}wgpEd4J7C$wL{M#IMioBJ7dHQ)1&Bm(G;kL_Zz?)Yz5y7irK=kXBj5S3k%+K_#SUP9 zHHcwJJJdbb1DmWl7!&XZ>d@g*pQ5-#zzP;9?M2j~2?_|C7lWz8HFyKL<~6`9gvuax zu??e100qn(EoaFinbk9VRfBQhlALAJ#*OFEp5DqJD8 zr_(_U^k~p>&i-gNc9O5Jqe*Sv+w?MW>I-zk)xt_Q7!y^;^?a>}Gh zcMvsfr}KA!=)ryxgj-pF0Fojp1QuFg<#2R4LK+C~gtia_8u^66;Mjh-FPg;4= zlQ&U~OjoIL9IkV%Z~&mXbb`Yq>_1LI=*J`|>(SXYOi}ok65s`S`HLuN(|!BMaE>Hh zh&JeRsvrEf@KfZSot%bJ09-q5D2M$~e67+}uRr~TiRqb!Vyi0c6S5&rf0 zv$YbuHL0?UpEFO(`8v9wv^jtzYmN5n+m6a+sJ8|b+z>LA-Ori#rg_7#n$9~9a+){z z7oT%0Yj|2V>QRNA*^@==-m>PWJIDQp)Zz4s_L0D7LLW#6OADS~-rXE4Q9f=k;LaS^ zgVw`s0h)YU3O*nr`u_Eow-&bTy4KX3HWA~mS=N^i|C|Z^C8NItp9y-`FEvEc6NVpN zG<@ZtZZue03MiD%5dCqFFAoN1xVmA5{LsWf4vVSQ%P7vEf9u{t-Ld7Xy#8|<_D8Dz z6|up~BT!G;EUjSu;ec<)Hp=ApzMM4J7jRJ9^PslY+QH_SnsZdZ7!4Y|x?XwBbi`qw ziY1vmaS5bRy}!gt}EZ^Jp))j)$l84)r>r7Sch-%N)(au`b6u-}DG zIyzcJ#QW!y#@~}}mBb0i|!bi>?aTVi!l)l0suMFq@7C$+7nNb~aYFDO}=&xR=3l5#tIpPjl zK|Oo^9K`7>mNfE7dwY9P)UF$$1f9YbD$_s$6$GYaMqQ**IG>y5m~-&c)3 z+AHDq0N#*glEFq=$7qqc(cueqzpi9FDHwLtZ+qfoBO)0FB`DBVLyBU^hsJ^WNVqG0 z-a5M;(!%9)@VMYZlyL|}X0_l*oKS9w3a(vSntH~dw;DM=AOcjpP2qRQ)2)U_C(CPANr;*kM?OfBf5!#<_Kv1mK8g=(BN470=4N_pG(4%huX+!$q zv)Pyf6n*WBt|glu%pG4oBorK!eZZi1OnC!bZN;KKj;lg{+E1EPQ1v4{1>Z z6a>TWOX0=jPr{2qqJ@OQF|i$!eT^}p`h|GCA$YeWV~ z!yIr!KzdF+Bq&KEE6lzR(^B_;6o+wBkV~+`DK+G8F-Xi2@{v2`(OY?TFa~0BZnx2E zBsB?I*1plT7ev~0j5sDfSs{2U9ba*0qKN2k|9hfg z=~(~}yKP@JT?x+Omy=Oo`Tg+D0p;6Q{;6Es>IxB-QZ$Ru`_;ar2X+nO z)1*G$@3a*eI-8*w_#jSX!|7F>b`z>*VvI2}$?UW{RoJ7UzmNI}Q9ECY{BZiO!v;gRQ_ z!y{93hB!ae!9-xk;M*$^yXLa7Y1}rvJ&R9^@RynR+j>A-1AnWl2~!|jNgvwe$C_711LnIrGajCr}$@GT?H^l81i3jPiYkn56BSbY3jfgJ6_ z5E1Ovy?*=Hhw~zhv;}QC@mzNFj+;w2k=_c87pUS5>N*{OkL*BLF|UK`M?Nf+;6Ql? zwK>(@>CV0Bn@gAA3CH3I%>f$XrF)e+2o_O~7j6YrkX70$Akhy(bzm(&wVyS+0oK|B zo9I+gQ4Xau1a_{lEDk|IBRP10!^SY=64-p>#*OEtb8+?cxH@%6q1Gm%$7hJR6#8V< z>C8kJwiYu*&ab*<697DF@c<1}Nt!sel3(Z(6u?+D%~7k9N4_mMC^^_GxhBZw>2oO3DD}g-62SE-AE;Hy+f=ay{$L_{EU>5bVho^i~DOu+yW2;7_9=55dc!yIdDFGlEBdZ zi1k5zP~gdYi=U%YL@N~{tONKbt_hW^-VF%w^zb+m5H|*a$WK`5-LP~cqZ~gj^n1xz z^CfOnLtCBgmpVy*n8;Rk^ui|Dv{7`-PoGZR7|_rIpQ37zNu-P2K@-R zv|(S_k9CZu6$QBYsd#vO%Y;q9;|fC50~Ax<&z6@@@HjeNL_~DPW7%^Mi@~tXwI~+w z*gQ()dLv#f&>C_0_idib4qMC$Y1WkeD@pF+Fi_-#5;b(Mx(gW?c7RZtsSu--I`td^ z(wDCb3_^y^Gb)zEApqq?pqH_eE-;EV?oD7ZXaz=86m)pR7s2`tvrpg35K#yTbuhjp zwF4fGvn&=7lOSR>4s{%{`50e9X#l!{p+dyMiQ_(cWFVW|3X@iL{v&%E;(1_ulZU-c z5D~`VhfV=N_E4uJps+N zO&7PTft*(jzTS!jI8|0{x>5zgVisvI#q53;_(iFpQ@mDBpG32}c zsuXgD`7FU8?h39??_lFNfP)T<4bT*rLsHgCN-mb>{d6awmWqNP>k@!$Ru!z^V&`6d8E3F?j+*C4O+l zEfQ2A5H-j&_Q)n3iN6t5QezhynO3>+<-n?fTFBfC(*IFxtZ?w` z>C^GP7v0_YSf%hv*N*tCw-UKx%)xiL^#<6}DA#1>q7LB0QA=RW>_Et$rPiz|tvC3$ zOxS~}j{fE~5atJgfC+(i)ZwGYmb&mFI8eh6S1HRF4y?qmV9!y2&@oxo8D#Dk9*k>( z5CY!l*BS6md~0Et*$g+>LKejC8b_1*I08n3L{Pjs3vB6kt`!`zrzp1UD98s}Ru*t- zp_a4J(!c7AM-B5CBGNggwk*~86yKoH#`kZ@Ep7`qEA~f+pMJlE1(RqfrR6Ns1WwBm zl3!4aG!b{Q`7*C^+IVX`8yQ5;Kd&>K+u ztg%NDiZDvbM-eTX2sA};W&Mw<{zq<{Zugu|DO6F6a(}gVOG-Y@?X0$(%^O%Cg9ms4 z?+H9!3_r0>I>TD2^27kq!flyG0AKIv6DSsjejs61V+rnxtS5n^t0VoTP!(H3E%IT| zRmmT_w;N?%N`Zhtp-c)}J{yE`m4f#1SYyM#s*cC~kLoxzyE$wL<^g}hWC*Y;N!WmW zPK(z3fEnF|b0N38^vZszM)|u68$*x0+tApGVXR|Cb5hii^S=Vxpd;fk8j~ABAhpZfI)kID{ zMw;erybKNqOW_O%F^~kRum_l?p#N1FgM0$B*PgwSgVrL?4srb>SrD*u=Q&vL9r22| z^KMu~7u6@8=!$|?!4~dq#~m950}w7>dgV$!uQsgf$FUH<0_Ra-3yKz*7Xgo_ri4@` z0&Tu!HHvU$nFRb46)T21tSLv$gbb5HK7JxB|KFN49l`lvA=2XRI+su08qatK!rmWV z)e4f#Az}ugCB(3JhDvYK-TIl0eHD(lx&dYg53UYMXIJyNNeC2`MymG=)a2y9w2TuV zL~3=gu*QZ;d;kW7s#!t-32<#71bKufY4u9&-GuF#o866&gGg95Cv{kS(6ZeX)J_0} z$@t29aPLS=+(YLATF&4y#5thCCY}fCY#q!lsWt@%t6>?#y7|K<68Pe0i9bMa`ca!2 zI9`@e(!-U&eP{vXXVhYug6DOEq&feA$rdHFez2tRChanV?t+`WQo&c1BoNrlsKg18 zkG|otWATEwII<1z=(4GXWPomxc5htMJ}tvOd6!u8RlL?EIu{iL4}Png{Do~YP;BTr zQ1Mf85c#>qxvWw>Y8d{TcG2xG{k7x0Ti zcmjNQm73CqL3T@eo++4rAf~8+IwmvdrzFLp0Sx*@#4bD>&4{ussOp`77D6lFmv;bf z0V&hx5OmMXg&2w0Y*3r?|0-lgs8$PRu{{K)81S8bN~ROE$)TwLtb_s)s7#$a`7T`1 z)esL#u<$Y*z#5Sl=iR{-qz{K8gL}9SR`1j$V}h{KU>NOC{;Je6h_u>(b|^Fi?L^Wb z9wJEcuR$Bp-{6{9I|Uu9V zy#O+JfKnRO1OVkBzK~qE>HAS4B7sJyWLaQQbCsi<5%1LJK<>od@3NhOfF6(%f$XB; zAz-z;<|_E6A-26ayK6dUsnv8oW{f{PQY5W$sM4N$&Ce5N#vcxYJoyiT;xGEkKl3{S z%!PB9^){^`Vh=Q)Z8hpV`|YGmf0eCv>d*v<@`2(1Mji64XioRk7i}Vv-^Mn5p`jL& zjLw-P&+`XEHs$HgF%#JmKHPe6B$d9FR-4on!H_kBfac5O=a|jh6258}6y4MR1Kam! z{di_=_!mfN5S#XNJxJEjcc#v(X_dQStaV408V%js#8q*Tqy3)ZWF0b?{B z{_PJfz_)6-Q{}^;hn?esJoVc&%wNCy4;bc~6qjFLff(h+nYwedv_>3NN*gt}cks)W za4erSgAg&N%KHwHsQxg%SZ}oXAigV(!}$s^ebcjjS<@yyf#zM;A(vc72fmPBzxHwSr7RZ+>Fh5~cAxg)T*b|( zW524cnzP+=?6qy*y`Q;HZ1nt`-@e~^*WD)clFc0} z8j%0Px`-)F>t$71aeth&fZ7G)MuO{F~w@5|K&&iWz?Qvrs9cs z#qv%u9D9ogTk^o&e;vlZ`%Rhyq7mA1cE4XZBGc-DJ$>!0zZhKy@&J=xnc))_c8` z#{H)4NTeUe##Z4-ehoM{>X*kSjRZ1@HFqCAeE6xg4NgP#hf5GfnWBhwx{`x!VPWA? z*b)Pqo`*u;C#u1$3L zQ(g7`bTLAo)e*;&4M49Qt$}*w5dABI3A1HubO76jAJt7cVb4wN?>2zNeiw}BZUYL6 z=XXN@wHI-Aa>ES8V}~P)rb+Ljs1rRX*x z!GdNrb4j|`RWNokz-lspowR^|ssjIz4V=mgv5yiOG}NefKvh}=b?9q|UzZ+hD&OwC zd;utfEHrAng>FN$K;~v61S$$>0CM>fZEwBW+uJet`*H)B_Avf#L1ElNV0;;5nDp95 zK6;Cxj*bpgTDJk7--Dd=CVJyRf8+%?M-CcF3s`GIzf{%Q9c`bCh3p~@F&^C0_B*u( zNLC`=%OrnjX}yQ@#l^+D>U2`Q8C}qK-UI{jfZuJCB|i@w+wsWA(xLAG-C94NZnhWC z*Y#vt$`!o5z~p2l;0CV%q57sv9GAx9Te>H5xm=&4g$L|G-7N*Pt%%U;fR$A?0y68m z(BPnefZ1j~M>d-$pYSZj4fvv1{3Ci*`~o;zE3yZTiAJlbf8SCt*d(_U+r@hKyXLMt<`px0D`<=GHD8jNZm)rj-bEM z0|U6e*YYEcQ+g|9s}bCmR;FfJ(1y2qIqKb{^<$--fu{TRwHHOEB*(a^{kzBYr7 zefp9;8=XF1^~+B>52@`-EgeHoSZ96&gr1EG%?wKxA<>p8T~*_MT0E0)V6y|3lOBwB zaL==b3+6sl@7rUbtYOq(7p9+d^bq&a=U0rE?&wJ;cB1JqQ)41E)XsoF>@(W_Me3K} zscl})@nSG#&_3l+M{;9C<7yC(Hh2L+9L@=pai1_$P8SD6N_<(cnXm z{Sld=!RZ zT@e~)@#nnjmNzQ-?Gr$jECoThk-(`f%=lh(^fIuruTf|IuEOS^U|UMJA}u8(t7y~~ z4KDiS&W8I9s0+x#oO1Z&oLr2J_Of;u+el_X${j(U5R%rU3@qGwE33D;$d7MawLXkhzhQy08A zuYm_mDoVlZ-i!2;$=>jtd?3H#P*KW>uFu`EfP&2+Ja^<2#XgVCiK$* zNuM}R+%{+3fkTHf@n)m(^A1f#S|u(+hS3I!=2eOSTda;X*}&WH*bbVd#dtOJ<7Is% zWvrr==)T?iRJnIU12mzwwzhl0D(c1`{#6w#5$*qGRr}beIziKI7iQnzRV{EX?RR=o zj~nYd4vFNm?hP}NIAJ_7o?(ePk@(~K_3NJi_#_#|^`+DcM5$h`bUn;3xR)f9 zx+fT$VZn73rS=su^!@5kxp5+{4{zJa-8;ZdVPLz$xnYgYG#^inlX(GIs1L5k5Zb?6 z^{%^VtJTQw#BMO&q0faxd?K2C^ zj}59J8VX(~;4&wwSC_ql=#>7Cv0S>^MHw*pPqg z5G$F7e)auwy!wO5hQ5M^0=Ww+$s%k02t2rn^?-?Yi*|e+LzY&u316qtfuFSWL}wG@ zCEWHj%2EO{I7NbbjauZ!xhN@L!vo(ZOLN*?&Q1&c-t4r1J@x5tJ{oM<ZQRoK>cp_btgNi=QwxjuawO%)0+JK9jXaKR zqeaKLO~)Q?aMr(1+VT;UYMVvMl&(+F*;OE-RdXF5zQ$zw3>rb18Fl#m6C;bbL&CIC zYjO_t#HOaIvrsZqyF%xFBnwK{U;56M)(hxOcmMFZ$O8K~7>wM)LT_v{j>!@|Z3rM; ze5o5I9YS;*-&}q`gDQSawtjBt#CP~{I7>0@#E$$vsifW4p)QokhW+G1Lqo%ob~s!t zBoPvuv25S#nwSPObJTTzoQ?vEFn3@3ww#ZLSaHSHD#>}VJ8;Z#Q5<9>Sc5*9W{~Vq zEA)m(Em;zNM~dPc9(5}!x89j(n%dW%0jM+IB)+AcCE4>f-H4xkYzrc+UtALt6PH41 z+S?wNnhC398%W&q8?%c%MoFGn?AKFV{TWp&M~hOxw@@44S9TD&GG3BdL&veiHpoj4 zmbS;nnW9NdLerCR0>cN`g?#L*Zq|PK^!og~+c%(rwGF$q#AGvUSFYf**SD2cL;tgr zjon-7rqc1F3JMBK?LU7!@!4!AGE%KV?fPo9fy7svkC+%rmtuf?ba5W>JTUh6XGNtf zH)%C93d9z_cjKq_R9PJ(JEzhV=ZYk`)doGaEcs*4g|}egaJIDf|Ecaf!=lW#E(;ST zPz-HCKt;ib0Tm=_qX;4>QlLZ?6eLPc63n4d6hwjq715>;0i`I(1|%pM3J`=sat47S zhgpa2Z@TBs?UsJ#&hyRq!)~D{-g@72_StLgwb#aG*UFXb$rjY=6t8d_A9Z$Np*g=* zhmJ84BB)9`cp0EIoju%%L{5F40m%$Vq|)V|8xQ8BRfWqUf~78D{`JjQe9C0ko(wch z+(o5&7f8hmINBb7_7f!)Ys}F4NP;~Iu397w>BPL zQ_g~nrU)BaDOge*+6b%BlvE41;flde8YzXXd4udiq~3N$!%2 zwHI=g`uB50ve9Sd#O0zumd7UDB(V@YrX84qx#`3!K~PXRhSEL$`1+gDd|%V{s!Bxr z`07h@Na{&mv3c`me{t)x$dR16T(U|!DY^*uBtK88UD=t5n$~M9=|HPb>*Fyt7r!Q} z#Ce$o<|U0(bIN2oSM>yw3D3<&<;egi8AN$aDfyp^aTOlsSP<0~mh`3@6a+#LqMgaNuW* z4+qzlrqRnnoBsvz{tHx_z=3B2=eRwa6!;C0%njR~do|^^yY$B|oxsO`pu69(pP9=} zYpJHGe+_5ln5@qE1(Cjo^|QmJ9Iofc_|)MbtPSfm5|M_9hZ=V`>vHR=fgj7847 zesIVCSSPm3e{xNciqwdJ1ioIbBJIgn-?r!~9KR3@61y(ALs5ttU$@M3fI1H#p^U{`KxuVHX#G3& zGUKX4Y1(0nzV%0LEZH@fd_WvK!6=&cK#ksT`*^tVVXa$IfylmoxYKR_5x0aGQanl4 zYDR=HmA3BA@pBEDZC`${Rws5b>72h^Laq4GefXbI>M|;kH1(afQca}M*GTh&4w- zLoyJg*+IygJ@{p$ktAi!5lMMLyGm;Z=3#hOltPPa7>cd;~0HilmNBgD)Lg~ zQbi>t519@o!faT0x219^1h-4yS$U;3{UPXVDI8&x!x--Wgn@NAnSD5h7gqeHw_nXCSqAi_PHAc*i7 zvTyLLAv2W?(RC-)0!3C9uVdZ46EUavL){;UCUFCZFOX*%lKV&yEtnQl&je(6YawFN z#<5?7bR2!*^+@h>!Lk&lx{Z$@&&vS==Ui-SYkLMIMtEH7qCVw|J~BfjMvhQLc?&{( z3N4Ve-FK0mauQ7?)TmT$sowmNCV81pz^@NwkZTjd1?g!wGs<%3m*Chq|Y@(IfAo(}s|2}mgI3Fp#(+ycK(yw+pKE2w5Ke4C?}Nv^S~ zDj4#RdXQwf$od{Y0))0Vyp^&ULLyC6r?Cu%A)yc9UsY64aBoMh*c!TKqrn!ovWO|Y3RVPAYy{tOm70?#2& z0XvXpLSM?S!d1+T;R0$nQqOMeqljyPNhQ{EFpSQ?qTp|d=RtPhs~Tm-9T_gAI`%rF z)(A&&6)7a2fAKoEh2Ei&Iz-(gA+f`J@kWBoC z1eo%P17x_+d#&$w(z@RL5l) zP0b;KUvSZ_{e8*hal_LY$^Fa;rbvfLx{=w}ciB-jBADIK6)`*OE9}5fv^QzntCbcO zdI1{k2HNU1XPTv23@01_@mRgN4o0J&01;VTwh$iN2UnDO_!T?63Y`Ej5J?=VC@)X= zFa(>0`IMc5~tZl|vIFYL3+vX=Ly+EaIf!{{Y=-WGJ)XAqf1`Z>RU z=6}Tbbb_$*Hf`4?#A7mFE6D!VzAC|GyUn#n9V+mkU()Gx>04(sY%8K-MlJ2ArRC+C zAA2YrQ3v*eTP6%jw*%+${p`gcPk($! zZ`{PIIJNS$GpH_kG>boOLwRFxAVa3gj0HtdfM9$JEg~T&=TKZO=LilIZ$W=V`zTvt z9p^MxT9;w2T7u%tz};9u|Ix46kJu@RiI|yi2eE1lvhN%4sF3cD z$m{u;f9MFxR;fvFW`LB*La#r@)5Vl<7eRYklBRLFp_~0IB4Q&Tcs2p}B-S{YXLp8`<^QSc%K7j|y-u8`3-!=5-s@@8zz&!}A; z@4RJeV^fFltz>9uNQeL>|LtK~m0&!#qhvw&S9nC6NOg7bsv|WWP&wov!#UizFl0cE zL4w6u@MnZZLRwXb?+KE~xaCdtB~qQh2oX0}u_T#KuyGLJ1qq_$Vf_jh2JWSuR6We& z>mQ(W#&+mB1Kly(j4WLks%W$9+v%kZ7^Ot$hLk>fRC~AKh-R$X?SPt0twKUFIQ=q2 zOBT^BTKZpF0Mb(4p7%J3wPc7DDtH__8H5v4h^w-W8y_3)A4)-5*gv58n%q-+a`l># z4=!`>5hfoCvq3MKetESPd}9_V=geKU{b@#wIixj1$3Bo!AM7+=;{`9kv_fV68Qm&h z)@)su_5UGNBxNka4p*s%7xiaCf1|=>fI^XY-QAz93idA{_14avy=$}NrMvGTr;;Lk z4(PjApprb6@7yr)KsRd^n=~ErA_*L3Rt+M-3xePAS@diy+hbz{hA7VfUr)Z4VqntW z0l$JALM4)77+!(YBMaGJQB_qH-XqSHvkN4aHTlgeJ00XPay)=kS_u(m#;7bIFRA(r zB4~F5r_8`!Fhu>3@$xCi%gak+$2X?0u(gwbi)lhL2|CxkEA6Cj;DH(5T_YIV&0qv*~58Cq)e~jl+%U&wwo-Pv*XA z_|PJZTb%MI1javL;wCU|NfOUS>LfH16OZjUlN#1yTqEYY?$5%5zkLwu;C(Cu4=tSJ z!Z;qO9#)dZvoU894{qWSP&fa^oX~cft?xVk*9^y>kUf0^HPRo_6flsJW|l7d*Jgxl zoE#OPrgNA#hCJZOkd<8ORJs~n^H}NSl*!0M{u!S~_Rar=+yDMpa_^US`dU`9CZ8X= zEMHX9!Lm>J@?3V+o|^IH_1IrzE2-K}@O>ubs%_thpyNjZnBR5=Z)0K7WOv2{X(pB% zc5~9CnJN=OXVQf43))Wmz(dF6GopW_4Vnlkrx0gEf8QazsgvFz2!)Yk6Ha=?(>H`O z0}}s+wUp>31y=$MNcn-t3UW|2L|d4b1)Sj}Uc@&&`33)aRaA;nP3(uEzf%C&{&y&V zOr{a@Xo=oD$gBt9l+{?OCINmb8#}tg5vN;CsYXXYoY`qB`TtzID^RvgYZ!gfS9}Q*H)-pAbQ$iQI!M$ zBH}HiLUa>WXenvHRJa_}0+G%J>Wmuc?LcHPiq?!AjN1LF0@cbukV%8-yHoCA7{z*0 zVYO~2av5aF$)y?=7tjBvi5XqjBaoNaVXnfxd9GcT30_U^KtJaN!jGXPRw^o~ThTK? z1RnH65rnR>ZuB}3@c?;g3QUDaa!&LKAoVIk&0z{fcq=>spZ&l5bOz~-Bf5L7a(0#y z3U3e=2!TYDkS9}Hxt1^wz3eDAsZ=x+_jryEcn*q;*QXl5uiBza(^tpt1RC=Fl>)`K zvBt;xU!$vdtpd^AkZLKx6X<(;g~_t!wnPgSm*_uG2Yq2>Lw_cG`eOOh-lnETAUxaIX=dpjcbp1y-RAYX{SmPR+TF&-j6NldH*&F0dbrQ&LJ-4+8< ztf4F`)puL-WJ#ngN)ssQ z&y)%(nuJmzThd8ttQC5$w_2I7F|!{GrWxnjCyk=*T%M7t2aytqQ{AEbqrzlqGF&id zA`{%5m*90?tAkM)6>%=0N7!a)Db7VZ`;Z#L?6%oslL{bj_%}A7#{4Q{NP;HO^yo5C zJrLavd3`k_B7tM-3&w%V#@RH|qe463{Vuev!5mpFdm}nPWXy8}$V22UHXVO9IVB#-$2M#ej z+LSB%hVAUc2PV`e&&vDG@5hpIsla@pmI{7|{B&F6%-kRZI>9OdUBdtIRYXF2Y1tT5 zRYXRU*V1~Z5~OpBPI7ymt%fbuJDZal7iA)dbj~OM>tYv)yj~spX9#81pE^FO-~~I5 zKFvh4VNU6;i{=%K(SOR5_<|=9%^~llM)ko5tiQ45PE%Yb2;akAB$z;e))Hp{iV^Y` zFd$MXyUevJ^IZF0^Ii5VjnvZMe>>9hIIE(CfP1IsW)GpN)J6+Ta)}Ex26>1%7^d@z zh$jfmX~A}2JGwUg%>M~&v@haMIE)0_Tc!JAJlRX-DhW-Lzm@Dy>Hhec$I2R!5 z!4gKwgpg9f3q~NRo!@O*p}_f))NW?+neZ!cU@1vF4P~e}v=v3r*MZ^OM$|#-yCLjU z^4q!!-y_l%nB9a3I@bGWY)1<*p*%3Bb1+Rvx?n<5M}iLFWnmeC?+GfPLgY1P%Nqg0 zppe=M+H;{|#FPU+_!|p-8FER3&9Blcc2x=}^ac!4Pyn@usgw}t{XM_Iu9qJTh*ir0 zzrly&bLd#|;pCHrtHdAC8=qP_tl5-M8nrGUbd6T`Rmot%6KIAvab0aU%<|pM?{x40 zyE|vD#r@}~@nrCQablIV4$e&`vN`CQbjOE3i=+mk@BR!NSSy1iL6$n>JoTH1K@g>S z3xckA!E$5ZnK%hZK<;Jzaj{0Re7tEVIid;V2f!|AWianRF+!%QMzKb|L)lYTrtg_U z$X2pKprp=$&ddvnl5Lnxl?N>T-~+eB3wgpU-y>2w+?Q+=o(RMJ0@5iArBwpKOzLL! zNY*-!GT`Ds1ZMHLzJF5{A`6Jr`aFqpj3`3R(kP7L7a;&f>1JOu@gs?5EW2}d(5=OT4Yr0}_ACzC!CL-tKlDzMf*xVo z{n1v~s5j2mgD^#*`<~|oL85$x&4@pQdqlc|F-M=kq50u-XD=V}BFl#8cBL^y#t`p^ z;QsOvAipNEe>+^RZx3RG`rZDdMk&+^a{ScFpOGIlj z>nyiWdrBrpdK{;kbcp%VCJR?yl;F)LjSAA^yBZb$o=W+R?hq$uMZ>`NAHDiFBITcc z!b8TJNrT9w?jCw4snkgWU-f_R)>~_}2du;X@>%}|*9Z@FJkq!W^bK>;n3L(XPT5+4 znf-B+;NApX9RZW<7dbhJXZT-F_5{1Dq=3TD~ z<_bfK7CUY&%EYzWl_Db;ajVY@{(+)qLXxIQqjg{Pqfn;*fGhg99Ot`v?uw0<`-mXCejVaC$=L2fL?qLQpaV` zh~q@}2DAP6qG7HH6GTEq6p?LKY$MJ)jj5xI@dwEA!y+R$L+@x$WC<70vywAD5;DGn z=)9v$M065Fi5z7jtwi>@Y`ek1s_%E~>u?t4$v~6e0Lx~h_bSzqt>mY?7b=UbBIoMe zRXMx%<2>7_PFm7}BQk$67GXCg2mYB+-SiO?R%oC$(F5q#cH3YdjJY(sBR~r;W?Qm$b>fJC_(j!F4@F8jEO#Ld=;HT5hM*{;^2-DWUji- zt4ieN7H@@4+4F)zkkSRBf9a*B;8Z!j+pT9edx(?>sVLd_JSES(YP7>%L!Q@C&K831 z5>FI#J@{IQjyDqZUc4cOMp0q8lCr1f#u^&BBi`ulKJ)4R*)icN)f8Z}Qnxz<>9Ci$ zeP2RF3ly#>1F{ZUM1%?BPQRwBOrUMa3945MDWS(i0eis($j;{}>=}*NiLB9=DV^Ul z_@lhkppx$Da5Z%}v~a}84@TEX%f-&0^m&?4=XHpt8Hw^fHS&1O6Q}+}md@Jnv5fHn z{zThsl8M6Z!ocV05L$+g5V(Mr2`Aj?2zXK?D5?h86e@6yZ%T4SYsatGuLTjsOiSl5 z8j&GsTZ~J^I0FFcId<9egmyht=h-6T-6Bl4@y_w&ZT!D( zC5#OglPa-ZOaSN7TG0uL07}`TR4-%j2`W)&i#Y)7TT$+?ei)okvVYr^q%mG}yEhulLy{-lea^oA+H`>e7uah_hBu?!vFgOUA11 zAgXcGfc?tQHDA&WgQq33!;<_iE-qn`NCV~MHH#`=zSgy4w@@kWsnBn<3=Ry) zs(7lLkqUqLk{eYgN}6XQ=D_(qd>BfjDMpCfN;$e3nV5V)bu?N(gBv3=YA{c1CZ<8W z8HH?QuC%oD)@|D^-oDL+?D`^}<82qiwi6!=50$KefebuNxG769wZUlF{vmKDu`Y_{i?%47(4wv+!J7EQE^eFCdHA75Ze)jCy zncUpz@M66e9K1zSWcBJP$f-FfywVqz;&t$haSsXMM>pXw{H_BWSVyVMt-wOeRzI0>LQbN1{@a;x`R zTkn8**)N!VYzDeBgA_A+-C}*mxaI zw7N@~MUl@v8-q=w9zW(lyjsrqQUKjQwb0bmbgONP8irxWj24IWEp-mC#M8Z^v~H@q zvPFTELl-*aO-;Xs?UFEIM3}uwQP9)lhhs_Rr%(INoLNikIU%{>)z#IdxTEh)00tKW zDH5=hm<^AvqdGdbA>ls-0{nea6lO^7e-oAwTUwN1trEK%&RBBt@}c1*M^Ji;vva5U z5~C1LF$`KQkW^7op}Ylpi8cNu#*l;4RmlYACiuk1202`l4<9>rEYvQ=V;947Ps?%T z%JvX)zog@}@4yJ{0vcj7KY#uJmKbOJ^yxv;$!6x}cQAAjbk+iJ#d{SMXJg9pk)ua1 zl8%K`YJbSA@~`RbpJIG`=|?D(#eoWPd(}!8HgaOSK(N3Gg~|4o)>fXyi?6~z>~_V2 z&-KP3LveKabjsI6dlh{N52=k}UHY1zKYeH4@6*ObQJsGB5vZMB}*bUvkD6@0gc~izzB$`l&_VQ zJGm~#7|!5yeIb8PZ~^*AmQlJe3hLO}ar6QU3k$nnyvRZ3G214BKjEO5!l+|L^(qsw3aDwnC;#-+EL)7wBw_hwd{z4vVy{19i5ek17z%GOmeWa z3<;dbDMTctq>vUK(0jhd>Sny=0P}93hFVC7a8)eAxv%Fc?cc#vVMP zuOF&PBG=(yNq@@Sn>T0aq`K;4YQ-Ayz#*mpnkus45_l!7T5!QEGQz5H#Vq=DlhJo+jt$VZc~teFP4Ml3*>NiMs0{W>RR5CwFwQbja%k5$Xd z*&r z%41_BYaG1^JIp7lQ86+1RF54yhuI2?czKnO)EMASK-w0H1FsM@rS-da_bYIz7+ydp zS}*$8y{}%K?(gS!7pFj^UaIcerZt7U13b2)Baha1tyv9kKp|Yw6j|_KPltw_!rpem z;0KnOa#dATxTl%m&M|;B{LPy;5&WF`DpIp}qNpF1>U(T^HfP`)cRKmMmG3U{<3H(s zcdFldZo`+9cW^5Nhq}$aFG&c%s+Jxb&=2bcRQq}Ly^|wU%h&dGsl@OB9bz&8oh1%UuZG7 z5hRn#m!y}~*5ZSgzzus{S67#NXlSiI-P_yyGN~5u4%{q@w-)N|?v6hHZ687&+s;1v z!l0Gtu3e{bwj@_BPA}81nfP(6Rs@{4^SL1}7kUbSo2Ph4DFWpon_3;XNa`j+BB z%zcZ`3iI9duwOY?Dab8i(Dy@Jf= z>({SaU50E%00{SqqhyeTvD6fIn7`xk&6HVLk!;)g6QrCwP!s+MlqgObk_IA+fO3+% zU<{6;c;Q=|Ta+$L)LA1eJQL3b&v2iq=_Ux`Xm%HF-@bi3(QY&D+NpErW-VN}@J)RD zDKsr)W@gSGotyY-p3y7Z2Z}8Gfzw}so`uctl(x1u0q?Bp=H{DV0-n(6)G*VG>$XU- z$(Xg7A>pWjqJ(-eJ^cW^0^yf~asllDI(!TDU(8#TZli5(zU73b<^sz0UAvwkDYUY( zT1|DRAH$P}izQ|<-@t%RxKJv<_gN2nv-fq|D#3$M7<70M9@2Qhf8 z1ySxke7FLZhWFGqtfkb|*Y7`k`0$2N5U5kWR8%aaAi_K)@c>Bn;OcwxDG4QSDX6nNDBosd(~!Lk7r2gMaO%`v7}(dfw;#rk zr)lnFxY~Vk-ebBQ;&)8UV`$W7$pHV&|3qdX4CrD$j@;h8d+VB-gnJzU**557TF-J0 z0U;qFxcvHeS;)x9z_fHh%0uM5J_)dit7~pvAKQsQO)h5R#*GEr><#(z2|ql|9sUJE z1taJ+;Gw`~nL}Jm>~2bm^x*KYcVc2WAJhp)ORw-3v%7f61~?VH<5>=B=AfWlV*_RObX!XPi=@Ek`(-&MFJ zIF#mdjV#)`UsjfK#?Ww1GuDczMU~_fS$sN0+eLf5krTi?vH*MY3XJsjIRQY{+v$61}w9EHT|Jb-0?+bAQ7U&gRyrk86WMi?gS*DL3 zo8}8g-9jfNkC>FJQ)QkNxsH67pCW4&A82fBtk%6a)qtOC1cNBBi*97+(yKQ6^QXzKFH?mUV=BiZ+UWm`hkNW}E)*9S7xZVBps*ajPKj{FoiqwS~DX3kx)OKI&W zW-z)dt^3*1avNd_wHp}@aS8S5g+sO2o;^p*zvy4q zM@DdspgOfMGGgX(q>SsA->`w{@D&^j`_{or!K%2Z=ylO9KDxvA)8Hn*VVp+V^AOit z2<59cZJJA5tJN>w_iJl2O-oC&8LFvnX)!La!S*URsat6n7!op%LU;(8g=gZt8|RFT zr%;wITXt?!M91*9ojb2yzC0D9;yhsVa|-@Jii3Q7eECJkMjz_oeE9HTDomH(*fcL7 ze*Zq(5h5t=m}qa(#;^av0*7*Q?6qq%C{4X<<8hpAxTt4lwwY3mHBF2JpI6KuUW;G1 zK~w$v9RC|~4BYH^Wk#5}v#07bDdgnFpUcY2jZL420@*!%_N)ekV;Z31(IZFP0fP^Q zsS>b(W|qsz$;l<{=pHx)HM#J{jX$fYEvj;CTgh!q#n^kI52(|kPn(*VSq^re!IFvk%%`?{u`1Bv1yjGQm1 zw+nspWIo^{ZaS}o-CR7hbeO!{_42y(~VGpR0eK7pJ)zM}bQIoiE`0}$vw!7ZcRHP%nnq9_9`_7Aq z0!YRYn<}b7_H2{lbYSr5`D0ZHtbHmLWQ=BhQPI!Gj(Il?&$_5*;bM0k3l%5R4G6QV zk*0v|kOgrBs$t`O0M($l$4we1Pd;jj%*$=)v%T)?yTrXui&5^dU|1GXnyX=5vuDrV zvl&a}oT;hYxpV8?_4+%>X}g~_cu?+rplpoO%ASu6KW$GB=0v5xGJldtpm)GE2c`x}+Na6dVkC11mnNPKs2V=VxyN)tnSFN%Dd*dpnBA+j8AGUf% z*J?{0?)kWA@Rp<1O6WsQB6*i8l(~u%je|nQ=+b*;NI0nuyPr-unIUi@8^ZB>uyB2tQb-?;uO_G4H`;&Et3Jz1I|}AR!?Eqk^SaR!b%9HW82V?wd0)tmvSU zQk#v>OfzDeNm4;HOU~!#_rze1un|NqK_MZ1$ka6%@i-nRvZ|^JV9_b`lofBy31500 z-C2TLws6C96#SXGBI~u`JmkRw_YQ&|6?mGMkT8V;6IeM75A5HoY8yU+fw*5X{bgk2 zeoSpJk{u9(uI~!qBcg@Ch7F4KH_H%s;0vQLFz#K>iAl&D6b!@Yj19!kBK1G2s=E5= zN*PyPD5&_{`#Lq+Xf%8Ws=3XQfm0|;M0C@j8>CRsA+k7`8R1Z0wf4ht zy?o1hZlr-&5UY`JPLU-O_oA)ju?kg_A3XTU2`w2{>_ag-=q^&h%)C6$?Ck6-y(1$R z9%GhI^?Dm^+nS?D+JHCrQ4XqLXoHm0Ih51uIy#iGg{QfrRi!E{CJzK})AL_`nS;~W zOKDwe$)}aKmT;~BU}P|MPv_(;BA)88KXebyOB z+%^>3+t@rs3P}<*Fg=JH-c5$gFNVK9GU_>syz2e%Opd#Wi4x?OXm44v(%Qa{#D0|Rm1NC2>1+1VM1o4dPi4Z-#UJN{!{gLs;f`ZqN0|x zYskq><9LJ-9+4UEm$o_&+~O~COi4)*bMD)O!MI@9JdnS?&CZ^So~|^k|6=LEjXsJb z6Gzya&6tIwmJq=9_V$~OM^ga*pY((!=p!0u=Hz@tMZyEW=xdVWLioaCog6@h3x(Ro z7d^B{V67=21Fs>m0Y3pB;9E!-1U7D*V{UG)V{8I%T)!QL+yDzl)YY$n`~8rXHVs7? zz?K=r7(T2UJix)jhd)AKM(9O+1Oo#D;mVW|&_#DZK$44i11JH9T|&j8iScHNd7Y*B zo;@`{(gSE8B;+&3Vy=>r;a68z_uFam6I!K1)y5RsrUFsi@br|owWSvhrF*`Li#q@m z293l`%#5r>Um7;)TePWN!s$+KG@ zobQ}9qLBmoF}Goq0Nq-H303A|as#kE*X-IACqMLIY3s@hA3bA~O)C=?Q?^>wW$Jd! zDq6c`%ND=g7JOi-H@%21)I!xN=G2E7SFT(+pPx~-!<~i92ka;xhH_lR$u+0*?3&eW zU*i{Ie$*ECzFD0fqYq$wH4FaRk-=MCy>J(!;nrVprfR9a3O`7_TuhdDkM8ZO5ahkX zASxhA_)qVrQWv}T2^nMSvOXspBple{s}Dq;T*);sG(^)Wyt}Qh_nTI-QX>Y1FM{ow zUUhBlWvIgp3=J>e=t5W2NsJVJ(iu-!gx~`s=Q)4p9yb2x_=NuuE%Cp+&3Cur4xV>K Tdrn=V;E%$7Wx1F8PG0&S-cmfk diff --git a/galaxy/wrapper/test-data/heatmapper_result2.png b/galaxy/wrapper/test-data/heatmapper_result2.png index 6b49b4a368b78e8ec69a898e197d696cc5b67614..fb3bd36759988f9325382fc6389083ec6d135d66 100644 GIT binary patch literal 39981 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 Bq8|VN literal 56250 zcmc${2UJwq)-{USm_wTb3f&44R8Wwd%vuCd1QAIp0+KUGDhzEzL`#qylq6Yl25kfc z1eBanBu4>>MR;>#_y6wwzT4e;$3Nb?qb~}URp;!p_F8k!HP`musguW7EZwq{fq`KK z<-`$r28IP33=E65FJ6eBnEsOU8-Dr8{18Q9G5%-2`0`zRzr^H(vN;0-^Y7&U^NikG zO5le=7DvxnoH5q6u)b)f#b9{R!oTk+;r`dB`Fe9d;(PyUA`q@pGQ@`qitS zNx5-_osBx*T@m&~-G1;W+s>Wp-A3~_HkJiTYbih7T_kU2X6DHvxoeknvA1AyJx5PA ze?dXPXskQ8+WCL*nA&EkC}Rw?{2a;d8!=QpDM)iU=j1zQ*)1 zdF#z7m$wKQa1_Pux9Y7K4rdWG@<}qRKbzzm&LCh|7t}o6Z@mRSBfnqEezLPBR`Yzk zwzHpYH>a9iUt(RdadUA0PKKJr9ItHl=3RMnceU-;569j7{G#8!Jt00jH9R?(&*J9g z6`pfvmHu#hvF+^im}Q5rwG=IDyk%LGdgkPsv8^d$h7BpF2L}hk&qjG|-?4+o(wdto z|KYYXWBrYZI;G4OCJ<}6-%N(zfz=CMzcl@fJ6vFrxpvis9VlGW0!&L`@* zMW?oJakN;?p)@m^oUL0Ku9)`eHq(BCnwQdzzD38>)%~Uq7OGh{whjCF9=y4bQ$XM> z?Q4~a@kG2G!zqsWOS!$)?>hTJ&R-(@Oz6WyhYnS|ym(lAvNMn@Na?h>nc05F8GGkV z`wsQhC7x+avs}M*YvhX;9F6wF#a?1IaVP!6l&{!n=09}PQr4?^`HYp5lat~iHgtE( z{wo26Zo48*2OgXJ%re_)8f8hPW+80F6OEhIPoF-$bj1oq+!mfF%lf*K)`BN)-rlD!Q|v~2KfHasqcX$B{MPN;wvD?pZHBcor-q8s`jYA^5_Hetr(C;t%j`Ly z@c!=V9a8%}4;UFmhsbz7*N@3Od-38$5?#^RGq$qWB@+`9>JD7*VzOt#FXr41Q;yeO zx@_5*D_36NaRoo#ah!{vKe2}DnwKi+eed2q><|y^g2+dY9vz}j=5Ew@VceW`|K7dR zCr;c&yjte05WLdz=HAg6?$*}U&c5X4v!N$_6#|c~U}R(rvmNQyYsyHq{o47A^GrzR zmrps&{A>=5CF1Th6S;s`yD=k5SrJdRL2?^)ot1`^l+=CotDhJd7cT7fwQk}}a@6Yj z+EqSTq%rfHY{pUNwrwI7@85ayIrI-uSL{*@4>}Wi(#B9D;mTu&EF}$x#8S?yqCfK~H%!qQ8E%pvce8OfPGU(a5IKN@h-`WFKcRp==I#AolhB;bXL}n%F>_ zu|{jz0|%}>ZXLOM_wL?ZXCuFaI}R5MI`nIN`G94A;^WgBKP@>sQF@G~`##{hGCp(3 zvSq_I4{onu@~Ws%FrWOYTON4ak^ALX}StR>jmEARZT5;w(68oBmqgy<%ceIDEbSY(HgACpqVo83 ze`9)IUo({+RXyl$*Dq|BuBF_L&`_sa^wm|K;GLcvN&h(PxnGyo*o1t%v~i%`I6HA{ zcqDlt!<6&28@!*XYvq%T)Yfj@YCy6}yve6S=3hP@j5qH%$){V!x^~MJJyy@|$_Vdi z`j}mXoUce_gH4BTJ3?w-kvoqdb~W#vmD_lGs$&G7?3CrT?5X0Xy~B-ujCUAg3Jq6` z@InGFPcl>)u2jSv$zWes zSC@8Mp<8<%lkt9<3<8NFBlGpj4o=R38J3B|tHdo{$JB=UQ}tM4bjw4uM|*3v5s})Z ze&X7bU%RX}EnU8RzvS#x{P8|K`QADgiOCo51tca~*V<+O_S;V`hGAi0?e}*@@1@Bg z&lMwUXi@2Xg66GnSI1lSoaHlW5L&xt&82MZ4zBT#B%{W(5cN#k_UW-^LFBu3q;2gF z&yTiuehAF-h&N8t)YL=@*L;Tv(HAgoGFZtXVL+qN-gWpp8l_ouU1Ih8`0+yg#hiuy z9lRG_F}Mic&7K-^qR7b!G6@>(mlGTOEp~U&epKMMf_42DI;d+?t`1%@N0ps>3V0fH zx<;y*R=nxwyzSYJY;7~O53r>^efkulRrGZ3-Upg8=kC8L!)7!~SXkIfF@&L5Lun%CvI2Q=g+jMaRayN75`zL?5UR6sE^)tD3niVH2DVIjbV>NyaNl-U{?(`cMYENL__F>mk(TA#%ii?Z#xRUVnZr8WO&TWE#9_! zDbpTK4sr3uib&=16TJ8ox6;q5@2+hxc;~S%N8jJaXKQ)b8Fu>3o7i|ReZU&npd-~9 z1A|k8pYvreTnIn_E@u*WcY@b(>NAV@=md~fUlQ)y_H{=&@EzSco&z8%zJ43OUIk%WgzRFzof>Zm0KTK zjHV4^Sz{bX&D8OCI7@SV^e6x+#>T)AtII}db{O*=9cUg`LQMw(`SMmDhqRLP?mPUuMMyl~_ zT2J(_jiVA)e_Fh-xVZ8T3$-&g6Pp1gHA`DtyRMW+B}pbVHC3-X#Mz-VpT;IFrq?)& z`%3Z>G^W1p_?RUZmO^h`Iuj*k+VbYxV?jFKxMfQ?Qr7ykOu#(6m&=!G4abohD{P19 z=>bP2Jl0D(2W#owdqT8 zQ>NXjiI|eX44C@ zQtmNM2@f(bxc<}=5b%!Quufs#ym_~bj1j@pmS$#gb&2}yUA^A%co@34_S_`X-kR7$ z$*DSfhJrt`-?GF5`MRlp`lP=^-=O_ScV%CU3$yrn14*YAzdfOpCp(W)f3F2R2NvxH zUS{UIM3J|!NJz8l3%|8&W4Ffar2DalTf1T##hH|W5i=xCTi+4We1Hw4_*{ZT#Nx$! zLl8LbH~~B;0%pY5$ol}fbBc*I%p}trR1&V7zN~h!Ud~78S*G2X6s^gAST=K_-J7lZ z_~{PS^Gd3wx3+KJzO+$&@7461_ND+mmSl(830d`?b3jfPp-!bNT)rs)TOb@MB@L;n zGSyrsQNOz6gYgM0dDN$zJJPf~7nYbb%N}(aHRZ70MPTB#)f|mruYthmy7fth=i@Hl z>jx;K%&uTTy*LXTY?Sh8;q;fBRp-+z!Y0QCVj?4VN2#XD%hxil8{-&Fb<8hOG|Ahi zv7?#cqwxbQ{rWM-Bp~Hvywcl+bZzDyad;ku2_4EvT_fBSd zW-QyC)&ERe+WPemrPBTBYfmH}bKX*`;eJ`F;dx4FCadw{2D*=E_%G9AaW9Z*bb+}> zhba`wXyHhQdK26FZ9_|+xVb5ICUGf-uTvHUL=yEu$~cUA`2lffIsWA$ot}Q-^?bWo z^X&Y7X*pbrlR@aq>S6m5C9X*y>4=o-7rQ5GUYy<$rIvnnmDrbS;R<2T@oaPfByF*@ zgay1nxj%X`&><{0KVKio_r8-;Im_&LzI2rfZD!l>h-lZ!P0fz8nL+U^+L0>BClPz2 zo&Blwsjua7BIfN6@{^XeG3&m2`Fo^o9A{-jC3?%syfGi9}Q zLh~0a$gGm)Oz|s3{GaL-;p&J8lGMqfvNz8AjGU-=?AUGU_@_l}9UT#d^+}`C#}R)| zzcxQ!Kjx@;>5>@t(afLwKfIZmn%eGYz3k!nje>`kFw7hP7D3p04-E}rZ1j-@G|i^Y~-`GInr(iiZ2mmSZOx>m8;~rm?%dEiJ8fk(}uqZld+XWUDKNE1Z^>r{RT#Q!{HR2)Fob zgrfhl#!?4ePu4`N(7U=t*MmhE9cZG_%%&Zn1`z-@?7lmBV(be z27rQbJge-c2J@xum%J}{!Y+PRH>>Tb3ahW$NWHlCQy!9ym5Ngv+--tGLiD=Ig3rfZ zy0uNjUag6(z%NXO*5o)ly~a0Zf=h^3zGh4aygy#MnCt7NzWQYM)>M(vR4l(3_gYbR zx=%LLAD7LwKHCKZs3rV9q%E(5DB{p3K@69uYmXIfda>^J0z^ z4nK!cWfvx%Mv%Sd!shKKXft2#NOA}Xohx%Rekp-WT3zAY-vRXW!KvmmO}{MYp7@GB z)SC*V=1ZZ^Wlx-VPZ-rcSrZ6ZePIs%jx#p?`8BELq3U*h{3y{6)XaV5WMo|Onxy7tm@!~YC#IFdu^L|E<3>P&aBvSdQ)|lzUP@C;Y zrIJ&FBq~jPvhmo}=$9s+k`Ra#oq^X}LXCs`)vB7a5*s!=oEdV@z5Q1>pfWhwr_j4*9)0ePh~XYQvWgADB$t1=UPpU-_dRyMM;2C9LSuIpbeJu2 zCUPWFmi(zxkCZ%22ZkZy)sEeD)jF_b`SOGXU5+!uEdJS_S?s@DcNnM(&gfXgAf{TO zc=pt@b*dBz4vx2Pa&tYQ*3@kkv3SeM&hCvnY=rzYp-Pznr3*m;Jx06t@Sy;ChuTcL zMh}5`;5NMI&x~t-tM3PWhXCh z*@Mk|dAl{T8UUN}gF-{S_oyU!tdbaig))(&zV+qD`=9czMh`VTKe~+1x?eTkahCc7 zEJpjC$LUt7p$^;r)Q;ZD!U&}pBM2D&_Hl0sW44QZ8xZizaH!;T0eS1KLME@sTZ8x) zzw;BXU(PI6^V^*}-nH>Mb`|axrjnXs8;9(%1B>&VnTk=0i@_NB48caY%${Z6*j0ey zF^#C;Z-)}5jT)zo=bP7NwmzLUHC!q=5F5}5v8Z^ouU-~;vNqj1Mmftq)lyzaZ&TiYR4pG|jx#3?x3Q7Q;=ZQth2n|BHe*V<2yRJV79`U{NoRF9qS zEsfh<9xT0acr1IiF;Y1`kKDpmv8(S{Sy??$pz9=^5bdLS^y`b5_tG9f#UN^cs8#P? zq6PrgXoEx@qfJlxl^$|-1jz1fo@JAM>H#s?0~F`UlP8+U3R071lUmR6h>S#*3sScy zcCaT@tKrWsl3q{;*QL@j>cJ)2V>>m0IWtFN57>(xp}EdI`4etD(iT-3&UCPZfN%4gM?9f4q#hm3*`&EBNTT@app)T#098s=kxSdm;m zC5r3LfKBFBm4jIh^rxM6X8ncDY+Qn6{zWV2(8g=S_$aZvm;_a={8B2tZI|nK4P&L2Sq0;3e9_#7LH}eL`l;#`e z++GoaM0?9my6EYiVsL0~sd@$ziIg|XHs(UEO1xaK1|V1(`(EC}1%a8? z72=(tN1!GFD+n_s6kCur#Ta#Q1eToS%y=NPU2m+k$72sqAcb41o_|7i$L>p`A~yx;ovaUF_$f96=z zC3+e5DQQuRX4fa^YVy21=L%Ix59+v=uz3hxqFx!HBnN^(uA3lR#2C?V>#`iuA=REv z+xX&IXXlk^Jhv^vW}i4c5z1OO(- z_U(tN)$O8)_zc)z=We(@sp+nk@)kbr2N0PElMTbuB!cw(`SaJIK?De@-}(NTm!xA> zrch8e1ay7qW9O3$JZ~@G{2V);6S(gB_3QWV-!Fp*5Ca+Q{4S;FiXh4pF+Ip$`%PPp zG(zChtBUjl0a&+gT@bFm5$k4){g7xoqDLS4{l@daK$4-Iw+hRXrNf;+fBxKp-j}Qo z42xF55TmaWo^#@*+@<6h;mPi@$lT6;_rZe-U_*3>&gJIiaqZu)uzL0CG_a157{_U8 zfBPZI<1=o@j~*rMsnP6ZO^z)aHf`!O)lgPeZ&Eykte;@|`B>(c-ekA9#0rJooNq(1idkC_Zf3eSFfec&zV4p3fZ>!pWc%*&P?y`Q zSfU}Fs^J|K(A-_1kY8dml;0&s=)IX~lR| z1JCAu=4_WdhjGUO2DV&r@~Qe&ksmCp)s$K#2tS6F)EWEbZXIF{rPcI11rA$(XMA<;~{5dW#zgQ(?HfR(59u! zcUy-pW?(414g~<+gcG!i5LqVN{diO(pS9~)4Tk$Ip|H^j!zuZUntzucEIfz*K4UDI?;U+s!rQ=`#5HneDIlvOTU z?}}?f?e1MY+?E>|T-OTM<|i0RXRwxz@yt|2R+cYa`Y@%luk|uZb<&=-Jhq}7EQM+Z zIIqfTUP;`wZo_(qC3Xt}GM21-m{Fm|aB8JmxE=3}8#~6+7v_Ij!-EfGczE!@w% z-M@X?*1yvRKX659ic@{6Q8!QO{_1~!#sByV|KnR3zU2%Irw%I5dm70gDZ|%$N8l87 z?+x^xuNBn+Rh2|{$-mhFu~nxJt+dK`9l6RErw>CpI}3e`bUqG^Sxd{vRJ^*r0If7b zEbl?9W# z78RAhxwn=yuOW|cp=XNTd^L3A=SaSF5zde$Mh2QSLgoCcfKj3o685vPvU0Go9R=N~ zM(>&5qVrTtT1JK#n2UpmS?gVpoIqeDu3vvW2-Uv3F+I7gyu1>H7+lt_a^;r&Cy+2m zT6Lq*E>(+<)@X`2OeTO7g+5`Iv#k`LXni7e;>0P)=n01P0z`!X#PeYcg=UyIw zZanhB8;w2akIy0hA`><;doEeAq7uNGbl{PKJDqs4zPwO@gCJ|7oe4sKUi&*w)HE6^ zI;CCCf=#DTeu!5A@lhOT1dwG5j?GFzlOPM=;unh5tIoQ_2oitTMK%>$Iy(9&+O!}P z<-;T)XZFp|2ddvcJFNBK1Gtj(u$lYPc_iZ3-`{r(u;dA=f8aL3MvEus6Rtc1{)~CG z7g(O6bDST^UMz{QFtS-#yNGc>xjIHe5~bMAVA-lw)ewN$DPEuy`AKtRkZ5{%IQYZG zi{GQW)f(TAHm(A?dnnssOvV`>dbT!pI2cK~gFXVD!o@(^#_m%q2&PWyNg)&N6uTYu+!L)?hRR?JrOx%e+^g)rd9Dl z*alK+>;+kz)0Zkq@bU1(R9J#Aj-s|-7n-w_Krzc)6< zVl>MQE9cV37FJYJauyBid)*C&DLL2aLb;XXfq?9)_ia22&039d(V|_VqAJkg&@JaY ztp?p3xy9AhH3*&6M)Xf4#?pU&KqB##F~T*}!^2}cOK>IR>}g<&N-VGC)VQgZwstpa zcqIWoSV#gmQHEp3O5eVH#EPU+oHf>}3UJO$_oFA;*-^TQ8q++buBwKL4>wMKrM9W% zt&zl+B1Lfu;8OC{>l@C#jNZNPk2H>;>>N?WdR2mmldB>o5kH&u&3n`{&e3}LPnP)B zMg+jaL!lw^3?-FJ3|)WM<4K5qSr-?*D>^1PYM1m})fgvqjimYP1meMfm=lJaNEA^R zc-C#+9QNqZ&rsByxbQG^SShFyN&e>5srt)i()U{)P3(vmtq42Qp{S%_mphV}V5xO) z&eW70rj|Zx)2wMG(ZF{OxkA6A#Fr>NJf}r$zrJ{|Pl9K7$TF-v)&0!G((_r}K$TqX zMZr+O4)HjdNe-B$0$_gn&<;z|{it1$F}Er=YxXJ*NS{$MQ912?U2Snc!4?Nn6-{=A z0}oJilziMv9{$wZm|m^Zh&(1f>K23&RhMsW%tKKFW)weaVrt1)&vDhKr5iZCFY%<5 zygQh%3vFGmzNsZd_|X-!j6H>G$i@q}fvStjDW;lbd}QnnQfR$K`f;P~>X;ZH9SZGi zx6G*~C@kfR zSnNN>_xsuPpGGu;>?NADNyV63_>ZMd_rl*r{2++gn4?>lRY8a@)_+|PcZfifS6cdL zKogmOa2=Npmu;dU`7DmAq#wiD73{7)R5L?bT(~RZ3uyWLS?j@L*1o1pmBY7}KV}u5 z`jRtx!l@qC7K_~VN*w$4!M5WZcYHI7h$WKsEn5AfmX;Q=Zc=JC>^YD2q8eKF zRe1EQ6yW6wNXo>U1=tInLY>)?7={q{u=PYB&2!=9G}k9j0*L_z?+*hBtVTIv-Gm>Z z4<=0`WCUDJTEuRE0yP&O5rmK?T(>JZNsF$-d`6746<{68I`!T9hT5B&;S zzVHvh=%9e!6$nEx0MO)ec3MT6rGAt~wmRud{r>y!gx1}p0L`+uNi%&~^2x&3T&3FUrA4 zRYfLX5L!4_^{;9EeCqGM-CMjDsgF^M@m$>eslCN7S?Ufvl16aqk`-N>H^e@Ln4=foh{}DT??rmH)7neKRu2)0Sq6a8*mFT-^-M7EZQKVHc zl(X*D%#{Ugi*|gM3syM;cf`f9>lJPN$2-ayQ|}iRt~&O&3-mvh@6Yv0-L1_1Z)E5n zuiYaTv@qbgnX>#f7Ks?`4Lq*%zwes=@b!9VZ~CK{?3R?7*X!~p3;WIwz7aQnxAHuy zM{dz7!+@!8B9IInqXZwh|( z1KVL~p_y{r)ZUz@lHa|L{=Dvx%`mdRcrkxB=c`rzN{bL^QV;(tp3W`(w5LVxzljin zQ?v(f#Luz&e~ha?edqsYGfrqNy%4hbnC|!e^>6#(|4LZ06TV11(q)IfKKO_F{bLXG?L7M8RUDL9|)OEfjHwn#u z^5Fm9%06vo%4VtDGyhHIb8ib(&e*Lzc&Om-Gj5=2Gb_txWo5;{aJa!4IF5Ub>05@S zGX(euS$=&aFl!rTH&1BQAKN)l)g=J8A7H}m?jN#w^e~>o_iegAo`W*CyK1!4tW9DY z(U!ja7lnjF=^C5TwI6+yTpaFN1xRT*Lj$|jiL-Eb5e*tO>;%=LfHrmY%j^sQJKle0 z-?>xowib;OEbue{6{tRH8RW*c_3) ztorJ<2$>MX>=ao9+c$AyLA4J&bhxTGiYcCJaR&tVUSX z&Zn4Md~B(8Yi_@tGGg7ilS@J(>j*vX&6^kKMoJ_r!k5@FEd6x%2M8`v<)Lx}V%&Fj zt_0fUNADZdLyowVAcALh6OBT}DD~*^hg(mhNmU78(^nIFnCKlo!sZFULy1>D{2pNh zgDUaJfbd2VT^}MBOqpK%`cK=7y+hHDJP%m-B^<5wAZWZVU{fWG7q42hin+pFgBr%T zY(poeG0Nck&FF?sQvrdHh$Yv6=;oE)iTOwagq)eC_n_Hli-r~S!Vr9Ra8S?-II!x_V7|R_ z8-S*}dnnwAa^xocB^(m02h@p5uxF1fWT>;YwrRwtgVm0ygW$snO9ruM%gf96rsXr+ z$w1gTn@ydz7;2@&q@kfHzhuc0V*Ua_3n79Sl&-ZqWlmvwfv^JfI%Coxt&yAi@ZrPx zbgQVU7>yX1Gl;|k1Zz9l6*>ZeWF5UueepNCb_?!9IbgtYX`aj=P=8*@8PNPF;N>uw z#cY9m*RNa0N+CTDbRO4%9AY`IfU_`Lns<~`qSH=fC1ME=Bqu0SWqXnvTFkTI zMgD^(T%Ic&XRqs9L2gp&oyqf9!y<~YD_E*eArEBshj9>h`3Mx@o=aQ1mkvz2eRi@9`JB=H4FXOP z@w=t*{^f*4D?)gAofdcO4^d!he2_F9n{0db_?OcsdF{tdVmb(oBwGo31ST(r385k^ zwQ4r%6V1&{Yk+C%*52V1v@dC_z7h^~)ad<|w<@1ns+l_MF;r9DLF&;fd2hI5G?6Bml`RjaK3mJDJDGa{pE9mi#%A7@uVU${1TgyCaB?>1RE6K~F<{ecN zEz!e@c2EF@!*_*ewoIO{`{UBDHN&BkUNPpet{wA1ijX5iPWp1WM;NqINf$C)DJFWy z@rPH?thYKKJZ8qF@oP~vn>^$?$er?3D)pKB(NuryR8_?8OMe%%80Q2k(d6P5?i}8{ znusR%km!#|&$$<*pPDO_*NVzOEiWrSg@VG2wJiEP2*FZ{wo}F<08&yHno_$4O&bNn z;6AA<+2TqkzY)Dl|%=y`UwFllM&_~VqN zqlqbLkiY1+XKz?)%?%e`D>{qhhAi=M#H3jcZrvr@giH>=AItS&5MA>~C@WG!KC-*_ z?mdNOt{ZFAx!B)zqUaOY3QeDF#{QRrb>rz@D_HJ~b19Kq8e!#zsi&OGyPr}_KVN=u z8ur(F4<{yjVv05eq6us3oc6W9QH8c&GjF+z<#AR{q+w#GW(|XRQ=(@EW?{QMCLW%i zx;zP2`&;hzryX_LP`hKJ5n4NwA8)R*uWB?e700NB!lg^k&qk|uSw8GnY%lH8fg6=5 zl!$V>JuT;6Mnkw%Uv}~-8@a9njKEw}JE2^J%n0h49+Y(EQXMU=E;N86@Bn_H*tUD> zWN624*>~x;=#-YFm~bSm&ry!UC^P-pv(z?Nf=WaO6rkxHS3@zXK-VWYG*llWc`%*3 zvUZ`fvqkLcOVScSF^0xl6o~M$>W178DTLqT;{m)}nug^dn*r}14w;%jkK<}kYxZCL za)DCz=-0yuWS&ZAK%De7o*#8uw`R?A^wI1ppvM$Yjc`flv#FVxhG;C2&H|zd3g8)< z`((y9QJm`mq-`=F21~ah%q6|_!vHLOANQh}BTny)S5HLid$RS396Vmu1f>x54x*89 zH9QHYNSi`Q4TCQjYKcNExPlZn30=_welmlbRbYAbS& z0E8hm3DwsEo_HeIqgkVP?wp5GBUXk?9FiOa=g*mc*NgmTr$Qb28O5P*61M>9l)?3P z7B8;4x0bz^E>DIUW28S6Zka=?FZN=|h)cDLJPf=&aaNG&OGv9qC6EJFc0XKyB(AynknTc;WKKi7u2wvt3+jAH!3FNb$ zYUx5@La}*I^ssntF)>xln!Se*h2H57qDw)I>;4dU2Nga9y5wZ!vgOMw{#q9r+T2j+ zr6m=w(4ln!ZNJfCi5-$t>Wcc~Gr!KeHXLg?d|kSck)iEPSm2$nZR1p0P(?)rueWWo z5M%SM5nJ7)aD@n)5A|Y}Ujrl@+axG6;!3K1{{z9lmK{P$UGLf!x;bh0qT&|D4$c3D zGjY4KDZR?|pI^grW^>?o$`E^*D35>`u2+J z`oOFAHoo(6+O*y>m$L4GNP)*5H=!!+qI0R8TzT~dY!5f{ggv;tX1((+uE3Q$)unbj zwf^Y^*sB+K_r{LG1DZEaFsx23Z=^4(&rE1+*q*`MRT|nIMKdoMo}sQ#xNq!d?gyjJ zraZ`N3G!`boNZ=|dCQe9tgzZD0yXo%MWV3$r>`E6FWyUewj5pE6@XQ`HP^}h%dZ#T z?PWNyOOabq`=^(jIR-1X!Tb@hmk1>P>8lLnvn#<;!SaQ{eUg_V6t45vn0Efar?|^= z8_%wO<#z7owmU0PIZtgO+webq4Y@iGw{2J$oDlZvw;`U^?r&5%`D34BLw8|_ezT=l$O207wciP?_)lN= zLf{Q>%zW$={c-@bSq&)kc-f@Q-L9$Q|J z{*mX-)@H_*x7>J)t>*gQKgf&sH_io$I~QMW(I%dx8-MluM86&$a%UOU9<8NMm)bJD zde|Cd-=j8_8gbuqdZ)GDEQJYY>s~QkL&ntefL7{ z4shdgljd|!o?ZM=p0Vme{onGCMjg`z9}KF+_z{{x7w zSAy$YrF73+U;WBZDsOpw+kbw_HP5C>XD1}jaJk8IxeZ}d&LXf{)=x|rVoxb-oR3lD zwIC5q6v$C&fcS<(bd2pkMjtUmr_>L#<(lXZx$o1=Yt30D*>G7+R#ui9?sXtpQQ|5A z9yBXpa}Np$(SBkHzvxAPvL`@9!5FXU0w)G`@WiyAL7WkA{{;A=4^Tk}AX=@ai#Q0= zmyGciC-2CJh=?K#-}~jP6x|JadlEx)W_Gn~@ljAQwGd3h-)Dh8*ei9oO^hCss$->kMJxgU)9Le}!Z zECL^xg0!NdqMn|fS>9%y%jkd$clemgD=Ae+j^0?t{T60>^LP95gVNH{V*BHYxQozo zHHQ;M2Y#&L?r01*kPm^o(*_PDKCMDm1tq19+e}6$3=IvT@42O#cL+oHSnqV@1>xD2@s|)Me}*$kp7>hTaZ<`~tqtgjcVTu>9R_iX&^um{AA^tY zGCWMWm`@@RX)(|wPALQRA>+lH_g*-F2zw+tkP%O5oSGOmuU4~Wqx5Id`+M9HXgxF_@Fdttxr{q3ZC6zuDjX~FL@C(*fSa$*#-6ONsI`EYo(d+B)7B7 zd}84>`S?l|E5no-os}g)j_05y)bt7AXp!=4$Jt2ey~-ChNmA`;BWlh#0cO8&HAF!l z`=J5~4fDDIxoL1oiGrjVnngpdB9EQc3jdX{S^w)rEHX4qC+~)Up=%b6j`Rd9(~XxJ zceser(6`qD0TAwf5$HAjV1?uu`31u~vEoL}OGJ7iovWa??St5*Z$(vEjgm9o zkdC81;;#<2OtoyxzS3)ufRGWv=z<(=`8JV+T>UK%aV~|UkrM(wt@W)_Pb;GE7%D3( zRTQdU9y=^_W!$g0lKcp6N8O~EyzWuRO7QwiK%6Xq4T#D3PQ9uco_%?`^}stHVLljJ z-r-<{`W8$7r%3e&a$&{49A8~gU2Qx#Mg~FL)opdHYPH<=cfUrrFZyrf+bT#W0j?M zeNWZ5zYdti^#=e7UQu-wR*bTEol?W0%oPJ-!mzIlTRVROyFV<=$WKsEFUzH>f8k8L6zrZE^$Z+P&dO8G|a^j?}-st=aHxoJbCNro!7 z4vv;Fifg~WewTnsa%`qiBqBd+FltQYO!B8x*~W#Vx}JcSuR6-$H}H}Vb1gq9x(8DP zN>54$sAK7@1sLdhlsQ_r>-bhv1p6|L@k6u`-)opIN*vFG=S9!Vkk*ScC7f5q%smAd z7z7_KZc=T$t#2?c?j4~Ij{Q0PWKvLcNJvPmblfL(K{DH&mbYj|FtWailx2xzglqhT z*Eh8NZ+CD?%#45DeeUHiaF58u%{Z`;YoWEm|6)8S%Jh&0waYo53_YN(+DG&VOpT0& zGodU!8H+Q}RfDt=3{y|6vcyK4_WLrPcZdxdE9O;8G0EhCA8J9I7KXm! zU9n;_FDum2BIuC3X02~`pHJYR#G$W6awz$f(FXHURr|qQ*={5iw`DvTdnvq-!LZHQ z3nq2s06VK}v zq!dR;+EMBC%^^?;$(6!(_ZX)*@Sy8p9iN8WPV#oCY5q2MxP`1Y(2J^0lRC6awc3%s5bxhOx z*!8D!x=DEo7@h|*dAut+WjiU(RhGJY(Qm+6Y5W`2EKWn@qM-|fbjdwYVx9E_PeL0= zc25GN)Z@m%FBk#bf!?5Wm_i}e+8f)*exgXjD3+8xa#V_WUt+a3On9XLg7KK0 zu>Z`|{FdAk5OC7DYCr=qL~<&2&#<85uprQcbsPpje6F_Kvq5e)$0VlljNsTAu1e$L z2ocFes1ccYcO1e)r!_}w)9E@HJ1*QQ3$EA6TySC0V3Xal^3Z|iofM37r57I?Frqfj z&Kd{Dx@5Z=i6<3{QUtUHZ%jmL#UJIyZt~nrd@`}$$->G))_}>p{2?au12pR!UFC8I!P>Pq zH)6j2%g^usZ}Zk~6!;IS>k0-af3)iQp5X7IaS1bL?)@Os#rhh~ZvKAlA>``mBY&^7 ze0%Jh_?AO&ag*+mbUU{w$@Q;j@i(F4o2=0$Ulx)uecZsaCAaEFmNop{;tQI$Yq$LU zW&KMW);qpA%l6OQ_#0>52Xj-D>%N?IkH6<0f?3;^F0bLuafR80N<7IC>(Ida9WG~oP^%bHW>7No5Cj~iC=4t1ecB@gr4LSIp8RXu~% zFVaopMLL;`NSiZ-{Qe^w0v>%6IBK4WLS8gb6{dLODG$xwjpv_o_&X8m-!`)3uS7!m|Akre*bpRoA&rr_|K2v3{0Kp!vIyW_%1bEihnJj+D8); zIoQ86FM!Y2-da8a1VJCXpjC)q?nMP{vGT}v%;rOAt848*d#0|_3vH^mFf)_`5?b`u z?1O8e2o1B2L)w1F=P9Ctb0=C@>z(W)jO!K>wx5V)Bk%t(q z(Y7S`61tQ>paj9OKwT#I{F_AN!PNSpnKq3XHjF|W#iv1-Si9?R+{LFjJPw<}L@NgWK$uIo*0pA>?F)tAgi-^!aYxkOQ<7Lb+6Uhp1(|FDroK*|r zkuU&Uy#2(GwxyD~jTSzn3|d15z^Es$mQ;8|ggMU92}(*5z$if>@SJxgk!Hx2RsNX9A<3fBQRcN2FNE6<}K++ zB?zCj0K%RxUMoo1vLFvL7G&KUEXrkNyRpDjA0|8RNZ<0-^nzQ%Ev?hMx)ufLd{RE-yFvcE5}`? zSmAPfEUT26qP&GnFG23C>YYmZxEa)yiyW%yovG~)^+dae=))8<RQy#NjJ?GJ z^jh>(?ZHG#0Ri*9iPh@G(Q23!Lmbdpv5yT0>F}<35iWo;LHxb98eipbIAaOrEnh>? zofTqESX7kZa#@x0g2qi5?|elCv9FEf1uwsSq`fVSl}NIr%TBTj-n(c{Nf~q8LRM=% zA6`_f4lQgptm;KnR5A3lVI2S4iiwJoaEh42aF%?v&wu7?=+0~^_BBEE?cm8rxl=yg z*x7-mzAub#J1LW3^(|xkTm2ygeU8Pz1f(cir|vCPR~9c?(Hx(eh96x<>%X|F`CKEQ zyf0p_gVwz#Uaxte_J7Jf4czl`_dvYw{n-d7Ab|YkIUaEwuxl=&u=~1h)Uc0L-rEfk zd?tT(oW%w8a@!K>WhmQtyF(zd{wXPpFFYVGapI`c2JU7MdpjL4 zRAmT!@bEo>`R+2F<3yjaqc=I!O4e^PsU=>OV_7JwpoLo-qH$nyBAi>Vn5Z*!xVwi~LK`8^X z%hU9a)TbO)lTL);U_7E*AhD@^G%eAxo~D8-TJ!5R=qWZhje_XyB)dZeFWFGJ?dr$t zU2u`oTA}Cbie<&thY3`a?U7IKjgu~H8`@9_M^i7ja&c9IY9o7fgQ^--_RlH<$sv%| zywg_nmJ^Ys<|1K~8jvr~C@Hz)VvJ1Hat?Px%F-80!o(Lpvp>H+x&$lov%lQp+0Q&D z72W+b68;Vq^aA8eV410sArCSGiW z6SG1n*5EMqnKF#GIN#f!hdSs4aWs@|u6=?5SS!tr%Q?xci1GdpmU-ce2Wi=<(JrcfN-%g44mjO3RmX{51%f%Q@% zCw;oLQ6Q_9igraRPPia@bNQD292gO|eUkR;;oFySpp`Q68);!dOJbuyCiX^CMU0>- z3=w)__%ww=lsfWGJ1J1GD#xc}5kP;f7JX<b%uN3B+H}A^|O(sV#6{gvF@w|IIhYKDLr&B_wI^S*I7*8tR|Zz4*eB& z3jQo{t5wZK3JnwMfrAr|UbS9DGW+dxZg@D2=E9i%h%`R=C`#HchU-ylQtR|!`1 z1Lk>(*_b&QKX-(LWrjSjRX}3{R!}p0HE$8waRoRXvK)pcqWo+YGPw|+2H4R?G$>fL z;~>zIX2QQ{P-2iwCrEOLG$N=5-wh+fhrk&v41_g|)&v@jJ275X0QXwYgRR1G%D|UB zL(azbI|x97Rpw6#YTr+!QA1AG5v1!3SCh^*+yP+`H9B^}NOa~f^R}T0CynYcj04-- z0GOp}6FErfe!`kDYIHykaL?yQy&$Js4p)WAk!NUd{#`+soo6w-<7_8s6?t%*E zp+#-E$xYGc7PU!Fuac3k{X5~Qj#|ZpIhFX+T$P~;b=0*<0;>P0Ec`144z39Csk{Hr z+~}K^;+tneK8!n9UhTUT7*0#h;Q2qSKuLwkg(=+ImorlD@V(ZIGu~!;yW)O`1xp2| zxk_2CSN_K}`=-VOR|LB*l^G2GQS(9f8L-KBCSla{n16Jq%(2j@I#+p>A2n!H2CIfg zyoCwmKRXZp^qTx3*adS38_X_I`3{54zr~BZgB0;!a90|SeXnRDWhfOE_0QM!?|zML zd9F&u%iC(?|6alRH(~9JyIB%E9^YXB`nJfEu3WqqBeEb_27bSo5Uvm|9hNYizx)S0 zL*DW~8kmI$OzHm}nCq8t5a3C2DXf?KMM-;{R8x{e`OqNA0Az5hSp%cg0lbtP-A{-= zC{=91AdbwfCY@#cgB%{v>Dy4U@4`oX*Sg|u7=Jq<) z0-Rg#i*|w#yN}5sQW8nu_{EzfxR-8(oj5=kI%(1%9q(uM2J<8cm$aSGV4rJmO~Kr)&k?@( z@%kcd)F-zZoJnp(sV9fBOvPy}2a`_x;wl{_CH$ZgN$e`IYB6&pCVVvybLwPf;z5bCuK%-V8J| zWnm14KMKm~OY6s&*)*URAQn+vbU~s!$MGct;#0oLM^gsC3NZ?B#xs7d($_tQp9kWJ zYV(@l6ASJxhT?5csrJ6h8GT(DFNmB#i$XQY7}ztB_IAATaxbV%7Ic4m&Pe<`8a+Oe+(6g#I_n>I@fHrgF8~mwziL6< zYdF+#h}g?y-_7>(ed`t=)J2{h<}-|xAwU_RK`%K3>6O?^XIAB`j$s+yRnjddrCn#y z*Z8HkhSDuvn%qoQr=Sjtr#MTJ4 z|0jwpusNrLYllbS6v>2;AoNNBI{3$em2bHB zIu14~t>i@;ON5vn>`<)=3$)6{0=Ip+b~wviU9?q0PUP=FhM$e} z?n=&*lxTL&V6m6S|8X?4?h-Wr;A4M))T*D%L!Kf^rSNQS;1yTlzuR!*=lEAPho)ku z_?Aw`4*L;140-?~oA+ntQilKL;JgxzNG;BT80`03c*c~&wV-?J0I-QHmX3k1)Wual zgCI1`u4-^Ot=rHn8@V{?+~{J5QoDmKqD=W-WLw7Emu$RURY|uMK#_822bw_!D}~`{(yCtw|2NVV5SfJKrPs&~opy>DAg&X=hGYXf0bWH{_ z5U5jF`{a@S*m8azRMjQubMGzl=&~k?x#hG<_s#L@*myzfCpoG0hInt=%qG%Q1h3%* zg<^V(h~?z_Z4M<6(6^Xw|0mo&rR&~C(uS$4fX-Fav{ew##MRt5I2$H`3+}?jO#gPe zRZsYM;e*K>wKbF%FQni7BwsBn#LL;M6>=i>CM?91sZ~rLQ|X zLldD-ow(-7;B07hyuojN^wlwBvY}52*IFQp=nVx@Z*5TTe7c^Cs0lV(j>aze_3WGX z@Z&l@69$_EVze0b=6Gab0|pKmvnsg6e#-8{YwLu8aJ< zc_ahi2?@2OH@^o`#9R{cNxRjm|0C2R;ie@@Vg$GrCLYa0j0uEWOQ_a@Dn&uZw%G~v z2)AquJ9-@}a2f*sff8;9+G1PC(y204>Cz2N_zuChkk9MW+9zJTZqg6) z2&Y7!M-bR~8NlwlV2pVMw;YBgO!XBoab75}df(D9q7(Utd7~Xr6uS!b1)SDc?9S>n z8wYQG)G|l^7Iu3rfKEaL8}3WtfcbU7c#SW3Q+erYd%X#Fhd65mmDTB;g*>b9>-2}xx(e0lGt8E_Oft6d z`a{JID%A-Wv>#inby+`Ew0ir#di7n!pZ-J#V&L^AAig49sLiukgl3RFZntx7DA60J zpm_9fvU%=pQ3QYUDl; zCF<;p!rL{C_<3wrU%jbH4&3iriuZd_%%S*$TR$BF!9&N_4_*}aO#wOUqAMHC*@@k) z;VPEV;t;R^`LWHOAFlQLXAKI4>6sI{!)&0FsD{PcGnDitl}|1pYhkk2kCA6UVPqYP z5>)PnA{2o#Py%8r-1+ua>b#Rjo)?RW67*W!c@&|x1{k*&urnIXkxQu&5IPfJFBB8U ztp4!qd zF9c@#F7&%)ljs_2zZ$l^&{N|dnp#CT3_S_b>)`(6p`!UZN0@MOr`w|*mg29-vU#76 zbxso~EO2qG{W`7b`{K)sJUlu?{OB_4Cjq0}-^Vku@BzpUyR;6JkM85HXuoa*+vS9M z){j9}c^M(?g9L^dA058xdV$y>0D*3U5^3b9rU=y+`f4PBkzx8uBqaxs;zya#j<>B{fV)B2>i~dO!-{BtQcaa$8pWJGHv!ODM!*>u#=MOrLG`!#(t0+H$ z=7}F|g(XA>q9%*w3z)TL={`0nphR5*+yyLUZ@|Mg1Y$xc!*ml4 z>GlGw0(esk()H}VW=VePmEER2ZqZg2EMQ+7I2$d1fp&m@@9Ydly#Au3ZDYv zY&i(n+yL2yIDV|Ob@cTEkpdpTBcgb<9A_2@sR4YMUOTc0#$7&?INL8?J;Cm;i8`m2 zz99{iZQ@HvB?r7t5i%;Ky}dm~ew+euOCIF(RO6Ddw@e=XGNKlMA8E+3HHbM(f{c3S z5M-gy1xNDbPAS=|~@9s z&ZD>c4UB-9Y^-lZ{H!&5#jx|3B}f!!5{T&lkr4RL_1J;~b&UygM3}nyePeU1@e7%h z0D;Ds%{*6rktlh>nDJ-=hn_;IHdj}Yypdm5?xuDL^fk<7Qra+CNJTGv!{f7(pc*#; zUBYA|C&|c4A}JqJ1`!^rwD7DXQu&n$dL7Q$WB8*Q_zXYNv15Cfe_6h=`%TcBY9xxW zkQ5V_Auo)MTd609uICHsf={o>P*gd>kUFqQ!NsGn(D(d+J;?;xMjUs8)*yv zWG)l*UFkl9N1tg<;Dt>38bFTR81?+G8l7J_Q5?=@OUnjrKI}MnS(b*QDT^~Jy1cna zUu6It*W5zm!-Yv0y{j+Q7v~6fD@CSh^fogR(hH_D)!#u~%r!8P=vJLXy&y$Ny$h`!VsW|uA}{jD4*~|s4VInbND{7!r21-VINd(WwfU?RUt#q283VC zmJB7rn-WDnyg3;B9Ay)s1f$J9^BW2zuTNaQ!`i14L#KqLtq_Ipo zt#v2dP?8MNadGX>5ntmV>?9HC50e)?!#irmTU@CE--H=K)69-$GLh}cbs8Y0QDcJ( zjQw1Es%cZnu7+@K*{+6!m~Sd-dV~Ec>O{wMaQL@A?`=8I(=yXWJt!{;`xjm=t z&__cv0oB3s5#3Gr2eY?t@n$;uHU&AF)oO=dDBl*Jlx*Nog0?KDb9I2)DR(rnu!^zT z?^3?Yz|F0v&lo+4^_(2ncOHr(wyJ&a_sfst)ixZz@yp{W*C!qk8zfzM^itsXC6OVU znQQE}r6~*<=C$0pPGfWJdaVc4z!>nkFahzT9YQ!$EJ3MQmx9?(mLhGMV1nZOr zkGTk2w=XIzU^ZiCwd=i(?*nt@;U++Pd)jlmSuOKb0mm zq6X(}UsR?GM+0<01bqDXF%?U+p)F0Yfcie%EzmvH_MFMrd=(fF(0pdQ>(9)(?fQZe z>dCw{yLV7`Nam0+a%gz> zc=dsd2&#wANaG@#4iDl6@aMTAi8j?>}c#q-z>_`?i#1S8=8cLQ&^k zsPYx^^71;U9D*!9*j+jsmaBBSF|u&B7&hIr>pUI zxHyG1VpOc`sm}s?DZirP2KsV}f(~VXQX@S2cq1(K%I=fFb;=Q`|Sb`50Wz=FgivletIxO z*hQzf^L=$TiuuLp(9%STK{A!3cB5y?FSXJN=f0cx5sBXZw5^4mS>Cp-zbS<;6zdLM znSTE>&u!!ymAh826SnBz`@npIRJ`2Un_F?HI>Wa}*;ezS{KsF1MR!!6_h>g(EP9g} z)JCM6a_dbTC>Is#B4(n|s%^NGL-}{^`OLXhq6QDCi#5HveIzzQ)wGqXoda0)I@W^> zEDG!rtOYj+auxLT2$rLQlCV(5Er?`7@aH)%p`<{v96Sb`EIx>mE2&EH+T+cjzq}1z zOClPJcrthtRfAN@16X>6AOmo4xg+LYdwCm>kv*O8gltjnPSPzZcQFCP7}A3z9MLVm zjdj1HT8;))p>4)IAj&V`JP^+1E=D8IbNIZlQSY@z2y1Gdkwp8OZlB&H4XASd zzWb?M`emxqU3#m!PZHN~v`m4BEb1pAkdo3m?1BS0i3u>JwI^bf>9~;qFQ<$QUv%Mk z0Nyygs6&lVT$?;uekHoC>SV7mvQ(9uFB2H;4=NvTmZVyg{F7225JSEN$UDl4a3Byh zXN!{5lsHO4(rUMRD4+swz{e;i&m!F#b-&Ty24SuaJcjbeD_5=i#S%^_H(aX~1z9c?EjNfhHM6#U0f^}x1ZzrN_#&_r zE*pmrE!MHq2zHbx_+D)39$EA6J{ei(F11!!LRNxjMcvg;L@dWX5h}M#Bo>`Y)Y2%e z_yv)&dmd_Yjg$(H_iPbqMf+P*MRLji@RvzlIyHi0o>}y(eXy5^^7*Ha6|pw`J_dPW|oA5i-Rl{_%^bYj#htjLFr(q7LEzaMk@EPdv)72o5LI z9Ie-zqSyBID}4X>QU89!B)-KBmtN$K6RwdQz!yX>h@8G`Z8(>lbkMga_s3iO z!!1yw`hztrmSV!D=pk+)B9-``T@i^&@e~JiEg}x|6ltG__(J=vHsF_J9xtvhRdh^Q z)X)7NUgaOx0n1lw^wm2oR+q=<&i)pA(VNPtu$TK?3!w4WZ;fLPpEn&xoUg0j|3tx+8CZsGhF3(lOiGfLLvzuAkN!s#na?hmqf zXFOmya9c~f3u@bgdJst9ew5am+R>t0b-N}i)B%q(5JlKmz2iny0Y&@ zbKJ_);tsoziITXL$UATYjq!~E7BNgs&DU0mIPmIi%8QDMD7%4Vj;Ph;$h1gCjpnC1 zs~3qlVM%*}k)T0C#;#sU>R40d7XN$k@eK)$AX!O9Nq>cqUit)xa`H<{lgpBUR8&S8 z^_Y`}Xr|rEwFGYv3fYbBtqMy6BpdDN?P;k^ZcRB5eiPJn4PX!*`HuRD(nskPSnE?s zVhf094wE!FAb*s}a)6q|ab|xc7(gez+1Itf!blhoR{1mO5P6vd=m~pat5^-m^K+zR z%OT|6;x98BvcG34utBRP8j$i{coMWm=%>3nQA;CfrA3@HT2iT>Ea}~;88(^Xj&!^e zi{f062Cch1&Ub3^qI?BNNERw|kr0SJl9E=)vfCrdFglz1Bk$e27m}1DPd^74ye)eyhob#nVq&#q-)Bj01|}kjPJTmSbzUIJ&LjBT#J91)CP+S6lImou zjMAJkC;Wqp*h(T&kroKZv2%gFgTu#L=az^%{|Q}1h6a;QCW;o4!P3{T)t4~2e#1=- z0f3WcNcq#Tu|##XCBJZMw52Z~a|g@~x~p0~CH>P$JOdJrijY2BDb?D9s=qENApyBD zpbMos>T;)N0JM`d#uzyhKvWb}+w|f|gy;lr@5|Se4)qbD2LXaW2`PR@N=8@8OjMX{ zJyaM_XJFiOg@sHTplFTWZRit~tVH{3HZ=r5xvDsP=HWH$1AwfO&@U|mMKI~WLA2Lu zJ5tSxq;49uk{PlyFo2S}JMfvPAjVg4(JZr+Z?b z_cftixA;R2;nHrghghg|AI9`*^m&2Fu~HELCKPdMsH9bhk4oH6h&r%dZw5B_Ze9~V z-UG;8n;T$5BHTK)`0<-`R@FEMDT&?>ydfIz_Qup*L`(7tIXP4O80jn!6$RlUohOkY z_zi+(fi!dZ{Ip4w=#5^ETTn_zJ&1ovTVXalHA$OUSv^;Q>eNngB|ziu*D5`l%Ae0{ zuS8oy4oGC5@Egwb-Ypw}v*iZLNt3)Axx79PDhQprzKRZazw7o5f{u8C%6dMwD-{-+ z$EWso3fo+^CRdnlx3@O5-EI$c1@V=!a8gO*lywyU56nREqPs`X=f)P-OogzfxZx{> zbP3t;Yc`t+9LK)@NZ}0Bu0P?#_#|fUi>iHD7Xv@JkhWzGb0ww$3lin*Q#j>(dlv9jpz2(!Y{K4%{Vm;GaQvuGDGAr zAaEbm=u-@j&H`28Ky4n*!$Wu#=vX$zOh6IcjB}u9NOqufc-`WIZ4PG&5YYo5qYTxK zYG{s)i0OgrYxbv?r@crtK?&e45}{032gP?$U+#KUkr4&;1CR>d zQP6mMPv?(CDOkFN3d5U6raJQr*8E^oXJM>LnSp$un#~|l~&XP;cM+@ z&qp*)BXd?p$Gcw*>PVu7h?GJ)lR)9Asj8}yo(zA+$U=;<#jXvD zkC!Dy5;+lA5oVVI_}ZHR6;uuoEbsdJ?FTToD+xR(@i-Dgz9TxbGo9L-fC_LWfhd>R zyxuAoiVb9hk-Uyw;u({+7Gf-x!LNh`x2-JXZ4YAKUGJ#$^XNU+;;sdsGQP|g>)BBD zl-rTfc=TtHQ$dgOhp*2adiBlP#DlVysWt}nO-U^a5Xx1GFYgmDx_aY!g&DmT#H1g{ zR2oOu%j1!|PMZ2>>ZSw!*~MmnV2Tk);*sf%9ph)~zeWR!xo z1Ru0yd?fMTaFwsWN!ZU=dFa_R(`!3CCg*}drx1sP)EI7}NtjqIgL!rm_5}AKiThoW z54)&5Q2#qJq^o8KzHS27B;D4j)buT_YFKUJi1;tsK;@*z?i7-Eg%ZmgXxn_rs!5b; z5uyWj7r|yPv1m|a^zxU4d$?6fNs6?3NT}!)A>vV&qzzOUq-Re%<;|enj`A8(|5Lvo z8AZ{@QnC<-@y-BtVsFoA#tfh;JSd`l2|ijOD{BlA4JlYH0ZbVGL#S{yGWaZLNuFb> z@M_F?%_7VTA9@Fp?E3rtiYbzVr&cR9Ws%koOVJh4_&MB&;*1_KZ=D!?2cVCq8_*x; za1qw<=*09vV#7Fk@%t?v|6QHjUv_*$EDG6r++_oUL^yh=YGn8Q6GrfNxBv^d!0v{= z0RjWuqTu<4qj#Nf?|0K1NL6-zTG*Na6j|TyR`y`-VdLDTZv7AKANAKi*S7rtjd|ff zz@k3@G%W6B^Z2I&gn!KAhi&~#=+a+94*&G7{)?**<~(1(GA+DhAI$q}MCOlGxAs7A zng05@F52PHgbyaC*!-GemllLE9w6T z710d{QO&RG-_a~Zx&DCqm`bxtGwMsSJ zNNp4G7oY32J#MeD?q5=^LaOppvyO*0>O@B=` zAAkBBMXlDYPV^2ujwo0R7`hcL<*4bgV_JRx@@D^OS!)0N$BW>Bzkz=$ zEPJ3W2q66#4)W(zZjkQXsH>EZmhmg)MezvG8ixMfoUIGj42{gZmXW~!K=(qgg$Ra2L% zj#7BbbKSJYqq#Bbl;q&9r|0w&t6Rgh=ZKo@_Ft3_nfNQ(-7T&4+9AF7IbUwd?JC;X=QiM0FOOlQj8$R+|bT6IfMpDUJ6ety2FbU^x( zhqW0*>TuE3E=jJrMZg@%F-T1UkN~M(70e^ma1mr?SzsP75l=-uJjs2>y1pGkpjKL= zZBW;4RH@ep0fDtv{f>5OD*)!@zrt)M#(Vmcw3M<-DhYr)n7|;AWFub5)aeYAj$Rd5 zJ2vS4kEn!Rpu3N1#;S8h-TNp-RPMX@g*^Hmlodf?^BN@tps0)-s0$4Rf;VrjQF|c~ z&TIzBfD%O?i-z3}a#F3PrgM;b>`L*bqpI#m&E_ykPt^??uui)jf~TKI2SPeAYmcrn zDDlO0gy*NrE+Cr@3|wIoSca!tUPm5}lm*hV@d9q;Y-)lHMC3i;Qr)m!%%dvDO60yq zYCH&P7=){d%+g5WZ-d5n)8@*o4(d#qVRiqeemNQ!FF`#$pV|CKvUh3I(M&~lh{RH= zvgwuS3p%wElToZ!LE@**-VHim9#pC@lL`mCxJ78jg($ZCiFGBH-21?^0yqNL79*W; z9qwc7N|;APHbrq3IF{S%uv<$TR#E>7l%Iz%;#PIfeRM;3*VmZC%vpd^6kjhJiqY5H61m-t!%rr07U}@% zFx{ryQ7I90S7@8jv3d&JN#Q;*`}9m3wI!*a9vT#p=(gm}-t}G|x{l+OuE{90kLy}H zyeG(oW(9Z?w$P7R>G9+HAo7T6LY=RsuAXDapB*XiNzbUm%%l90k|aL$WD6bqb#zFk zC@jBu9RlRV=zPz^;w4LxFn+sx)SHG8Vrw4R4Lwm_q9gZ8hsA1IRNsBNGuv13)P$K( zbxnhkmKRUR6htM8jrt|&ZZ3%*+#&%xiA-9;lVfC)AFkzh)kj(p6op=GuQo@PBl=3h z0XGwf1&myHV!{_KvPM7)j56Bpa|t(xElFEvvPjwzyceRl^h|zz)T}sKqNLgcxK&Nw zpmkl;a>K~lds=wzX5vp-dp&;iQ%^8Wyx;T zIUl@N^l6ftJK#TK0%X+*D5niPK&e5h@yIkC{_M?U28Uy)O@>#o#NN53N-J$Bx1x?r zXQ<;lUeD6cZ=-#KB+OyP$X8ynvao_$&&xhVfp1Umf(KV`-Bp%Xld* zifY&nh@MFlx|3jn;&OchbVX?kvo3CXfNI#;jfX=rz0AV95=v}th7tdBdV#E*9AEXj zrbw%5SqFFEll1E#`+UFTgoFfVzXR2_<(dXSAbL*qUH=A_C8p7tMlzaa92V6iTEn2{ z76ZfME6~UFHr-TITglj;+s8^hN$6%Kjk@@IH$D)D) zpY5*iCop$wdTU!LQVWQ1^PMXQY$x!yu7MW7CPckX4H)_1(ot!BN* zhZHb-`_W%NJhzwZsZkXHDM+7*duMV7l_^i3@g@)_JxOVaeIjn_4LY=tl2l3vV?c`0 z77_F|2x8IC(s}R$Tue=IbTHXC%u_4OYMV=5xUVFCP(6Kp61^6tj3VF&4TnJ1NmgQv zg;8FI)W{!4d}vyl5_K$KQL-60rg8xby@n`>MDFM+Jersc@un$OWG$2}#I51a7!(dj z9da)r;UgSOa$zC)ic4>X;3@V2I>-TC)r}*7h^)#2*lAj->e|}%oAm0-y zKK6+|8YJD*j<}jC_HkQtOhrTDF(HATfX|jgu+@!7;R1|NCfymhO;V&bQUDC6&!6KtML=EE(u`B8CQMZLC#7j6Iya*jU$zPlhwaB=0HS{*} z?|zx!TmV~vB?Nk7RMK@4@8T4sB0&5kTEZ#jJbEru2B)j27lQhbV2in&{Hl<`+W@gA z5mY^?lp5oKI=M7oZ*ra64$af)t8kU|*XDA`VlC(z*^wR^hLI3!MG~zZ=Bim`9q&p8^2c z?^61g@aF#lAjB82BF#rn6$!om=AK3BKP|3yXwlywF*SU-tc?BZG%uQ4by@@sd+D|M zv+!a+_u0*J4mze>sP2h3`hMzI>V`rP43O%^<-8^wrT`hcqKzd zv5Yz#3G1MY1@kTlv>+dF`bgb-2X~P48Vnh7NibxWftQeAfqpK--Hmh`qNqGWB%>1Iwa5ncU?spmdl`866oVgn@4+z7>KkmjX=JBvXA6&4wRBVzh#;h%ET% zF;K%p3#DZpiWT}44XiDwIlCEX)#|>UjK216zrJQ88)&VY6661WFETPu^m~!UqT6hJ zh4x(k1FAav!KId8+=_`NBr#%FB6~FB*<ryDtA=6_kv3>#o`q>L;m zBAo5)XqL@(w>r(VB5Go$x&`7Z0x{da&NMK%As18)Ba{{*gGtN;+0Ol(Wa_p9Dp+&G z)#&h8(#=p;fBk1!nuIgt`GM1<<--;;C@m`^r63Jgp;FKmJ`-(6Em7@a#jqLB&6x9= z9HA{Tfj0{kp2-bO$@ASD?LiukMbXb7coYz*(u%ft>OG*XLmD0~dAznYzI;x-@Z@+3 z{uV37-CLyPY4=ztlD3fFyo>8rmTcpz7D(;-UNuw$c9O!R>aFRJ;Z>t+p~2x0kXowG z*retWw)G@`;h`xj-I`z;EX1I?4K@8G=>fW^B# z8p@rHPAoj$`#CYrVf^=(?nur0W$RDT%m?aIhn$^vF2XZ=(vLq*(%7)EX^7$Vaha25 zPK?PuuQL;}kklof3!lmScxhw8njejSh#D{T<4UFeDQd-U#-U9bPoOE9z6 zux#|`(Y_2!WqGRiaeLbPx-0f+?9MvtwAc-Rb;KfWZIRzHsJ`@~I)UA75)(Y+XO2mO zQC}x;ka(ANE6eia!ho#oT01=q+eG;F!RImX;Q-@!h+3i<+U3I?AoqtH5Yf3tcs}Uu8EQ zX11NRx_wY_cHs{rM%=w&|6V-}NTTj-#>OtaooN`|Ej-nCt1Wvxox5W5-b2{;8fEe9 zr0q^KCr%83BY-*^UKeRa_KTZJ@@M!@KCLZZ%`M_O%^*#qg*hG7V}Vje0(akS7I0|Gap!lmWIY#?F5fLcl17P zV6Qm%@+V#!^l?&N!)M-D?Ue8Q^8LxNs&<9?sYmb1+PvGTp%IK0DQB+So(Ez>hYmGE zcf4Ml$%RbiAd>fbgOa+b!_90jrMOlFh#4>l=ySEq&&hz!%j@iG^EX12dA+%%MHa(fjg5_& zYz%O3h4_NLfTN!n19hHZqB9AbB6i$nFo9+J$;ikst^+OwOkIE=S7oO_^Kz35e;7SF z{tAr{2TFN28-nC;SO#g1IlZ0+T}VsYN3Po9q&y;g=FHVcUrrCxD_Xg&ZT;#X&kq2^eZoB*wjG93*aVhvYLfDG^4@E`$a(!Rr3_F_kIY7E4 z+GsQ~LhF1fsrB#Py)!RQj{njm;N|9Sk-xqTUAsCo*i|(RDp{H!4_I+0mK*x5qd-R1 zLF0+h#0A)b^vu1S@#2y(t(~UQF8t}IHF!BREZE*C8w?Q-E(}KXi<20lv7T?YFP4_x zj=8Z#UKZ2eT)Q?iu_{JAcHjQ}ZP@5hn0kVNwE+%|ZzAvATY>T2W;oqC0Rzgqd^yB> zw}FibB6^m^ch;gA`SPQ88hUyGP#}fl*36;QGJJG~@gy_T0%ro9Q!K8YY-ngGt<_}Y zX!neBCgUR%RHnzmDu5i;G2-_I=&Z`at5#rGcn?+#eFBSTXncp0oD00x%%C#YWh^Iw`lf*{73r@2e{^{7Cb;$aKM z_D>@%9wrJ>o|eREqY(SoU&a9v7t`8tvTDUS9j8M>e20tX760wmeY+TpTZQ|~*?j?f zi^mP@FY2O`1lMWu`M5Ye*T1-;JL{zWwsI73lsFV`=UE@4mZ#^6;c5 ziwy5b4eTX;yXd8POL0O@Vjavj9r<>hZAap<>=S>zT7SRLMRc~ZeCGRP?;S7g-(39t zg3_{t%n1kJV4`t(YdL*M#q3x9K8P(IrbrVthz9T86+ zNMFkk^N6sMnny=|TN9|7DCi_670(d!eS${hf>8A-%zUJo1(>TavT>ZJO3IMoVuCM=f4XK`2~50a zjya99aAESo2SJkuZOljQjGh!Z$^l0H@Pj5!;Z_`zLeQt7R<_7)rYqP*OkZ*Er|{R2 z=sK=NZBhs+OU|8Yu_aI69sb($`nKxW#FgoNy)MXpwjg=6QMk@AOiK=svyOq0ln}k% zh2R9!tQ3`$4AASc14rki$&cv()tMjiQVwF1m=qB_gX6T*{t(zhy zy=786v<(3d9;}hdLSFaGuC5^KyWzuUFz3vlpLI>yt+Z(+j3Lb*K74qd0f= z1PKW%hX4Kht6IR^?LMV6=7LKk~VJ0KSbT zfWG$nHk7CE)nv8?toZDhIH=o$r4U??-}&X#sp(7;5Q$-T?!273KNlV*ThP&RoLkO=!5dGr)=yD?Vfob^h)*5&M6=x%CkT|$+LrcBWoIdWulEK;gKcnUfl^70(KJ79sh z2Hu#mR2BxXmfc7L{^fPKmN$;@4TM-DF2QLkS)z~IBbr33LLn^K$m9;@tRo_VLO31xTXX`w^b#>VtL# zYsJRJVM6D4W`$QC^fpmHOG)|q`c}PGk~DUTmYz57CAuElKzT>tQuI(Fku${j#6I96 z5ir9WId-fL018>xuZJ5185xh$hp=>gm7E&|8AhrXXI^H^o;%mYAT!<--E+$E{y{-J zRBt!8lzpeM4Bs=G2@%RdRvIJ}3#Fxbxm`oGOeobx#|c(3tP$&XNX(oW9TLJ|ri-iQ z)a^1tZH98t49qbW-W8~xZowJX=Y9{Igp7b_YG6HKvE4@6UWWpKwQt`oB-6V4+@NHP z9aII4!WG8JQ>Qri3`72zbLVXJ6B$s)#cfmDZ7&_aRcz7+80}wTpy#M32vFrp?ykG* zl9G~?`DGZB0#xNT#1)(6<>me2d25W{DXe_@`0>1X^PUM6dS|NUyx$ds`=de*BMpw- zx_z5!l=-t}-F$2*3DXak&qK;KD|1=Y!K(xf*BeZ zK{SWS!9)n`X1+awM^!=$&vG)?CDL+m#8ku zX+=UTH>&uU`H%{QW501AphCrRg33;0=#jy}!Kn^IzG@y3pK(s{)a1o2Rjc$SXLiD; zK?Cl`mvP#bYiDM1^~_#(!LE6iKGm^=8($UBL#$}9bhT`=HR8~>as zTT};GMf)yofU%<`R_|iBLXh#bP(p*HRpR;HPGNTKEx$w8;DyVcIC=6%oxmv;e8I{= zTGtSOv4`}8e4dVpNfwO<95ep23DPcd@W6Vf#@vfo6ho=;#72qnp9=$`$ zjM9O;Ih8NA7{TkL2&qbU%y6xtG5bIC_H^NuHrb1NT)b^;AML1cot6c+RFrbS_91<2K1Pw6}ucePjdU7Im4)=j&an?1Dsi9?FcJ8Mx;aRA&C+RJz)T@ZM z&<=WTMoV>&97HU&uwH)Zu88J!SOkA%$OpKq=`TBVUt&LYU*mPQHCMg zI`dWR>LS$*8)|TzY9WiT$K%3LppHPW(4hxE)=-gFW>JED$Y26JTVyuHb3r671&7X*&buP z>YQflhR7N@-t0o}=Y4KTcO*PjmYnfPl?<$Y5yY#nKeSO*HA>Y>Vs?T~QD!Gm22cyK z5FG74yXnM#wPai0Yo}mC&y81?m|jo!tiJJc9+BNE(~ys37Ws=%$=LbJ%qZSWK7H0TaF&R zFMs&0C+iE;8v)qTfgn2kaZicPr^iaJL|V0seg4tArGU-nrHBt%a0X}VwEuh*V^NmZ zk=!f{ildLn1KJPr?qzmDNI8{Bj&Tyk@a&Q~a^%P+wiy7MtlZpt*$J8jmnkKBAD=f{{mN9N(9{c6cNIU;pMqh*+oEePCsjx6?1$}Zj&P^o6Z8_T zEMaiE5C24GOxqUz8lD6KZUyay!XLi>e(7SpdrL9(Vi`auS;WIl>=C0zt$?dj>a~;+ z-H}Q#JuGV4v3vJ5Ge}C?T=+aA6>n^ngkBh9;`@DkCh{75Kko9l>$xwt<1JmfR2C(T zGgaK*Ol?tJ12O6us4%a!H6g-Im^>M;tET3l_l+CwOx`#Re^!Zl>TU?lwsChS?F1&x zN6W0wjTBvu6g8#Q)_FFY(5@!P!U7`j$>OvH`f=!(h3QwK~Rr-rlz% z{nNq?u?`=;gA*TphPtoH*Nq@^KRTqu6^kr8fMI91DZPm^^*Vmyge(Y4n-U4J2NMPj z{puaCZ2u`Jy>8L7w$nLO1+e)Q1ici~?CXnnWMyTUqxRV77?q1~uzk$wM@>OLZ2y$e z@o~oJnX5Dal@qRMUKAY(qP7;;Y61Q-5e~dEw0Jh*yOyGA1@FK?*<+3~%(=ahOD7R> z&&7rANcWk?jvaFbgSDBJ5&ihdlUg(oyhMf#+qbZh4L^u!u?XP{=3p!Cz-pT)A>qz! zKwi9l+O%oYLg^!Y`+PJcl5)D>wvxLWFP*S3BNBsveVU9UidFph1`8X z!ka2s`Sal_7UtMBy;x@oybp?;XDo)J@678WW z45zdV2Sb}nkfB=}iKFoTPSwveq)ukI60bo6$0 zcTcBXiS#@IOK0Th(JUl>g@2J^E=61;Igs1_dlPy{I2(}OFj{4igVll6QVnVs?Gh51H(ojT&muEo_oX%oRF zU1ngX-rZg2TZx>Kh1!P-4NuQ=lI(3aR!0Kd*K5z9orU15vu)eO%w&ih6O|`8IXOWG zA5J%flpKVf8v4~U+)-EWODxRr@L=YXhoPC`_hO%d25Bs)t*xD-pirtNgCmN;U|hX= zb*fa>8`KDN)^1{#q&V{Q({S8KWkF_{YuSPH?K}e@g+);=WAq5%?Y$L``tpJC6DDj$;?Nd{xE_^{1 zRk2W6+9>@EXskzSGJEMY7I29T@Bfli;GigQ>aR{@Pokd(BxOsTN|0Y5I0-wP`~ z8N9DB5FvAB&H4?G(jRqhj=42dwAzwrbRX$`>C&Euj~-oMXhvx-hFyWPm-79JCba5g zeK%}a0C2Ye5LEg+N076*fa7w}=Y1f)3=3801{&QLj(+F2cM0?Kt<#Jd{%C#LZAa`S z9xrSv-Q$}&U9ooyLmO|)A?nDob78;I82={T2rSMrm}JW!Dr2B$(c{ca{h)Ys(q|J8 z#H~P^TXgRiA^(M%3?&ibiViD82?UiA9Vm^?HRxlRT|O`dfjq2hl-T`MgGXwN#NrME zE(Lr6J{w!LwXd+gAdm+F^${|j`FX-$XBgh9)tlmw@bDC_2l7CgH*poYLCRw3C1R7> zKsN>AI+GUXWMwUb!FKfJ18^mJw2#^+9PPs$}>$covs zpI9UbO6{{bi(gMw&Df;Gy@mF!%A03K&tMu>eH zK4|E?lSnmp2|7(pOq_kTBS0(ox6BSs#o4=wOcuhB_HQvXyitonQa|m|r60YoUOkAJENi`9Ei=OLqqnyA;ZJVw z+?~2|r|l;nY%G#-0 z7J^D!3n7n7t!O%o`hcq&w~5^fwb@ah(@0T}W?g2uAptNflTdQLml=Dj-SX%{%t`WQ zwDVhSA^|cZp$bJ$L=?_P_H>GJqBE(pWopvf)8u;#DogN-;w@g;A9W2%uGmSNQ}6 zM&U#~h!T>{Cftr;y^=x&rTWg+w{P8Al5B-^f)H`1MNI(PP;%IHwwh6i?sNK=Uyk;i zkGB>WqMG(w7FOJzUl^X7n>)UJsF;QW*pzug`B`bg@0!*jmS|{bTzWCLh$hh#poXUN z9jSZ~&eU)?*XqrmKfmrxQXF=yz-`6TgJ@($MOp+zV#$yAZ?3QzTV=C?hfGuK{>(AV zYEw^O>dt4}6p8cx&`I-HU)f_SKoqih9H6|%4sNVBT?rQaCBW7fAb~>xXUI1L))Jzk zJY-7qm*m1o&CKxTTfEw;N;?JFBkwnm1Odfk5#D>eP1RIRhKvqcg2ocaY{CM~_A(BKs5+~n)01hf-(h*o`PJzK%NnBCJ`gQB@43UPWp4yBm z2XDv>VF5;HL3WtteBajy9=T84=ODM`qDY<8WtePo!ZvTraItxk;5kCyDqLRV{9acJ z!WsT$-}m2r_gxJhS3b-!A|S+Z1AOibrKHc*s}Tqm&bdpg&cR<;74e2@EF>JEK_0!j zKo4cAr5g%Rqs(UF3^x?I%uqVg#$uOkF)k@7VOO>ckvjMMBd%YsemjzZkXV(qi>w4^ z(|J!$uG7&_aB2?W+gOi%yQsA2N%pz)u&PjinFLEfbSRBGanFZe+|NwCghT%PaU=Xt z4C0X8PH`Mue=D?$0HC@*s|K0wS*T$C-ttu9t=+#B2cAot8_J#AGp?ei!(f=$ZUs6? zAQ1D`>JF8}iGl~*9F>Oy)C?Uy*~k)cgV8xAkdcr$B_rs050F778&Nn0=W!$e0IL_n zKUeR(#=f6^GyPL+@ca9QD$MM>y!dsRM^un+8W-spb^7}I>mJ(m6-U|ZtnkaXR02`O zBOTm|3-)6G|9c+p3^rw~QtKuAjv!teCCsOluGpDn=Z#%jZ>EeB z^UML^@3RgB&g|=b3B`d(4JIkd>==*N3?RoG9XNW)c9CtZjZiW?+Mjmrh`~BaM!jNz z_XuO7W8Ws%&sS1PE4IFUj!tGkNj*m2}g)GPz-ogJ)PR{CP|as-d+ia^NFECb*agbCSzyk zWJV;;=P3;{#DWiv)9~C`Q=XE@FaxAxsJeM`a?>M8xbXTioK`>Mg$O?wRK-|#pF?AJ zVs`6O0oKrbWo1Jk(w&$||4#F|2yucEV~0u4eJ#ANxWVO^mh*mx`^VgAc{h~w*>>oe z^|KIUpS36mUX|%3nYb-i|K7oOwrTxnSjBBaCc?~;+U^5mrq}{&TD<%I%l#dYPu@g! z4~lCZim%(N<>YiI|IciOw#E$hGd2LiP*JSThG2z@yyO|Gv}Ma)@ge2#8AMA5g#Z`O zNeBckqa~GhBMpqpCTyms-J>t@_;J^u6YmiwUK56T!TJ6HV`JU9-BaAp2|E*|A7P{G`~ zb!!D)5~9be56yQ7sReu2XA!S&h@^~B>-y}Pob`?PZpb{7(YlM}7l|AK^2LzdT`X

0S%*-xlE^3i@Vj+h8mTCe%iX&gN>P&|bF>HU z+wn$Hr`QPj{YL%|BS+?=Z9f<=iiIxTIHa4>%;|~_(R}szUQsA9CcW%L{*!H*s?=rC$MaHYgPoGX_hGA$@ z(S+1<%4^H7s@&)~{LaP?O6`0#8RQZnswD`Z)=K3mU=8Nro!-Nwp5nP#JiYjA=NL6$ z6cGGeuSMkv_9U*9T0z~M6wfb9R~a4}V(Ku_jqQrceJgmEwhdnqFZ^-(ITg&WONW_pnSWL4|!_?|9dYUdg!C+0K=F%P1Mss=5HbAB5nsNz1FEiH*edf zjkN@+>ydb~*PC408;QGyq%|15@N03(=%G&FGPG)f>#9MWD3O8^*SC%8Ia>kAU&=D{=?d3}i;?Tw_e+?#@(YAUU z9@9Y-UieboyUXK%i@D+aCAAqqYhNIfxZ;E85Y Date: Fri, 18 Aug 2023 13:36:44 +0200 Subject: [PATCH 42/90] replace plotprofile png in planemo test --- galaxy/wrapper/test-data/profiler_result1.png | Bin 46658 -> 42550 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/galaxy/wrapper/test-data/profiler_result1.png b/galaxy/wrapper/test-data/profiler_result1.png index dcb1d2602c657dc703a92def8af9f647c13b8714..a0f14d8b351d0c64028f5ae6d694f9849fe2d1ec 100644 GIT binary patch literal 42550 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 From 2d2088571d0da8e77bad9e09761ac42ccb4f574b Mon Sep 17 00:00:00 2001 From: WardDeb Date: Fri, 18 Aug 2023 14:38:34 +0200 Subject: [PATCH 43/90] test with NA in fp qualmets --- .../wrapper/test-data/plotFingerprint_quality_metrics.tabular | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular b/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular index 6ca50181..1a5bb2d7 100644 --- a/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular +++ b/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular @@ -1,3 +1,3 @@ Sample AUC Synthetic AUC X-intercept Synthetic X-intercept Elbow Point Synthetic Elbow Point JS Distance Synthetic JS Distance % genome enriched diff. enrichment CHANCE divergence -bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 nan 0.26900449806812143 nan nan nan +bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 NA 0.26900449806812143 NA NA NA bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 0.0 0.26900449806812143 0 0 0 From 02d0d11348d5dd90318c24f492920b121cf995f0 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Fri, 18 Aug 2023 15:03:40 +0200 Subject: [PATCH 44/90] remove extra float + switch back to lower case nan qual metrics --- .../wrapper/test-data/plotFingerprint_quality_metrics.tabular | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular b/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular index 1a5bb2d7..f2e16088 100644 --- a/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular +++ b/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular @@ -1,3 +1,3 @@ Sample AUC Synthetic AUC X-intercept Synthetic X-intercept Elbow Point Synthetic Elbow Point JS Distance Synthetic JS Distance % genome enriched diff. enrichment CHANCE divergence -bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 NA 0.26900449806812143 NA NA NA -bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 0.0 0.26900449806812143 0 0 0 +bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 nan 0.2690044980681214 nan nan nan +bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 0.0 0.2690044980681214 0 0 0 From 6fc8baea415f4093263333cab13e22eb7504a907 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Fri, 18 Aug 2023 15:50:41 +0200 Subject: [PATCH 45/90] include dist creation + test wheel install --- .github/workflows/test.yml | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9bb7fcb0..2638132d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -58,15 +58,30 @@ jobs: run: | mamba activate foo pytest - #- name: make an artifact - # run: | - # source activate foo - # rm -f dist/* - # python setup.py sdist - #- uses: actions/upload-artifact@master - # with: - # name: "Dist files" - # path: "dist" + - name: make an artifact + run: | + micromamba activate foo + rm -f dist/* + python -m build + - uses: actions/upload-artifact@master + with: + name: "Dist files" + path: "dist" + test-wheel: + needs: build-linux + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ['3.7','3.8','3.9','3.10'] + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + cache: 'pip' + run: | + pip install dist/*whl + deeptools --version build-osx: name: Test on OSX runs-on: macOS-latest From 60e81f9aecacef3c4bc5c7afbbf77e3e5cefe869 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Fri, 18 Aug 2023 15:51:36 +0200 Subject: [PATCH 46/90] add name to test wheel wf --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2638132d..7f0d3d60 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -68,6 +68,7 @@ jobs: name: "Dist files" path: "dist" test-wheel: + name: test wheel needs: build-linux runs-on: ubuntu-latest strategy: From 250d4f7185313400e4bfa29c2dca9935a21dff2d Mon Sep 17 00:00:00 2001 From: WardDeb Date: Fri, 18 Aug 2023 15:53:22 +0200 Subject: [PATCH 47/90] name in diff place --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7f0d3d60..212d48cb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -68,7 +68,6 @@ jobs: name: "Dist files" path: "dist" test-wheel: - name: test wheel needs: build-linux runs-on: ubuntu-latest strategy: @@ -80,6 +79,7 @@ jobs: with: python-version: ${{ matrix.python-version }} cache: 'pip' + - name: test wheel run: | pip install dist/*whl deeptools --version From 8c2d070e027820e07a20efc8bfa809be56521637 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Fri, 18 Aug 2023 15:56:33 +0200 Subject: [PATCH 48/90] include build in building env --- .github/env.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/env.yml b/.github/env.yml index 718f888d..ce2b2008 100644 --- a/.github/env.yml +++ b/.github/env.yml @@ -4,4 +4,7 @@ channels: dependencies: - python = 3.10 - flake8 - - pytest \ No newline at end of file + - pytest + - pip + - pip: + - build \ No newline at end of file From 755a084535efda8bbcdeb9e181d74f351fab5262 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Fri, 18 Aug 2023 16:04:42 +0200 Subject: [PATCH 49/90] purge checkout from testwheel --- .github/workflows/test.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 212d48cb..a585d356 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -74,7 +74,6 @@ jobs: matrix: python-version: ['3.7','3.8','3.9','3.10'] steps: - - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} From 2ee0a98d54b3a6c07761452c70d7ba0e03c57f3a Mon Sep 17 00:00:00 2001 From: WardDeb Date: Fri, 18 Aug 2023 16:08:34 +0200 Subject: [PATCH 50/90] ship test wheels inside build-linux job --- .github/workflows/test.yml | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a585d356..bb5fa130 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -39,6 +39,9 @@ jobs: build-linux: name: Test on Linux runs-on: ubuntu-latest + strategy: + matrix: + python-version: ['3.7','3.8','3.9','3.10'] steps: - uses: actions/checkout@v3 - uses: mamba-org/setup-micromamba@main @@ -67,21 +70,14 @@ jobs: with: name: "Dist files" path: "dist" - test-wheel: - needs: build-linux - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ['3.7','3.8','3.9','3.10'] - steps: - - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - cache: 'pip' - - name: test wheel - run: | - pip install dist/*whl - deeptools --version + - uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + cache: 'pip' + - name: test wheel + run: | + pip install dist/*whl + deeptools --version build-osx: name: Test on OSX runs-on: macOS-latest From c7374db4bfc11508e26bfb6c763ec047f7a27497 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Fri, 18 Aug 2023 16:14:18 +0200 Subject: [PATCH 51/90] testwheels as separate job with artifact download --- .github/workflows/test.yml | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bb5fa130..af1d6579 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -39,9 +39,6 @@ jobs: build-linux: name: Test on Linux runs-on: ubuntu-latest - strategy: - matrix: - python-version: ['3.7','3.8','3.9','3.10'] steps: - uses: actions/checkout@v3 - uses: mamba-org/setup-micromamba@main @@ -70,14 +67,24 @@ jobs: with: name: "Dist files" path: "dist" - - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - cache: 'pip' - - name: test wheel - run: | - pip install dist/*whl - deeptools --version + test-wheels: + name: test wheel + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ['3.7','3.8','3.9','3.10'] + steps: + - uses: actions/download-artifact@v3 + with: + name: "Dist files" + - uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + cache: 'pip' + - name: install wheel + run: | + pip install dist/*whl + deeptools --version build-osx: name: Test on OSX runs-on: macOS-latest From 4f8a44766f6965388d7cab2f1e6cda3201c1e818 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Fri, 18 Aug 2023 16:15:24 +0200 Subject: [PATCH 52/90] add depends on --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index af1d6579..1dfcf3c5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -70,6 +70,7 @@ jobs: test-wheels: name: test wheel runs-on: ubuntu-latest + needs: build-linux strategy: matrix: python-version: ['3.7','3.8','3.9','3.10'] From 9410a11d7fdfb3cf2356f747fac7588eac4f3013 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Fri, 18 Aug 2023 16:22:51 +0200 Subject: [PATCH 53/90] ls to see if download works --- .github/workflows/test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1dfcf3c5..61df9597 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -84,6 +84,8 @@ jobs: cache: 'pip' - name: install wheel run: | + ls -al + ls dist pip install dist/*whl deeptools --version build-osx: From d3d56048f74eb6f3b6aa9d69c8752a28c4b90989 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Fri, 18 Aug 2023 16:27:26 +0200 Subject: [PATCH 54/90] list wdir after artifact dl --- .github/workflows/test.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 61df9597..57027d78 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -84,10 +84,8 @@ jobs: cache: 'pip' - name: install wheel run: | - ls -al + ls ls dist - pip install dist/*whl - deeptools --version build-osx: name: Test on OSX runs-on: macOS-latest From e6bc30d1b27e862279a82ff96c98ef0cad74c747 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Fri, 18 Aug 2023 16:31:01 +0200 Subject: [PATCH 55/90] add checkout to test-wheels --- .github/workflows/test.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 57027d78..115da07d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -56,7 +56,7 @@ jobs: flake8 . --exclude=.venv,.build,build --ignore=E501,F403,E402,F999,F405,E722,W504,W605 - name: Test deepTools run: | - mamba activate foo + micromamba activate foo pytest - name: make an artifact run: | @@ -75,6 +75,7 @@ jobs: matrix: python-version: ['3.7','3.8','3.9','3.10'] steps: + - uses: actions/checkout@v3 - uses: actions/download-artifact@v3 with: name: "Dist files" From c836875b587ff318392699cf7e6fd12a68002f91 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Fri, 18 Aug 2023 16:36:54 +0200 Subject: [PATCH 56/90] whl in dist folder --- .github/workflows/test.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 115da07d..647b389f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -79,14 +79,15 @@ jobs: - uses: actions/download-artifact@v3 with: name: "Dist files" + path: ~/dist/ - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} cache: 'pip' - name: install wheel run: | - ls - ls dist + pip install dist/*whl + deeptools -h build-osx: name: Test on OSX runs-on: macOS-latest From 8bcb1731ba19c00a288706a9d9c775010d01cc19 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Fri, 18 Aug 2023 16:39:47 +0200 Subject: [PATCH 57/90] tilde in pip install --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 647b389f..e6f686d3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -86,7 +86,7 @@ jobs: cache: 'pip' - name: install wheel run: | - pip install dist/*whl + pip install ~/dist/*whl deeptools -h build-osx: name: Test on OSX From b84e4edbdffd1bf4a1074ee50b61bacbec10a67a Mon Sep 17 00:00:00 2001 From: WardDeb Date: Sat, 19 Aug 2023 09:45:03 +0200 Subject: [PATCH 58/90] importlib toml req for python 3.7 --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 7c3d2a0d..fbc65a2e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,8 @@ dependencies = [ "pyBigWig >= 0.2.1", "py2bit >= 0.2.0", "plotly >= 4.9", - "deeptoolsintervals >= 0.1.8" + "deeptoolsintervals >= 0.1.8", + "importlib-metadata" # python 3.7 support ] description = "Useful tools for exploring deep sequencing data." license = {file = "LICENSE.txt"} From 2efc3f2a1d97cf39e4f25a52046dee5ff88a6a01 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Sat, 19 Aug 2023 10:09:46 +0200 Subject: [PATCH 59/90] importlib escapes for python 3.7 --- deeptools/alignmentSieve.py | 5 ++++- deeptools/bamPEFragmentSize.py | 5 ++++- deeptools/computeMatrix.py | 5 ++++- deeptools/computeMatrixOperations.py | 5 ++++- deeptools/deeptools_list_tools.py | 5 ++++- deeptools/estimateReadFiltering.py | 5 ++++- deeptools/multiBamSummary.py | 5 ++++- deeptools/multiBigwigSummary.py | 5 ++++- deeptools/parserCommon.py | 5 ++++- deeptools/plotCorrelation.py | 5 ++++- deeptools/plotCoverage.py | 5 ++++- deeptools/plotPCA.py | 5 ++++- 12 files changed, 48 insertions(+), 12 deletions(-) diff --git a/deeptools/alignmentSieve.py b/deeptools/alignmentSieve.py index 9e1d621b..7a04b242 100644 --- a/deeptools/alignmentSieve.py +++ b/deeptools/alignmentSieve.py @@ -7,7 +7,10 @@ from deeptools import parserCommon from deeptools.bamHandler import openBam from deeptools.mapReduce import mapReduce -from importlib.metadata import version +try: # keep python 3.7 support. + from importlib.metadata import version +except ModuleNotFoundError: + from importlib_metadata import version from deeptools.utilities import getTLen, smartLabels, getTempFileName diff --git a/deeptools/bamPEFragmentSize.py b/deeptools/bamPEFragmentSize.py index 35cedfa4..cb02f2c0 100755 --- a/deeptools/bamPEFragmentSize.py +++ b/deeptools/bamPEFragmentSize.py @@ -18,7 +18,10 @@ # own tools from deeptools.parserCommon import writableFile from deeptools.getFragmentAndReadSize import get_read_and_fragment_length -from importlib.metadata import version +try: # keep python 3.7 support. + from importlib.metadata import version +except ModuleNotFoundError: + from importlib_metadata import version def parse_arguments(): diff --git a/deeptools/computeMatrix.py b/deeptools/computeMatrix.py index 25cf9521..5fe77678 100644 --- a/deeptools/computeMatrix.py +++ b/deeptools/computeMatrix.py @@ -7,7 +7,10 @@ import multiprocessing from deeptools.parserCommon import writableFile, numberOfProcessors -from importlib.metadata import version +try: # keep python 3.7 support. + from importlib.metadata import version +except ModuleNotFoundError: + from importlib_metadata import version from deeptools import parserCommon from deeptools import heatmapper import deeptools.computeMatrixOperations as cmo diff --git a/deeptools/computeMatrixOperations.py b/deeptools/computeMatrixOperations.py index 6b3272d4..d0172bc1 100755 --- a/deeptools/computeMatrixOperations.py +++ b/deeptools/computeMatrixOperations.py @@ -6,7 +6,10 @@ import sys import os import csv -from importlib.metadata import version +try: # keep python 3.7 support. + from importlib.metadata import version +except ModuleNotFoundError: + from importlib_metadata import version def parse_arguments(): diff --git a/deeptools/deeptools_list_tools.py b/deeptools/deeptools_list_tools.py index 32dcf702..3d530c62 100644 --- a/deeptools/deeptools_list_tools.py +++ b/deeptools/deeptools_list_tools.py @@ -3,7 +3,10 @@ import argparse import sys -from importlib.metadata import version +try: # keep python 3.7 support. + from importlib.metadata import version +except ModuleNotFoundError: + from importlib_metadata import version def parse_arguments(args=None): diff --git a/deeptools/estimateReadFiltering.py b/deeptools/estimateReadFiltering.py index 63b02327..051ad55d 100644 --- a/deeptools/estimateReadFiltering.py +++ b/deeptools/estimateReadFiltering.py @@ -5,7 +5,10 @@ from deeptools import parserCommon, bamHandler, utilities from deeptools.mapReduce import mapReduce from deeptools.utilities import smartLabels -from importlib.metadata import version +try: # keep python 3.7 support. + from importlib.metadata import version +except ModuleNotFoundError: + from importlib_metadata import version def parseArguments(): diff --git a/deeptools/multiBamSummary.py b/deeptools/multiBamSummary.py index 433adb4e..04cf376c 100644 --- a/deeptools/multiBamSummary.py +++ b/deeptools/multiBamSummary.py @@ -9,7 +9,10 @@ import deeptools.countReadsPerBin as countR from deeptools import parserCommon from deeptools.utilities import smartLabels -from importlib.metadata import version +try: # keep python 3.7 support. + from importlib.metadata import version +except ModuleNotFoundError: + from importlib_metadata import version old_settings = np.seterr(all='ignore') diff --git a/deeptools/multiBigwigSummary.py b/deeptools/multiBigwigSummary.py index ad616090..4653769e 100644 --- a/deeptools/multiBigwigSummary.py +++ b/deeptools/multiBigwigSummary.py @@ -7,10 +7,13 @@ import numpy as np import multiprocessing from deeptools import parserCommon -from importlib.metadata import version from deeptools.utilities import smartLabels import deeptools.getScorePerBigWigBin as score_bw import deeptools.deepBlue as db +try: # keep python 3.7 support. + from importlib.metadata import version +except ModuleNotFoundError: + from importlib_metadata import version old_settings = np.seterr(all='ignore') diff --git a/deeptools/parserCommon.py b/deeptools/parserCommon.py index 8e726ea0..c144745b 100755 --- a/deeptools/parserCommon.py +++ b/deeptools/parserCommon.py @@ -1,6 +1,9 @@ import argparse import os -from importlib.metadata import version +try: # keep python 3.7 support. + from importlib.metadata import version +except ModuleNotFoundError: + from importlib_metadata import version def check_float_0_1(value): diff --git a/deeptools/plotCorrelation.py b/deeptools/plotCorrelation.py index e3a553f5..fe330335 100644 --- a/deeptools/plotCorrelation.py +++ b/deeptools/plotCorrelation.py @@ -13,7 +13,10 @@ from deeptools.correlation import Correlation from deeptools.parserCommon import writableFile -from importlib.metadata import version +try: # keep python 3.7 support. + from importlib.metadata import version +except ModuleNotFoundError: + from importlib_metadata import version old_settings = np.seterr(all='ignore') diff --git a/deeptools/plotCoverage.py b/deeptools/plotCoverage.py index d0b8613b..35e22a9d 100755 --- a/deeptools/plotCoverage.py +++ b/deeptools/plotCoverage.py @@ -18,7 +18,10 @@ import deeptools.countReadsPerBin as countR from deeptools import parserCommon from deeptools.utilities import smartLabels -from importlib.metadata import version +try: # keep python 3.7 support. + from importlib.metadata import version +except ModuleNotFoundError: + from importlib_metadata import version old_settings = np.seterr(all='ignore') diff --git a/deeptools/plotPCA.py b/deeptools/plotPCA.py index 394dcfba..23a964c4 100644 --- a/deeptools/plotPCA.py +++ b/deeptools/plotPCA.py @@ -11,7 +11,10 @@ from deeptools.correlation import Correlation from deeptools.parserCommon import writableFile -from importlib.metadata import version +try: # keep python 3.7 support. + from importlib.metadata import version +except ModuleNotFoundError: + from importlib_metadata import version def parse_arguments(args=None): From da21abe67b24b31eb328b0e9522beec9e9529134 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Sat, 19 Aug 2023 10:14:09 +0200 Subject: [PATCH 60/90] flake fix try except --- deeptools/alignmentSieve.py | 2 +- deeptools/bamPEFragmentSize.py | 2 +- deeptools/computeMatrix.py | 2 +- deeptools/computeMatrixOperations.py | 2 +- deeptools/deeptools_list_tools.py | 2 +- deeptools/estimateReadFiltering.py | 2 +- deeptools/multiBamSummary.py | 2 +- deeptools/multiBigwigSummary.py | 2 +- deeptools/parserCommon.py | 2 +- deeptools/plotCorrelation.py | 2 +- deeptools/plotCoverage.py | 2 +- deeptools/plotPCA.py | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/deeptools/alignmentSieve.py b/deeptools/alignmentSieve.py index 7a04b242..c795c470 100644 --- a/deeptools/alignmentSieve.py +++ b/deeptools/alignmentSieve.py @@ -7,7 +7,7 @@ from deeptools import parserCommon from deeptools.bamHandler import openBam from deeptools.mapReduce import mapReduce -try: # keep python 3.7 support. +try: # keep python 3.7 support. from importlib.metadata import version except ModuleNotFoundError: from importlib_metadata import version diff --git a/deeptools/bamPEFragmentSize.py b/deeptools/bamPEFragmentSize.py index cb02f2c0..72590c38 100755 --- a/deeptools/bamPEFragmentSize.py +++ b/deeptools/bamPEFragmentSize.py @@ -18,7 +18,7 @@ # own tools from deeptools.parserCommon import writableFile from deeptools.getFragmentAndReadSize import get_read_and_fragment_length -try: # keep python 3.7 support. +try: # keep python 3.7 support. from importlib.metadata import version except ModuleNotFoundError: from importlib_metadata import version diff --git a/deeptools/computeMatrix.py b/deeptools/computeMatrix.py index 5fe77678..8351b1d2 100644 --- a/deeptools/computeMatrix.py +++ b/deeptools/computeMatrix.py @@ -7,7 +7,7 @@ import multiprocessing from deeptools.parserCommon import writableFile, numberOfProcessors -try: # keep python 3.7 support. +try: # keep python 3.7 support. from importlib.metadata import version except ModuleNotFoundError: from importlib_metadata import version diff --git a/deeptools/computeMatrixOperations.py b/deeptools/computeMatrixOperations.py index d0172bc1..b246b9ce 100755 --- a/deeptools/computeMatrixOperations.py +++ b/deeptools/computeMatrixOperations.py @@ -6,7 +6,7 @@ import sys import os import csv -try: # keep python 3.7 support. +try: # keep python 3.7 support. from importlib.metadata import version except ModuleNotFoundError: from importlib_metadata import version diff --git a/deeptools/deeptools_list_tools.py b/deeptools/deeptools_list_tools.py index 3d530c62..0e4b6a38 100644 --- a/deeptools/deeptools_list_tools.py +++ b/deeptools/deeptools_list_tools.py @@ -3,7 +3,7 @@ import argparse import sys -try: # keep python 3.7 support. +try: # keep python 3.7 support. from importlib.metadata import version except ModuleNotFoundError: from importlib_metadata import version diff --git a/deeptools/estimateReadFiltering.py b/deeptools/estimateReadFiltering.py index 051ad55d..148006d0 100644 --- a/deeptools/estimateReadFiltering.py +++ b/deeptools/estimateReadFiltering.py @@ -5,7 +5,7 @@ from deeptools import parserCommon, bamHandler, utilities from deeptools.mapReduce import mapReduce from deeptools.utilities import smartLabels -try: # keep python 3.7 support. +try: # keep python 3.7 support. from importlib.metadata import version except ModuleNotFoundError: from importlib_metadata import version diff --git a/deeptools/multiBamSummary.py b/deeptools/multiBamSummary.py index 04cf376c..f0caadb5 100644 --- a/deeptools/multiBamSummary.py +++ b/deeptools/multiBamSummary.py @@ -9,7 +9,7 @@ import deeptools.countReadsPerBin as countR from deeptools import parserCommon from deeptools.utilities import smartLabels -try: # keep python 3.7 support. +try: # keep python 3.7 support. from importlib.metadata import version except ModuleNotFoundError: from importlib_metadata import version diff --git a/deeptools/multiBigwigSummary.py b/deeptools/multiBigwigSummary.py index 4653769e..cafee224 100644 --- a/deeptools/multiBigwigSummary.py +++ b/deeptools/multiBigwigSummary.py @@ -10,7 +10,7 @@ from deeptools.utilities import smartLabels import deeptools.getScorePerBigWigBin as score_bw import deeptools.deepBlue as db -try: # keep python 3.7 support. +try: # keep python 3.7 support. from importlib.metadata import version except ModuleNotFoundError: from importlib_metadata import version diff --git a/deeptools/parserCommon.py b/deeptools/parserCommon.py index c144745b..37e9f359 100755 --- a/deeptools/parserCommon.py +++ b/deeptools/parserCommon.py @@ -1,6 +1,6 @@ import argparse import os -try: # keep python 3.7 support. +try: # keep python 3.7 support. from importlib.metadata import version except ModuleNotFoundError: from importlib_metadata import version diff --git a/deeptools/plotCorrelation.py b/deeptools/plotCorrelation.py index fe330335..f427d769 100644 --- a/deeptools/plotCorrelation.py +++ b/deeptools/plotCorrelation.py @@ -13,7 +13,7 @@ from deeptools.correlation import Correlation from deeptools.parserCommon import writableFile -try: # keep python 3.7 support. +try: # keep python 3.7 support. from importlib.metadata import version except ModuleNotFoundError: from importlib_metadata import version diff --git a/deeptools/plotCoverage.py b/deeptools/plotCoverage.py index 35e22a9d..1aeacdf7 100755 --- a/deeptools/plotCoverage.py +++ b/deeptools/plotCoverage.py @@ -18,7 +18,7 @@ import deeptools.countReadsPerBin as countR from deeptools import parserCommon from deeptools.utilities import smartLabels -try: # keep python 3.7 support. +try: # keep python 3.7 support. from importlib.metadata import version except ModuleNotFoundError: from importlib_metadata import version diff --git a/deeptools/plotPCA.py b/deeptools/plotPCA.py index 23a964c4..409f9639 100644 --- a/deeptools/plotPCA.py +++ b/deeptools/plotPCA.py @@ -11,7 +11,7 @@ from deeptools.correlation import Correlation from deeptools.parserCommon import writableFile -try: # keep python 3.7 support. +try: # keep python 3.7 support. from importlib.metadata import version except ModuleNotFoundError: from importlib_metadata import version From a1eb5558148621fdc0a68399f709795b9a0062f7 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Sat, 19 Aug 2023 15:02:04 +0200 Subject: [PATCH 61/90] test pypi build with micromamba --- .github/env.yml | 1 + .github/workflows/pypi.yml | 54 +++++++++++++++++++------------------- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/.github/env.yml b/.github/env.yml index ce2b2008..e216f344 100644 --- a/.github/env.yml +++ b/.github/env.yml @@ -5,6 +5,7 @@ dependencies: - python = 3.10 - flake8 - pytest + - twine - pip - pip: - build \ No newline at end of file diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index e30e5771..f8df1391 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -1,35 +1,35 @@ name: pypi -on: - create: - tags: +on: [push, pull_request] +#on: +# create: +# tags: + +defaults: + run: + shell: bash -l {0} + jobs: pypi: name: upload to pypi runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - name: Setup conda + - uses: actions/checkout@v3 + - uses: mamba-org/setup-micromamba@main + with: + environment-file: .github/env.yml + cache-downloads: true + environment-name: foo + - name: build run: | - curl https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -o miniconda.sh - bash miniconda.sh -b -p $HOME/miniconda - export PATH="$HOME/miniconda/bin:$PATH" - hash -r - conda config --set always_yes yes --set changeps1 no - - name: create env - run: | - export PATH=$HOME/miniconda/bin:$PATH - conda create -n foo -q --yes -c conda-forge -c bioconda python=3.7 twine - - name: sdist - run: | - export PATH=$HOME/miniconda/bin:$PATH - source activate foo + micromamba activate foo rm -f dist/* - python setup.py sdist - - name: upload - env: - TWINE_USERNAME: "__token__" - TWINE_PASSWORD: ${{ secrets.pypi_password }} - run: | - export PATH=$HOME/miniconda/bin:$PATH - source activate foo - twine upload dist/* + python -m build + which twine + #- name: upload + # env: + # TWINE_USERNAME: "__token__" + # TWINE_PASSWORD: ${{ secrets.pypi_password }} + # run: | + # export PATH=$HOME/miniconda/bin:$PATH + # source activate foo + # twine upload dist/* From e27b9080d0867abec559767df111c30c481117d3 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Sat, 19 Aug 2023 15:08:50 +0200 Subject: [PATCH 62/90] pypi push on tag --- .github/workflows/pypi.yml | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index f8df1391..5f973d37 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -1,8 +1,8 @@ name: pypi -on: [push, pull_request] -#on: -# create: -# tags: + +on: + create: + tags: defaults: run: @@ -24,12 +24,10 @@ jobs: micromamba activate foo rm -f dist/* python -m build - which twine - #- name: upload - # env: - # TWINE_USERNAME: "__token__" - # TWINE_PASSWORD: ${{ secrets.pypi_password }} - # run: | - # export PATH=$HOME/miniconda/bin:$PATH - # source activate foo - # twine upload dist/* + - name: upload + env: + TWINE_USERNAME: "__token__" + TWINE_PASSWORD: ${{ secrets.pypi_password }} + run: | + micromamba activate foo + twine upload dist/* From 9c2a86dd02ba324e74ebed2752f4642d97fabf70 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Mon, 21 Aug 2023 13:35:41 +0200 Subject: [PATCH 63/90] include pytest in test-wheels --- .github/workflows/test.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e6f686d3..24146377 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -88,6 +88,10 @@ jobs: run: | pip install ~/dist/*whl deeptools -h + - name: pytest + run: | + pip install pytest + pytest build-osx: name: Test on OSX runs-on: macOS-latest From a11eedcf6e31b0b2659446f2cd3afb18a244d03d Mon Sep 17 00:00:00 2001 From: WardDeb Date: Mon, 21 Aug 2023 14:28:35 +0200 Subject: [PATCH 64/90] rounding qual metrics fingerprint galaxy test --- .../wrapper/test-data/plotFingerprint_quality_metrics.tabular | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular b/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular index f2e16088..84d5d720 100644 --- a/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular +++ b/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular @@ -1,3 +1,3 @@ Sample AUC Synthetic AUC X-intercept Synthetic X-intercept Elbow Point Synthetic Elbow Point JS Distance Synthetic JS Distance % genome enriched diff. enrichment CHANCE divergence -bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 nan 0.2690044980681214 nan nan nan -bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 0.0 0.2690044980681214 0 0 0 +bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 nan 0.2690044980681213 nan nan nan +bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 0.0 0.2690044980681213 0 0 0 From 09a7a9547828429aed555f96e84b9c69fc1cd809 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Mon, 21 Aug 2023 14:45:56 +0200 Subject: [PATCH 65/90] set version to 3.5.3 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index fbc65a2e..68e9cabb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ requires = [ [project] name = "deepTools" -version = "3.5.3.dev1" +version = "3.5.3" authors = [ {name="Fidel Ramirez"}, {name="Devon P Ryan"}, From 1b3ae45029c4fde32c4bebd721632be42db67aef Mon Sep 17 00:00:00 2001 From: WardDeb Date: Mon, 21 Aug 2023 15:03:44 +0200 Subject: [PATCH 66/90] revert back to fingerprint qual metrics --- .../wrapper/test-data/plotFingerprint_quality_metrics.tabular | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular b/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular index 84d5d720..f2e16088 100644 --- a/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular +++ b/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular @@ -1,3 +1,3 @@ Sample AUC Synthetic AUC X-intercept Synthetic X-intercept Elbow Point Synthetic Elbow Point JS Distance Synthetic JS Distance % genome enriched diff. enrichment CHANCE divergence -bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 nan 0.2690044980681213 nan nan nan -bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 0.0 0.2690044980681213 0 0 0 +bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 nan 0.2690044980681214 nan nan nan +bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 0.0 0.2690044980681214 0 0 0 From 6b4ad368179fb03a81c59698a4c4ef7bf893c07c Mon Sep 17 00:00:00 2001 From: WardDeb Date: Mon, 21 Aug 2023 15:23:08 +0200 Subject: [PATCH 67/90] rollback galaxy again --- .../wrapper/test-data/plotFingerprint_quality_metrics.tabular | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular b/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular index f2e16088..84d5d720 100644 --- a/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular +++ b/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular @@ -1,3 +1,3 @@ Sample AUC Synthetic AUC X-intercept Synthetic X-intercept Elbow Point Synthetic Elbow Point JS Distance Synthetic JS Distance % genome enriched diff. enrichment CHANCE divergence -bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 nan 0.2690044980681214 nan nan nan -bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 0.0 0.2690044980681214 0 0 0 +bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 nan 0.2690044980681213 nan nan nan +bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 0.0 0.2690044980681213 0 0 0 From f0ad1f0c1631fc0cc4d7d3f055c9eb7ee3c3e9ad Mon Sep 17 00:00:00 2001 From: WardDeb Date: Mon, 21 Aug 2023 15:45:52 +0200 Subject: [PATCH 68/90] update installation instructions doc --- docs/content/installation.rst | 36 +++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/content/installation.rst b/docs/content/installation.rst index c45ecacf..d0f77ac7 100644 --- a/docs/content/installation.rst +++ b/docs/content/installation.rst @@ -10,26 +10,26 @@ Remember -- deepTools are available for **command line usage** as well as for Requirements ------------- -* Python 2.7 or Python 3.x -* numpy >= 1.8.0 +* Python >= 3.7 +* numpy >= 1.9.0 * scipy >= 0.17.0 -* py2bit >= 0.1.0 +* matplotlib >= 3.3.0 +* pysam >= 0.14.0 +* numpydoc >= 0.5 * pyBigWig >= 0.2.1 -* pysam >= 0.8 -* matplotlib >= 1.4.0 +* py2bit >= 0.2.0 +* plotly >= 4.9 +* deeptoolsintervals >= 0.1.8 +* importlib-metadata (when running python 3.7) -The fastest way to obtain **Python 2.7 or Python 3.x together with numpy and scipy** is -via the `Anaconda Scientific Python -Distribution `_. -Just download the version that's suitable for your operating system and -follow the directions for its installation. All of the requirements for deepTools can be installed in Anaconda with: +DeepTools (including the requirements) can be installed with conda: .. code:: bash $ conda install -c bioconda deeptools -Command line installation using ``pip`` ------------------------------------------ +Command line installation using ``pip`` from pypi +-------------------------------------------------- Install deepTools using the following command: :: @@ -45,10 +45,10 @@ If you need to specify a specific path for the installation of the tools, make u $ pip install --install-option="--prefix=/MyPath/Tools/deepTools2.0" git+https://github.com/deeptools/deepTools.git -Command line installation without ``pip`` -------------------------------------------- +Command line installation using ``pip`` from source +--------------------------------------------------- -You are highly recommended to use `pip` rather than these more complicated steps. +You are highly recommended to use the 'pypi installation' rather than these more complicated steps. 1. Install the requirements listed above in the "requirements" section. This is done automatically by `pip`. @@ -63,11 +63,11 @@ or if you want a particular release, choose one from https://github.com/deeptool $ wget https://github.com/deeptools/deepTools/archive/1.5.12.tar.gz $ tar -xzvf -3. install the source code (if you don't have root permission, you can set -a specific folder using the ``--prefix`` option) +3. install the source code :: - $ python setup.py install --prefix /User/Tools/deepTools2.0 + $ python -m build + $ pip install dist/*whl Galaxy installation -------------------- From e5a051da6654bbe1204c883ee0a28dc22307c46d Mon Sep 17 00:00:00 2001 From: WardDeb Date: Mon, 21 Aug 2023 16:18:19 +0200 Subject: [PATCH 69/90] qual metrics 14 --- .../wrapper/test-data/plotFingerprint_quality_metrics.tabular | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular b/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular index 84d5d720..f2e16088 100644 --- a/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular +++ b/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular @@ -1,3 +1,3 @@ Sample AUC Synthetic AUC X-intercept Synthetic X-intercept Elbow Point Synthetic Elbow Point JS Distance Synthetic JS Distance % genome enriched diff. enrichment CHANCE divergence -bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 nan 0.2690044980681213 nan nan nan -bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 0.0 0.2690044980681213 0 0 0 +bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 nan 0.2690044980681214 nan nan nan +bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 0.0 0.2690044980681214 0 0 0 From d7543b1a51502df172c26546b64d10f4b26445b5 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Tue, 22 Aug 2023 11:50:04 +0200 Subject: [PATCH 70/90] usage and -h for all executables --- deeptools/alignmentSieve.py | 3 +- deeptools/bamCompare.py | 3 +- deeptools/bamCoverage.py | 4 +- deeptools/bamPEFragmentSize.py | 9 ++- deeptools/bigwigAverage.py | 7 +- deeptools/bigwigCompare.py | 4 +- deeptools/computeGCBias.py | 5 +- deeptools/computeMatrix.py | 4 + deeptools/correctGCBias.py | 8 +- deeptools/estimateReadFiltering.py | 4 +- deeptools/estimateScaleFactor.py | 117 +++++++++++++++++++++++++++++ deeptools/multiBamSummary.py | 12 ++- deeptools/multiBigwigSummary.py | 10 ++- deeptools/plotCorrelation.py | 4 +- deeptools/plotCoverage.py | 4 +- deeptools/plotEnrichment.py | 4 +- deeptools/plotFingerprint.py | 6 +- deeptools/plotHeatmap.py | 4 +- deeptools/plotPCA.py | 4 +- deeptools/plotProfile.py | 6 +- 20 files changed, 194 insertions(+), 28 deletions(-) create mode 100644 deeptools/estimateScaleFactor.py diff --git a/deeptools/alignmentSieve.py b/deeptools/alignmentSieve.py index c795c470..4f2aa187 100644 --- a/deeptools/alignmentSieve.py +++ b/deeptools/alignmentSieve.py @@ -18,7 +18,8 @@ def parseArguments(): parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, description="This tool filters alignments in a BAM/CRAM file according the the specified parameters. It can optionally output to BEDPE format.", - usage='Example usage: alignmentSieve.py -b sample1.bam -o sample1.filtered.bam --minMappingQuality 10 --filterMetrics log.txt') + usage='alignmentSieve -b sample1.bam -o sample1.filtered.bam --minMappingQuality 10 --filterMetrics log.txt\n' + 'help: alignmentSieve -h / alignmentSieve --help') required = parser.add_argument_group('Required arguments') required.add_argument('--bam', '-b', diff --git a/deeptools/bamCompare.py b/deeptools/bamCompare.py index 9f19321f..223bc06c 100644 --- a/deeptools/bamCompare.py +++ b/deeptools/bamCompare.py @@ -44,7 +44,8 @@ def parseArguments(): 'independently. If this is undesirable, then use the --samFlagInclude ' 'or --samFlagExclude options.', - usage=' bamCompare -b1 treatment.bam -b2 control.bam -o log2ratio.bw', + usage='bamCompare -b1 treatment.bam -b2 control.bam -o log2ratio.bw\n' + 'help: bamCompare -h / bamCompare --help', add_help=False) diff --git a/deeptools/bamCoverage.py b/deeptools/bamCoverage.py index c0002a59..acca196f 100644 --- a/deeptools/bamCoverage.py +++ b/deeptools/bamCoverage.py @@ -36,8 +36,8 @@ def parseArguments(): 'Million mapped reads (RPKM), counts per million (CPM), bins per ' 'million mapped reads (BPM) and 1x depth (reads per genome ' 'coverage, RPGC).\n', - usage='An example usage is:' - '$ bamCoverage -b reads.bam -o coverage.bw', + usage='bamCoverage -b reads.bam -o coverage.bw\n' + 'help: bamCoverage -h / bamCoverage --help', add_help=False) return parser diff --git a/deeptools/bamPEFragmentSize.py b/deeptools/bamPEFragmentSize.py index 72590c38..9c9e92f2 100755 --- a/deeptools/bamPEFragmentSize.py +++ b/deeptools/bamPEFragmentSize.py @@ -33,7 +33,10 @@ def parse_arguments(): 'Properly paired reads are preferred for computation, i.e., ' 'it will only use discordant pairs if no concordant alignments ' 'overlap with a given region. ' - 'The default setting simply prints the summary statistics to the screen.') + 'The default setting simply prints the summary statistics to the screen.', + usage='bamPEFragmentSize -b sample1.bam sample2.bam -o hist.png\n' + 'help: bamPEFragmentSize -h / bamPEFragmentSize --help' + ) parser.add_argument('--bamfiles', '-b', help='List of BAM files to process', nargs='+', @@ -293,6 +296,10 @@ def printTable(args, fragDict, readDict): def main(args=None): args = parse_arguments().parse_args(args) + if len(sys.argv) == 1: + parse_arguments().print_help() + sys.exit() + fraglengths = {} readlengths = {} of = None diff --git a/deeptools/bigwigAverage.py b/deeptools/bigwigAverage.py index 5cc41553..7153d98f 100644 --- a/deeptools/bigwigAverage.py +++ b/deeptools/bigwigAverage.py @@ -23,7 +23,9 @@ def parse_arguments(args=None): 'of mapped reads. To average the bigWig files, the genome is ' 'partitioned into bins of equal size, then the scores ' 'in each bigwig file are computed per bin.' - 'These scores are averaged and scaleFactors can be applied before the average.') + 'These scores are averaged and scaleFactors can be applied before the average.', + usage='bigwigAverage -b sample1.bw sample2.bw -o outfile.bw\n' + 'help: bigwigAverage -h / bigwigAverage --help') # define the arguments parser.add_argument('--bigwigs', '-b', @@ -94,6 +96,9 @@ def average(tileCoverage, args): def main(args=None): args = parse_arguments().parse_args(args) + if len(sys.argv) == 1: + parse_arguments().print_help() + sys.exit() nFiles = len(args.bigwigs) diff --git a/deeptools/bigwigCompare.py b/deeptools/bigwigCompare.py index dc1a70e0..4e15c7df 100644 --- a/deeptools/bigwigCompare.py +++ b/deeptools/bigwigCompare.py @@ -24,7 +24,9 @@ def parse_arguments(args=None): 'partitioned into bins of equal size, then the number of reads found ' 'in each BAM file are counted per bin and finally a summary ' 'value is reported. This value can be the ratio of the number of reads' - 'per bin, the log2 of the ratio, the sum or the difference.') + 'per bin, the log2 of the ratio, the sum or the difference.', + usage='bigwigCompare -b1 sample1.bw -b2 sample2.bw -o log2.bw\n' + 'help: bigwigCompare -h / bigwigCompare --help') # define the arguments parser.add_argument('--bigwig1', '-b1', diff --git a/deeptools/computeGCBias.py b/deeptools/computeGCBias.py index 0c51f906..f261a9fc 100755 --- a/deeptools/computeGCBias.py +++ b/deeptools/computeGCBias.py @@ -30,8 +30,9 @@ def parse_arguments(args=None): '[Benjamini & Speed (2012). Nucleic Acids Research, 40(10). doi: 10.1093/nar/gks001]. ' 'The GC-bias is visualized and the resulting table can be used to' 'correct the bias with `correctGCBias`.', - usage='\n computeGCBias ' - '-b file.bam --effectiveGenomeSize 2150570000 -g mm9.2bit -l 200 --GCbiasFrequenciesFile freq.txt [options]', + usage='computeGCBias ' + '-b file.bam --effectiveGenomeSize 2150570000 -g mm9.2bit -l 200 --GCbiasFrequenciesFile freq.txt\n' + 'help: computeGCBias -h / computeGCBias --help', conflict_handler='resolve', add_help=False) diff --git a/deeptools/computeMatrix.py b/deeptools/computeMatrix.py index 8351b1d2..440358c9 100644 --- a/deeptools/computeMatrix.py +++ b/deeptools/computeMatrix.py @@ -356,6 +356,10 @@ def computeMatrixOptArgs(case=['scale-regions', 'reference-point'][0]): def process_args(args=None): args = parse_arguments().parse_args(args) + if len(sys.argv) == 1: + parse_arguments().print_help() + sys.exit() + if args.quiet is True: args.verbose = False diff --git a/deeptools/correctGCBias.py b/deeptools/correctGCBias.py index ba6d893a..404b8740 100755 --- a/deeptools/correctGCBias.py +++ b/deeptools/correctGCBias.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python + #!/usr/bin/env python # -*- coding: utf-8 -*- import os @@ -38,10 +38,10 @@ def parse_arguments(args=None): '(typically AT-rich regions). ' 'The tool ``computeGCBias`` needs to be run first to generate the ' 'frequency table needed here.', - usage='An example usage is:\n correctGCBias ' + usage='correctGCBias ' '-b file.bam --effectiveGenomeSize 2150570000 -g mm9.2bit ' - '--GCbiasFrequenciesFile freq.txt -o gc_corrected.bam ' - '[options]', + '--GCbiasFrequenciesFile freq.txt -o gc_corrected.bam\n' + 'help: correctGCBias -h / correctGCBias --help', conflict_handler='resolve', add_help=False) return parser diff --git a/deeptools/estimateReadFiltering.py b/deeptools/estimateReadFiltering.py index 148006d0..d7427403 100644 --- a/deeptools/estimateReadFiltering.py +++ b/deeptools/estimateReadFiltering.py @@ -34,7 +34,9 @@ def parseArguments(): The sum of these may be more than the total number of reads. Note that alignments are sampled from bins of size --binSize spaced --distanceBetweenBins apart. """, - usage='Example usage: estimateReadFiltering.py -b sample1.bam sample2.bam > log.txt') + usage='estimateReadFiltering -b sample1.bam sample2.bam\n' + 'help: estimateReadFiltering -h / estimateReadFiltering --help' + ) required = parser.add_argument_group('Required arguments') required.add_argument('--bamfiles', '-b', diff --git a/deeptools/estimateScaleFactor.py b/deeptools/estimateScaleFactor.py new file mode 100644 index 00000000..c3650ad4 --- /dev/null +++ b/deeptools/estimateScaleFactor.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python +#-*- coding: utf-8 -*- + +import deeptools.misc +import argparse +import sys + +from deeptools.SES_scaleFactor import estimateScaleFactor +from deeptools.parserCommon import numberOfProcessors +try: # keep python 3.7 support. + from importlib.metadata import version +except ModuleNotFoundError: + from importlib_metadata import version + +debug = 0 + + +def parseArguments(args=None): + parser = argparse.ArgumentParser( + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + description='Given two BAM files, this estimates scaling factors ' + '(bigger to smaller).', + usage='estimateScaleFactor -b sample1.bam sample2.bam\n' + 'help: estimateScaleFactor -h / estimateScaleFactor --help' + ) + + # define the arguments + parser.add_argument('--bamfiles', '-b', + metavar='list of bam files', + help='List of indexed BAM files, space delineated', + nargs='+', + required=True) + + + parser.add_argument('--ignoreForNormalization', '-ignore', + help='A comma-separated list of chromosome names, ' + 'limited by quotes, ' + 'containing those ' + 'chromosomes that should be excluded ' + 'during normalization computations. For example, ' + '--ignoreForNormalization "chrX, chrM" ') + + parser.add_argument('--sampleWindowLength', '-l', + help='Length in bases for a window used to ' + 'sample the genome and compute the size or scaling ' + 'factors', + default=1000, + type=int) + + parser.add_argument('--numberOfSamples', '-n', + help='Number of samplings taken from the genome ' + 'to compute the scaling factors', + default=100000, + type=int) + + parser.add_argument('--normalizationLength', '-nl', + help='By default, data is normalized to 1 ' + 'fragment per 100 bases. The expected value is an ' + 'integer. For example, if normalizationLength ' + 'is 1000, then the resulting scaling factor ' + 'will cause the average coverage of the BAM file to ' + 'have on average 1 fragment per kilobase', + type=int, + default=10) + + parser.add_argument('--skipZeros', + help='If set, then zero counts that happen for *all* ' + 'BAM files given are ignored. This will result in a ' + 'reduced number of read counts than that specified ' + 'in --numberOfSamples', + action='store_true', + required=False) + + parser.add_argument('--numberOfProcessors', '-p', + help='Number of processors to use. The default is ' + 'to use half the maximum number of processors.', + metavar="INT", + type=numberOfProcessors, + default="max/2", + required=False) + + parser.add_argument('--verbose', '-v', + help='Set to see processing messages.', + action='store_true') + + parser.add_argument('--version', action='version', + version='%(prog)s {}'.format(version('deeptools'))) + + args=parser.parse_args(args) + if args.ignoreForNormalization: + args.ignoreForNormalization=[x.strip() for x in args.ignoreForNormalization.split(',')] + else: + args.ignoreForNormalization = [] + return args + +def main(args=None): + """ + The algorithm samples the genome a number of times as specified + by the --numberOfSamples parameter to estimate scaling factors of + between to samples + + """ + args = parseArguments().parse_args(args) + if len(args.bamfiles) > 2: + print("SES method to estimate scale factors only works for two samples") + exit(0) + + sys.stderr.write("{:,} number of samples will be computed.\n".format(args.numberOfSamples)) + sizeFactorsDict = estimateScaleFactor(args.bamfiles, args.sampleWindowLength, + args.numberOfSamples, + args.normalizationLength, + numberOfProcessors=args.numberOfProcessors, + chrsToSkip=args.ignoreForNormalization, + verbose=args.verbose) + + for k, v in sizeFactorsDict.items(): + print("{}: {}".format(k, v)) \ No newline at end of file diff --git a/deeptools/multiBamSummary.py b/deeptools/multiBamSummary.py index f0caadb5..89229511 100644 --- a/deeptools/multiBamSummary.py +++ b/deeptools/multiBamSummary.py @@ -73,7 +73,8 @@ def parse_arguments(args=None): add_help=False, usage='%(prog)s ' '--bamfiles file1.bam file2.bam ' - '-o results.npz \n') + '-o results.npz \n' + 'help: multiBamSummary bins -h / multiBamSummary bins --help\n') # BED file arguments subparsers.add_parser( @@ -87,7 +88,8 @@ def parse_arguments(args=None): "that should be considered for the coverage analysis. A " "common use is to compare ChIP-seq coverages between two " "different samples for a set of peak regions.", - usage='%(prog)s --BED selection.bed --bamfiles file1.bam file2.bam -o results.npz\n', + usage='%(prog)s --BED selection.bed --bamfiles file1.bam file2.bam -o results.npz\n' + 'help: multiBamSummary BED-file -h / multiBamSummary bins --help\n', add_help=False) return parser @@ -194,7 +196,11 @@ def bamcorrelate_args(case='bins'): def process_args(args=None): args = parse_arguments().parse_args(args) - + + if len(sys.argv) == 1: + parse_arguments().print_help() + sys.exit() + if args.labels and len(args.bamfiles) != len(args.labels): print("The number of labels does not match the number of bam files.") exit(0) diff --git a/deeptools/multiBigwigSummary.py b/deeptools/multiBigwigSummary.py index cafee224..e06f3264 100644 --- a/deeptools/multiBigwigSummary.py +++ b/deeptools/multiBigwigSummary.py @@ -72,7 +72,8 @@ def parse_arguments(args=None): add_help=False, usage='multiBigwigSummary bins ' '-b file1.bw file2.bw ' - '-o results.npz\n') + '-o results.npz\n' + 'help: multiBigwigSummary bins -h / multiBigwigSummary bins --help\n') # BED file arguments subparsers.add_parser( @@ -89,7 +90,8 @@ def parse_arguments(args=None): "different samples over a set of pre-defined peak regions.", usage='multiBigwigSummary BED-file ' '-b file1.bw file2.bw ' - '-o results.npz --BED selection.bed\n', + '-o results.npz --BED selection.bed\n' + 'help: multiBigwigSummary BED-file -h / multiBigwigSummary BED-file --help\n', add_help=False) return parser @@ -97,6 +99,10 @@ def parse_arguments(args=None): def process_args(args=None): args = parse_arguments().parse_args(args) + + if len(sys.argv) == 1: + parse_arguments().print_help() + sys.exit() if not args.labels and args.smartLabels: args.labels = smartLabels(args.bwfiles) diff --git a/deeptools/plotCorrelation.py b/deeptools/plotCorrelation.py index f427d769..2b8d9f79 100644 --- a/deeptools/plotCorrelation.py +++ b/deeptools/plotCorrelation.py @@ -44,7 +44,9 @@ def parse_arguments(args=None): epilog='example usages:\n' 'plotCorrelation -in results_file --whatToPlot heatmap --corMethod pearson -o heatmap.png\n\n' ' \n\n', - parents=[basic_args, heatmap_parser, scatter_parser]) + parents=[basic_args, heatmap_parser, scatter_parser], + usage='plotCorrelation -in matrix.gz -c spearman -p heatmap -o plot.png\n' + 'help: plotCorrelation -h / plotCorrelation --help\n') return parser diff --git a/deeptools/plotCoverage.py b/deeptools/plotCoverage.py index 1aeacdf7..d748a5a8 100755 --- a/deeptools/plotCoverage.py +++ b/deeptools/plotCoverage.py @@ -49,7 +49,9 @@ def parse_arguments(args=None): epilog='example usages:\nplotCoverage ' '--bamfiles file1.bam file2.bam -o results.png\n\n' ' \n\n', - conflict_handler='resolve') + conflict_handler='resolve', + usage='plotCoverage -b sample1.bam sample2.bam -o coverage.png \n' + 'help: plotCoverage -h / plotCoverage --help\n') parser.add_argument('--version', action='version', version='plotCoverage {}'.format(version('deeptools'))) diff --git a/deeptools/plotEnrichment.py b/deeptools/plotEnrichment.py index 7ef474ef..bbd53f90 100755 --- a/deeptools/plotEnrichment.py +++ b/deeptools/plotEnrichment.py @@ -51,7 +51,9 @@ def parse_arguments(args=None): epilog='example usages:\n' 'plotEnrichment -b file1.bam file2.bam --BED peaks.bed -o enrichment.png\n\n' ' \n\n', - parents=[basic_args, parent_parser, read_options]) + parents=[basic_args, parent_parser, read_options], + usage='plotEnrichment -b sample1.bam sample2.bam --BED peaks.bed -o enrichment.png\n' + 'help: plotEnrichment -h / plotEnrichment --help\n') return parser diff --git a/deeptools/plotFingerprint.py b/deeptools/plotFingerprint.py index f5e26072..646da2c7 100755 --- a/deeptools/plotFingerprint.py +++ b/deeptools/plotFingerprint.py @@ -42,8 +42,10 @@ def parse_arguments(args=None): 'these counts are sorted ' 'and the cumulative sum is finally plotted. ', conflict_handler='resolve', - usage='An example usage is: plotFingerprint -b treatment.bam control.bam ' - '-plot fingerprint.png', + usage='plotFingerprint -b treatment.bam control.bam ' + '-plot fingerprint.png\n' + 'help: plotFingerprint -h / plotFingerprint --help' + , add_help=False) return parser diff --git a/deeptools/plotHeatmap.py b/deeptools/plotHeatmap.py index 6b0f2133..ad666998 100755 --- a/deeptools/plotHeatmap.py +++ b/deeptools/plotHeatmap.py @@ -41,7 +41,9 @@ def parse_arguments(args=None): 'scores associated with genomic regions. ' 'The program requires a matrix file ' 'generated by the tool ``computeMatrix``.', - epilog='An example usage is: plotHeatmap -m ', + epilog='An example usage is: plotHeatmap -m matrix.gz', + usage='plotHeatmap -m matrix.gz\n' + 'help: plotHeatmap -h / plotHeatmap --help', add_help=False) return parser diff --git a/deeptools/plotPCA.py b/deeptools/plotPCA.py index 409f9639..c6fdedbe 100644 --- a/deeptools/plotPCA.py +++ b/deeptools/plotPCA.py @@ -33,7 +33,9 @@ def parse_arguments(args=None): epilog='example usages:\n' 'plotPCA -in coverages.npz -o pca.png\n\n' ' \n\n', - parents=[basic_args, ]) + parents=[basic_args, ], + usage='plotPCA -in coverage.npz -o pca.png\n', + 'help: plotPCA -h / plotPCA --help\n') return parser diff --git a/deeptools/plotProfile.py b/deeptools/plotProfile.py index 415a487c..7497875f 100755 --- a/deeptools/plotProfile.py +++ b/deeptools/plotProfile.py @@ -44,8 +44,10 @@ def parse_arguments(args=None): 'any other regions defined in BED ' ' will work. A matrix generated ' 'by computeMatrix is required.', - epilog='An example usage is: plotProfile -m ', - add_help=False) + epilog='An example usage is: plotProfile -m matrix.gz', + add_help=False, + usage='plotProfile -m matrix.gz\n' + 'help: plotProfile -h / plotProfile --help') return parser From 3a5279c5faf84503f26137bfd8858950da4c2218 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Tue, 22 Aug 2023 12:15:18 +0200 Subject: [PATCH 71/90] flakes --- deeptools/bamPEFragmentSize.py | 2 +- deeptools/correctGCBias.py | 2 +- deeptools/estimateReadFiltering.py | 2 +- deeptools/estimateScaleFactor.py | 36 ++++++++++++++++-------------- deeptools/multiBamSummary.py | 4 ++-- deeptools/multiBigwigSummary.py | 2 +- deeptools/plotCoverage.py | 2 +- deeptools/plotFingerprint.py | 3 +-- deeptools/plotPCA.py | 2 +- 9 files changed, 28 insertions(+), 27 deletions(-) diff --git a/deeptools/bamPEFragmentSize.py b/deeptools/bamPEFragmentSize.py index 9c9e92f2..ad63fa14 100755 --- a/deeptools/bamPEFragmentSize.py +++ b/deeptools/bamPEFragmentSize.py @@ -36,7 +36,7 @@ def parse_arguments(): 'The default setting simply prints the summary statistics to the screen.', usage='bamPEFragmentSize -b sample1.bam sample2.bam -o hist.png\n' 'help: bamPEFragmentSize -h / bamPEFragmentSize --help' - ) + ) parser.add_argument('--bamfiles', '-b', help='List of BAM files to process', nargs='+', diff --git a/deeptools/correctGCBias.py b/deeptools/correctGCBias.py index 404b8740..1154b936 100755 --- a/deeptools/correctGCBias.py +++ b/deeptools/correctGCBias.py @@ -1,4 +1,4 @@ - #!/usr/bin/env python +#!/usr/bin/env python # -*- coding: utf-8 -*- import os diff --git a/deeptools/estimateReadFiltering.py b/deeptools/estimateReadFiltering.py index d7427403..52fded53 100644 --- a/deeptools/estimateReadFiltering.py +++ b/deeptools/estimateReadFiltering.py @@ -36,7 +36,7 @@ def parseArguments(): """, usage='estimateReadFiltering -b sample1.bam sample2.bam\n' 'help: estimateReadFiltering -h / estimateReadFiltering --help' - ) + ) required = parser.add_argument_group('Required arguments') required.add_argument('--bamfiles', '-b', diff --git a/deeptools/estimateScaleFactor.py b/deeptools/estimateScaleFactor.py index c3650ad4..31acea3f 100644 --- a/deeptools/estimateScaleFactor.py +++ b/deeptools/estimateScaleFactor.py @@ -1,7 +1,6 @@ #!/usr/bin/env python -#-*- coding: utf-8 -*- +# -*- coding: utf-8 -*- -import deeptools.misc import argparse import sys @@ -17,12 +16,12 @@ def parseArguments(args=None): parser = argparse.ArgumentParser( - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - description='Given two BAM files, this estimates scaling factors ' - '(bigger to smaller).', - usage='estimateScaleFactor -b sample1.bam sample2.bam\n' - 'help: estimateScaleFactor -h / estimateScaleFactor --help' - ) + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + description='Given two BAM files, this estimates scaling factors ' + '(bigger to smaller).', + usage='estimateScaleFactor -b sample1.bam sample2.bam\n' + 'help: estimateScaleFactor -h / estimateScaleFactor --help' + ) # define the arguments parser.add_argument('--bamfiles', '-b', @@ -31,7 +30,6 @@ def parseArguments(args=None): nargs='+', required=True) - parser.add_argument('--ignoreForNormalization', '-ignore', help='A comma-separated list of chromosome names, ' 'limited by quotes, ' @@ -80,19 +78,23 @@ def parseArguments(args=None): required=False) parser.add_argument('--verbose', '-v', - help='Set to see processing messages.', - action='store_true') + help='Set to see processing messages.', + action='store_true') - parser.add_argument('--version', action='version', - version='%(prog)s {}'.format(version('deeptools'))) + parser.add_argument('--version', + action='version', + version='%(prog)s {}'.format(version('deeptools'))) - args=parser.parse_args(args) + args = parser.parse_args(args) if args.ignoreForNormalization: - args.ignoreForNormalization=[x.strip() for x in args.ignoreForNormalization.split(',')] + args.ignoreForNormalization = [ + x.strip() for x in args.ignoreForNormalization.split(',') + ] else: - args.ignoreForNormalization = [] + args.ignoreForNormalization = [] return args + def main(args=None): """ The algorithm samples the genome a number of times as specified @@ -114,4 +116,4 @@ def main(args=None): verbose=args.verbose) for k, v in sizeFactorsDict.items(): - print("{}: {}".format(k, v)) \ No newline at end of file + print("{}: {}".format(k, v)) diff --git a/deeptools/multiBamSummary.py b/deeptools/multiBamSummary.py index 89229511..b010001f 100644 --- a/deeptools/multiBamSummary.py +++ b/deeptools/multiBamSummary.py @@ -196,11 +196,11 @@ def bamcorrelate_args(case='bins'): def process_args(args=None): args = parse_arguments().parse_args(args) - + if len(sys.argv) == 1: parse_arguments().print_help() sys.exit() - + if args.labels and len(args.bamfiles) != len(args.labels): print("The number of labels does not match the number of bam files.") exit(0) diff --git a/deeptools/multiBigwigSummary.py b/deeptools/multiBigwigSummary.py index e06f3264..50f40bee 100644 --- a/deeptools/multiBigwigSummary.py +++ b/deeptools/multiBigwigSummary.py @@ -99,7 +99,7 @@ def parse_arguments(args=None): def process_args(args=None): args = parse_arguments().parse_args(args) - + if len(sys.argv) == 1: parse_arguments().print_help() sys.exit() diff --git a/deeptools/plotCoverage.py b/deeptools/plotCoverage.py index d748a5a8..e233dcb7 100755 --- a/deeptools/plotCoverage.py +++ b/deeptools/plotCoverage.py @@ -51,7 +51,7 @@ def parse_arguments(args=None): ' \n\n', conflict_handler='resolve', usage='plotCoverage -b sample1.bam sample2.bam -o coverage.png \n' - 'help: plotCoverage -h / plotCoverage --help\n') + 'help: plotCoverage -h / plotCoverage --help\n') parser.add_argument('--version', action='version', version='plotCoverage {}'.format(version('deeptools'))) diff --git a/deeptools/plotFingerprint.py b/deeptools/plotFingerprint.py index 646da2c7..550931f9 100755 --- a/deeptools/plotFingerprint.py +++ b/deeptools/plotFingerprint.py @@ -44,8 +44,7 @@ def parse_arguments(args=None): conflict_handler='resolve', usage='plotFingerprint -b treatment.bam control.bam ' '-plot fingerprint.png\n' - 'help: plotFingerprint -h / plotFingerprint --help' - , + 'help: plotFingerprint -h / plotFingerprint --help', add_help=False) return parser diff --git a/deeptools/plotPCA.py b/deeptools/plotPCA.py index c6fdedbe..c43942b8 100644 --- a/deeptools/plotPCA.py +++ b/deeptools/plotPCA.py @@ -34,7 +34,7 @@ def parse_arguments(args=None): 'plotPCA -in coverages.npz -o pca.png\n\n' ' \n\n', parents=[basic_args, ], - usage='plotPCA -in coverage.npz -o pca.png\n', + usage='plotPCA -in coverage.npz -o pca.png\n' 'help: plotPCA -h / plotPCA --help\n') return parser From fff9904b460658ef0d6087877dbae7ab4201052d Mon Sep 17 00:00:00 2001 From: WardDeb Date: Tue, 22 Aug 2023 12:29:47 +0200 Subject: [PATCH 72/90] switch pytest to -v --- .github/workflows/test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 24146377..1d3e5f6e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -91,7 +91,7 @@ jobs: - name: pytest run: | pip install pytest - pytest + pytest -v build-osx: name: Test on OSX runs-on: macOS-latest @@ -113,4 +113,4 @@ jobs: - name: Test deepTools run: | micromamba activate foo - pytest + pytest -v From ac433560a22010908753351efe5bbc6c7d01eb86 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Tue, 22 Aug 2023 12:35:28 +0200 Subject: [PATCH 73/90] switch pytest to -v in init build as well --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 1d3e5f6e..9de35bbe 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -57,7 +57,7 @@ jobs: - name: Test deepTools run: | micromamba activate foo - pytest + pytest -v - name: make an artifact run: | micromamba activate foo From 70c827444519aba762191f4d7ce9bffe8bd928b6 Mon Sep 17 00:00:00 2001 From: Ward D Date: Thu, 24 Aug 2023 08:43:11 +0200 Subject: [PATCH 74/90] Update .github/workflows/planemo.yml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Björn Grüning --- .github/workflows/planemo.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/planemo.yml b/.github/workflows/planemo.yml index c66fc228..8a992156 100644 --- a/.github/workflows/planemo.yml +++ b/.github/workflows/planemo.yml @@ -2,7 +2,7 @@ name: Planemo on: [push, pull_request] env: - GALAXY_BRANCH: release_22.05 + GALAXY_BRANCH: release_23.1 defaults: run: From 8d3c964da90dad00e4af0ac8c444654cfd92a556 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Thu, 24 Aug 2023 10:01:18 +0200 Subject: [PATCH 75/90] python >=3.7, combine env/planemo envs, planemo test galaxy 23.1 --- .github/env.yml | 11 ---------- .github/{planemo.yml => test_and_build.yml} | 8 +++++-- .github/workflows/planemo.yml | 10 ++++----- .github/workflows/pypi.yml | 8 +++---- .github/workflows/test.yml | 24 +++++++++------------ .planemo.sh | 2 +- 6 files changed, 26 insertions(+), 37 deletions(-) delete mode 100644 .github/env.yml rename .github/{planemo.yml => test_and_build.yml} (66%) diff --git a/.github/env.yml b/.github/env.yml deleted file mode 100644 index e216f344..00000000 --- a/.github/env.yml +++ /dev/null @@ -1,11 +0,0 @@ -channels: - - conda-forge - - bioconda -dependencies: - - python = 3.10 - - flake8 - - pytest - - twine - - pip - - pip: - - build \ No newline at end of file diff --git a/.github/planemo.yml b/.github/test_and_build.yml similarity index 66% rename from .github/planemo.yml rename to .github/test_and_build.yml index 8716e588..a3e6ea06 100644 --- a/.github/planemo.yml +++ b/.github/test_and_build.yml @@ -2,7 +2,7 @@ channels: - conda-forge - bioconda dependencies: - - python = 3.10 + - python >= 3.7 - numpy - scipy - flake8 @@ -11,6 +11,10 @@ dependencies: - pytest - planemo - samtools - - allure-python-commons==2.12.0 + #- allure-python-commons==2.12.0 - py2bit - pyBigWig + - twine + - pip + - pip: + - build \ No newline at end of file diff --git a/.github/workflows/planemo.yml b/.github/workflows/planemo.yml index 8a992156..45ed8c19 100644 --- a/.github/workflows/planemo.yml +++ b/.github/workflows/planemo.yml @@ -19,16 +19,16 @@ jobs: - uses: actions/checkout@v3 - uses: mamba-org/setup-micromamba@main with: - environment-file: .github/planemo.yml + environment-file: .github/test_and_build.yml cache-downloads: true - environment-name: foo + environment-name: test_and_build - name: pip install run: | - micromamba activate foo + micromamba activate test_and_build pip install . - name: planemo run: | - micromamba activate foo + micromamba activate test_and_build ./.planemo.sh ${{ matrix.chunk }} ${{ env.GALAXY_BRANCH }} - uses: actions/upload-artifact@v3 with: @@ -40,7 +40,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.10'] + python-version: ['3.7', '3.11'] steps: - uses: actions/download-artifact@v3 with: diff --git a/.github/workflows/pypi.yml b/.github/workflows/pypi.yml index 5f973d37..e97cfbdb 100644 --- a/.github/workflows/pypi.yml +++ b/.github/workflows/pypi.yml @@ -16,12 +16,12 @@ jobs: - uses: actions/checkout@v3 - uses: mamba-org/setup-micromamba@main with: - environment-file: .github/env.yml + environment-file: .github/test_and_build.yml cache-downloads: true - environment-name: foo + environment-name: test_and_build - name: build run: | - micromamba activate foo + micromamba activate test_and_build rm -f dist/* python -m build - name: upload @@ -29,5 +29,5 @@ jobs: TWINE_USERNAME: "__token__" TWINE_PASSWORD: ${{ secrets.pypi_password }} run: | - micromamba activate foo + micromamba activate test_and_build twine upload dist/* diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9de35bbe..124fbacf 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -43,24 +43,24 @@ jobs: - uses: actions/checkout@v3 - uses: mamba-org/setup-micromamba@main with: - environment-file: .github/env.yml + environment-file: .github/test_and_build.yml cache-downloads: true - environment-name: foo + environment-name: test_and_build - name: pip install run: | - micromamba activate foo + micromamba activate test_and_build pip install . - name: PEP8 run: | - micromamba activate foo + micromamba activate test_and_build flake8 . --exclude=.venv,.build,build --ignore=E501,F403,E402,F999,F405,E722,W504,W605 - name: Test deepTools run: | - micromamba activate foo + micromamba activate test_and_build pytest -v - name: make an artifact run: | - micromamba activate foo + micromamba activate test_and_build rm -f dist/* python -m build - uses: actions/upload-artifact@master @@ -99,18 +99,14 @@ jobs: - uses: actions/checkout@v3 - uses: mamba-org/setup-micromamba@main with: - environment-file: .github/env.yml + environment-file: .github/test_and_build.yml cache-downloads: true - environment-name: foo - condarc: | - channels: - - conda-forge - - bioconda + environment-name: test_and_build - name: pip install run: | - micromamba activate foo + micromamba activate test_and_build pip install . - name: Test deepTools run: | - micromamba activate foo + micromamba activate test_and_build pytest -v diff --git a/.planemo.sh b/.planemo.sh index 6f9e0810..7411ccc4 100755 --- a/.planemo.sh +++ b/.planemo.sh @@ -29,6 +29,6 @@ else fi planemo lint ${wrappers} -planemo test --no_dependency_resolution --galaxy_python_version 3.10 --galaxy_branch $2 --install_galaxy ${wrappers} 2>&1 +planemo test --galaxy_branch $2 --install_galaxy ${wrappers} 2>&1 mkdir upload mv tool_test_output* upload/ From b0496a70fd4c4e00cb69062e6e782236ea1dea8b Mon Sep 17 00:00:00 2001 From: WardDeb Date: Thu, 24 Aug 2023 10:11:14 +0200 Subject: [PATCH 76/90] force conda prefix to micromamba env dir on runner --- .planemo.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.planemo.sh b/.planemo.sh index 7411ccc4..7a51d6df 100755 --- a/.planemo.sh +++ b/.planemo.sh @@ -29,6 +29,6 @@ else fi planemo lint ${wrappers} -planemo test --galaxy_branch $2 --install_galaxy ${wrappers} 2>&1 +planemo test --conda_prefix /home/runner/micromamba/envs --galaxy_branch $2 --install_galaxy ${wrappers} 2>&1 mkdir upload mv tool_test_output* upload/ From 558442d12c9c8eb9cf3301b850f01fdcb25374f9 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Thu, 24 Aug 2023 10:28:29 +0200 Subject: [PATCH 77/90] include pytests for 3.11 --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 124fbacf..8a478907 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -73,7 +73,7 @@ jobs: needs: build-linux strategy: matrix: - python-version: ['3.7','3.8','3.9','3.10'] + python-version: ['3.7','3.8','3.9','3.10', '3.11'] steps: - uses: actions/checkout@v3 - uses: actions/download-artifact@v3 From ad574352483983268d1b018d27ff7361696eb5c9 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Thu, 24 Aug 2023 10:28:48 +0200 Subject: [PATCH 78/90] bring back no dependency resolution planemo --- .planemo.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.planemo.sh b/.planemo.sh index 7a51d6df..8a6fd978 100755 --- a/.planemo.sh +++ b/.planemo.sh @@ -29,6 +29,6 @@ else fi planemo lint ${wrappers} -planemo test --conda_prefix /home/runner/micromamba/envs --galaxy_branch $2 --install_galaxy ${wrappers} 2>&1 +planemo test --no_dependency_resolution --conda_prefix /home/runner/micromamba/envs --galaxy_branch $2 --install_galaxy ${wrappers} 2>&1 mkdir upload mv tool_test_output* upload/ From 8df4889e5309cacc09faa4566a140a5be4e7396c Mon Sep 17 00:00:00 2001 From: WardDeb Date: Fri, 25 Aug 2023 12:35:44 +0200 Subject: [PATCH 79/90] parse toml for tool tests + verify version --- deeptools/test/test_tools.py | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/deeptools/test/test_tools.py b/deeptools/test/test_tools.py index 6d4a5a07..e06390e8 100644 --- a/deeptools/test/test_tools.py +++ b/deeptools/test/test_tools.py @@ -1,17 +1,28 @@ -import subprocess +from subprocess import PIPE, run import os +try: + import tomllib +except ModuleNotFoundError: + import tomli as tomllib -ROOT = os.path.dirname(os.path.abspath(__file__)) + "/../../bin" +TOMLFILE = os.path.dirname(os.path.abspath(__file__)) + "/../../pyproject.toml" def test_tools(): """ - Checks everything that is in /bin/ - and tries to run it - + Check every script in 'pyproject.toml' + makes sure the version of all tools == version set in toml file + makes sure exitcodes are all 0 """ - if os.path.isdir(ROOT): - for _file in os.listdir(ROOT): - print(_file) - if os.path.isfile(os.path.join(ROOT, _file)): - subprocess.check_call("{}/{} --version".format(ROOT, _file).split()) + with open(TOMLFILE, 'rb') as f: + _toml = tomllib.load(f) + for _p in _toml['project']['scripts'].keys(): + _res = run( + [_p, f"--version"], + stdout=PIPE, + stderr=PIPE + ) + _version = _res.stdout.decode().splitlines()[0] + assert f"{_version}" == f"{_p} {_toml['project']['version']}" + assert f"{_res.returncode}" == f"0" + From bfda73784615c7bfeafa4841641eb8a57ec1e4f5 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Fri, 25 Aug 2023 12:36:00 +0200 Subject: [PATCH 80/90] fstring tests --- .../test/test_bamCoverage_and_bamCompare.py | 22 +-- deeptools/test/test_bigwigAverage.py | 6 +- ...st_bigwigCompare_and_multiBigwigSummary.py | 8 +- .../test/test_computeMatrixOperations.py | 15 +- deeptools/test/test_heatmapper.py | 132 +++++++++--------- deeptools/test/test_readFiltering.py | 14 +- deeptools/test/test_writeBedGraph.py | 20 ++- 7 files changed, 111 insertions(+), 106 deletions(-) diff --git a/deeptools/test/test_bamCoverage_and_bamCompare.py b/deeptools/test/test_bamCoverage_and_bamCompare.py index a7e5e4ad..ac1f23ce 100644 --- a/deeptools/test/test_bamCoverage_and_bamCompare.py +++ b/deeptools/test/test_bamCoverage_and_bamCompare.py @@ -45,7 +45,7 @@ def test_bam_coverage_arguments(): resp = _foo.readlines() _foo.close() expected = ['3R\t0\t50\t0\n', '3R\t50\t150\t1\n', '3R\t150\t200\t2\n'] - assert resp == expected, "{} != {}".format(resp, expected) + assert f"{resp}" == f"{expected}", f"{resp} != {expected}" unlink(outfile) @@ -58,7 +58,7 @@ def test_bam_coverage_extend(): resp = _foo.readlines() _foo.close() expected = ['3R\t0\t150\t1\n', '3R\t150\t200\t3\n'] - assert resp == expected, "{} != {}".format(resp, expected) + assert f"{resp}" == f"{expected}", f"{resp} != {expected}" unlink(outfile) @@ -75,7 +75,7 @@ def test_bam_coverage_extend_and_normalizeUsingRPGC(): # the scale factor should be 0.5, thus the result is similar to # that of the previous test divided by 0.5 expected = ['3R\t0\t150\t0.5\n', '3R\t150\t200\t1.5\n'] - assert resp == expected, "{} != {}".format(resp, expected) + assert f"{resp}" == f"{expected}", f"{resp} != {expected}" unlink(outfile) @@ -89,7 +89,7 @@ def test_bam_coverage_skipnas(): resp = _foo.readlines() _foo.close() expected = ['3R\t50\t150\t1\n', '3R\t150\t200\t2\n'] - assert resp == expected, "{} != {}".format(resp, expected) + assert f"{resp}" == f"{expected}", f"{resp} != {expected}" unlink(outfile) @@ -175,7 +175,7 @@ def test_bam_compare_ZoverZ(): resp = _foo.readlines() _foo.close() expected = ['3R\t50\t100\t-1\n', '3R\t100\t150\t0\n', '3R\t150\t200\t-0.584963\n'] - assert resp == expected, "{} != {}".format(resp, expected) + assert f"{resp}" == f"{expected}", f"{resp} != {expected}" unlink(outfile) @@ -227,7 +227,7 @@ def test_bam_compare_diff_files_skipnas(): resp = _foo.readlines() _foo.close() expected = ['3R\t100\t150\t0\n', '3R\t150\t200\t-1\n'] - assert resp == expected, "{} != {}".format(resp, expected) + assert f"{resp}" == f"{expected}", f"{resp} != {expected}" unlink(outfile) @@ -245,7 +245,7 @@ def test_bam_compare_extend(): resp = _foo.readlines() _foo.close() expected = ['3R\t0\t100\t-1\n', '3R\t100\t150\t1\n', '3R\t150\t200\t-1\n'] - assert resp == expected, "{} != {}".format(resp, expected) + assert f"{resp}" == f"{expected}", f"{resp} != {expected}" unlink(outfile) @@ -285,7 +285,7 @@ def test_bam_compare_scale_factors_ratio(): """ expected = ['3R\t0\t50\t1\n', '3R\t50\t100\t0.666667\n', '3R\t100\t150\t1.33333\n', '3R\t150\t200\t1\n'] - assert resp == expected, "{} != {}".format(resp, expected) + assert f"{resp}" == f"{expected}", f"{resp} != {expected}" unlink(outfile) @@ -327,7 +327,7 @@ def test_bam_compare_scale_factors_subtract(): """ expected = ['3R\t0\t50\t0\n', '3R\t50\t100\t-250000\n', '3R\t100\t150\t250000\n', '3R\t150\t200\t0\n'] - assert resp == expected, "{} != {}".format(resp, expected) + assert f"{resp}" == f"{expected}", f"{resp} != {expected}" unlink(outfile) @@ -357,7 +357,7 @@ def test_bam_coverage_filter_blacklist(): '3R\t950\t1000\t1.62672\n', '3R\t1000\t1050\t0.813362\n', '3R\t1050\t1500\t0\n'] - assert resp == expected, "{} != {}".format(resp, expected) + assert f"{resp}" == f"{expected}", f"{resp} != {expected}" unlink(outfile) @@ -458,5 +458,5 @@ def test_bam_compare_filter_blacklist(): '3R\t750\t800\t-0.123451\n', '3R\t900\t950\t0.212545\n', '3R\t950\t1000\t0.199309\n', '3R\t1000\t1050\t0.167945\n', '3R\t1050\t1500\t0\n'] - assert resp == expected, "{} != {}".format(resp, expected) + assert f"{resp}" == f"{expected}", f"{resp} != {expected}" unlink(outfile) diff --git a/deeptools/test/test_bigwigAverage.py b/deeptools/test/test_bigwigAverage.py index 22f5427e..fed8f216 100644 --- a/deeptools/test/test_bigwigAverage.py +++ b/deeptools/test/test_bigwigAverage.py @@ -42,7 +42,7 @@ def test_bigwigAverage(): resp = _foo.readlines() _foo.close() expected = ['3R\t0\t50\t0\n', '3R\t50\t100\t0.5\n', '3R\t100\t150\t1\n', '3R\t150\t200\t1.5\n'] - assert resp == expected, "{} != {}".format(resp, expected) + assert f"{resp}" == f"{expected}", f"{resp} != {expected}" unlink(outfile) @@ -55,7 +55,7 @@ def test_bigwigAverage_skipnas(): resp = _foo.readlines() _foo.close() expected = ['3R\t100\t150\t1\n', '3R\t150\t200\t1.5\n'] - assert resp == expected, "{} != {}".format(resp, expected) + assert f"{resp}" == f"{expected}", f"{resp} != {expected}" unlink(outfile) @@ -67,5 +67,5 @@ def test_bigwigAverageWithScale(): resp = _foo.readlines() _foo.close() expected = ['3R\t0\t50\t0\n', '3R\t50\t100\t0.25\n', '3R\t100\t150\t0.75\n', '3R\t150\t200\t1\n'] - assert resp == expected, "{} != {}".format(resp, expected) + assert f"{resp}" == f"{expected}", f"{resp} != {expected}" unlink(outfile) diff --git a/deeptools/test/test_bigwigCompare_and_multiBigwigSummary.py b/deeptools/test/test_bigwigCompare_and_multiBigwigSummary.py index 83192427..076baa21 100644 --- a/deeptools/test/test_bigwigCompare_and_multiBigwigSummary.py +++ b/deeptools/test/test_bigwigCompare_and_multiBigwigSummary.py @@ -45,7 +45,7 @@ def test_bigwigCompare(): resp = _foo.readlines() _foo.close() expected = ['3R\t0\t50\t0\n', '3R\t50\t100\t1\n', '3R\t100\t150\t2\n', '3R\t150\t200\t3\n'] - assert resp == expected, "{} != {}".format(resp, expected) + assert f"{resp}" == f"{expected}", f"{resp} != {expected}" unlink(outfile) @@ -58,7 +58,7 @@ def test_bigwigCompare_skipnas(): resp = _foo.readlines() _foo.close() expected = ['3R\t100\t150\t2\n', '3R\t150\t200\t3\n'] - assert resp == expected, "{} != {}".format(resp, expected) + assert f"{resp}" == f"{expected}", f"{resp} != {expected}" unlink(outfile) @@ -70,7 +70,7 @@ def test_bigwigCompare_skipZeroOverZero(): resp = _foo.readlines() _foo.close() expected = ['3R\t100\t200\t-1\n'] - assert resp == expected, "{} != {}".format(resp, expected) + assert f"{resp}" == f"{expected}", f"{resp} != {expected}" unlink(outfile) @@ -105,7 +105,7 @@ def test_multiBigwigSummary_outrawcounts(): 3R 100 150 1.0 1.0 3R 150 200 1.0 2.0 """ - assert resp == expected, "{} != {}".format(resp, expected) + assert f"{resp}" == f"{expected}", f"{resp} != {expected}" unlink(outfile) unlink("/tmp/null") diff --git a/deeptools/test/test_computeMatrixOperations.py b/deeptools/test/test_computeMatrixOperations.py index 433e25bd..d19ceb9d 100644 --- a/deeptools/test/test_computeMatrixOperations.py +++ b/deeptools/test/test_computeMatrixOperations.py @@ -32,7 +32,6 @@ def testSubset(self): dCorrect = {"verbose": True, "scale": 1, "skip zeros": False, "nan after end": False, "sort using": "mean", "unscaled 5 prime": [0, 0, 0, 0], "body": [1000, 1000, 1000, 1000], "sample_labels": ["SRR648667.forward", "SRR648668.forward", "SRR648669.forward", "SRR648670.forward"], "downstream": [0, 0, 0, 0], "unscaled 3 prime": [0, 0, 0, 0], "group_labels": ["genes"], "bin size": [10, 10, 10, 10], "upstream": [0, 0, 0, 0], "group_boundaries": [0, 196], "sample_boundaries": [0, 100, 200, 300, 400], "max threshold": None, "ref point": [None, None, None, None], "min threshold": None, "sort regions": "no", "proc number": 20, "bin avg type": "mean", "missing data as zero": False} oname = "/tmp/subset.mat.gz" args = "subset -m {} --sample SRR648667.forward SRR648668.forward SRR648669.forward SRR648670.forward -o {}".format(self.matrix, oname) - print(args) args = args.split() cmo.main(args) f = gzip.GzipFile(oname) @@ -40,7 +39,7 @@ def testSubset(self): h = hashlib.md5(f.read()).hexdigest() f.close() assert d == dCorrect - assert h == "edb3c8506c3f27ebb8c7ddf94d5ba594" + assert f"{h}" == f"edb3c8506c3f27ebb8c7ddf94d5ba594" os.remove(oname) def testRelabel(self): @@ -74,7 +73,7 @@ def testfilterStrand(self): h = hashlib.md5(f.read()).hexdigest() f.close() assert d == dCorrect - assert h == "300f8000be5b5f51e803b57ef08f1c9e" + assert f"{h}" == f"300f8000be5b5f51e803b57ef08f1c9e" os.remove(oname) dCorrect = {u'verbose': True, u'scale': 1, u'skip zeros': False, u'nan after end': False, u'sort using': u'mean', u'unscaled 5 prime': [0, 0, 0, 0, 0, 0, 0, 0], u'body': [1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000], u'sample_labels': [u'SRR648667.forward', u'SRR648668.forward', u'SRR648669.forward', u'SRR648670.forward', u'SRR648667.reverse', u'SRR648668.reverse', u'SRR648669.reverse', u'SRR648670.reverse'], u'downstream': [0, 0, 0, 0, 0, 0, 0, 0], u'unscaled 3 prime': [0, 0, 0, 0, 0, 0, 0, 0], u'group_labels': [u'genes'], u'bin size': [10, 10, 10, 10, 10, 10, 10, 10], u'upstream': [0, 0, 0, 0, 0, 0, 0, 0], u'group_boundaries': [0, 89], u'sample_boundaries': [0, 100, 200, 300, 400, 500, 600, 700, 800], u'missing data as zero': False, u'ref point': [None, None, None, None, None, None, None, None], u'min threshold': None, u'sort regions': u'no', u'proc number': 20, u'bin avg type': u'mean', u'max threshold': None} @@ -87,7 +86,7 @@ def testfilterStrand(self): h = hashlib.md5(f.read()).hexdigest() f.close() assert d == dCorrect - assert h == "0a6ca070a5ba4564f1ab950ac3b7c8f1" + assert f"{h}" == f"0a6ca070a5ba4564f1ab950ac3b7c8f1" os.remove(oname) def testrbind(self): @@ -104,7 +103,7 @@ def testrbind(self): h = hashlib.md5(f.read()).hexdigest() f.close() assert d == dCorrect - assert h == "3dd96c7b05e0ca5ada21212defe57fba" + assert f"{h}" == f"3dd96c7b05e0ca5ada21212defe57fba" os.remove(oname) def testrbind2(self): @@ -121,7 +120,7 @@ def testrbind2(self): h = hashlib.md5(f.read()).hexdigest() f.close() assert d == dCorrect - assert h == "5d8b1517fc4c63d000b6b37f70ee163b" + assert f"{h}" == f"5d8b1517fc4c63d000b6b37f70ee163b" os.remove(oname) def testcbind(self): @@ -138,7 +137,7 @@ def testcbind(self): h = hashlib.md5(f.read()).hexdigest() f.close() assert d == dCorrect - assert h == "e55d89704bb16a11f366663a8fd90a47" + assert f"{h}" == f"e55d89704bb16a11f366663a8fd90a47" os.remove(oname) def testsort(self): @@ -155,5 +154,5 @@ def testsort(self): h = hashlib.md5(f.read()).hexdigest() f.close() assert d == dCorrect - assert h == "10ea07d1aa58f44625abe2142ef76094" + assert f"{h}" == f"10ea07d1aa58f44625abe2142ef76094" os.remove(oname) diff --git a/deeptools/test/test_heatmapper.py b/deeptools/test/test_heatmapper.py index 800d4d7b..2b14826b 100644 --- a/deeptools/test/test_heatmapper.py +++ b/deeptools/test/test_heatmapper.py @@ -142,107 +142,107 @@ def test_computeMatrix_metagene(): def test_chopRegions_body(): region = [(0, 200), (300, 400), (800, 900)] lbins, bodybins, rbins, padLeft, padRight = deeptools.heatmapper.chopRegions(region, left=0, right=0) - assert lbins == [] - assert rbins == [] - assert bodybins == region - assert padLeft == 0 - assert padRight == 0 + assert f"{lbins}" == f"[]" + assert f"{rbins}" == f"[]" + assert f"{bodybins}" == f"{region}" + assert f"{padLeft}" == f"0" + assert f"{padRight}" == f"0" # Unscaled 5', 3' lbins, bodybins, rbins, padLeft, padRight = deeptools.heatmapper.chopRegions(region, left=150, right=150) - assert lbins == [(0, 150)] - assert rbins == [(350, 400), (800, 900)] - assert bodybins == [(150, 200), (300, 350)] - assert padLeft == 0 - assert padRight == 0 + assert f"{lbins}" == f"[(0, 150)]" + assert f"{rbins}" == f"[(350, 400), (800, 900)]" + assert f"{bodybins}" == f"[(150, 200), (300, 350)]" + assert f"{padLeft}" == f"0" + assert f"{padRight}" == f"0" def test_chopRegions_TSS(): region = [(0, 200), (300, 400), (800, 900)] # + strand, 250 downstream downstream, body, unscaled3prime, padRight, _ = deeptools.heatmapper.chopRegions(region, left=250) - assert downstream == [(0, 200), (300, 350)] - assert body == [(350, 400), (800, 900)] - assert unscaled3prime == [] - assert padRight == 0 - assert _ == 0 + assert f"{downstream}" == f"[(0, 200), (300, 350)]" + assert f"{body}" == f"[(350, 400), (800, 900)]" + assert f"{unscaled3prime}" == f"[]" + assert f"{padRight}" == f"0" + assert f"{_}" == f"0" # + strand, 500 downstream downstream, body, unscaled3prime, padRight, _ = deeptools.heatmapper.chopRegions(region, left=500) - assert downstream == region - assert body == [] - assert unscaled3prime == [] - assert padRight == 100 - assert _ == 0 + assert f"{downstream}" == f"{region}" + assert f"{body}" == f"[]" + assert f"{unscaled3prime}" == f"[]" + assert f"{padRight}" == f"100" + assert f"{_}" == f"0" # - strand, 250 downstream (labeled "upstream" due to being on the - strand) unscaled5prime, body, upstream, _, padLeft = deeptools.heatmapper.chopRegions(region, right=250) - assert upstream == [(150, 200), (300, 400), (800, 900)] - assert body == [(0, 150)] - assert unscaled5prime == [] - assert padLeft == 0 - assert _ == 0 + assert f"{upstream}" == f"[(150, 200), (300, 400), (800, 900)]" + assert f"{body}" == f"[(0, 150)]" + assert f"{unscaled5prime}" == f"[]" + assert f"{padLeft}" == f"0" + assert f"{_}" == f"0" # - strand, 500 downstream (labeled "upstream" due to being on the - strand) unscaled5prime, body, upstream, _, padLeft = deeptools.heatmapper.chopRegions(region, right=500) - assert upstream == region - assert body == [] - assert unscaled5prime == [] - assert padLeft == 100 - assert _ == 0 + assert f"{upstream}" == f"{region}" + assert f"{body}" == f"[]" + assert f"{unscaled5prime}" == f"[]" + assert f"{padLeft}" == f"100" + assert f"{_}" == f"0" def test_chopRegions_TES(): region = [(0, 200), (300, 400), (800, 900)] # + strand, 250 upstream unscaled5prime, body, upstream, _, padLeft = deeptools.heatmapper.chopRegions(region, right=250) - assert unscaled5prime == [] - assert body == [(0, 150)] - assert upstream == [(150, 200), (300, 400), (800, 900)] - assert _ == 0 - assert padLeft == 0 + assert f"{unscaled5prime}" == f"[]" + assert f"{body}" == f"[(0, 150)]" + assert f"{upstream}" == f"[(150, 200), (300, 400), (800, 900)]" + assert f"{_}" == f"0" + assert f"{padLeft}" == f"0" # + strand, 500 upstream unscaled5prime, body, upstream, _, padLeft = deeptools.heatmapper.chopRegions(region, right=500) - assert unscaled5prime == [] - assert body == [] - assert upstream == region - assert _ == 0 - assert padLeft == 100 + assert f"{unscaled5prime}" == f"[]" + assert f"{body}" == f"[]" + assert f"{upstream}" == f"{region}" + assert f"{_}" == f"0" + assert f"{padLeft}" == f"100" # + strand, 250 downstream (labeled "upstream" due to being on the - strand) downstream, body, unscaled3prime, padRight, _ = deeptools.heatmapper.chopRegions(region, left=250) - assert downstream == [(0, 200), (300, 350)] - assert body == [(350, 400), (800, 900)] - assert unscaled3prime == [] - assert padRight == 0 - assert _ == 0 + assert f"{downstream}" == f"[(0, 200), (300, 350)]" + assert f"{body}" == f"[(350, 400), (800, 900)]" + assert f"{unscaled3prime}" == f"[]" + assert f"{padRight}" == f"0" + assert f"{_}" == f"0" # + strand, 500 downstream (labeled "upstream" due to being on the - strand) downstream, body, unscaled3prime, padRight, _ = deeptools.heatmapper.chopRegions(region, left=500) - assert downstream == region - assert body == [] - assert unscaled3prime == [] - assert padRight == 100 - assert _ == 0 + assert f"{downstream}" == f"{region}" + assert f"{body}" == f"[]" + assert f"{unscaled3prime}" == f"[]" + assert f"{padRight}" == f"100" + assert f"{_}" == f"0" def test_chopRegionsFromMiddle(): region = [(0, 200), (300, 400), (800, 900)] # + strand, 100 upstream/200 downstream upstream, downstream, padLeft, padRight = deeptools.heatmapper.chopRegionsFromMiddle(region, left=100, right=200) - assert upstream == [(100, 200)] - assert downstream == [(300, 400), (800, 900)] - assert padLeft == 0 - assert padRight == 0 + assert f"{upstream}" == f"[(100, 200)]" + assert f"{downstream}" ==f"[(300, 400), (800, 900)]" + assert f"{padLeft}" == f"0" + assert f"{padRight}" == f"0" # + strand, 250 upstream/300 downstream upstream, downstream, padLeft, padRight = deeptools.heatmapper.chopRegionsFromMiddle(region, left=250, right=300) - assert upstream == [(0, 200)] - assert downstream == [(300, 400), (800, 900)] - assert padLeft == 50 - assert padRight == 100 + assert f"{upstream}" == f"[(0, 200)]" + assert f"{downstream}" == f"[(300, 400), (800, 900)]" + assert f"{padLeft}" == f"50" + assert f"{padRight}" == f"100" # - strand, 100 upstream/200 downstream upstream, downstream, padLeft, padRight = deeptools.heatmapper.chopRegionsFromMiddle(region, left=200, right=100) - assert upstream == [(0, 200)] - assert downstream == [(300, 400)] - assert padLeft == 0 - assert padRight == 0 + assert f"{upstream}" == f"[(0, 200)]" + assert f"{downstream}" == f"[(300, 400)]" + assert f"{padLeft}" == f"0" + assert f"{padRight}" == f"0" # - strand, 250 upstream/300 downstream upstream, downstream, padLeft, padRight = deeptools.heatmapper.chopRegionsFromMiddle(region, left=300, right=250) - assert upstream == [(0, 200)] - assert downstream == [(300, 400), (800, 900)] - assert padLeft == 100 - assert padRight == 50 + assert f"{upstream}" == f"[(0, 200)]" + assert f"{downstream}" == f"[(300, 400), (800, 900)]" + assert f"{padLeft}" == f"100" + assert f"{padRight}" == f"50" diff --git a/deeptools/test/test_readFiltering.py b/deeptools/test/test_readFiltering.py index 07f19b32..cfce0530 100644 --- a/deeptools/test/test_readFiltering.py +++ b/deeptools/test/test_readFiltering.py @@ -29,7 +29,7 @@ def test_estimate_read_filtering_minimal(): _ = resp[1].split("\t") _[0] = os.path.basename(_[0]) resp[1] = "\t".join(_) - assert resp == expected + assert f"{resp}" == f"{expected}", f"{resp} != {expected}" unlink(outfile) @@ -50,7 +50,7 @@ def test_estimate_read_filtering_params(): resp[1] = "\t".join(_) expected = ['Sample\tTotal Reads\tMapped Reads\tAlignments in blacklisted regions\tEstimated mapped reads filtered\tBelow MAPQ\tMissing Flags\tExcluded Flags\tInternally-determined Duplicates\tMarked Duplicates\tSingletons\tWrong strand\n', 'test_filtering.bam\t193\t193\t7\t193\t41.4\t0.0\t186.5\t31.6\t0.0\t0.0\t0.0\n'] - assert resp == expected + assert f"{resp}" == f"{expected}", f"{resp} != {expected}" unlink(outfile) @@ -71,14 +71,14 @@ def test_sieve(): expected = ['#bamFilterReads --filterMetrics\n', '#File\tReads Remaining\tTotal Initial Reads\n', 'test_filtering\t5\t193\n'] - assert resp == expected + assert f"{resp}" == f"{expected}", f"{resp} != {expected}" unlink(outlog) h = hashlib.md5(pysam.view(outfile).encode('utf-8')).hexdigest() - assert h == "acbc4443fb0387bfd6c412af9d4fc414" + assert f"{h}" == f"acbc4443fb0387bfd6c412af9d4fc414" unlink(outfile) h1 = hashlib.md5(pysam.view(outfiltered).encode('utf-8')).hexdigest() - assert h1 == "b90befdd5f073f14acb9a38661f301ad" + assert f"{h1}" == f"b90befdd5f073f14acb9a38661f301ad" unlink(outfiltered) @@ -120,7 +120,7 @@ def test_sieve_BED(): 'chr2\t5001491\t5001527\n', 'chr2\t5001700\t5001736\n'] - assert resp == expected + assert f"{resp}" == f"{expected}", f"{resp} != {expected}" unlink(outfile) @@ -160,5 +160,5 @@ def test_sieve_BED_shift(): 'chr2\t5001119\t5001266\n', 'chr2\t5001230\t5001600\n'] - assert resp == expected + assert f"{resp}" == f"{expected}", f"{resp} != {expected}" unlink(outfile) diff --git a/deeptools/test/test_writeBedGraph.py b/deeptools/test/test_writeBedGraph.py index bdf0bca1..1a9c6ec4 100644 --- a/deeptools/test/test_writeBedGraph.py +++ b/deeptools/test/test_writeBedGraph.py @@ -31,7 +31,8 @@ def test_writeBedGraph_worker(self, bc): _foo = open(tempFile[3], 'r') res = _foo.readlines() _foo.close() - assert res == ['3R\t0\t100\t0\n', '3R\t100\t200\t1\n'] + expected = ['3R\t0\t100\t0\n', '3R\t100\t200\t1\n'] + assert f"{res}" == f"{expected}" os.remove(tempFile[3]) def test_writeBedGraph_worker_zerotonan(self, bc): @@ -42,7 +43,8 @@ def test_writeBedGraph_worker_zerotonan(self, bc): _foo = open(tempFile2[3], 'r') res = _foo.readlines() _foo.close() - assert res == ['3R\t100\t200\t1\n'] + expected = ['3R\t100\t200\t1\n'] + assert f"{res}" == f"{expected}" os.remove(tempFile2[3]) def test_writeBedGraph_worker_scaling(self, bc): @@ -52,7 +54,8 @@ def test_writeBedGraph_worker_scaling(self, bc): _foo = open(tempFile[3], 'r') res = _foo.readlines() _foo.close() - assert res == ['3R\t0\t100\t0\n', '3R\t100\t200\t3\n'] + expected = ['3R\t0\t100\t0\n', '3R\t100\t200\t3\n'] + assert f"{res}" == f"{expected}" os.remove(tempFile[3]) def test_writeBedGraph_worker_ignore_duplicates(self, bc): @@ -69,7 +72,8 @@ def test_writeBedGraph_worker_ignore_duplicates(self, bc): _foo = open(tempFile[3], 'r') res = _foo.readlines() _foo.close() - assert res == ['3R\t50\t200\t1\n'] + expected = ['3R\t50\t200\t1\n'] + assert f"{res}" == f"{expected}" os.remove(tempFile[3]) def test_writeBedGraph_worker_smoothing(self, bc): @@ -81,7 +85,8 @@ def test_writeBedGraph_worker_smoothing(self, bc): _foo = open(tempFile[3], 'r') res = _foo.readlines() _foo.close() - assert res == ['3R\t100\t120\t1\n', '3R\t120\t180\t1.33333\n', '3R\t180\t200\t1\n'] + expected = ['3R\t100\t120\t1\n', '3R\t120\t180\t1.33333\n', '3R\t180\t200\t1\n'] + assert f"{res}" == f"{expected}" os.remove(tempFile[3]) def test_writeBedGraph_cigar(self, bc): @@ -100,12 +105,13 @@ def test_writeBedGraph_cigar(self, bc): res = _foo.readlines() _foo.close() - # the sigle read is split into bin 10-30, and then 40-50 - assert res == [ + # the single read is split into bin 10-30, and then 40-50 + expected = [ 'chr_cigar\t0\t10\t0\n', 'chr_cigar\t10\t30\t1\n', 'chr_cigar\t30\t40\t0\n', 'chr_cigar\t40\t50\t1\n', 'chr_cigar\t50\t100\t0\n' ] + assert f"{res}" == f"{expected}" os.remove(tempFile[3]) From 21d1326205412ff7010d83224f96e8a84b933a9e Mon Sep 17 00:00:00 2001 From: WardDeb Date: Fri, 25 Aug 2023 12:37:05 +0200 Subject: [PATCH 81/90] 1 env for test/builds, pip planemo, python min version 3.7, drop allure restriction --- .github/test_and_build.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/test_and_build.yml b/.github/test_and_build.yml index a3e6ea06..e2dcd08b 100644 --- a/.github/test_and_build.yml +++ b/.github/test_and_build.yml @@ -9,12 +9,12 @@ dependencies: - pysam - deeptoolsintervals - pytest - - planemo - samtools - #- allure-python-commons==2.12.0 - py2bit - pyBigWig - twine - pip + - tomli # remove dependency when lowest supported version is py 3.11 - pip: - - build \ No newline at end of file + - build + - planemo \ No newline at end of file From c238997e6cda944ded277eb1ab7a2d5ce523a994 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Fri, 25 Aug 2023 12:37:39 +0200 Subject: [PATCH 82/90] setup-miniconda runner instead of micromamba for planemo test --- .github/workflows/planemo.yml | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/.github/workflows/planemo.yml b/.github/workflows/planemo.yml index 45ed8c19..0677670f 100644 --- a/.github/workflows/planemo.yml +++ b/.github/workflows/planemo.yml @@ -8,6 +8,10 @@ defaults: run: shell: bash -l {0} +# setup micromamba doesn't work as galaxy setup by planemo requires conda. +# installing conda over into micromamba built env screws up the PATH +# setup-miniconda + changing over to libmamba to solve is the easiest workaround + jobs: planemo_test: name: Planemo test @@ -17,18 +21,24 @@ jobs: chunk: [1, 2, 3] steps: - uses: actions/checkout@v3 - - uses: mamba-org/setup-micromamba@main + - uses: conda-incubator/setup-miniconda@v2 with: - environment-file: .github/test_and_build.yml - cache-downloads: true - environment-name: test_and_build + miniconda-version: "latest" + auto-activate-base: true + channels-priority: strict + - name: setup env + run: | + conda env list + conda install -n base conda-libmamba-solver + conda config --set solver libmamba + conda env create -f .github/test_and_build.yml -n test_and_build - name: pip install run: | - micromamba activate test_and_build + conda activate test_and_build pip install . - name: planemo run: | - micromamba activate test_and_build + conda activate test_and_build ./.planemo.sh ${{ matrix.chunk }} ${{ env.GALAXY_BRANCH }} - uses: actions/upload-artifact@v3 with: From b80278aa04df9ab29eb3abf34aad8ba8a5a28c88 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Fri, 25 Aug 2023 12:37:54 +0200 Subject: [PATCH 83/90] print planemo version in shell runner --- .planemo.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.planemo.sh b/.planemo.sh index 8a6fd978..0a10b883 100755 --- a/.planemo.sh +++ b/.planemo.sh @@ -28,7 +28,8 @@ else galaxy/wrapper/plotProfiler.xml" fi +planemo --version planemo lint ${wrappers} -planemo test --no_dependency_resolution --conda_prefix /home/runner/micromamba/envs --galaxy_branch $2 --install_galaxy ${wrappers} 2>&1 +planemo test --no_dependency_resolution --galaxy_branch $2 --install_galaxy ${wrappers} 2>&1 mkdir upload mv tool_test_output* upload/ From 5d00cb57025c9f93820475ce800aa48f6e8d9932 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Fri, 25 Aug 2023 14:28:07 +0200 Subject: [PATCH 84/90] flake fixes tests --- .../test/test_computeMatrixOperations.py | 21 +- deeptools/test/test_heatmapper.py | 183 ++++++++++++------ deeptools/test/test_readFiltering.py | 6 +- deeptools/test/test_tools.py | 9 +- deeptools/test/test_writeBedGraph.py | 2 +- 5 files changed, 146 insertions(+), 75 deletions(-) diff --git a/deeptools/test/test_computeMatrixOperations.py b/deeptools/test/test_computeMatrixOperations.py index d19ceb9d..c253431d 100644 --- a/deeptools/test/test_computeMatrixOperations.py +++ b/deeptools/test/test_computeMatrixOperations.py @@ -39,7 +39,8 @@ def testSubset(self): h = hashlib.md5(f.read()).hexdigest() f.close() assert d == dCorrect - assert f"{h}" == f"edb3c8506c3f27ebb8c7ddf94d5ba594" + expectedh = 'edb3c8506c3f27ebb8c7ddf94d5ba594' + assert f'{h}' == f'{expectedh}' os.remove(oname) def testRelabel(self): @@ -73,7 +74,8 @@ def testfilterStrand(self): h = hashlib.md5(f.read()).hexdigest() f.close() assert d == dCorrect - assert f"{h}" == f"300f8000be5b5f51e803b57ef08f1c9e" + expectedh = '300f8000be5b5f51e803b57ef08f1c9e' + assert f'{h}' == f'{expectedh}' os.remove(oname) dCorrect = {u'verbose': True, u'scale': 1, u'skip zeros': False, u'nan after end': False, u'sort using': u'mean', u'unscaled 5 prime': [0, 0, 0, 0, 0, 0, 0, 0], u'body': [1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000], u'sample_labels': [u'SRR648667.forward', u'SRR648668.forward', u'SRR648669.forward', u'SRR648670.forward', u'SRR648667.reverse', u'SRR648668.reverse', u'SRR648669.reverse', u'SRR648670.reverse'], u'downstream': [0, 0, 0, 0, 0, 0, 0, 0], u'unscaled 3 prime': [0, 0, 0, 0, 0, 0, 0, 0], u'group_labels': [u'genes'], u'bin size': [10, 10, 10, 10, 10, 10, 10, 10], u'upstream': [0, 0, 0, 0, 0, 0, 0, 0], u'group_boundaries': [0, 89], u'sample_boundaries': [0, 100, 200, 300, 400, 500, 600, 700, 800], u'missing data as zero': False, u'ref point': [None, None, None, None, None, None, None, None], u'min threshold': None, u'sort regions': u'no', u'proc number': 20, u'bin avg type': u'mean', u'max threshold': None} @@ -86,7 +88,8 @@ def testfilterStrand(self): h = hashlib.md5(f.read()).hexdigest() f.close() assert d == dCorrect - assert f"{h}" == f"0a6ca070a5ba4564f1ab950ac3b7c8f1" + expectedh = '0a6ca070a5ba4564f1ab950ac3b7c8f1' + assert f'{h}' == f'{expectedh}' os.remove(oname) def testrbind(self): @@ -103,7 +106,8 @@ def testrbind(self): h = hashlib.md5(f.read()).hexdigest() f.close() assert d == dCorrect - assert f"{h}" == f"3dd96c7b05e0ca5ada21212defe57fba" + expectedh = '3dd96c7b05e0ca5ada21212defe57fba' + assert f'{h}' == f'{expectedh}' os.remove(oname) def testrbind2(self): @@ -120,7 +124,8 @@ def testrbind2(self): h = hashlib.md5(f.read()).hexdigest() f.close() assert d == dCorrect - assert f"{h}" == f"5d8b1517fc4c63d000b6b37f70ee163b" + expectedh = '5d8b1517fc4c63d000b6b37f70ee163b' + assert f'{h}' == f'{expectedh}' os.remove(oname) def testcbind(self): @@ -137,7 +142,8 @@ def testcbind(self): h = hashlib.md5(f.read()).hexdigest() f.close() assert d == dCorrect - assert f"{h}" == f"e55d89704bb16a11f366663a8fd90a47" + expectedh = 'e55d89704bb16a11f366663a8fd90a47' + assert f'{h}' == f'{expectedh}' os.remove(oname) def testsort(self): @@ -154,5 +160,6 @@ def testsort(self): h = hashlib.md5(f.read()).hexdigest() f.close() assert d == dCorrect - assert f"{h}" == f"10ea07d1aa58f44625abe2142ef76094" + expectedh = '10ea07d1aa58f44625abe2142ef76094' + assert f'{h}' == f'{expectedh}' os.remove(oname) diff --git a/deeptools/test/test_heatmapper.py b/deeptools/test/test_heatmapper.py index 2b14826b..7eb9d6d7 100644 --- a/deeptools/test/test_heatmapper.py +++ b/deeptools/test/test_heatmapper.py @@ -142,107 +142,168 @@ def test_computeMatrix_metagene(): def test_chopRegions_body(): region = [(0, 200), (300, 400), (800, 900)] lbins, bodybins, rbins, padLeft, padRight = deeptools.heatmapper.chopRegions(region, left=0, right=0) - assert f"{lbins}" == f"[]" - assert f"{rbins}" == f"[]" + e_lbins = [] + e_rbins = [] + e_padLeft = 0 + e_padRight = 0 + assert f"{lbins}" == f"{e_lbins}" + assert f"{rbins}" == f"{e_rbins}" assert f"{bodybins}" == f"{region}" - assert f"{padLeft}" == f"0" - assert f"{padRight}" == f"0" + assert f"{padLeft}" == f"{e_padLeft}" + assert f"{padRight}" == f"{e_padRight}" # Unscaled 5', 3' lbins, bodybins, rbins, padLeft, padRight = deeptools.heatmapper.chopRegions(region, left=150, right=150) - assert f"{lbins}" == f"[(0, 150)]" - assert f"{rbins}" == f"[(350, 400), (800, 900)]" - assert f"{bodybins}" == f"[(150, 200), (300, 350)]" - assert f"{padLeft}" == f"0" - assert f"{padRight}" == f"0" + e_lbins = [(0, 150)] + e_rbins = [(350, 400), (800, 900)] + e_bodybins = [(150, 200), (300, 350)] + e_padLeft = 0 + e_padRight = 0 + assert f"{lbins}" == f"{e_lbins}" + assert f"{rbins}" == f"{e_rbins}" + assert f"{bodybins}" == f"{e_bodybins}" + assert f"{padLeft}" == f"{e_padLeft}" + assert f"{padRight}" == f"{e_padRight}" def test_chopRegions_TSS(): region = [(0, 200), (300, 400), (800, 900)] # + strand, 250 downstream downstream, body, unscaled3prime, padRight, _ = deeptools.heatmapper.chopRegions(region, left=250) - assert f"{downstream}" == f"[(0, 200), (300, 350)]" - assert f"{body}" == f"[(350, 400), (800, 900)]" - assert f"{unscaled3prime}" == f"[]" - assert f"{padRight}" == f"0" - assert f"{_}" == f"0" + e_downstream = [(0, 200), (300, 350)] + e_body = [(350, 400), (800, 900)] + e_unscaled3prime = [] + e_padRight = 0 + e_ = 0 + assert f"{downstream}" == f"{e_downstream}" + assert f"{body}" == f"{e_body}" + assert f"{unscaled3prime}" == f"{e_unscaled3prime}" + assert f"{padRight}" == f"{e_padRight}" + assert f"{_}" == f"{e_}" # + strand, 500 downstream downstream, body, unscaled3prime, padRight, _ = deeptools.heatmapper.chopRegions(region, left=500) + e_body = [] + e_unscaled3prime = [] + e_padRight = 100 + e_ = 0 assert f"{downstream}" == f"{region}" - assert f"{body}" == f"[]" - assert f"{unscaled3prime}" == f"[]" - assert f"{padRight}" == f"100" - assert f"{_}" == f"0" + assert f"{body}" == f"{e_body}" + assert f"{unscaled3prime}" == f"{e_unscaled3prime}" + assert f"{padRight}" == f"{e_padRight}" + assert f"{_}" == f"{e_}" # - strand, 250 downstream (labeled "upstream" due to being on the - strand) unscaled5prime, body, upstream, _, padLeft = deeptools.heatmapper.chopRegions(region, right=250) - assert f"{upstream}" == f"[(150, 200), (300, 400), (800, 900)]" - assert f"{body}" == f"[(0, 150)]" - assert f"{unscaled5prime}" == f"[]" - assert f"{padLeft}" == f"0" - assert f"{_}" == f"0" + e_upstream = [(150, 200), (300, 400), (800, 900)] + e_body = [(0, 150)] + e_unscaled5prime = [] + e_padLeft = 0 + e_ = 0 + assert f"{upstream}" == f"{e_upstream}" + assert f"{body}" == f"{e_body}" + assert f"{unscaled5prime}" == f"{e_unscaled5prime}" + assert f"{padLeft}" == f"{e_padLeft}" + assert f"{_}" == f"{e_}" # - strand, 500 downstream (labeled "upstream" due to being on the - strand) unscaled5prime, body, upstream, _, padLeft = deeptools.heatmapper.chopRegions(region, right=500) + e_body = [] + e_unscaled5prime = [] + e_padLeft = 100 + e_ = 0 assert f"{upstream}" == f"{region}" - assert f"{body}" == f"[]" - assert f"{unscaled5prime}" == f"[]" - assert f"{padLeft}" == f"100" - assert f"{_}" == f"0" + assert f"{body}" == f"{e_body}" + assert f"{unscaled5prime}" == f"{e_unscaled5prime}" + assert f"{padLeft}" == f"{e_padLeft}" + assert f"{_}" == f"{e_}" def test_chopRegions_TES(): region = [(0, 200), (300, 400), (800, 900)] # + strand, 250 upstream unscaled5prime, body, upstream, _, padLeft = deeptools.heatmapper.chopRegions(region, right=250) - assert f"{unscaled5prime}" == f"[]" - assert f"{body}" == f"[(0, 150)]" - assert f"{upstream}" == f"[(150, 200), (300, 400), (800, 900)]" - assert f"{_}" == f"0" - assert f"{padLeft}" == f"0" + e_unscaled5prime = [] + e_body = [(0, 150)] + e_upstream = [(150, 200), (300, 400), (800, 900)] + e_ = 0 + e_padLeft = 0 + assert f"{unscaled5prime}" == f"{e_unscaled5prime}" + assert f"{body}" == f"{e_body}" + assert f"{upstream}" == f"{e_upstream}" + assert f"{_}" == f"{e_}" + assert f"{padLeft}" == f"{e_padLeft}" # + strand, 500 upstream unscaled5prime, body, upstream, _, padLeft = deeptools.heatmapper.chopRegions(region, right=500) - assert f"{unscaled5prime}" == f"[]" - assert f"{body}" == f"[]" + e_unscaled5prime = [] + e_body = [] + e_ = 0 + e_padLeft = 100 + assert f"{unscaled5prime}" == f"{e_unscaled5prime}" + assert f"{body}" == f"{e_body}" assert f"{upstream}" == f"{region}" - assert f"{_}" == f"0" - assert f"{padLeft}" == f"100" + assert f"{_}" == f"{e_}" + assert f"{padLeft}" == f"{e_padLeft}" # + strand, 250 downstream (labeled "upstream" due to being on the - strand) downstream, body, unscaled3prime, padRight, _ = deeptools.heatmapper.chopRegions(region, left=250) - assert f"{downstream}" == f"[(0, 200), (300, 350)]" - assert f"{body}" == f"[(350, 400), (800, 900)]" - assert f"{unscaled3prime}" == f"[]" - assert f"{padRight}" == f"0" - assert f"{_}" == f"0" + e_downstream = [(0, 200), (300, 350)] + e_body = [(350, 400), (800, 900)] + e_unscaled3prime = [] + e_padRight = 0 + e_ = 0 + assert f"{downstream}" == f"{e_downstream}" + assert f"{body}" == f"{e_body}" + assert f"{unscaled3prime}" == f"{e_unscaled3prime}" + assert f"{padRight}" == f"{e_padRight}" + assert f"{_}" == f"{e_}" # + strand, 500 downstream (labeled "upstream" due to being on the - strand) downstream, body, unscaled3prime, padRight, _ = deeptools.heatmapper.chopRegions(region, left=500) + e_body = [] + e_unscaled3prime = [] + e_padRight = 100 + e_ = 0 assert f"{downstream}" == f"{region}" - assert f"{body}" == f"[]" - assert f"{unscaled3prime}" == f"[]" - assert f"{padRight}" == f"100" - assert f"{_}" == f"0" + assert f"{body}" == f"{e_body}" + assert f"{unscaled3prime}" == f"{e_unscaled3prime}" + assert f"{padRight}" == f"{e_padRight}" + assert f"{_}" == f"{e_}" def test_chopRegionsFromMiddle(): region = [(0, 200), (300, 400), (800, 900)] # + strand, 100 upstream/200 downstream upstream, downstream, padLeft, padRight = deeptools.heatmapper.chopRegionsFromMiddle(region, left=100, right=200) - assert f"{upstream}" == f"[(100, 200)]" - assert f"{downstream}" ==f"[(300, 400), (800, 900)]" - assert f"{padLeft}" == f"0" - assert f"{padRight}" == f"0" + e_upstream = [(100, 200)] + e_downstream = [(300, 400), (800, 900)] + e_padLeft = 0 + e_padRight = 0 + assert f"{upstream}" == f"{e_upstream}" + assert f"{downstream}" == f"{e_downstream}" + assert f"{padLeft}" == f"{e_padLeft}" + assert f"{padRight}" == f"{e_padRight}" # + strand, 250 upstream/300 downstream upstream, downstream, padLeft, padRight = deeptools.heatmapper.chopRegionsFromMiddle(region, left=250, right=300) - assert f"{upstream}" == f"[(0, 200)]" - assert f"{downstream}" == f"[(300, 400), (800, 900)]" - assert f"{padLeft}" == f"50" - assert f"{padRight}" == f"100" + e_upstream = [(0, 200)] + e_downstream = [(300, 400), (800, 900)] + e_padLeft = 50 + e_padRight = 100 + assert f"{upstream}" == f"{e_upstream}" + assert f"{downstream}" == f"{e_downstream}" + assert f"{padLeft}" == f"{e_padLeft}" + assert f"{padRight}" == f"{e_padRight}" # - strand, 100 upstream/200 downstream upstream, downstream, padLeft, padRight = deeptools.heatmapper.chopRegionsFromMiddle(region, left=200, right=100) - assert f"{upstream}" == f"[(0, 200)]" - assert f"{downstream}" == f"[(300, 400)]" - assert f"{padLeft}" == f"0" - assert f"{padRight}" == f"0" + e_upstream = [(0, 200)] + e_downstream = [(300, 400)] + e_padLeft = 0 + e_padRight = 0 + assert f"{upstream}" == f"{e_upstream}" + assert f"{downstream}" == f"{e_downstream}" + assert f"{padLeft}" == f"{e_padLeft}" + assert f"{padRight}" == f"{e_padRight}" # - strand, 250 upstream/300 downstream upstream, downstream, padLeft, padRight = deeptools.heatmapper.chopRegionsFromMiddle(region, left=300, right=250) - assert f"{upstream}" == f"[(0, 200)]" - assert f"{downstream}" == f"[(300, 400), (800, 900)]" - assert f"{padLeft}" == f"100" - assert f"{padRight}" == f"50" + e_upstream = [(0, 200)] + e_downstream = [(300, 400), (800, 900)] + e_padLeft = 100 + e_padRight = 50 + assert f"{upstream}" == f"{e_upstream}" + assert f"{downstream}" == f"{e_downstream}" + assert f"{padLeft}" == f"{e_padLeft}" + assert f"{padRight}" == f"{e_padRight}" diff --git a/deeptools/test/test_readFiltering.py b/deeptools/test/test_readFiltering.py index cfce0530..8227530f 100644 --- a/deeptools/test/test_readFiltering.py +++ b/deeptools/test/test_readFiltering.py @@ -74,11 +74,13 @@ def test_sieve(): assert f"{resp}" == f"{expected}", f"{resp} != {expected}" unlink(outlog) h = hashlib.md5(pysam.view(outfile).encode('utf-8')).hexdigest() - assert f"{h}" == f"acbc4443fb0387bfd6c412af9d4fc414" + expectedh = 'acbc4443fb0387bfd6c412af9d4fc414' + assert f'{h}' == f'{expectedh}' unlink(outfile) h1 = hashlib.md5(pysam.view(outfiltered).encode('utf-8')).hexdigest() - assert f"{h1}" == f"b90befdd5f073f14acb9a38661f301ad" + expectedh = 'b90befdd5f073f14acb9a38661f301ad' + assert f"{h1}" == f"{expectedh}" unlink(outfiltered) diff --git a/deeptools/test/test_tools.py b/deeptools/test/test_tools.py index e06390e8..c9b7a806 100644 --- a/deeptools/test/test_tools.py +++ b/deeptools/test/test_tools.py @@ -18,11 +18,12 @@ def test_tools(): _toml = tomllib.load(f) for _p in _toml['project']['scripts'].keys(): _res = run( - [_p, f"--version"], + [_p, "--version"], stdout=PIPE, stderr=PIPE ) _version = _res.stdout.decode().splitlines()[0] - assert f"{_version}" == f"{_p} {_toml['project']['version']}" - assert f"{_res.returncode}" == f"0" - + e_ver = _p + " " + _toml['project']['version'] + assert f"{_version}" == f"{e_ver}" + e_retc = 0 + assert f"{_res.returncode}" == f"{e_retc}" diff --git a/deeptools/test/test_writeBedGraph.py b/deeptools/test/test_writeBedGraph.py index 1a9c6ec4..1ca05e7c 100644 --- a/deeptools/test/test_writeBedGraph.py +++ b/deeptools/test/test_writeBedGraph.py @@ -31,7 +31,7 @@ def test_writeBedGraph_worker(self, bc): _foo = open(tempFile[3], 'r') res = _foo.readlines() _foo.close() - expected = ['3R\t0\t100\t0\n', '3R\t100\t200\t1\n'] + expected = ['3R\t0\t100\t0\n', '3R\t100\t200\t1\n'] assert f"{res}" == f"{expected}" os.remove(tempFile[3]) From 04b7a670a7fd29c0b466d96e25a5686d5f5c88d0 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Fri, 25 Aug 2023 14:44:07 +0200 Subject: [PATCH 85/90] drop channelprio / planemo fingerprint back to 13 (again) --- .github/workflows/planemo.yml | 1 - .../wrapper/test-data/plotFingerprint_quality_metrics.tabular | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/planemo.yml b/.github/workflows/planemo.yml index 0677670f..bc7e4b0b 100644 --- a/.github/workflows/planemo.yml +++ b/.github/workflows/planemo.yml @@ -25,7 +25,6 @@ jobs: with: miniconda-version: "latest" auto-activate-base: true - channels-priority: strict - name: setup env run: | conda env list diff --git a/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular b/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular index f2e16088..84d5d720 100644 --- a/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular +++ b/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular @@ -1,3 +1,3 @@ Sample AUC Synthetic AUC X-intercept Synthetic X-intercept Elbow Point Synthetic Elbow Point JS Distance Synthetic JS Distance % genome enriched diff. enrichment CHANCE divergence -bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 nan 0.2690044980681214 nan nan nan -bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 0.0 0.2690044980681214 0 0 0 +bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 nan 0.2690044980681213 nan nan nan +bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 0.0 0.2690044980681213 0 0 0 From ba71cbe6c98d833f56d4f7cdfd957ffeab56319e Mon Sep 17 00:00:00 2001 From: WardDeb Date: Fri, 25 Aug 2023 15:19:26 +0200 Subject: [PATCH 86/90] update changelog --- CHANGES.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGES.txt b/CHANGES.txt index d17ab90f..335dbc80 100755 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,3 +1,13 @@ +3.5.3 +* requirement cap for matplotlib lifted (changes in plotting can occur) +* nose has been deprecated in favor of pytests +* pytests run with python 3.7 - 3.11 +* toml file for installation, requirements, versioning and executables +* planemo tests updated to galaxy 23.1 +* custom github action runner deprecated +* deprecation of np types for builtin types +* stricter label checks and validator in galaxy + 3.5.2 * new subcommand: Bigwig average #1169 * dendogram of plotCorrelation now matches each cell correctly From f536776850f08d54de8724cc5cf551f76ad3064f Mon Sep 17 00:00:00 2001 From: WardDeb Date: Mon, 28 Aug 2023 15:11:07 +0200 Subject: [PATCH 87/90] update galaxy version & tool version in galaxy xml --- galaxy/wrapper/deepTools_macros.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/galaxy/wrapper/deepTools_macros.xml b/galaxy/wrapper/deepTools_macros.xml index 7846e9ae..98c916c8 100755 --- a/galaxy/wrapper/deepTools_macros.xml +++ b/galaxy/wrapper/deepTools_macros.xml @@ -1,8 +1,8 @@ --numberOfProcessors "\${GALAXY_SLOTS:-4}" - 3.5.2 - 20.01 + 3.5.3 + 23.01 deeptools From 816033ded354769691c43a95b2001990d043fe25 Mon Sep 17 00:00:00 2001 From: WardDeb Date: Mon, 28 Aug 2023 16:52:30 +0200 Subject: [PATCH 88/90] round getJSDcommon to 16 decimals, attempt to fix planemo test --- deeptools/plotFingerprint.py | 4 ++-- .../wrapper/test-data/plotFingerprint_quality_metrics.tabular | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/deeptools/plotFingerprint.py b/deeptools/plotFingerprint.py index 550931f9..a3bbfc54 100755 --- a/deeptools/plotFingerprint.py +++ b/deeptools/plotFingerprint.py @@ -344,8 +344,8 @@ def signalAndBinDist(x): # Compute the JSD from the PMFs M = (PMFinput + PMFchip) / 2.0 JSD = 0.5 * (np.nansum(PMFinput * np.log2(PMFinput / M))) + 0.5 * (np.nansum(PMFchip * np.log2(PMFchip / M))) - - return np.sqrt(JSD) + # Round sqrt of JSD to 16 decimals, as planemo test has issue with rounding ? + return round(np.sqrt(JSD), 16) def getExpected(mu): diff --git a/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular b/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular index 84d5d720..f2e16088 100644 --- a/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular +++ b/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular @@ -1,3 +1,3 @@ Sample AUC Synthetic AUC X-intercept Synthetic X-intercept Elbow Point Synthetic Elbow Point JS Distance Synthetic JS Distance % genome enriched diff. enrichment CHANCE divergence -bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 nan 0.2690044980681213 nan nan nan -bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 0.0 0.2690044980681213 0 0 0 +bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 nan 0.2690044980681214 nan nan nan +bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 0.0 0.2690044980681214 0 0 0 From 2402f0e7333348ef55ee831c878ee3a1b423a29a Mon Sep 17 00:00:00 2001 From: WardDeb Date: Mon, 28 Aug 2023 18:57:26 +0200 Subject: [PATCH 89/90] JSD round to 15 decimals --- deeptools/plotFingerprint.py | 4 ++-- .../wrapper/test-data/plotFingerprint_quality_metrics.tabular | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/deeptools/plotFingerprint.py b/deeptools/plotFingerprint.py index a3bbfc54..3adce87a 100755 --- a/deeptools/plotFingerprint.py +++ b/deeptools/plotFingerprint.py @@ -344,8 +344,8 @@ def signalAndBinDist(x): # Compute the JSD from the PMFs M = (PMFinput + PMFchip) / 2.0 JSD = 0.5 * (np.nansum(PMFinput * np.log2(PMFinput / M))) + 0.5 * (np.nansum(PMFchip * np.log2(PMFchip / M))) - # Round sqrt of JSD to 16 decimals, as planemo test has issue with rounding ? - return round(np.sqrt(JSD), 16) + # Round sqrt of JSD to 15 decimals, as planemo test has issue with rounding ? + return round(np.sqrt(JSD), 15) def getExpected(mu): diff --git a/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular b/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular index f2e16088..69cba649 100644 --- a/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular +++ b/galaxy/wrapper/test-data/plotFingerprint_quality_metrics.tabular @@ -1,3 +1,3 @@ Sample AUC Synthetic AUC X-intercept Synthetic X-intercept Elbow Point Synthetic Elbow Point JS Distance Synthetic JS Distance % genome enriched diff. enrichment CHANCE divergence -bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 nan 0.2690044980681214 nan nan nan -bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 0.0 0.2690044980681214 0 0 0 +bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 nan 0.269004498068121 nan nan nan +bowtie2 test1.bam 0.00493632029863651 0.481650684757865 0.984443061605476 1.1531044350267195e-24 0.9849408836341008 0.5232688298112538 0.0 0.269004498068121 0 0 0 From 292b4923fc452caea8615dd109338b89e572a781 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gr=C3=BCning?= Date: Tue, 29 Aug 2023 09:42:18 +1000 Subject: [PATCH 90/90] decrease galaxy profile version The profile version does not need to be the latest Galaxy version. It specifies the latest version in which those tools will work. So it would be better to keep it a bit lower. Otherwise, older Galaxy instances can not install this tool. --- galaxy/wrapper/deepTools_macros.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/galaxy/wrapper/deepTools_macros.xml b/galaxy/wrapper/deepTools_macros.xml index 98c916c8..2f8b8200 100755 --- a/galaxy/wrapper/deepTools_macros.xml +++ b/galaxy/wrapper/deepTools_macros.xml @@ -2,7 +2,7 @@ --numberOfProcessors "\${GALAXY_SLOTS:-4}" 3.5.3 - 23.01 + 22.05 deeptools