Skip to content

Commit 6bd719c

Browse files
authored
Remove FormatInvariant helper method. (#1253)
1 parent ea3d329 commit 6bd719c

35 files changed

+285
-162
lines changed

src/MySqlConnector/Core/BinaryRow.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ protected override void GetDataOffsets(ReadOnlySpan<byte> data, int[] dataOffset
4949
ColumnType.Short or ColumnType.Year => 2,
5050
ColumnType.Tiny => 1,
5151
ColumnType.Date or ColumnType.DateTime or ColumnType.NewDate or ColumnType.Timestamp or ColumnType.Time => reader.ReadByte(),
52-
ColumnType.DateTime2 or ColumnType.Timestamp2 => throw new NotSupportedException("ColumnType {0} is not supported".FormatInvariant(columnDefinition.ColumnType)),
52+
ColumnType.DateTime2 or ColumnType.Timestamp2 => throw new NotSupportedException($"ColumnType {columnDefinition.ColumnType} is not supported"),
5353
_ => checked((int) reader.ReadLengthEncodedInteger()),
5454
};
5555

@@ -98,9 +98,9 @@ protected override object GetValueCore(ReadOnlySpan<byte> data, ColumnDefinition
9898

9999
case ColumnType.String:
100100
if (Connection.GuidFormat == MySqlGuidFormat.Char36 && columnDefinition.ColumnLength / ProtocolUtility.GetBytesPerCharacter(columnDefinition.CharacterSet) == 36)
101-
return Utf8Parser.TryParse(data, out Guid guid, out int guid36BytesConsumed, 'D') && guid36BytesConsumed == 36 ? guid : throw new FormatException("Could not parse CHAR(36) value as Guid: {0}".FormatInvariant(Encoding.UTF8.GetString(data)));
101+
return Utf8Parser.TryParse(data, out Guid guid, out int guid36BytesConsumed, 'D') && guid36BytesConsumed == 36 ? guid : throw new FormatException($"Could not parse CHAR(36) value as Guid: {Encoding.UTF8.GetString(data)}");
102102
if (Connection.GuidFormat == MySqlGuidFormat.Char32 && columnDefinition.ColumnLength / ProtocolUtility.GetBytesPerCharacter(columnDefinition.CharacterSet) == 32)
103-
return Utf8Parser.TryParse(data, out Guid guid, out int guid32BytesConsumed, 'N') && guid32BytesConsumed == 32 ? guid : throw new FormatException("Could not parse CHAR(32) value as Guid: {0}".FormatInvariant(Encoding.UTF8.GetString(data)));
103+
return Utf8Parser.TryParse(data, out Guid guid, out int guid32BytesConsumed, 'N') && guid32BytesConsumed == 32 ? guid : throw new FormatException($"Could not parse CHAR(32) value as Guid: {Encoding.UTF8.GetString(data)}");
104104
goto case ColumnType.VarString;
105105

106106
case ColumnType.VarString:
@@ -153,7 +153,7 @@ protected override object GetValueCore(ReadOnlySpan<byte> data, ColumnDefinition
153153
return data.ToArray();
154154

155155
default:
156-
throw new NotImplementedException("Reading {0} not implemented".FormatInvariant(columnDefinition.ColumnType));
156+
throw new NotImplementedException($"Reading {columnDefinition.ColumnType} not implemented");
157157
}
158158
}
159159

@@ -199,7 +199,7 @@ private object ReadDateTime(ReadOnlySpan<byte> value)
199199
}
200200
catch (Exception ex)
201201
{
202-
throw new FormatException("Couldn't interpret value as a valid DateTime".FormatInvariant(Encoding.UTF8.GetString(value)), ex);
202+
throw new FormatException($"Couldn't interpret value as a valid DateTime: {Encoding.UTF8.GetString(value)}", ex);
203203
}
204204
}
205205

src/MySqlConnector/Core/CachedProcedure.cs

+1-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
using System.Text.RegularExpressions;
44
using MySqlConnector.Logging;
55
using MySqlConnector.Protocol.Serialization;
6-
using MySqlConnector.Utilities;
76

87
namespace MySqlConnector.Core;
98

