Skip to content

Commit da5f7de

Browse files
shimatclaude
andcommitted
Migration: leaf modules (barcode/flann/highgui/imgcodecs/img_hash/quality/saliency/superres/text/videoio/wechat_qrcode/xfeatures2d) to the ArrayProxy ABI (by-pointer) + tests
44 functions across 17 native headers migrated to the by-pointer InputArrayProxy/OutputArrayProxy ABI, following the established core/imgproc pattern (issue #1976). Also fixes a pre-existing bug uncovered by the new flann.Index test: IndexParams and all its subclasses (LinearIndexParams, KDTreeIndexParams, KMeansIndexParams, LshIndexParams, CompositeIndexParams, AutotunedIndexParams, SavedIndexParams, SearchParams) stored the cv::Ptr<T> smart pointer returned by their native constructor directly as their Handle, instead of extracting the underlying raw T* via the corresponding flann_Ptr_*_get() call. Native functions expecting a raw cv::flann::IndexParams*/SearchParams* therefore dereferenced the smart pointer's own memory layout, corrupting state and crashing inside flann_Index_new. Fixed by switching IndexParams to the established CvPtrObject smart-pointer/raw-pointer pattern used elsewhere in the codebase (e.g. QualityGMSD). This bug predates the ArrayProxy migration and was never exercised because flann.Index had no test before. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1 parent 3318259 commit da5f7de

78 files changed

Lines changed: 1000 additions & 473 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/OpenCvSharp/Cv2/Cv2_features.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public static KeyPoint[] AGAST(InputArray image, int threshold, bool nonmaxSuppr
7373

7474
using var vector = new StdVector<KeyPoint>();
7575
NativeMethods.HandleException(
76-
NativeMethods.xfeatures2d_AGAST(image.CvPtr, vector.CvPtr, threshold, nonmaxSuppression ? 1 : 0, (int) type));
76+
NativeMethods.xfeatures2d_AGAST(image.ToInputProxy(), vector.CvPtr, threshold, nonmaxSuppression ? 1 : 0, (int) type));
7777
GC.KeepAlive(image);
7878
return vector.ToArray();
7979
}

src/OpenCvSharp/Cv2/Cv2_highgui.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,7 @@ public static Rect SelectROI(string windowName, InputArray img, bool showCrossha
311311
img.ThrowIfDisposed();
312312

313313
NativeMethods.HandleException(
314-
NativeMethods.highgui_selectROI1(windowName, img.CvPtr, showCrosshair ? 1 : 0, fromCenter ? 1 : 0, out var ret));
314+
NativeMethods.highgui_selectROI1(windowName, img.ToInputProxy(), showCrosshair ? 1 : 0, fromCenter ? 1 : 0, out var ret));
315315

316316
GC.KeepAlive(img);
317317
return ret;
@@ -335,7 +335,7 @@ public static Rect SelectROI(InputArray img, bool showCrosshair = true, bool fro
335335
img.ThrowIfDisposed();
336336

337337
NativeMethods.HandleException(
338-
NativeMethods.highgui_selectROI2(img.CvPtr, showCrosshair ? 1 : 0, fromCenter ? 1 : 0, out var ret));
338+
NativeMethods.highgui_selectROI2(img.ToInputProxy(), showCrosshair ? 1 : 0, fromCenter ? 1 : 0, out var ret));
339339

340340
GC.KeepAlive(img);
341341
return ret;
@@ -364,7 +364,7 @@ public static Rect[] SelectROIs(string windowName, InputArray img, bool showCro
364364

365365
using var boundingBoxesVec = new StdVector<Rect>();
366366
NativeMethods.HandleException(
367-
NativeMethods.highgui_selectROIs(windowName, img.CvPtr, boundingBoxesVec.CvPtr, showCrosshair ? 1 : 0, fromCenter ? 1 : 0));
367+
NativeMethods.highgui_selectROIs(windowName, img.ToInputProxy(), boundingBoxesVec.CvPtr, showCrosshair ? 1 : 0, fromCenter ? 1 : 0));
368368

