From fdf34f51e5cddf5a2c817e150a1e0f6e7a29d80e Mon Sep 17 00:00:00 2001 From: Jonathan Manning Date: Thu, 4 Feb 2021 10:34:38 +0000 Subject: [PATCH 1/4] Add Bioconda install instructions --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 74b3d40..a33ccea 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,13 @@ -[![Anaconda-Server Badge](https://anaconda.org/ebi-gene-expression-group/perl-atlas-modules/badges/installer/conda.svg)](https://conda.anaconda.org/ebi-gene-expression-group) +[![Anaconda-Server Badge](https://anaconda.org/bioconda/perl-atlas-modules/badges/installer/conda.svg)](https://conda.anaconda.org/bioconda) # Atlas in house perl modules Repository includes internal perl modules that is used for processing studies in atlas data production pipeline particularly handling MAGE-TABs, baseline and differential analysis, zooma mappings, release data exports. + +## Install + +perl-atlas-modules can be installed from Bioconda: + +``` +conda install -c bioconda perl-atlas-modules +``` From 1997696720040052d23783fd751c6900631ef758 Mon Sep 17 00:00:00 2001 From: anjaf Date: Fri, 19 Mar 2021 10:02:11 +0000 Subject: [PATCH 2/4] Optional ADFs-checked files (#11) * Make adf_checked files writing optional based on flag in config * Option in AE config for using the adf_checked files * Reverse logic to actively (not passively) skip checks --- perl_modules/EBI/FGPT/CheckSet/AEAtlas.pm | 233 ++++++++++---------- supporting_files/ArrayExpressSiteConfig.yml | 1 + 2 files changed, 120 insertions(+), 114 deletions(-) diff --git a/perl_modules/EBI/FGPT/CheckSet/AEAtlas.pm b/perl_modules/EBI/FGPT/CheckSet/AEAtlas.pm index 42875d4..ee3e9ad 100644 --- a/perl_modules/EBI/FGPT/CheckSet/AEAtlas.pm +++ b/perl_modules/EBI/FGPT/CheckSet/AEAtlas.pm @@ -1390,26 +1390,26 @@ Checks ADF(s) against YAML config file to ensure they are supported by the Atlas sub check_microarray_adf_support { - my ( $self ) = @_; + my ($self) = @_; + + $self->info("Checking for array design support in Atlas..."); - $self->info( "Checking for array design support in Atlas..." ); - my $microarrayAssays = $self->_collect_microarray_assays; - unless( @{ $microarrayAssays } ) { + unless (@{$microarrayAssays}) { - $self->debug( "No microarray assays found, not checking array design support." ); + $self->debug("No microarray assays found, not checking array design support."); return; } - + # Get the unique array design accessions from these assays. my $assaysWithAdfs = {}; - foreach my $assay ( @{ $microarrayAssays } ) { + foreach my $assay (@{$microarrayAssays}) { - unless( $assay->has_arrayDesign ) { + unless ($assay->has_arrayDesign) { $self->warn( "No array design found for assay \"", @@ -1417,17 +1417,17 @@ sub check_microarray_adf_support { "\" -- cannot check array design support." ); - $self->_add_atlas_fail_code( -2 ); + $self->_add_atlas_fail_code(-2); next; } - else { + else { $assaysWithAdfs->{ $assay->get_name } = $assay; } } - + # If there are no assays with ADFs, quit here. - unless( keys %{ $assaysWithAdfs } ) { + unless (keys %{$assaysWithAdfs}) { $self->error( "No assays with array designs found." @@ -1436,131 +1436,136 @@ sub check_microarray_adf_support { return; } - my %magetabAdfAccs = map { $_->get_arrayDesign->get_name => 1 } ( values %{ $assaysWithAdfs } ); - - - - ####################################### - ####################################### - # TODO: can/should we consolidate files? - my $adf_tracking_file_path = $CONFIG->get_ADF_CHECKED_LIST; + my %magetabAdfAccs = map {$_->get_arrayDesign->get_name => 1} (values %{$assaysWithAdfs}); - my $expt_tracking_file_path = $CONFIG->get_ATLAS_EXPT_CHECKED_LIST; - my ( %absent_adf_acc_count, @checked_expt_list ); - open( IN, $adf_tracking_file_path ) - || $self->logdie( -"Can't open file $adf_tracking_file_path to fetch the list of ADFs which are not in the Atlas database." - ); - - while () { - my ( $old_adf_acc, $count ) = $_ =~ /^(A-[A-Z]{4}-\d+)\t(\d+)$/; - $absent_adf_acc_count{$old_adf_acc} = $count; - } - - close IN; + # A "true" flag in the config can be used to skip the writing to the "checked files" + my $skip_tracking_files = $CONFIG->get_SKIP_CHECKED_LIST_FILES eq "true"; + if ($skip_tracking_files) { + $self->debug("Skipping writing to ADF checked files"); + } + my (%absent_adf_acc_count, @checked_expt_list); - open( IN2, $expt_tracking_file_path ) - || $self->logdie( -"Can't open file $expt_tracking_file_path to fetch the list of experiments already checked for Atlas eligibility." - ); - while () { - chomp $_; - push( @checked_expt_list, $_ ); - } + my @acc_comments = + grep {$_->get_name eq "ArrayExpressAccession"} + @{$self->get_investigation->get_comments || []}; + my $expt_acc; + if ($acc_comments[0]) { # In case the spreadsheet is in AE curation stage still and has no such comment yet + $expt_acc = $acc_comments[0]->get_value if ($acc_comments[0]); + } + else { + $expt_acc = "dummy_expt_acc"; + } - close IN2; -# We need to keep track of whether this experiment has been checked before for Atlas eligibility -# If yes, and if the experiment's ADF is not in Atlas database, we don't increment the ADF count -# in adfs_not_in_atlas.txt file (or else many ADFs will be counted multiple times as the cause -# of failing Atlas eligiblity) + my $atlasSiteConfig = $self->get_atlas_site_config; - my @acc_comments = - grep { $_->get_name eq "ArrayExpressAccession" } - @{ $self->get_investigation->get_comments || [] }; - my $expt_acc; - if ( $acc_comments[0] ) - { # In case the spreadsheet is in AE curation stage still and has no such comment yet - $expt_acc = $acc_comments[0]->get_value if ( $acc_comments[0] ); - } - else { - $expt_acc = "dummy_expt_acc"; - } - # TODO: end - ####################################### - ####################################### + my %supportedAdfs = map {$_ => 1} (keys %{$atlasSiteConfig->get_atlas_supported_adfs}); + foreach my $arrayDesignAcc (keys %magetabAdfAccs) { - my $atlasSiteConfig = $self->get_atlas_site_config; + if ($arrayDesignAcc =~ /A-[A-Z]{4}-\d+$/) { - my %supportedAdfs = map { $_ => 1 } ( keys %{ $atlasSiteConfig->get_atlas_supported_adfs } ); + ### FIXME: Need to get ADF synonyms and parse them too. get from AE2 DB? - foreach my $arrayDesignAcc ( keys %magetabAdfAccs ) { - - if ( $arrayDesignAcc =~ /A-[A-Z]{4}-\d+$/ ) { - - ### FIXME: Need to get ADF synonyms and parse them too. get from AE2 DB? + unless ($supportedAdfs{ $arrayDesignAcc }) { - unless( $supportedAdfs{ $arrayDesignAcc } ) { - $self->error( - "Array design \"$arrayDesignAcc\" is not currently supported by Atlas." + "Array design \"$arrayDesignAcc\" is not currently supported by Atlas." ); - - $self->_add_atlas_fail_code( 2 ); - - # if this experiment is checked for Atlas eligility for the first time - if ( ( !grep $expt_acc eq $_, @checked_expt_list ) ) { - - push( @checked_expt_list, $expt_acc ); - - # if this ADF acc has been flagged before, increment the count - if ( $absent_adf_acc_count{ $arrayDesignAcc } ) { - $absent_adf_acc_count{ $arrayDesignAcc }++; - } - else { - # initiate a record of this ADF acc and start with count 1 - $absent_adf_acc_count{ $arrayDesignAcc } = 1; - } - } - } - } + + $self->_add_atlas_fail_code(2); + + # if this experiment is checked for Atlas eligility for the first time + if ((!grep $expt_acc eq $_, @checked_expt_list)) { + + push(@checked_expt_list, $expt_acc); + + # if this ADF acc has been flagged before, increment the count + if ($absent_adf_acc_count{ $arrayDesignAcc }) { + $absent_adf_acc_count{ $arrayDesignAcc }++; + } + else { + # initiate a record of this ADF acc and start with count 1 + $absent_adf_acc_count{ $arrayDesignAcc } = 1; + } + } + } + } # Catch cases where non AE ADF accession is provided. - else { + else { - $self->error( + $self->error( "Array design \"", $arrayDesignAcc, "\" is not a valid ArrayExpress array design accession and hence is not supported by Atlas." - ); + ); - $self->_add_atlas_fail_code( 2 ); - } - } + $self->_add_atlas_fail_code(2); + } + } - # TODO: investigate consolidating the two files. - # Now update the tracking files - open( OUT, ">$adf_tracking_file_path" ) - || $self->logdie( -"Can't open file $adf_tracking_file_path to write the list of updated ADFs which are not supported by Atlas." - ); - foreach my $key ( keys %absent_adf_acc_count ) { - print OUT "$key\t$absent_adf_acc_count{$key}\n"; - } - close OUT; - - open( OUT2, ">$expt_tracking_file_path" ) - || $self->logdie( -"Can't open file $expt_tracking_file_path to write the list of experiments already checked for Atlas eligiblity." - ); - foreach (@checked_expt_list) { - print OUT2 "$_\n"; - } - close OUT2; + unless ($skip_tracking_files) { + + ####################################### + ####################################### + # TODO: can/should we consolidate files? + + my $adf_tracking_file_path = $CONFIG->get_ADF_CHECKED_LIST; + my $expt_tracking_file_path = $CONFIG->get_ATLAS_EXPT_CHECKED_LIST; + + open(IN, $adf_tracking_file_path) + || $self->logdie( + "Can't open file $adf_tracking_file_path to fetch the list of ADFs which are not in the Atlas database." + ); + + while () { + my ($old_adf_acc, $count) = $_ =~ /^(A-[A-Z]{4}-\d+)\t(\d+)$/; + $absent_adf_acc_count{$old_adf_acc} = $count; + } + + close IN; + + open(IN2, $expt_tracking_file_path) + || $self->logdie( + "Can't open file $expt_tracking_file_path to fetch the list of experiments already checked for Atlas eligibility." + ); + + while () { + chomp $_; + push(@checked_expt_list, $_); + } + + close IN2; + + # We need to keep track of whether this experiment has been checked before for Atlas eligibility + # If yes, and if the experiment's ADF is not in Atlas database, we don't increment the ADF count + # in adfs_not_in_atlas.txt file (or else many ADFs will be counted multiple times as the cause + # of failing Atlas eligiblity) + + # TODO: investigate consolidating the two files. + # Now update the tracking files + open(OUT, ">$adf_tracking_file_path") + || $self->logdie( + "Can't open file $adf_tracking_file_path to write the list of updated ADFs which are not supported by Atlas." + ); + foreach my $key (keys %absent_adf_acc_count) { + print OUT "$key\t$absent_adf_acc_count{$key}\n"; + } + close OUT; + + open(OUT2, ">$expt_tracking_file_path") + || $self->logdie( + "Can't open file $expt_tracking_file_path to write the list of experiments already checked for Atlas eligiblity." + ); + foreach (@checked_expt_list) { + print OUT2 "$_\n"; + } + close OUT2; + } $self->info( "Finshed checking for Atlas array design support..." ); } diff --git a/supporting_files/ArrayExpressSiteConfig.yml b/supporting_files/ArrayExpressSiteConfig.yml index 59a8c88..860be7c 100755 --- a/supporting_files/ArrayExpressSiteConfig.yml +++ b/supporting_files/ArrayExpressSiteConfig.yml @@ -78,6 +78,7 @@ VALIDATION_SCRIPT: # Location of ADF and Experiments checked in Atlas.pm ADF_CHECKED_LIST: /nfs/production3/ma/home/atlas3-production/sw/configs/adfs_not_in_atlas.txt ATLAS_EXPT_CHECKED_LIST: /nfs/production3/ma/home/atlas3-production/sw/configs/expts_checked_for_atlas.txt +SKIP_CHECKED_LIST_FILES: true PRIVATE_ADF_USERNAME: xxxx PRIVATE_ADF_PASSWORD: xxxxx From 920a56cdffd037a4c356a1829197c67065f9b004 Mon Sep 17 00:00:00 2001 From: anjaf Date: Thu, 29 Apr 2021 11:35:06 +0100 Subject: [PATCH 3/4] Remove usage of AE database for curation checks (#16) * Comment out usage of AE database for curation checks * Remove check_for_previously_loaded_files entirely * Decrease severity for file check skipping (it's making the output hard to read) * Better solution for identifying and skipping Illumina matrix files * Remove ADF name retrieval from AE DB, it's seems to be just for the error message * Reinstate warning about GEO arrays without features * Fix how variable is passed to get_array_design_name * Remove debug-print --- perl_modules/EBI/FGPT/CheckSet/Curation.pm | 142 ++---------------- .../EBI/FGPT/Resource/ArrayExpressREST.pm | 75 +++++---- 2 files changed, 54 insertions(+), 163 deletions(-) diff --git a/perl_modules/EBI/FGPT/CheckSet/Curation.pm b/perl_modules/EBI/FGPT/CheckSet/Curation.pm index 18ba245..4dd6b5c 100644 --- a/perl_modules/EBI/FGPT/CheckSet/Curation.pm +++ b/perl_modules/EBI/FGPT/CheckSet/Curation.pm @@ -14,16 +14,16 @@ EBI::FGPT::CheckSet::Curation =head1 SYNOPSIS - + use EBI::FGPT; - + my $check_sets = { 'EBI::FGPT::CheckSet::Curation' => 'curator_checks', }; my $idf = $ARGV[0]; - my $checker = EBI::FGPT::Reader::MAGETAB->new( - 'idf' => $idf, + my $checker = EBI::FGPT::Reader::MAGETAB->new( + 'idf' => $idf, 'check_sets' => $check_sets, ); $checker->parse(); @@ -87,8 +87,6 @@ MD5, compression checks and previously loaded file checks are only run on non-ma For files with a Comment[MD5] their actual MD5 sum must match that specified (ERROR) -File MD5 is checked against those stored in AE to check for previously loaded (WARN) - The following checks are only run on files which are assoicated with an array design: Affymetrix CHP file must be listed as Derived data (ERROR) @@ -107,7 +105,7 @@ If file contains exactly 65535 rows it may have been truncated by old version of All design elements in the file must be described on the array design (ERROR) -We skip MD5, compression checks and previously loaded file checks for raw seq files +We skip MD5, compression checks for raw seq files =cut @@ -227,7 +225,6 @@ augment 'run_sdrf_checks' => sub { # Only run on non-matrix files $self->run_data_md5_check(); $self->check_compressed_file_integrity(); - $self->check_for_previously_loaded_files(); $self->check_for_derived_data(); }; @@ -311,7 +308,7 @@ sub check_compressed_file_integrity { $is_seq = grep { $_ =~ /sequencing/i } @tech_types; if ( $is_seq and ( $type eq "raw" ) ) { - $self->warn( "Skipping compression check for", + $self->info( "Skipping compression check for", $name . " (assuming it is sequencing data)" ); next; } @@ -427,7 +424,7 @@ sub run_data_md5_check { grep { $_ and $_->get_name eq "MD5" } $file->get_comments; if ( $is_seq and ( $type eq "raw" ) ) { - $self->warn( "Skipping MD5 checks for ", + $self->info( "Skipping MD5 checks for ", $name . " (assuming it is sequencing data)" ); # Should throw error if no MD5s provided by submitter @@ -483,116 +480,6 @@ sub run_data_md5_check { } } -sub check_for_previously_loaded_files { - my ($self) = @_; - - if ( $self->get_skip_data_checks ) { - $self->warn("Skipping check for previously loaded files"); - return; - } - - # MD5 of loaded files is stored in AE data table - foreach my $file ( $self->get_magetab->get_dataFiles ) { - my ( $path, $name ) = $self->_get_file_path($file); - - # Ignore raw seq files, to do this we determine if assay - # attached to file has technology type "sequencing" - - my $type = $file->get_dataType->get_value; - my @inputEdges = $file->get_inputEdges; - my $assay; - my @tech_types; - - # Store technology type associated with raw file - if ( $type eq "raw" ) { - foreach my $inputEdge (@inputEdges) { - - # If file input is an assay get technology type - if ( $inputEdge->get_inputNode->isa("Bio::MAGETAB::Assay") ) { - $assay = $inputEdge->get_inputNode; - push @tech_types, $assay->get_technologyType->get_value; - } - - # If file input is a scan - elsif ( - $inputEdge->get_inputNode->isa( - "Bio::MAGETAB::DataAcquisition") - ) - { - - my $scan = $inputEdge->get_inputNode; - my @scanEdges = $scan->get_inputEdges; - - foreach my $scanEdge (@scanEdges) { - if ( - $scanEdge->get_inputNode->isa( - "Bio::MAGETAB::Assay") - ) - { - $assay = $scanEdge->get_inputNode; - push @tech_types, - $assay->get_technologyType->get_value; - } - } - } - - else { - $self->warn( - "Cannot determine technology type for " . $name ); - } - - } - } - - my $is_seq; - $is_seq = grep { $_ =~ /sequencing/i } @tech_types; - - if ( $is_seq and ( $type eq "raw" ) ) { - $self->warn( - "Skipping previously loaded file check for", - $name . " (assuming it is sequencing data)" - ); - next; - } - - open( my $fh, "<", $path ) - or ( - $self->error( - "Could not open $path to check for previously loaded files"), - next - ); - - my $md5 = Digest::MD5->new(); - my $chunk; - my $chunksize = - 65536; # 64k for reasonable efficiency (untested though). - while ( my $bytes = read( $fh, $chunk, $chunksize ) ) { - $md5->add($chunk); - } - - my $actual_md5 = $md5->hexdigest(); - - # Connect to AE to check MD5 - my $ae_db = EBI::FGPT::Resource::Database::ArrayExpress->new(); - my $md5_info = $ae_db->check_md5_in_database($actual_md5); - my @md5_info = @{$md5_info}; - - if (@md5_info) { - foreach my $ae_md5_info (@md5_info) { - my @ae_md5_info = @{$ae_md5_info}; - my $accs = $ae_md5_info[0]; - $accs =~ s/\\.+//g; - my $ae_file_name = $ae_md5_info[1]; - my $ae_md5 = $ae_md5_info[2]; - $self->warn( -"$name has been previously loaded for experiment: $accs with name $ae_file_name" - ); - } - } - - } # End checking of files - -} sub _get_file_path { @@ -678,11 +565,9 @@ sub run_data_checks { # Skip checking Illumina BeadChip files - my $ae_db = EBI::FGPT::Resource::Database::ArrayExpress->new(); - my $array_design_name = - $ae_db->get_array_design_name_by_acc( $file->{array} ) - if ($ae_db); - if ( ($array_design_name) && ( $array_design_name =~ /Illumina/ ) ) { + my $array_design_name = $self->get_ae_rest->get_array_design_name( $file->{array} ); + + if ( ($array_design_name ) && ( $array_design_name =~ /Illumina/ ) ) { $self->warn( "Recognised Illumina array using ADF name \'$array_design_name\', skipping checking file " . $file->{name} ); @@ -1233,13 +1118,8 @@ sub check_features_match_array { } elsif ( !$identifiers && $acc =~ /^A-GEOD-/ ) { - -# getting ADF name from DB and not from parsed ADF, in case ADF parsing failed and parser is undef - - my $ae_db = EBI::FGPT::Resource::Database::ArrayExpress->new(); - my $adf_name = $ae_db->get_array_design_name_by_acc($acc); $self->warn( - "No $heading found for GEO array $acc ($adf_name), ", + "No $heading found for GEO array $acc, ", "skipping identifier checks for file ", $file->get_name ); diff --git a/perl_modules/EBI/FGPT/Resource/ArrayExpressREST.pm b/perl_modules/EBI/FGPT/Resource/ArrayExpressREST.pm index 0880b4f..833d36e 100644 --- a/perl_modules/EBI/FGPT/Resource/ArrayExpressREST.pm +++ b/perl_modules/EBI/FGPT/Resource/ArrayExpressREST.pm @@ -1,7 +1,7 @@ #!/usr/bin/env perl # # EBI/FGPT/Resource/ArrayExpressREST -# +# # Anna Farne 2012 ArrayExpress team, EBI # # $Id: ArrayExpressREST.pm 21742 2012-11-19 12:55:13Z amytang $ @@ -25,19 +25,19 @@ use EBI::FGPT::Config qw($CONFIG); has 'array_list' => (is => 'rw', isa => 'HashRef', builder => '_load_array_list' , lazy => 1); sub _load_array_list{ - + my ($self) = @_; - + # Set the array list to empty hash so the builder is # not called again if array list fails to load $self->set_array_list({}); - + # FIXME: do we have external version of this uri for public arrays only? my $uri = $CONFIG->get_AE_ARRAYDESIGN_LIST or croak("AE_ARRAYDESIGN_LIST URI not set in Config file - cannot load array design list"); my $ua = $self->get_user_agent; - + my $response = $ua->get($uri); if ($response->is_success) { my @lines = split /\n/, $response->content; @@ -51,40 +51,51 @@ sub _load_array_list{ } else { croak("Could not get array design list from $uri - ".$response->status_line); - } + } } -sub get_affy_design_id{ - +sub get_array_design_name{ + my ($self, $acc) = @_; - + unless(scalar %{ $self->get_array_list }){ - croak("Array list not loaded"); + croak("Array list not loaded"); } - + my $name = $self->get_array_list->{$acc}; - + + if ($name){ + return $name; + } + else{ + croak("Array accession $acc not found in ArrayExpress"); + } +} + +sub get_affy_design_id{ + + my ($self, $acc) = @_; + + my $name = $self->get_array_design_name($acc); + if ($name){ my $design_id; - + if ($name =~ m/\[ ([^\]]+) \]/xms){ $design_id = $1; } - return $design_id; } - else{ - croak("Array accession $acc not found in ArrayExpress"); - } } + sub get_adf{ - my $uri_base = $CONFIG->get_PRIVATE_ADF_URI_BASE; + my $uri_base = $CONFIG->get_PRIVATE_ADF_URI_BASE; # e.g. "http://www.ebi.ac.uk/arrayexpress/files/", to be appended by "A-AFFY-1/A-AFFY-1.adf.txt" later - + my ($self,$acc) = @_; - + my $cookie_jar = HTTP::Cookies->new(); @@ -95,36 +106,36 @@ sub get_adf{ # Creating the user agent directl using LWP::UserAgent has solved the problem, hence this change. #my $ua = $self->get_user_agent(); - my $ua = LWP::UserAgent->new(); + my $ua = LWP::UserAgent->new(); $ua->cookie_jar($cookie_jar); #empty jar, no cookies yet. User agent also not associated with any proxy. - + # We are logging in with username and password to retrieve ADF. This is not # really required for public ADFs but at this point we don't really # know whether the ADF is public or private, so it's better to treat # all ADFs are private. - + # Fire the first HTTP request to get the login token cookie: - + my $username = $CONFIG->get_PRIVATE_ADF_USERNAME; my $password = $CONFIG->get_PRIVATE_ADF_PASSWORD; - + my $verify_site = 'http://www.ebi.ac.uk/arrayexpress/verify-login.txt?u='.$username.'&p='.$password; my $verify_response = $ua->get($verify_site); - + my $uri = $uri_base."$acc/$acc.adf.txt"; - + # Assign the two required cookies to the user agent object $cookie_jar->set_cookie(0,'AeLoginToken', $verify_response->content, '/','www.ebi.ac.uk'); $cookie_jar->set_cookie(0,'AeLoggedUser', 'curator','/','www.ebi.ac.uk'); - + # print "Set Cookie Jar?\n", $ua->cookie_jar->as_string, "\n"; # DEBUG - + # Fire the second HTTP request from the same user agent to get the ADF - + my $response = $ua->get($uri); - + my $adf; if ($response->is_success) { $adf = $response->content; @@ -132,7 +143,7 @@ sub get_adf{ else { croak("Could not get ADF from $uri - ".$response->status_line); } - + return $adf; } 1; From 6c27ad7ce708b89ed2167a613e32235b8f39ccb7 Mon Sep 17 00:00:00 2001 From: Anja Fullgrabe Date: Thu, 6 May 2021 14:45:50 +0100 Subject: [PATCH 4/4] New version 0.2.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index c946ee6..0ea3a94 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.6 +0.2.0