@@ -226,7 +225,7 @@ private static CachedParameter CreateCachedParameter(int ordinal, string? direct
226225
}
227226
catch (NullReferenceException ex)
228227
{
229-
throw new MySqlException("Failed to parse stored procedure parameter '{0}'; extracted data type was {1}".FormatInvariant(originalSql, dataType), ex);
228+
throw new MySqlException($"Failed to parse stored procedure parameter '{originalSql}'; extracted data type was {dataType}", ex);
230229
}
231230
}
232231

src/MySqlConnector/Core/CommandExecutor.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public static async Task<MySqlDataReader> ExecuteReaderAsync(IReadOnlyList<IMySq
6565
// the default MySQL Server value for max_allowed_packet (in MySQL 5.7) is 4MiB: https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_max_allowed_packet
6666
// use "decimal megabytes" (to round up) when creating the exception message
6767
int megabytes = payload.Span.Length / 1_000_000;
68-
throw new MySqlException("Error submitting {0}MB packet; ensure 'max_allowed_packet' is greater than {0}MB.".FormatInvariant(megabytes), ex);
68+
throw new MySqlException($"Error submitting {megabytes}MB packet; ensure 'max_allowed_packet' is greater than {megabytes}MB.", ex);
6969
}
7070
}
7171
catch (Exception ex) when (activity is { IsAllDataRequested: true })

src/MySqlConnector/Core/ConnectionPool.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System.Collections.Concurrent;
22
using System.Diagnostics;
3+
using System.Globalization;
34
using System.Net;
45
using System.Security.Authentication;
56
using MySqlConnector.Logging;
@@ -569,7 +570,7 @@ private ConnectionPool(ConnectionSettings cs)
569570
(ILoadBalancer) new RoundRobinLoadBalancer();
570571

571572
Id = Interlocked.Increment(ref s_poolId);
572-
m_logArguments = new object[] { "{0}".FormatInvariant(Id) };
573+
m_logArguments = new object[] { Id.ToString(CultureInfo.InvariantCulture) };
573574
if (Log.IsInfoEnabled())
574575
Log.Info("Pool{0} creating new connection pool for ConnectionString: {1}", m_logArguments[0], cs.ConnectionStringBuilder.GetConnectionString(includePassword: false));
575576
}

src/MySqlConnector/Core/ConnectionSettings.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public ConnectionSettings(MySqlConnectionStringBuilder csb)
7878
TlsVersions |= SslProtocols.Tls13;
7979
#endif
8080
else
81-
throw new InvalidOperationException("Unexpected character '{0}' for TLS minor version.".FormatInvariant(minorVersion));
81+
throw new InvalidOperationException($"Unexpected character '{minorVersion}' for TLS minor version.");
8282
}
8383
if (TlsVersions == default)
8484
throw new NotSupportedException("All specified TLS versions are incompatible with this platform.");
@@ -95,10 +95,10 @@ public ConnectionSettings(MySqlConnectionStringBuilder csb)
9595
tlsCipherSuites.Add(cipherSuite);
9696
else if (int.TryParse(suiteName, out var value) && Enum.IsDefined(typeof(TlsCipherSuite), value))
9797
tlsCipherSuites.Add((TlsCipherSuite) value);
98-
else if (Enum.TryParse<TlsCipherSuite>("TLS_" + suiteName, ignoreCase: true, out cipherSuite))
98+
else if (Enum.TryParse("TLS_" + suiteName, ignoreCase: true, out cipherSuite))
9999
tlsCipherSuites.Add(cipherSuite);
100100
else
101-
throw new NotSupportedException("Unknown value '{0}' for TlsCipherSuites.".FormatInvariant(suiteName));
101+
throw new NotSupportedException($"Unknown value '{suiteName}' for TlsCipherSuites.");
102102
}
103103
TlsCipherSuites = tlsCipherSuites;
104104
#else

src/MySqlConnector/Core/ResultSet.cs

+5-5
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ public async Task ReadResultSetHeaderAsync(IOBehavior ioBehavior)
103103
break;
104104

