From 761092b726e4bd92741bb221a1290c3fd8bd496b Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Tue, 14 Apr 2020 10:13:30 -0400 Subject: [PATCH] Remove deprecated LinearAlgebra::distributed::Vector member functions --- .../incompatibilities/20200414DanielArndt | 5 + .../lac/la_parallel_block_vector.templates.h | 27 +++- include/deal.II/lac/la_parallel_vector.h | 140 ------------------ .../lac/la_parallel_vector.templates.h | 127 ---------------- tests/mpi/parallel_vector_09.cc | 22 +-- tests/mpi/parallel_vector_11.cc | 12 +- tests/mpi/parallel_vector_interpolate.cc | 4 +- tests/petsc/copy_to_dealvec.cc | 121 --------------- ...y_to_dealvec.with_mpi=true.mpirun=4.output | 8 - tests/trilinos/copy_to_dealvec.cc | 123 --------------- ...y_to_dealvec.with_mpi=true.mpirun=4.output | 8 - 11 files changed, 53 insertions(+), 544 deletions(-) create mode 100644 doc/news/changes/incompatibilities/20200414DanielArndt delete mode 100644 tests/petsc/copy_to_dealvec.cc delete mode 100644 tests/petsc/copy_to_dealvec.with_mpi=true.mpirun=4.output delete mode 100644 tests/trilinos/copy_to_dealvec.cc delete mode 100644 tests/trilinos/copy_to_dealvec.with_mpi=true.mpirun=4.output diff --git a/doc/news/changes/incompatibilities/20200414DanielArndt b/doc/news/changes/incompatibilities/20200414DanielArndt new file mode 100644 index 0000000000..0bb5404f0d --- /dev/null +++ b/doc/news/changes/incompatibilities/20200414DanielArndt @@ -0,0 +1,5 @@ +Removed: For LinearAlgebra::distributed::Vector, deprecated overloads of the +member operator=(), sadd(), equ(), local_range(), n_ghost_entries(), +ghost_elements() and ghost_entries() have been removed. +
+(Daniel Arndt, 2020/04/13) diff --git a/include/deal.II/lac/la_parallel_block_vector.templates.h b/include/deal.II/lac/la_parallel_block_vector.templates.h index e9649242c2..59935321b0 100644 --- a/include/deal.II/lac/la_parallel_block_vector.templates.h +++ b/include/deal.II/lac/la_parallel_block_vector.templates.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -219,7 +220,18 @@ namespace LinearAlgebra { AssertDimension(this->n_blocks(), petsc_vec.n_blocks()); for (unsigned int i = 0; i < this->n_blocks(); ++i) - this->block(i) = petsc_vec.block(i); + { + const auto &partitioner = this->block(i).get_partitioner(); + IndexSet combined_set = partitioner->locally_owned_range(); + combined_set.add_indices(partitioner->ghost_indices()); + ReadWriteVector rw_vector(combined_set); + rw_vector.import(petsc_vec.block(i), VectorOperation::insert); + this->block(i).import(rw_vector, VectorOperation::insert); + + if (this->block(i).has_ghost_elements() || + petsc_vec.block(i).has_ghost_elements()) + this->block(i).update_ghost_values(); + } return *this; } @@ -237,7 +249,18 @@ namespace LinearAlgebra { AssertDimension(this->n_blocks(), trilinos_vec.n_blocks()); for (unsigned int i = 0; i < this->n_blocks(); ++i) - this->block(i) = trilinos_vec.block(i); + { + const auto &partitioner = this->block(i).get_partitioner(); + IndexSet combined_set = partitioner->locally_owned_range(); + combined_set.add_indices(partitioner->ghost_indices()); + ReadWriteVector rw_vector(combined_set); + rw_vector.import(trilinos_vec.block(i), VectorOperation::insert); + this->block(i).import(rw_vector, VectorOperation::insert); + + if (this->block(i).has_ghost_elements() || + trilinos_vec.block(i).has_ghost_elements()) + this->block(i).update_ghost_values(); + } return *this; } diff --git a/include/deal.II/lac/la_parallel_vector.h b/include/deal.II/lac/la_parallel_vector.h index 18b607f973..a8a607936c 100644 --- a/include/deal.II/lac/la_parallel_vector.h +++ b/include/deal.II/lac/la_parallel_vector.h @@ -411,38 +411,6 @@ namespace LinearAlgebra Vector & operator=(const Vector &in_vector); -#ifdef DEAL_II_WITH_PETSC - /** - * Copy the content of a PETSc vector into the calling vector. This - * function assumes that the vectors layouts have already been - * initialized to match. - * - * This operator is only available if deal.II was configured with PETSc. - * - * This function is deprecated. Use the interface through - * ReadWriteVector instead. - */ - DEAL_II_DEPRECATED - Vector & - operator=(const PETScWrappers::MPI::Vector &petsc_vec); -#endif - -#ifdef DEAL_II_WITH_TRILINOS - /** - * Copy the content of a Trilinos vector into the calling vector. This - * function assumes that the vectors layouts have already been - * initialized to match. - * - * This operator is only available if deal.II was configured with - * Trilinos. - * - * This function is deprecated. Use the interface through - * ReadWriteVector instead. - */ - DEAL_II_DEPRECATED - Vector & - operator=(const TrilinosWrappers::MPI::Vector &trilinos_vec); -#endif //@} /** @@ -884,31 +852,6 @@ namespace LinearAlgebra void sadd(const Number s, const Vector &V); - /** - * Scaling and multiple addition. - * - * This function is deprecated. - */ - DEAL_II_DEPRECATED - void - sadd(const Number s, - const Number a, - const Vector &V, - const Number b, - const Vector &W); - - /** - * Assignment *this = a*u + b*v. - * - * This function is deprecated. - */ - DEAL_II_DEPRECATED - void - equ(const Number a, - const Vector &u, - const Number b, - const Vector &v); - //@} @@ -924,58 +867,13 @@ namespace LinearAlgebra size_type local_size() const; - /** - * Return the half-open interval that specifies the locally owned range - * of the vector. Note that local_size() == local_range().second - - * local_range().first. - * - * This function is deprecated. - */ - DEAL_II_DEPRECATED - std::pair - local_range() const; - /** * Return true if the given global index is in the local range of this * processor. - * - * This function is deprecated. */ - DEAL_II_DEPRECATED bool in_local_range(const size_type global_index) const; - /** - * Return the number of ghost elements present on the vector. - * - * This function is deprecated. - */ - DEAL_II_DEPRECATED - size_type - n_ghost_entries() const; - - /** - * Return an index set that describes which elements of this vector are - * not owned by the current processor but can be written into or read - * from locally (ghost elements). - * - * This function is deprecated. - */ - DEAL_II_DEPRECATED - const IndexSet & - ghost_elements() const; - - /** - * Return whether the given global index is a ghost index on the - * present processor. Returns false for indices that are owned locally - * and for indices not present at all. - * - * This function is deprecated. - */ - DEAL_II_DEPRECATED - bool - is_ghost_entry(const types::global_dof_index global_index) const; - /** * Make the @p Vector class a bit like the vector<> class of * the C++ standard library by returning iterators to the start and end @@ -1540,16 +1438,6 @@ namespace LinearAlgebra - template - inline std::pair::size_type, - typename Vector::size_type> - Vector::local_range() const - { - return partitioner->local_range(); - } - - - template inline bool Vector::in_local_range( @@ -1574,34 +1462,6 @@ namespace LinearAlgebra - template - inline typename Vector::size_type - Vector::n_ghost_entries() const - { - return partitioner->n_ghost_indices(); - } - - - - template - inline const IndexSet & - Vector::ghost_elements() const - { - return partitioner->ghost_indices(); - } - - - - template - inline bool - Vector::is_ghost_entry( - const size_type global_index) const - { - return partitioner->is_ghost_entry(global_index); - } - - - template inline typename Vector::iterator Vector::begin() diff --git a/include/deal.II/lac/la_parallel_vector.templates.h b/include/deal.II/lac/la_parallel_vector.templates.h index b9d8215a4a..0e33633825 100644 --- a/include/deal.II/lac/la_parallel_vector.templates.h +++ b/include/deal.II/lac/la_parallel_vector.templates.h @@ -781,70 +781,6 @@ namespace LinearAlgebra } } // namespace petsc_helpers - template - Vector & - Vector:: - operator=(const PETScWrappers::MPI::Vector &petsc_vec) - { - // TODO: We would like to use the same compact infrastructure as for the - // Trilinos vector below, but the interface through ReadWriteVector does - // not support overlapping (ghosted) PETSc vectors, which we need for - // backward compatibility. - - Assert(petsc_vec.locally_owned_elements() == locally_owned_elements(), - StandardExceptions::ExcInvalidState()); - - // get a representation of the vector and copy it - PetscScalar * start_ptr; - PetscErrorCode ierr = - VecGetArray(static_cast(petsc_vec), &start_ptr); - AssertThrow(ierr == 0, ExcPETScError(ierr)); - - const size_type vec_size = local_size(); - petsc_helpers::copy_petsc_vector(start_ptr, - start_ptr + vec_size, - begin()); - - // restore the representation of the vector - ierr = VecRestoreArray(static_cast(petsc_vec), &start_ptr); - AssertThrow(ierr == 0, ExcPETScError(ierr)); - - // spread ghost values between processes? - if (vector_is_ghosted || petsc_vec.has_ghost_elements()) - update_ghost_values(); - - // return a reference to this object per normal c++ operator overloading - // semantics - return *this; - } - -#endif - - - -#ifdef DEAL_II_WITH_TRILINOS - - template - Vector & - Vector:: - operator=(const TrilinosWrappers::MPI::Vector &trilinos_vec) - { -# ifdef DEAL_II_WITH_MPI - IndexSet combined_set = partitioner->locally_owned_range(); - combined_set.add_indices(partitioner->ghost_indices()); - ReadWriteVector rw_vector(combined_set); - rw_vector.import(trilinos_vec, VectorOperation::insert); - import(rw_vector, VectorOperation::insert); - - if (vector_is_ghosted || trilinos_vec.has_ghost_elements()) - update_ghost_values(); -# else - AssertThrow(false, ExcNotImplemented()); -# endif - - return *this; - } - #endif @@ -1618,39 +1554,6 @@ namespace LinearAlgebra - template - void - Vector::sadd( - const Number x, - const Number a, - const Vector &v, - const Number b, - const Vector &w) - { - AssertIsFinite(x); - AssertIsFinite(a); - AssertIsFinite(b); - - AssertDimension(local_size(), v.local_size()); - AssertDimension(local_size(), w.local_size()); - - dealii::internal::VectorOperations:: - functions::sadd_xavbw( - thread_loop_partitioner, - partitioner->local_size(), - x, - a, - b, - v.data, - w.data, - data); - - if (vector_is_ghosted) - update_ghost_values(); - } - - - template Vector & Vector::operator*=(const Number factor) @@ -1726,36 +1629,6 @@ namespace LinearAlgebra - template - void - Vector::equ( - const Number a, - const Vector &v, - const Number b, - const Vector &w) - { - AssertIsFinite(a); - AssertIsFinite(b); - - AssertDimension(local_size(), v.local_size()); - AssertDimension(local_size(), w.local_size()); - - dealii::internal::VectorOperations:: - functions::equ_aubv( - thread_loop_partitioner, - partitioner->local_size(), - a, - b, - v.data, - w.data, - data); - - if (vector_is_ghosted) - update_ghost_values(); - } - - - template bool Vector::all_zero() const diff --git a/tests/mpi/parallel_vector_09.cc b/tests/mpi/parallel_vector_09.cc index a722428d58..e6dbe9c87f 100644 --- a/tests/mpi/parallel_vector_09.cc +++ b/tests/mpi/parallel_vector_09.cc @@ -76,34 +76,36 @@ test() // the above) if (myid == 0) { - AssertDimension(v.n_ghost_entries(), 5); + AssertDimension(v.get_partitioner()->n_ghost_indices(), 5); } else if (myid == 1) { - AssertDimension(v.n_ghost_entries(), 8); + AssertDimension(v.get_partitioner()->n_ghost_indices(), 8); } else if (myid == 2) { - AssertDimension(v.n_ghost_entries(), 7); + AssertDimension(v.get_partitioner()->n_ghost_indices(), 7); } else { - AssertDimension(v.n_ghost_entries(), 10); + AssertDimension(v.get_partitioner()->n_ghost_indices(), 10); } // count that 13 is ghost only on non-owning // processors if (myid == 0) { - Assert(v.is_ghost_entry(13) == false, ExcInternalError()); + Assert(v.get_partitioner()->is_ghost_entry(13) == false, + ExcInternalError()); } else { - Assert(v.is_ghost_entry(13) == true, ExcInternalError()); + Assert(v.get_partitioner()->is_ghost_entry(13) == true, + ExcInternalError()); } // count that 27 is ghost nowhere - Assert(v.is_ghost_entry(27) == false, ExcInternalError()); + Assert(v.get_partitioner()->is_ghost_entry(27) == false, ExcInternalError()); if (myid == 0) { Assert(v.in_local_range(27) == true, ExcInternalError()); @@ -116,11 +118,13 @@ test() // element with number set is ghost if (myid == 1) { - Assert(v.is_ghost_entry(set) == false, ExcInternalError()); + Assert(v.get_partitioner()->is_ghost_entry(set) == false, + ExcInternalError()); } else { - Assert(v.is_ghost_entry(set) == true, ExcInternalError()); + Assert(v.get_partitioner()->is_ghost_entry(set) == true, + ExcInternalError()); } if (myid == 0) diff --git a/tests/mpi/parallel_vector_11.cc b/tests/mpi/parallel_vector_11.cc index bfcb5fa9c4..78cd0dd600 100644 --- a/tests/mpi/parallel_vector_11.cc +++ b/tests/mpi/parallel_vector_11.cc @@ -116,7 +116,8 @@ test() if (myid == 0) deallog << "Check sadd (factor, factor, vector, factor, vector): "; - y.sadd(2., 3., v, 2., w); + y.sadd(2., 3., v); + y.add(2., w); for (int i = 0; i < actual_local_size; ++i) AssertThrow(y.local_element(i) == 5 * (i + my_start) + 2000, ExcInternalError()); @@ -126,7 +127,8 @@ test() if (myid == 0) deallog << "Check sadd (factor, factor, vector, factor, vector, factor, vector): "; - y.sadd(-1., 1., v, 2., w); + y.sadd(-1., 1., v); + y.add(2., w); y.add(2., x); for (int i = 0; i < actual_local_size; ++i) AssertThrow(y.local_element(i) == 20000, ExcInternalError()); @@ -177,7 +179,8 @@ test() if (myid == 0) deallog << "Check equ (factor, vector, factor, vector): "; - y.equ(10., v, -2., w); + y.equ(10., v); + y.add(-2., w); for (int i = 0; i < actual_local_size; ++i) AssertThrow(y.local_element(i) == 6. * (i + my_start) - 2000, ExcInternalError()); @@ -186,7 +189,8 @@ test() if (myid == 0) deallog << "Check equ (factor, vector, factor, vector, factor, vector): "; - y.equ(10., v, -2., w); + y.equ(10., v); + y.add(-2., w); y.add(3., x); for (int i = 0; i < actual_local_size; ++i) AssertThrow(y.local_element(i) == 6. * (i + my_start) + 28000, diff --git a/tests/mpi/parallel_vector_interpolate.cc b/tests/mpi/parallel_vector_interpolate.cc index 9900e96255..91b089b3a7 100644 --- a/tests/mpi/parallel_vector_interpolate.cc +++ b/tests/mpi/parallel_vector_interpolate.cc @@ -74,8 +74,8 @@ test() Assert(v2.local_element(i) == 1., ExcInternalError()); v2.update_ghost_values(); - for (unsigned int i = 0; i < v2.local_size() + v2.n_ghost_entries(); ++i) - Assert(v2.local_element(i) == 1., ExcInternalError()); + for (const auto i : locally_relevant_dofs2) + Assert(v2(i) == 1., ExcInternalError()); } diff --git a/tests/petsc/copy_to_dealvec.cc b/tests/petsc/copy_to_dealvec.cc deleted file mode 100644 index 5691c7670a..0000000000 --- a/tests/petsc/copy_to_dealvec.cc +++ /dev/null @@ -1,121 +0,0 @@ -// --------------------------------------------------------------------- -// -// Copyright (C) 2014 - 2018 by the deal.II authors -// -// This file is part of the deal.II library. -// -// The deal.II library is free software; you can use it, redistribute -// it, and/or modify it under the terms of the GNU Lesser General -// Public License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// The full text of the license can be found in the file LICENSE.md at -// the top level directory of deal.II. -// -// --------------------------------------------------------------------- - - - -// Test -// LinearAlgebra::distributed::Vector::operator=(PETScWrappers::MPI::Vector&) - -#include - -#include -#include - -#include -#include - -#include "../tests.h" - - -void -test() -{ - unsigned int myid = Utilities::MPI::this_mpi_process(MPI_COMM_WORLD); - unsigned int numproc = Utilities::MPI::n_mpi_processes(MPI_COMM_WORLD); - - if (myid == 0) - deallog << "numproc=" << numproc << std::endl; - - // each processor owns 2 indices and all - // are ghosting Element 1 (the second) - - IndexSet local_active(numproc * 2); - local_active.add_range(myid * 2, myid * 2 + 2); - IndexSet local_relevant(numproc * 2); - local_relevant.add_range(1, 2); - - PETScWrappers::MPI::Vector vb(local_active, MPI_COMM_WORLD); - PETScWrappers::MPI::Vector v(local_active, local_relevant, MPI_COMM_WORLD); - - LinearAlgebra::distributed::Vector copied(local_active, - local_relevant, - MPI_COMM_WORLD); - - // set local values - vb(myid * 2) = myid * 2.0; - vb(myid * 2 + 1) = myid * 2.0 + 1.0; - - vb.compress(VectorOperation::insert); - vb *= 2.0; - v = vb; - - Assert(!vb.has_ghost_elements(), ExcInternalError()); - Assert(v.has_ghost_elements(), ExcInternalError()); - - copied = vb; - - // check local values - if (Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) == 0) - { - deallog << myid * 2 << ":" << copied(myid * 2) << std::endl; - deallog << myid * 2 + 1 << ":" << copied(myid * 2 + 1) << std::endl; - } - - Assert(copied(myid * 2) == myid * 4.0, ExcInternalError()); - Assert(copied(myid * 2 + 1) == myid * 4.0 + 2.0, ExcInternalError()); - - copied = v; - - // check ghost values - if (Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) == 0) - deallog << "ghost: " << copied(1) << std::endl; - Assert(copied(1) == 2.0, ExcInternalError()); - - // check local values - if (Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) == 0) - { - deallog << myid * 2 << ":" << copied(myid * 2) << std::endl; - deallog << myid * 2 + 1 << ":" << copied(myid * 2 + 1) << std::endl; - } - - Assert(copied(myid * 2) == myid * 4.0, ExcInternalError()); - Assert(copied(myid * 2 + 1) == myid * 4.0 + 2.0, ExcInternalError()); - - - // done - if (myid == 0) - deallog << "OK" << std::endl; -} - - - -int -main(int argc, char **argv) -{ - Utilities::MPI::MPI_InitFinalize mpi_initialization(argc, argv, 1); - unsigned int myid = Utilities::MPI::this_mpi_process(MPI_COMM_WORLD); - - deallog.push(Utilities::int_to_string(myid)); - - if (myid == 0) - { - initlog(); - deallog << std::setprecision(4); - - test(); - } - else - test(); -} diff --git a/tests/petsc/copy_to_dealvec.with_mpi=true.mpirun=4.output b/tests/petsc/copy_to_dealvec.with_mpi=true.mpirun=4.output deleted file mode 100644 index 6ed3f0103a..0000000000 --- a/tests/petsc/copy_to_dealvec.with_mpi=true.mpirun=4.output +++ /dev/null @@ -1,8 +0,0 @@ - -DEAL:0::numproc=4 -DEAL:0::0:0 -DEAL:0::1:2.000 -DEAL:0::ghost: 2.000 -DEAL:0::0:0 -DEAL:0::1:2.000 -DEAL:0::OK diff --git a/tests/trilinos/copy_to_dealvec.cc b/tests/trilinos/copy_to_dealvec.cc deleted file mode 100644 index f88a59be6d..0000000000 --- a/tests/trilinos/copy_to_dealvec.cc +++ /dev/null @@ -1,123 +0,0 @@ -// --------------------------------------------------------------------- -// -// Copyright (C) 2014 - 2018 by the deal.II authors -// -// This file is part of the deal.II library. -// -// The deal.II library is free software; you can use it, redistribute -// it, and/or modify it under the terms of the GNU Lesser General -// Public License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// The full text of the license can be found in the file LICENSE.md at -// the top level directory of deal.II. -// -// --------------------------------------------------------------------- - - - -// Test -// LinearAlgebra::distributed::Vector::operator=(TrilinosWrappers::MPI::Vector&) - -#include - -#include -#include - -#include -#include - -#include "../tests.h" - - -void -test() -{ - unsigned int myid = Utilities::MPI::this_mpi_process(MPI_COMM_WORLD); - unsigned int numproc = Utilities::MPI::n_mpi_processes(MPI_COMM_WORLD); - - if (myid == 0) - deallog << "numproc=" << numproc << std::endl; - - // each processor owns 2 indices and all - // are ghosting Element 1 (the second) - - IndexSet local_active(numproc * 2); - local_active.add_range(myid * 2, myid * 2 + 2); - IndexSet local_relevant(numproc * 2); - local_relevant.add_range(1, 2); - - TrilinosWrappers::MPI::Vector vb(local_active, MPI_COMM_WORLD); - TrilinosWrappers::MPI::Vector v(local_active, local_relevant, MPI_COMM_WORLD); - - LinearAlgebra::distributed::Vector copied(local_active, - local_relevant, - MPI_COMM_WORLD); - - // set local values - vb(myid * 2) = myid * 2.0; - vb(myid * 2 + 1) = myid * 2.0 + 1.0; - - vb.compress(VectorOperation::insert); - vb *= 2.0; - v = vb; - // v.update_ghost_values(); - - Assert(!vb.has_ghost_elements(), ExcInternalError()); - Assert(v.has_ghost_elements(), ExcInternalError()); - - copied = vb; - - // check local values - if (Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) == 0) - { - deallog << myid * 2 << ":" << copied(myid * 2) << std::endl; - deallog << myid * 2 + 1 << ":" << copied(myid * 2 + 1) << std::endl; - } - - Assert(copied(myid * 2) == myid * 4.0, ExcInternalError()); - Assert(copied(myid * 2 + 1) == myid * 4.0 + 2.0, ExcInternalError()); - - copied.update_ghost_values(); - - // check ghost values - if (Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) == 0) - deallog << "ghost: " << copied(1) << std::endl; - Assert(copied(1) == 2.0, ExcInternalError()); - - // check local values - if (Utilities::MPI::this_mpi_process(MPI_COMM_WORLD) == 0) - { - deallog << myid * 2 << ":" << copied(myid * 2) << std::endl; - deallog << myid * 2 + 1 << ":" << copied(myid * 2 + 1) << std::endl; - } - - Assert(copied(myid * 2) == myid * 4.0, ExcInternalError()); - Assert(copied(myid * 2 + 1) == myid * 4.0 + 2.0, ExcInternalError()); - - - // done - if (myid == 0) - deallog << "OK" << std::endl; -} - - - -int -main(int argc, char **argv) -{ - Utilities::MPI::MPI_InitFinalize mpi_initialization( - argc, argv, testing_max_num_threads()); - unsigned int myid = Utilities::MPI::this_mpi_process(MPI_COMM_WORLD); - - deallog.push(Utilities::int_to_string(myid)); - - if (myid == 0) - { - initlog(); - deallog << std::setprecision(4); - - test(); - } - else - test(); -} diff --git a/tests/trilinos/copy_to_dealvec.with_mpi=true.mpirun=4.output b/tests/trilinos/copy_to_dealvec.with_mpi=true.mpirun=4.output deleted file mode 100644 index 6ed3f0103a..0000000000 --- a/tests/trilinos/copy_to_dealvec.with_mpi=true.mpirun=4.output +++ /dev/null @@ -1,8 +0,0 @@ - -DEAL:0::numproc=4 -DEAL:0::0:0 -DEAL:0::1:2.000 -DEAL:0::ghost: 2.000 -DEAL:0::0:0 -DEAL:0::1:2.000 -DEAL:0::OK -- 2.39.5