369369
GC.KeepAlive(img);
370370
return boundingBoxesVec.ToArray();

src/OpenCvSharp/Cv2/Cv2_imgcodecs.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ public static Mat ImDecode(InputArray buf, ImreadModes flags)
162162
buf.ThrowIfDisposed();
163163

164164
NativeMethods.HandleException(
165-
NativeMethods.imgcodecs_imdecode_InputArray(buf.CvPtr, (int) flags, out var ret));
165+
NativeMethods.imgcodecs_imdecode_InputArray(buf.ToInputProxy(), (int) flags, out var ret));
166166
GC.KeepAlive(buf);
167167
return new Mat(ret);
168168
}
@@ -222,7 +222,7 @@ public static bool ImEncode(string ext, InputArray img, out byte[] buf, int[]? p
222222

223223
using var bufVec = new StdVector<byte>();
224224
NativeMethods.HandleException(
225-
NativeMethods.imgcodecs_imencode_vector(ext, img.CvPtr, bufVec.CvPtr, prms, prms.Length, out var ret));
225+
NativeMethods.imgcodecs_imencode_vector(ext, img.ToInputProxy(), bufVec.CvPtr, prms, prms.Length, out var ret));
226226
GC.KeepAlive(img);
227227
buf = bufVec.ToArray();
228228
return ret != 0;

src/OpenCvSharp/Internal/PInvoke/NativeMethods/NativeMethods_barcode.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,18 @@ double thresh
4040
public static partial ExceptionStatus barcode_BarcodeDetector_delete(IntPtr obj);
4141