105105
default:
106-
throw new InvalidOperationException("Unsupported Source type: {0}".FormatInvariant(source.GetType().Name));
106+
throw new InvalidOperationException($"Unsupported Source type: {source.GetType().Name}");
107107
}
108108
}
109109
catch (Exception ex)
@@ -293,7 +293,7 @@ public string GetName(int ordinal)
293293
if (ColumnDefinitions is null)
294294
throw new InvalidOperationException("There is no current result set.");
295295
if (ordinal < 0 || ordinal >= ColumnDefinitions.Length)
296-
throw new IndexOutOfRangeException("value must be between 0 and {0}".FormatInvariant(ColumnDefinitions.Length - 1));
296+
throw new IndexOutOfRangeException($"value must be between 0 and {ColumnDefinitions.Length - 1}");
297297
return ColumnDefinitions[ordinal].Name;
298298
}
299299

@@ -302,7 +302,7 @@ public string GetDataTypeName(int ordinal)
302302
if (ColumnDefinitions is null)
303303
throw new InvalidOperationException("There is no current result set.");
304304
if (ordinal < 0 || ordinal >= ColumnDefinitions.Length)
305-
throw new IndexOutOfRangeException("value must be between 0 and {0}.".FormatInvariant(ColumnDefinitions.Length));
305+
throw new IndexOutOfRangeException($"value must be between 0 and {ColumnDefinitions.Length - 1}");
306306

307307
var mySqlDbType = ColumnTypes![ordinal];
308308
if (mySqlDbType == MySqlDbType.String)
@@ -315,7 +315,7 @@ public Type GetFieldType(int ordinal)
315315
if (ColumnDefinitions is null)
316316
throw new InvalidOperationException("There is no current result set.");
317317
if (ordinal < 0 || ordinal >= ColumnDefinitions.Length)
318-
throw new IndexOutOfRangeException("value must be between 0 and {0}.".FormatInvariant(ColumnDefinitions.Length));
318+
throw new IndexOutOfRangeException($"value must be between 0 and {ColumnDefinitions.Length - 1}");
319319

320320
var type = TypeMapper.Instance.GetColumnTypeMetadata(ColumnTypes![ordinal]).DbTypeMapping.ClrType;
321321
if (Connection.AllowZeroDateTime && type == typeof(DateTime))
@@ -348,7 +348,7 @@ public int GetOrdinal(string name)
348348
return column;
349349
}
350350

351-
throw new IndexOutOfRangeException("The column name '{0}' does not exist in the result set.".FormatInvariant(name));
351+
throw new IndexOutOfRangeException($"The column name '{name}' does not exist in the result set.");
352352
}
353353

354354
public Row GetCurrentRow()

src/MySqlConnector/Core/Row.cs

+7-7
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public Row Clone()
2828
public object GetValue(int ordinal)
2929
{
3030
if (ordinal < 0 || ordinal >= ResultSet.ColumnDefinitions!.Length)
31-
throw new ArgumentOutOfRangeException(nameof(ordinal), "value must be between 0 and {0}.".FormatInvariant(ResultSet.ColumnDefinitions!.Length - 1));
31+
throw new ArgumentOutOfRangeException(nameof(ordinal), $"value must be between 0 and {ResultSet.ColumnDefinitions!.Length - 1}");
3232

3333
if (m_dataOffsets[ordinal] == -1)
3434
return DBNull.Value;
@@ -216,7 +216,7 @@ public int GetInt32(int ordinal)
216216
and not ColumnType.Int24 and not ColumnType.Long and not ColumnType.Longlong
217217
and not ColumnType.Bit and not ColumnType.Year)
218218
{
219-
throw new InvalidCastException("Can't convert {0} to Int32".FormatInvariant(ResultSet.ColumnTypes![ordinal]));
219+
throw new InvalidCastException($"Can't convert {ResultSet.ColumnTypes![ordinal]} to Int32");
220220
}
221221

222222
var data = m_data.Slice(m_dataOffsets[ordinal], m_dataLengths[ordinal]).Span;
@@ -357,7 +357,7 @@ public DateTime GetDateTime(int ordinal)
357357
if (dateString.Length is >= 10 and <= 26)
358358
value = ParseDateTime(Encoding.UTF8.GetBytes(dateString));
359359
else
360-
throw new FormatException("Couldn't interpret '{0}' as a valid DateTime".FormatInvariant(value));
360+
throw new FormatException($"Couldn't interpret value as a valid DateTime: {value}");
361361
}
362362

