mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
#5200 Prototype of use of formation names for allen diagram
This commit is contained in:
parent
ba0ef5c7e8
commit
831b899091
@ -359,6 +359,22 @@ QString RiaDefines::completionTypeResultName()
|
|||||||
return "Completion Type";
|
return "Completion Type";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
QString RiaDefines::binaryAllenResultName()
|
||||||
|
{
|
||||||
|
return "Binary Allen";
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
QString RiaDefines::allCombinationsAllenResultName()
|
||||||
|
{
|
||||||
|
return "All Allen Categories";
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
@ -104,6 +104,10 @@ QString mobilePoreVolumeName();
|
|||||||
|
|
||||||
QString completionTypeResultName();
|
QString completionTypeResultName();
|
||||||
|
|
||||||
|
// Fault results
|
||||||
|
QString binaryAllenResultName();
|
||||||
|
QString allCombinationsAllenResultName();
|
||||||
|
|
||||||
// Mock model text identifiers
|
// Mock model text identifiers
|
||||||
QString mockModelBasic();
|
QString mockModelBasic();
|
||||||
QString mockModelBasicWithResults();
|
QString mockModelBasicWithResults();
|
||||||
|
@ -1379,6 +1379,12 @@ bool RimEclipseResultDefinition::hasCategoryResult() const
|
|||||||
|
|
||||||
if ( !this->hasStaticResult() ) return false;
|
if ( !this->hasStaticResult() ) return false;
|
||||||
|
|
||||||
|
if ( this->resultVariable() == RiaDefines::allCombinationsAllenResultName() ||
|
||||||
|
this->resultVariable() == RiaDefines::binaryAllenResultName() )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return RiaDefines::isNativeCategoryResult( this->resultVariable() );
|
return RiaDefines::isNativeCategoryResult( this->resultVariable() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,6 +71,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RigGridCrossPlotCurveGrouping.h
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/RigEclipseCrossPlotDataExtractor.h
|
${CMAKE_CURRENT_LIST_DIR}/RigEclipseCrossPlotDataExtractor.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RigEquil.h
|
${CMAKE_CURRENT_LIST_DIR}/RigEquil.h
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RigWbsParameter.h
|
${CMAKE_CURRENT_LIST_DIR}/RigWbsParameter.h
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RigEclipseAllenFaultsStatCalc.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -139,6 +140,7 @@ ${CMAKE_CURRENT_LIST_DIR}/RigCaseCellResultCalculator.cpp
|
|||||||
${CMAKE_CURRENT_LIST_DIR}/RigEclipseCrossPlotDataExtractor.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RigEclipseCrossPlotDataExtractor.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RigEquil.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RigEquil.cpp
|
||||||
${CMAKE_CURRENT_LIST_DIR}/RigWbsParameter.cpp
|
${CMAKE_CURRENT_LIST_DIR}/RigWbsParameter.cpp
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/RigEclipseAllenFaultsStatCalc.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
list(APPEND CODE_HEADER_FILES
|
list(APPEND CODE_HEADER_FILES
|
||||||
|
@ -44,6 +44,7 @@
|
|||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
|
||||||
|
#include "RigEclipseAllenFaultsStatCalc.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
@ -422,6 +423,13 @@ size_t RigCaseCellResultsData::findOrCreateScalarResultIndex( const RigEclipseRe
|
|||||||
QString( "%1K" ).arg( baseName ) ) );
|
QString( "%1K" ).arg( baseName ) ) );
|
||||||
statisticsCalculator = calc;
|
statisticsCalculator = calc;
|
||||||
}
|
}
|
||||||
|
else if ( resultName == RiaDefines::allCombinationsAllenResultName() ||
|
||||||
|
resultName == RiaDefines::binaryAllenResultName() )
|
||||||
|
{
|
||||||
|
cvf::ref<RigEclipseAllenFaultsStatCalc> calc = new RigEclipseAllenFaultsStatCalc( m_ownerMainGrid->nncData(),
|
||||||
|
resVarAddr );
|
||||||
|
statisticsCalculator = calc;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
statisticsCalculator = new RigEclipseNativeStatCalc( this, resVarAddr );
|
statisticsCalculator = new RigEclipseNativeStatCalc( this, resVarAddr );
|
||||||
@ -897,6 +905,17 @@ void RigCaseCellResultsData::createPlaceholderResultEntries()
|
|||||||
false );
|
false );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fault results
|
||||||
|
{
|
||||||
|
findOrCreateScalarResultIndex( RigEclipseResultAddress( RiaDefines::STATIC_NATIVE,
|
||||||
|
RiaDefines::binaryAllenResultName() ),
|
||||||
|
false );
|
||||||
|
|
||||||
|
findOrCreateScalarResultIndex( RigEclipseResultAddress( RiaDefines::STATIC_NATIVE,
|
||||||
|
RiaDefines::allCombinationsAllenResultName() ),
|
||||||
|
false );
|
||||||
|
}
|
||||||
|
|
||||||
// FLUX
|
// FLUX
|
||||||
{
|
{
|
||||||
if ( hasResultEntry( RigEclipseResultAddress( RiaDefines::DYNAMIC_NATIVE, "FLRWATI+" ) ) &&
|
if ( hasResultEntry( RigEclipseResultAddress( RiaDefines::DYNAMIC_NATIVE, "FLRWATI+" ) ) &&
|
||||||
@ -1203,6 +1222,11 @@ size_t RigCaseCellResultsData::findOrLoadKnownScalarResult( const RigEclipseResu
|
|||||||
{
|
{
|
||||||
computeRiTRANSbyAreaComponent( resultName );
|
computeRiTRANSbyAreaComponent( resultName );
|
||||||
}
|
}
|
||||||
|
else if ( resultName == RiaDefines::allCombinationsAllenResultName() ||
|
||||||
|
resultName == RiaDefines::binaryAllenResultName() )
|
||||||
|
{
|
||||||
|
computeAllenResults( this, m_ownerMainGrid );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if ( type == RiaDefines::DYNAMIC_NATIVE )
|
else if ( type == RiaDefines::DYNAMIC_NATIVE )
|
||||||
{
|
{
|
||||||
@ -2954,6 +2978,120 @@ RigStatisticsDataCache* RigCaseCellResultsData::statistics( const RigEclipseResu
|
|||||||
return m_statisticsDataCache[scalarResultIndex].p();
|
return m_statisticsDataCache[scalarResultIndex].p();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RigCaseCellResultsData::computeAllenResults( RigCaseCellResultsData* cellResultsData, RigMainGrid* mainGrid )
|
||||||
|
{
|
||||||
|
CVF_ASSERT( mainGrid );
|
||||||
|
CVF_ASSERT( cellResultsData );
|
||||||
|
|
||||||
|
auto allAllenEclResAddr = RigEclipseResultAddress( RiaDefines::STATIC_NATIVE,
|
||||||
|
RiaDefines::allCombinationsAllenResultName() );
|
||||||
|
|
||||||
|
auto binaryAllenEclResAddr = RigEclipseResultAddress( RiaDefines::STATIC_NATIVE, RiaDefines::binaryAllenResultName() );
|
||||||
|
|
||||||
|
if ( mainGrid->nncData()->staticConnectionScalarResult( allAllenEclResAddr ) ) return;
|
||||||
|
|
||||||
|
std::vector<double>& allAllenResults = mainGrid->nncData()->makeStaticConnectionScalarResult(
|
||||||
|
RiaDefines::allCombinationsAllenResultName() );
|
||||||
|
|
||||||
|
std::vector<double>& binaryAllenResults = mainGrid->nncData()->makeStaticConnectionScalarResult(
|
||||||
|
RiaDefines::binaryAllenResultName() );
|
||||||
|
|
||||||
|
mainGrid->nncData()->setEclResultAddress( RiaDefines::allCombinationsAllenResultName(), allAllenEclResAddr );
|
||||||
|
mainGrid->nncData()->setEclResultAddress( RiaDefines::binaryAllenResultName(), binaryAllenEclResAddr );
|
||||||
|
|
||||||
|
bool hasFormationData = cellResultsData->hasResultEntry(
|
||||||
|
RigEclipseResultAddress( RiaDefines::FORMATION_NAMES, RiaDefines::activeFormationNamesResultName() ) );
|
||||||
|
|
||||||
|
if ( hasFormationData )
|
||||||
|
{
|
||||||
|
const std::vector<double>& fnData =
|
||||||
|
cellResultsData->cellScalarResults( RigEclipseResultAddress( RiaDefines::FORMATION_NAMES,
|
||||||
|
RiaDefines::activeFormationNamesResultName() ),
|
||||||
|
0 );
|
||||||
|
|
||||||
|
std::map<std::pair<int, int>, int> formationCombinationToCategory;
|
||||||
|
|
||||||
|
for ( size_t i = 0; i < mainGrid->nncData()->connections().size(); i++ )
|
||||||
|
{
|
||||||
|
const auto& c = mainGrid->nncData()->connections()[i];
|
||||||
|
|
||||||
|
size_t globCellIdx1 = c.m_c1GlobIdx;
|
||||||
|
size_t globCellIdx2 = c.m_c2GlobIdx;
|
||||||
|
|
||||||
|
size_t i1, j1, k1;
|
||||||
|
mainGrid->ijkFromCellIndex( globCellIdx1, &i1, &j1, &k1 );
|
||||||
|
|
||||||
|
int formation1 = (int)( fnData[globCellIdx1] );
|
||||||
|
|
||||||
|
size_t i2, j2, k2;
|
||||||
|
mainGrid->ijkFromCellIndex( globCellIdx2, &i2, &j2, &k2 );
|
||||||
|
int formation2 = (int)( fnData[globCellIdx2] );
|
||||||
|
|
||||||
|
int category = -1;
|
||||||
|
if ( formation1 != formation2 )
|
||||||
|
{
|
||||||
|
if ( formation1 < formation2 )
|
||||||
|
{
|
||||||
|
std::swap( formation1, formation2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
auto formationCombination = std::make_pair( formation1, formation2 );
|
||||||
|
|
||||||
|
auto existingCategory = formationCombinationToCategory.find( formationCombination );
|
||||||
|
if ( existingCategory != formationCombinationToCategory.end() )
|
||||||
|
{
|
||||||
|
category = existingCategory->second;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
category = static_cast<int>( formationCombinationToCategory.size() );
|
||||||
|
|
||||||
|
formationCombinationToCategory[formationCombination] = category;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( category < 0 )
|
||||||
|
{
|
||||||
|
binaryAllenResults[i] = 0.0;
|
||||||
|
allAllenResults[i] = std::numeric_limits<double>::max();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
binaryAllenResults[i] = 1.0;
|
||||||
|
allAllenResults[i] = category;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for ( size_t i = 0; i < mainGrid->nncData()->connections().size(); i++ )
|
||||||
|
{
|
||||||
|
const auto& c = mainGrid->nncData()->connections()[i];
|
||||||
|
|
||||||
|
size_t globCellIdx1 = c.m_c1GlobIdx;
|
||||||
|
size_t globCellIdx2 = c.m_c2GlobIdx;
|
||||||
|
|
||||||
|
size_t i1, j1, k1;
|
||||||
|
mainGrid->ijkFromCellIndex( globCellIdx1, &i1, &j1, &k1 );
|
||||||
|
|
||||||
|
size_t i2, j2, k2;
|
||||||
|
mainGrid->ijkFromCellIndex( globCellIdx2, &i2, &j2, &k2 );
|
||||||
|
|
||||||
|
double binaryValue = 0.0;
|
||||||
|
if ( k1 != k2 )
|
||||||
|
{
|
||||||
|
binaryValue = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
allAllenResults[i] = k1;
|
||||||
|
binaryAllenResults[i] = binaryValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
///
|
///
|
||||||
//--------------------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
@ -191,6 +191,8 @@ private:
|
|||||||
|
|
||||||
RigStatisticsDataCache* statistics( const RigEclipseResultAddress& resVarAddr );
|
RigStatisticsDataCache* statistics( const RigEclipseResultAddress& resVarAddr );
|
||||||
|
|
||||||
|
static void computeAllenResults( RigCaseCellResultsData* cellResultsData, RigMainGrid* mainGrid );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
cvf::ref<RifReaderInterface> m_readerInterface;
|
cvf::ref<RifReaderInterface> m_readerInterface;
|
||||||
cvf::ref<RigFormationNames> m_activeFormationNamesData;
|
cvf::ref<RigFormationNames> m_activeFormationNamesData;
|
||||||
|
@ -0,0 +1,103 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015- Statoil ASA
|
||||||
|
// Copyright (C) 2015- Ceetron Solutions AS
|
||||||
|
//
|
||||||
|
// ResInsight is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
//
|
||||||
|
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||||
|
// for more details.
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "RigEclipseAllenFaultsStatCalc.h"
|
||||||
|
|
||||||
|
#include "RigActiveCellInfo.h"
|
||||||
|
#include "RigCaseCellResultsData.h"
|
||||||
|
#include "RigNNCData.h"
|
||||||
|
#include "RigStatisticsMath.h"
|
||||||
|
#include "RigWeightedMeanCalc.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
RigEclipseAllenFaultsStatCalc::RigEclipseAllenFaultsStatCalc( RigNNCData* cellResultsData,
|
||||||
|
const RigEclipseResultAddress& scalarResultIndex )
|
||||||
|
: m_caseData( cellResultsData )
|
||||||
|
, m_resultAddress( scalarResultIndex )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RigEclipseAllenFaultsStatCalc::minMaxCellScalarValues( size_t timeStepIndex, double& min, double& max )
|
||||||
|
{
|
||||||
|
MinMaxAccumulator acc( min, max );
|
||||||
|
traverseCells( acc, timeStepIndex );
|
||||||
|
min = acc.min;
|
||||||
|
max = acc.max;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RigEclipseAllenFaultsStatCalc::posNegClosestToZero( size_t timeStepIndex, double& pos, double& neg )
|
||||||
|
{
|
||||||
|
PosNegAccumulator acc( pos, neg );
|
||||||
|
traverseCells( acc, timeStepIndex );
|
||||||
|
pos = acc.pos;
|
||||||
|
neg = acc.neg;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RigEclipseAllenFaultsStatCalc::valueSumAndSampleCount( size_t timeStepIndex, double& valueSum, size_t& sampleCount )
|
||||||
|
{
|
||||||
|
SumCountAccumulator acc( valueSum, sampleCount );
|
||||||
|
traverseCells( acc, timeStepIndex );
|
||||||
|
valueSum = acc.valueSum;
|
||||||
|
sampleCount = acc.sampleCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RigEclipseAllenFaultsStatCalc::addDataToHistogramCalculator( size_t timeStepIndex,
|
||||||
|
RigHistogramCalculator& histogramCalculator )
|
||||||
|
{
|
||||||
|
traverseCells( histogramCalculator, timeStepIndex );
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RigEclipseAllenFaultsStatCalc::uniqueValues( size_t timeStepIndex, std::set<int>& values )
|
||||||
|
{
|
||||||
|
UniqueValueAccumulator acc;
|
||||||
|
traverseCells( acc, timeStepIndex );
|
||||||
|
values = acc.uniqueValues;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
size_t RigEclipseAllenFaultsStatCalc::timeStepCount()
|
||||||
|
{
|
||||||
|
return (size_t)1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
///
|
||||||
|
//--------------------------------------------------------------------------------------------------
|
||||||
|
void RigEclipseAllenFaultsStatCalc::mobileVolumeWeightedMean( size_t timeStepIndex, double& result ) {}
|
@ -0,0 +1,64 @@
|
|||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015- Statoil ASA
|
||||||
|
// Copyright (C) 2015- Ceetron Solutions AS
|
||||||
|
//
|
||||||
|
// ResInsight is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// ResInsight is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
//
|
||||||
|
// See the GNU General Public License at <http://www.gnu.org/licenses/gpl.html>
|
||||||
|
// for more details.
|
||||||
|
//
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
//==================================================================================================
|
||||||
|
///
|
||||||
|
//==================================================================================================
|
||||||
|
#include "RigStatisticsCalculator.h"
|
||||||
|
|
||||||
|
#include "RigActiveCellInfo.h"
|
||||||
|
#include "RigCaseCellResultsData.h"
|
||||||
|
|
||||||
|
#include "cvfArray.h"
|
||||||
|
|
||||||
|
class RigNNCData;
|
||||||
|
|
||||||
|
class RigEclipseAllenFaultsStatCalc : public RigStatisticsCalculator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RigEclipseAllenFaultsStatCalc( RigNNCData* cellResultsData, const RigEclipseResultAddress& scalarResultIndex );
|
||||||
|
|
||||||
|
void minMaxCellScalarValues( size_t timeStepIndex, double& min, double& max ) override;
|
||||||
|
void posNegClosestToZero( size_t timeStepIndex, double& pos, double& neg ) override;
|
||||||
|
void valueSumAndSampleCount( size_t timeStepIndex, double& valueSum, size_t& sampleCount ) override;
|
||||||
|
void addDataToHistogramCalculator( size_t timeStepIndex, RigHistogramCalculator& histogramCalculator ) override;
|
||||||
|
void uniqueValues( size_t timeStepIndex, std::set<int>& values ) override;
|
||||||
|
size_t timeStepCount() override;
|
||||||
|
void mobileVolumeWeightedMean( size_t timeStepIndex, double& result ) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
RigNNCData* m_caseData;
|
||||||
|
RigEclipseResultAddress m_resultAddress;
|
||||||
|
|
||||||
|
template <typename StatisticsAccumulator>
|
||||||
|
void traverseCells( StatisticsAccumulator& accumulator, size_t timeStepIndex )
|
||||||
|
{
|
||||||
|
const std::vector<double>* values = m_caseData->staticConnectionScalarResult( m_resultAddress );
|
||||||
|
|
||||||
|
if ( values && !values->empty() )
|
||||||
|
{
|
||||||
|
for ( const auto& v : *values )
|
||||||
|
{
|
||||||
|
accumulator.addValue( v );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user