4242
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
43-
public static partial ExceptionStatus barcode_BarcodeDetector_decodeWithType(
43+
internal static partial ExceptionStatus barcode_BarcodeDetector_decodeWithType(
4444
OpenCvSafeHandle obj,
45-
IntPtr inputImage,
45+
in InputArrayProxy inputImage,
4646
IntPtr points,
4747
IntPtr infos,
4848
IntPtr types
4949
);
5050

5151
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
52-
public static partial ExceptionStatus barcode_BarcodeDetector_detectAndDecodeWithType(
52+
internal static partial ExceptionStatus barcode_BarcodeDetector_detectAndDecodeWithType(
5353
OpenCvSafeHandle obj,
54-
IntPtr inputImage,
54+
in InputArrayProxy inputImage,
5555
IntPtr points,
5656
IntPtr infos,
5757
IntPtr types

src/OpenCvSharp/Internal/PInvoke/NativeMethods/NativeMethods_flann.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ static partial class NativeMethods
1414
#region Index
1515

1616
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
17-
public static partial ExceptionStatus flann_Index_new(IntPtr features, IntPtr @params, int distType, out IntPtr returnValue);
17+
internal static partial ExceptionStatus flann_Index_new(in InputArrayProxy features, IntPtr @params, int distType, out IntPtr returnValue);
1818

1919
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
2020
public static partial ExceptionStatus flann_Index_delete(IntPtr obj);

src/OpenCvSharp/Internal/PInvoke/NativeMethods/NativeMethods_highgui.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,15 @@ static partial class NativeMethods
5959
public static partial ExceptionStatus highgui_getMouseWheelDelta(int flags, out int returnValue);
6060

6161
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
62-
public static partial ExceptionStatus highgui_selectROI1(
63-
[MarshalAs(UnmanagedType.LPStr)] string windowName, IntPtr img, int showCrosshair, int fromCenter, out Rect returnValue);
62+
internal static partial ExceptionStatus highgui_selectROI1(
63+
[MarshalAs(UnmanagedType.LPStr)] string windowName, in InputArrayProxy img, int showCrosshair, int fromCenter, out Rect returnValue);
6464

6565
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
66-
public static partial ExceptionStatus highgui_selectROI2(IntPtr img, int showCrosshair, int fromCenter, out Rect returnValue);
66+
internal static partial ExceptionStatus highgui_selectROI2(in InputArrayProxy img, int showCrosshair, int fromCenter, out Rect returnValue);
6767

6868
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
69-
public static partial ExceptionStatus highgui_selectROIs(
70-
[MarshalAs(UnmanagedType.LPStr)] string windowName, IntPtr img, IntPtr boundingBoxes, int showCrosshair, int fromCenter);
69+
internal static partial ExceptionStatus highgui_selectROIs(
70+
[MarshalAs(UnmanagedType.LPStr)] string windowName, in InputArrayProxy img, IntPtr boundingBoxes, int showCrosshair, int fromCenter);
7171

7272
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
7373
public static partial ExceptionStatus highgui_createTrackbar(

src/OpenCvSharp/Internal/PInvoke/NativeMethods/NativeMethods_img_hash.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@ namespace OpenCvSharp.Internal;
1010
static partial class NativeMethods
1111
{
1212
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
13-
public static partial ExceptionStatus img_hash_ImgHashBase_compute(OpenCvSafeHandle obj, IntPtr inputArr, IntPtr outputArr);
13+
internal static partial ExceptionStatus img_hash_ImgHashBase_compute(OpenCvSafeHandle obj, in InputArrayProxy inputArr, in OutputArrayProxy outputArr);
1414

1515
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
16-
public static partial ExceptionStatus img_hash_ImgHashBase_compare(OpenCvSafeHandle obj, IntPtr hashOne, IntPtr hashTwo, out double returnValue);
16+
internal static partial ExceptionStatus img_hash_ImgHashBase_compare(OpenCvSafeHandle obj, in InputArrayProxy hashOne, in InputArrayProxy hashTwo, out double returnValue);
1717

1818

1919
// AverageHash

src/OpenCvSharp/Internal/PInvoke/NativeMethods/NativeMethods_imgcodecs.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,13 @@ public static unsafe partial ExceptionStatus imgcodecs_imdecode_vector(
5353
byte* buf, int bufLength, int flags, out IntPtr returnValue);
5454

5555
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
56-
public static partial ExceptionStatus imgcodecs_imdecode_InputArray(
57-
IntPtr buf, int flags, out IntPtr returnValue);
56+
internal static partial ExceptionStatus imgcodecs_imdecode_InputArray(
57+
in InputArrayProxy buf, int flags, out IntPtr returnValue);
5858

5959
// Do not consider that "ext" may not be ASCII characters
6060
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
61-
public static partial ExceptionStatus imgcodecs_imencode_vector(
62-
[MarshalAs(UnmanagedType.LPStr)] string ext, IntPtr img, IntPtr buf, [In] int[] @params, int paramsLength, out int returnValue);
61+
internal static partial ExceptionStatus imgcodecs_imencode_vector(
62+
[MarshalAs(UnmanagedType.LPStr)] string ext, in InputArrayProxy img, IntPtr buf, [In] int[] @params, int paramsLength, out int returnValue);
6363

6464
// haveImageReader (UTF-8 everywhere; native probes via a wide path on Windows)
6565

src/OpenCvSharp/Internal/PInvoke/NativeMethods/NativeMethods_quality.cs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ static partial class NativeMethods
1313
#region QualityBase
1414

1515
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
16-
public static partial ExceptionStatus quality_QualityBase_compute(OpenCvSafeHandle obj, IntPtr img, out Scalar returnValue);
16+
internal static partial ExceptionStatus quality_QualityBase_compute(OpenCvSafeHandle obj, in InputArrayProxy img, out Scalar returnValue);
1717

1818
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
19-
public static partial ExceptionStatus quality_QualityBase_getQualityMap(OpenCvSafeHandle obj, IntPtr dst);
19+
internal static partial ExceptionStatus quality_QualityBase_getQualityMap(OpenCvSafeHandle obj, in OutputArrayProxy dst);
2020

2121
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
2222
public static partial ExceptionStatus quality_QualityBase_clear(OpenCvSafeHandle obj);
@@ -29,14 +29,14 @@ static partial class NativeMethods
2929
#region QualityPSNR
3030

3131
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
32-
public static partial ExceptionStatus quality_createQualityPSNR(IntPtr @ref, double maxPixelValue, out IntPtr returnValue);
32+
internal static partial ExceptionStatus quality_createQualityPSNR(in InputArrayProxy @ref, double maxPixelValue, out IntPtr returnValue);
3333

3434
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
3535
public static partial ExceptionStatus quality_Ptr_QualityPSNR_delete(IntPtr obj);
3636

3737
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
38-
public static partial ExceptionStatus quality_QualityPSNR_staticCompute(
39-
IntPtr @ref, IntPtr cmp, IntPtr qualityMap, double maxPixelValue, out Scalar returnValue);
38+
internal static partial ExceptionStatus quality_QualityPSNR_staticCompute(
39+
in InputArrayProxy @ref, in InputArrayProxy cmp, in OutputArrayProxy qualityMap, double maxPixelValue, out Scalar returnValue);
4040

4141
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
4242
public static partial ExceptionStatus quality_QualityPSNR_getMaxPixelValue(OpenCvSafeHandle obj, out double returnValue);
@@ -52,7 +52,7 @@ public static partial ExceptionStatus quality_QualityPSNR_staticCompute(
5252
#region QualitySSIM
5353

5454
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
55-
public static partial ExceptionStatus quality_createQualitySSIM(IntPtr @ref, out IntPtr returnValue);
55+
internal static partial ExceptionStatus quality_createQualitySSIM(in InputArrayProxy @ref, out IntPtr returnValue);
5656

5757
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
5858
public static partial ExceptionStatus quality_Ptr_QualitySSIM_delete(IntPtr obj);
@@ -61,15 +61,15 @@ public static partial ExceptionStatus quality_QualityPSNR_staticCompute(
6161
public static partial ExceptionStatus quality_Ptr_QualitySSIM_get(IntPtr ptr, out IntPtr returnValue);
6262

6363
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
64-
public static partial ExceptionStatus quality_QualitySSIM_staticCompute(
65-
IntPtr @ref, IntPtr cmp, IntPtr qualityMap, out Scalar returnValue);
64+
internal static partial ExceptionStatus quality_QualitySSIM_staticCompute(
65+
in InputArrayProxy @ref, in InputArrayProxy cmp, in OutputArrayProxy qualityMap, out Scalar returnValue);
6666

6767
#endregion
6868

6969
#region QualityGMSD
7070

7171
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
72-
public static partial ExceptionStatus quality_createQualityGMSD(IntPtr @ref, out IntPtr returnValue);
72+
internal static partial ExceptionStatus quality_createQualityGMSD(in InputArrayProxy @ref, out IntPtr returnValue);
7373

7474
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
7575
public static partial ExceptionStatus quality_Ptr_QualityGMSD_delete(IntPtr obj);
@@ -78,15 +78,15 @@ public static partial ExceptionStatus quality_QualitySSIM_staticCompute(
7878
public static partial ExceptionStatus quality_Ptr_QualityGMSD_get(IntPtr ptr, out IntPtr returnValue);
7979

8080
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
81-
public static partial ExceptionStatus quality_QualityGMSD_staticCompute(
82-
IntPtr @ref, IntPtr cmp, IntPtr qualityMap, out Scalar returnValue);
81+
internal static partial ExceptionStatus quality_QualityGMSD_staticCompute(
82+
in InputArrayProxy @ref, in InputArrayProxy cmp, in OutputArrayProxy qualityMap, out Scalar returnValue);
8383

8484
#endregion
8585

8686
#region QualityMSE
8787

8888
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
89-
public static partial ExceptionStatus quality_createQualityMSE(IntPtr @ref, out IntPtr returnValue);
89+
internal static partial ExceptionStatus quality_createQualityMSE(in InputArrayProxy @ref, out IntPtr returnValue);
9090

9191
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
9292
public static partial ExceptionStatus quality_Ptr_QualityMSE_delete(IntPtr obj);
@@ -95,8 +95,8 @@ public static partial ExceptionStatus quality_QualityGMSD_staticCompute(
9595
public static partial ExceptionStatus quality_Ptr_QualityMSE_get(IntPtr ptr, out IntPtr returnValue);
9696

9797
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
98-
public static partial ExceptionStatus quality_QualityMSE_staticCompute(
99-
IntPtr @ref, IntPtr cmp, IntPtr qualityMap, out Scalar returnValue);
98+
internal static partial ExceptionStatus quality_QualityMSE_staticCompute(
99+
in InputArrayProxy @ref, in InputArrayProxy cmp, in OutputArrayProxy qualityMap, out Scalar returnValue);
100100

101101
#endregion
102102

@@ -118,14 +118,14 @@ public static partial ExceptionStatus quality_createQualityBRISQUE1(
118118
public static partial ExceptionStatus quality_Ptr_QualityBRISQUE_get(IntPtr ptr, out IntPtr returnValue);
119119

120120
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
121-
public static partial ExceptionStatus quality_QualityBRISQUE_staticCompute(
122-
IntPtr @ref,
121+
internal static partial ExceptionStatus quality_QualityBRISQUE_staticCompute(
122+
in InputArrayProxy @ref,
123123
[MarshalAs(UnmanagedType.LPStr)] string modelFilePath,
124124
[MarshalAs(UnmanagedType.LPStr)] string rangeFilePath,
125125
out Scalar returnValue);
126126

127127
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
128-
public static partial ExceptionStatus quality_QualityBRISQUE_computeFeatures(IntPtr img, IntPtr features);
128+
internal static partial ExceptionStatus quality_QualityBRISQUE_computeFeatures(in InputArrayProxy img, in OutputArrayProxy features);
129129

130130
#endregion
131131
}

src/OpenCvSharp/Internal/PInvoke/NativeMethods/NativeMethods_videoio.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public static partial ExceptionStatus videoio_VideoCapture_open1(
4949
public static partial ExceptionStatus videoio_VideoCapture_grab(OpenCvSafeHandle obj, out int returnValue);
5050

5151
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
52-
public static partial ExceptionStatus videoio_VideoCapture_retrieve_OutputArray(OpenCvSafeHandle obj, IntPtr image, int flag, out int returnValue);
52+
internal static partial ExceptionStatus videoio_VideoCapture_retrieve_OutputArray(OpenCvSafeHandle obj, in OutputArrayProxy image, int flag, out int returnValue);
5353
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
5454
public static partial ExceptionStatus videoio_VideoCapture_retrieve_Mat(OpenCvSafeHandle obj, IntPtr image, int flag, out int returnValue);
5555

@@ -60,7 +60,7 @@ public static partial ExceptionStatus videoio_VideoCapture_open1(
6060
//public static extern ExceptionStatus videoio_VideoCapture_operatorRightShift_UMat(IntPtr obj, IntPtr image);
6161

6262
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
63-
public static partial ExceptionStatus videoio_VideoCapture_read_OutputArray(OpenCvSafeHandle obj, IntPtr image, out int returnValue);
63+
internal static partial ExceptionStatus videoio_VideoCapture_read_OutputArray(OpenCvSafeHandle obj, in OutputArrayProxy image, out int returnValue);
6464
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
6565
public static partial ExceptionStatus videoio_VideoCapture_read_Mat(OpenCvSafeHandle obj, IntPtr image, out int returnValue);
6666

@@ -133,7 +133,7 @@ public static partial ExceptionStatus videoio_VideoWriter_open2(
133133
//public static extern ExceptionStatus videoio_VideoWriter_OperatorLeftShift(IntPtr obj, IntPtr image);
134134

135135
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
136-
public static partial ExceptionStatus videoio_VideoWriter_write(OpenCvSafeHandle obj, IntPtr image);
136+
internal static partial ExceptionStatus videoio_VideoWriter_write(OpenCvSafeHandle obj, in InputArrayProxy image);
137137

138138
[LibraryImport(DllExtern), UnmanagedCallConv(CallConvs = [typeof(CallConvCdecl)])]
139139
public static partial ExceptionStatus videoio_VideoWriter_set(OpenCvSafeHandle obj, int propId, double value, out int returnValue);

0 commit comments

Comments
 (0)