363363
if (value is MySqlDateTime mySqlDateTime)
@@ -436,7 +436,7 @@ public MySqlGeometry GetMySqlGeometry(int ordinal)
436436
var value = GetValue(ordinal);
437437
if (value is byte[] bytes && ResultSet.ColumnDefinitions![ordinal].ColumnType == ColumnType.Geometry)
438438
return new MySqlGeometry(bytes);
439-
throw new InvalidCastException("Can't convert {0} to MySqlGeometry.".FormatInvariant(ResultSet.ColumnDefinitions![ordinal].ColumnType));
439+
throw new InvalidCastException($"Can't convert {ResultSet.ColumnDefinitions![ordinal].ColumnType} to MySqlGeometry.");
440440
}
441441

442442
public MySqlDecimal GetMySqlDecimal(int ordinal)
@@ -447,7 +447,7 @@ public MySqlDecimal GetMySqlDecimal(int ordinal)
447447
var columnType = ResultSet.ColumnDefinitions![ordinal].ColumnType;
448448
if (columnType is ColumnType.NewDecimal or ColumnType.Decimal)
449449
return new MySqlDecimal(Encoding.UTF8.GetString(data));
450-
throw new InvalidCastException("Can't convert {0} to MySqlDecimal.".FormatInvariant(ResultSet.ColumnDefinitions![ordinal].ColumnType));
450+
throw new InvalidCastException($"Can't convert {ResultSet.ColumnDefinitions![ordinal].ColumnType} to MySqlDecimal.");
451451
}
452452

453453
public int GetValues(object[] values)
@@ -557,7 +557,7 @@ protected object ParseDateTime(ReadOnlySpan<byte> value)
557557
}
558558

559559
InvalidDateTime:
560-
throw new FormatException("Couldn't interpret '{0}' as a valid DateTime".FormatInvariant(Encoding.UTF8.GetString(value)), exception);
560+
throw new FormatException($"Couldn't interpret value as a valid DateTime: {Encoding.UTF8.GetString(value)}", exception);
561561
}
562562

563563
#if NET5_0_OR_GREATER
@@ -615,7 +615,7 @@ private void CheckBinaryColumn(int ordinal)
615615
columnType != ColumnType.Blob && columnType != ColumnType.MediumBlob && columnType != ColumnType.LongBlob &&
616616
columnType != ColumnType.Geometry))
617617
{
618-
throw new InvalidCastException("Can't convert {0} to bytes.".FormatInvariant(columnType));
618+
throw new InvalidCastException($"Can't convert {columnType} to bytes.");
619619
}
620620
}
621621

src/MySqlConnector/Core/SchemaProvider.cs

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
using System.Globalization;
12
using MySqlConnector.Protocol.Serialization;
2-
using MySqlConnector.Utilities;
33

44
namespace MySqlConnector.Core;
55

@@ -36,7 +36,12 @@ private void DoFillDataSourceInformation(DataTable dataTable)
3636
SupportedJoinOperators.RightOuter;
3737
dataTable.Rows.Add(row);
3838

39-
static string GetVersion(Version v) => "{0:00}.{1:00}.{2:0000}".FormatInvariant(v.Major, v.Minor, v.Build);
39+
static string GetVersion(Version v) =>
40+
#if NET6_0_OR_GREATER
41+
string.Create(CultureInfo.InvariantCulture, stackalloc char[10], $"{v.Major:00}.{v.Minor:00}.{v.Build:0000}");
42+
#else
43+
FormattableString.Invariant($"{v.Major:00}.{v.Minor:00}.{v.Build:0000}");
44+
#endif
4045
}
4146

4247
private static void DoFillDataTypes(DataTable dataTable)

src/MySqlConnector/Core/ServerSession.cs

+10-10
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public ServerSession(ConnectionPool? pool, int poolGeneration, int id)
3939
Pool = pool;
4040
PoolGeneration = poolGeneration;
4141
HostName = "";
42-
m_logArguments = new object?[] { "{0}".FormatInvariant(Id), null };
42+
m_logArguments = new object?[] { Id.ToString(CultureInfo.InvariantCulture), null };
4343
m_activityTags = new ActivityTagsCollection();
4444
Log.Trace("Session{0} created new session", m_logArguments);
4545
}
@@ -149,7 +149,7 @@ public async Task PrepareAsync(IMySqlCommand command, IOBehavior ioBehavior, Can
149149
if (cachedProcedure is null)
150150
{
151151
var name = NormalizedSchema.MustNormalize(command.CommandText!, command.Connection.Database);
152-
throw new MySqlException("Procedure or function '{0}' cannot be found in database '{1}'.".FormatInvariant(name.Component, name.Schema));
152+
throw new MySqlException($"Procedure or function '{name.Component}' cannot be found in database '{name.Schema}'.");
153153
}
154154

155155
var parameterCount = cachedProcedure.Parameters.Count;
@@ -467,7 +467,7 @@ public async Task DisposeAsync(IOBehavior ioBehavior, CancellationToken cancella
467467
if (authPluginName != "mysql_native_password" && authPluginName != "sha256_password" && authPluginName != "caching_sha2_password")
468468
{
469469
Log.Error("Session{0} unsupported authentication method AuthPluginName={1}", m_logArguments);
470-
throw new NotSupportedException("Authentication method '{0}' is not supported.".FormatInvariant(initialHandshake.AuthPluginName));
470+
throw new NotSupportedException($"Authentication method '{initialHandshake.AuthPluginName}' is not supported.");
471471
}
472472

473473
ServerVersion = new(initialHandshake.ServerVersion);
@@ -714,7 +714,7 @@ private async Task<PayloadData> SwitchAuthenticationAsync(ConnectionSettings cs,
714714
if (!m_isSecureConnection)
715715
{
716716
Log.Error("Session{0} needs a secure connection to use AuthenticationMethod '{1}'", m_logArguments);
717-
throw new MySqlException(MySqlErrorCode.UnableToConnectToHost, "Authentication method '{0}' requires a secure connection.".FormatInvariant(switchRequest.Name));
717+
throw new MySqlException(MySqlErrorCode.UnableToConnectToHost, $"Authentication method '{switchRequest.Name}' requires a secure connection.");
718718
}
719719

720720
// send the password as a NULL-terminated UTF-8 string
@@ -767,7 +767,7 @@ private async Task<PayloadData> SwitchAuthenticationAsync(ConnectionSettings cs,
767767

768768
default:
769769
Log.Error("Session{0} is requesting AuthenticationMethod '{1}' which is not supported", m_logArguments);
770-
throw new NotSupportedException("Authentication method '{0}' is not supported.".FormatInvariant(switchRequest.Name));
770+
throw new NotSupportedException($"Authentication method '{switchRequest.Name}' is not supported.");
771771
}
772772
}
773773

@@ -846,7 +846,7 @@ private async Task<string> GetRsaPublicKeyAsync(string switchRequestName, Connec
846846
{
847847
m_logArguments[1] = cs.ServerRsaPublicKeyFile;
848848
Log.Error(ex, "Session{0} couldn't load server's RSA public key from PublicKeyFile '{1}'", m_logArguments);
849-
throw new MySqlException("Couldn't load server's RSA public key from '{0}'".FormatInvariant(cs.ServerRsaPublicKeyFile), ex);
849+
throw new MySqlException($"Couldn't load server's RSA public key from '{cs.ServerRsaPublicKeyFile}'", ex);
850850
}
851851
}
852852

@@ -862,7 +862,7 @@ private async Task<string> GetRsaPublicKeyAsync(string switchRequestName, Connec
862862

863863
m_logArguments[1] = switchRequestName;
864864
Log.Error("Session{0} couldn't use AuthenticationMethod '{1}' because RSA key wasn't specified or couldn't be retrieved", m_logArguments);
865-
throw new MySqlException(MySqlErrorCode.UnableToConnectToHost, "Authentication method '{0}' failed. Either use a secure connection, specify the server's RSA public key with ServerRSAPublicKeyFile, or set AllowPublicKeyRetrieval=True.".FormatInvariant(switchRequestName));
865+
throw new MySqlException(MySqlErrorCode.UnableToConnectToHost, $"Authentication method '{switchRequestName}' failed. Either use a secure connection, specify the server's RSA public key with ServerRSAPublicKeyFile, or set AllowPublicKeyRetrieval=True.");
866866
}
867867

868868
public async ValueTask<bool> TryPingAsync(bool logInfo, IOBehavior ioBehavior, CancellationToken cancellationToken)
@@ -1329,7 +1329,7 @@ private async Task InitSslAsync(ProtocolCapabilities serverCapabilities, Connect
13291329
{
13301330
m_logArguments[1] = cs.CertificateThumbprint;
13311331
Log.Error("Session{0} certificate with Thumbprint={1} not found in store", m_logArguments);
1332-
throw new MySqlException("Certificate with Thumbprint {0} not found".FormatInvariant(cs.CertificateThumbprint));
1332+
throw new MySqlException($"Certificate with Thumbprint {cs.CertificateThumbprint} not found");
13331333
}
13341334

13351335
clientCertificates = new(foundCertificates);
@@ -1793,7 +1793,7 @@ private void VerifyState(State state)
17931793
if (m_state != state)
17941794
{
17951795
Log.Error("Session{0} should have SessionStateExpected {1} but was SessionState {2}", m_logArguments[0], state, m_state);
1796-
throw new InvalidOperationException("Expected state to be {0} but was {1}.".FormatInvariant(state, m_state));
1796+
throw new InvalidOperationException($"Expected state to be {state} but was {m_state}.");
17971797
}
17981798
}
17991799

@@ -1803,7 +1803,7 @@ private void VerifyState(State state1, State state2, State state3, State state4,
18031803
{
18041804
Log.Error("Session{0} should have SessionStateExpected {1} or SessionStateExpected2 {2} or SessionStateExpected3 {3} or SessionStateExpected4 {4} or SessionStateExpected5 {5} or SessionStateExpected6 {6} but was SessionState {7}",
18051805
m_logArguments[0], state1, state2, state3, state4, state5, state6, m_state);
1806-
throw new InvalidOperationException("Expected state to be ({0}|{1}|{2}|{3}|{4}|{5}) but was {6}.".FormatInvariant(state1, state2, state3, state4, state5, state6, m_state));
1806+
throw new InvalidOperationException($"Expected state to be ({state1}|{state2}|{state3}|{state4}|{state5}|{state6}) but was {m_state}.");
18071807
}
18081808
}
18091809

src/MySqlConnector/Core/SingleCommandPayloadCreator.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -119,9 +119,9 @@ private static void WritePreparedStatement(IMySqlCommand command, PreparedStatem
119119
var parameterName = preparedStatement.Statement.NormalizedParameterNames![i];
120120
var parameterIndex = parameterName is not null ? (parameterCollection?.UnsafeIndexOf(parameterName) ?? -1) : preparedStatement.Statement.ParameterIndexes[i];
121121
if (parameterIndex == -1 && parameterName is not null)
122-
throw new MySqlException("Parameter '{0}' must be defined.".FormatInvariant(preparedStatement.Statement.ParameterNames![i]));
122+
throw new MySqlException($"Parameter '{preparedStatement.Statement.ParameterNames![i]}' must be defined.");
123123
else if (parameterIndex < 0 || parameterIndex >= (parameterCollection?.Count ?? 0))
124-
throw new MySqlException("Parameter index {0} is invalid when only {1} parameter{2} defined.".FormatInvariant(parameterIndex, parameterCollection?.Count ?? 0, parameterCollection?.Count == 1 ? " is" : "s are"));
124+
throw new MySqlException($"Parameter index {parameterIndex} is invalid when only {parameterCollection?.Count ?? 0} parameter{(parameterCollection?.Count == 1 ? " is" : "s are")} defined.");
125125
parameters[i] = parameterCollection![parameterIndex];
126126
}
127127
for (var i = 0; i < attributeCount; i++)

0 commit comments

Comments
 (0)