Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bump mysql_common to 0.29 #338

Merged
merged 6 commits into from
Nov 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "mysql"
version = "22.2.0"
version = "23.0.0"
authors = ["blackbeam"]
description = "Mysql client library implemented in rust"
license = "MIT/Apache-2.0"
Expand Down Expand Up @@ -41,6 +41,17 @@ default = [
# use global buffer pool by default
"buffer-pool",
]
default-rustls = [
"rustls-tls",
"flate2/zlib",
"mysql_common/bigdecimal03",
"mysql_common/rust_decimal",
"mysql_common/time03",
"mysql_common/uuid",
"mysql_common/frunk",
"buffer-pool",
]
minimal = ["flate2/zlib"]
rustls-tls = ["rustls", "webpki", "webpki-roots", "rustls-pemfile"]
buffer-pool = []
nightly = []
Expand All @@ -58,8 +69,8 @@ bytes = "1.0.1"
crossbeam = "0.8.1"
io-enum = "1.0.0"
flate2 = { version = "1.0", default-features = false }
lru = "0.7"
mysql_common = { version = "0.28.0", default-features = false }
lru = "0.8.1"
mysql_common = { version = "0.29.1", default-features = false }
socket2 = "0.4"
once_cell = "1.7.2"
pem = "1.0.1"
Expand Down
6 changes: 3 additions & 3 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,9 @@ jobs:
maxParallel: 10
matrix:
v80:
DB_VERSION: "8.0"
DB_VERSION: "8-debian"
v57:
DB_VERSION: "5.7"
DB_VERSION: "5-debian"
v56:
DB_VERSION: "5.6"
steps:
Expand All @@ -204,7 +204,7 @@ jobs:
condition: eq(variables['DB_VERSION'], '5.6')
- bash: |
docker exec container bash -l -c "apt-get update"
docker exec container bash -l -c "apt-get install -y curl clang libssl-dev pkg-config"
docker exec container bash -l -c "apt-get install -y curl clang libssl-dev pkg-config build-essential"
docker exec container bash -l -c "curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain stable"
displayName: Install Rust in docker
- bash: |
Expand Down
28 changes: 19 additions & 9 deletions src/conn/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

use bytes::{Buf, BufMut};
use mysql_common::{
constants::UTF8MB4_GENERAL_CI,
crypto,
io::{ParseBuf, ReadMysqlExt},
misc::raw::Either,
Expand Down Expand Up @@ -205,7 +206,10 @@ pub struct Conn(Box<ConnInner>);
impl Conn {
/// Returns version number reported by the server.
pub fn server_version(&self) -> (u16, u16, u16) {
self.0.server_version.unwrap()
self.0
.server_version
.or_else(|| self.0.mariadb_server_version)
.unwrap()
}

/// Returns connection identifier.
Expand Down Expand Up @@ -662,10 +666,16 @@ impl Conn {
}

fn do_ssl_request(&mut self) -> Result<()> {
let charset = if self.server_version() >= (5, 5, 3) {
UTF8MB4_GENERAL_CI
} else {
UTF8_GENERAL_CI
};

let ssl_request = SslRequest::new(
self.get_client_flags(),
DEFAULT_MAX_ALLOWED_PACKET as u32,
UTF8_GENERAL_CI as u8,
charset as u8,
);
self.write_struct(&ssl_request)
}
Expand Down Expand Up @@ -1001,8 +1011,8 @@ impl Conn {
Ok(Transaction::new(self.into()))
}

fn _true_prepare(&mut self, query: &str) -> Result<InnerStmt> {
self.write_command(Command::COM_STMT_PREPARE, query.as_bytes())?;
fn _true_prepare(&mut self, query: &[u8]) -> Result<InnerStmt> {
self.write_command(Command::COM_STMT_PREPARE, query)?;
let pld = self.read_packet()?;
let mut stmt = ParseBuf(&*pld).parse::<InnerStmt>(self.connection_id())?;
if stmt.num_params() > 0 {
Expand All @@ -1026,7 +1036,7 @@ impl Conn {
Ok(stmt)
}

fn _prepare(&mut self, query: &str) -> Result<Arc<InnerStmt>> {
fn _prepare(&mut self, query: &[u8]) -> Result<Arc<InnerStmt>> {
if let Some(entry) = self.0.stmt_cache.by_query(query) {
return Ok(entry.stmt.clone());
}
Expand Down Expand Up @@ -1098,7 +1108,7 @@ impl Conn {
Ok(Some(row.into()))
}

fn has_stmt(&self, query: &str) -> bool {
fn has_stmt(&self, query: &[u8]) -> bool {
self.0.stmt_cache.contains_query(query)
}

Expand Down Expand Up @@ -1162,7 +1172,7 @@ impl Queryable for Conn {

fn prep<T: AsRef<str>>(&mut self, query: T) -> Result<Statement> {
let query = query.as_ref();
let (named_params, real_query) = parse_named_params(query)?;
let (named_params, real_query) = parse_named_params(query.as_bytes())?;
self._prepare(real_query.borrow())
.map(|inner| Statement::new(inner, named_params))
}
Expand Down Expand Up @@ -2083,9 +2093,9 @@ mod test {
.stmt_cache
.iter()
.map(|(_, entry)| &**entry.query.0.as_ref())
.collect::<Vec<&str>>();
.collect::<Vec<&[u8]>>();
order.sort();
assert_eq!(order, &["DO 3", "DO 5", "DO 6"]);
assert_eq!(order, &[b"DO 3", b"DO 5", b"DO 6"]);
}

#[test]
Expand Down
2 changes: 1 addition & 1 deletion src/conn/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ impl Pool {
/// Will verify and fix it via `Conn::ping` and `Conn::reset` if `call_ping` is `true`.
/// Will try to get concrete connection if `id` is `Some(_)`.
/// Will wait til timeout if `timeout_ms` is `Some(_)`
fn _get_conn<T: AsRef<str>>(
fn _get_conn<T: AsRef<[u8]>>(
&self,
stmt: Option<T>,
timeout_ms: Option<u32>,
Expand Down
4 changes: 2 additions & 2 deletions src/conn/stmt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,11 @@ impl InnerStmt {
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Statement {
pub(crate) inner: Arc<InnerStmt>,
pub(crate) named_params: Option<Vec<String>>,
pub(crate) named_params: Option<Vec<Vec<u8>>>,
}

impl Statement {
pub(crate) fn new(inner: Arc<InnerStmt>, named_params: Option<Vec<String>>) -> Self {
pub(crate) fn new(inner: Arc<InnerStmt>, named_params: Option<Vec<Vec<u8>>>) -> Self {
Self {
inner,
named_params,
Expand Down
14 changes: 7 additions & 7 deletions src/conn/stmt_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,16 @@ use std::{
use crate::conn::stmt::InnerStmt;

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct QueryString(pub Arc<String>);
pub struct QueryString(pub Arc<Vec<u8>>);

impl Borrow<str> for QueryString {
fn borrow(&self) -> &str {
impl Borrow<[u8]> for QueryString {
fn borrow(&self) -> &[u8] {
&**self.0.as_ref()
}
}

impl PartialEq<str> for QueryString {
fn eq(&self, other: &str) -> bool {
impl PartialEq<[u8]> for QueryString {
fn eq(&self, other: &[u8]) -> bool {
&**self.0.as_ref() == other
}
}
Expand Down Expand Up @@ -77,7 +77,7 @@ impl StmtCache {
}
}

pub fn put(&mut self, query: Arc<String>, stmt: Arc<InnerStmt>) -> Option<Arc<InnerStmt>> {
pub fn put(&mut self, query: Arc<Vec<u8>>, stmt: Arc<InnerStmt>) -> Option<Arc<InnerStmt>> {
if self.cap == 0 {
return None;
}
Expand All @@ -104,7 +104,7 @@ impl StmtCache {

pub fn remove(&mut self, id: u32) {
if let Some(entry) = self.cache.pop(&id) {
self.query_map.remove::<str>(entry.query.borrow());
self.query_map.remove::<[u8]>(entry.query.borrow());
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/error/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,9 @@ impl From<FromRowError> for Error {

impl From<MissingNamedParameterError> for Error {
fn from(MissingNamedParameterError(name): MissingNamedParameterError) -> Error {
Error::DriverError(DriverError::MissingNamedParameter(name))
Error::DriverError(DriverError::MissingNamedParameter(
String::from_utf8_lossy(&name).into_owned(),
))
}
}

Expand Down
26 changes: 14 additions & 12 deletions tests/ca.crt
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
-----BEGIN CERTIFICATE-----
MIIEBDCCAuygAwIBAgIUBI+G157VcfoRku8+hbCfVFkDNocwDQYJKoZIhvcNAQEL
BQAwgasxCzAJBgNVBAYTAlJVMQ8wDQYDVQQIDAZNb3Njb3MxDzANBgNVBAcMBk1v
MIIEVTCCAz2gAwIBAgIUM3nHiIik1t24hL0OkCEiIFKHYsIwDQYJKoZIhvcNAQEL
BQAwgasxCzAJBgNVBAYTAlJVMQ8wDQYDVQQIDAZNb3djb3cxDzANBgNVBAcMBk1v
c2NvdzEQMA4GA1UECgwHRlNJIFJTTDEiMCAGA1UECwwZcnVzdC1teXNxbC1zaW1w
bGUgdGVzdCBjYTEaMBgGA1UEAwwRcnVzdF9teXNxbF9zaW1wbGUxKDAmBgkqhkiG
9w0BCQEWGXJvb3RfZW1haWxAcm9vdC5sb2NhbGhvc3QwHhcNMjExMDE5MDk1ODI1
WhcNMjIxMDE5MDk1ODI1WjCBqzELMAkGA1UEBhMCUlUxDzANBgNVBAgMBk1vc2Nv
czEPMA0GA1UEBwwGTW9zY293MRAwDgYDVQQKDAdGU0kgUlNMMSIwIAYDVQQLDBly
9w0BCQEWGXJvb3RfZW1haWxAcm9vdC5sb2NhbGhvc3QwHhcNMjIxMTExMTI1NjA1
WhcNMzIxMTA4MTI1NjA1WjCBqzELMAkGA1UEBhMCUlUxDzANBgNVBAgMBk1vd2Nv
dzEPMA0GA1UEBwwGTW9zY293MRAwDgYDVQQKDAdGU0kgUlNMMSIwIAYDVQQLDBly
dXN0LW15c3FsLXNpbXBsZSB0ZXN0IGNhMRowGAYDVQQDDBFydXN0X215c3FsX3Np
bXBsZTEoMCYGCSqGSIb3DQEJARYZcm9vdF9lbWFpbEByb290LmxvY2FsaG9zdDCC
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMIKxR7MR16bxqAQoFJBh5UI
Expand All @@ -14,11 +14,13 @@ RhEWYwgfIxtibBMPIKFIvfzaFp+lsthmSNRuUX07MedeLNmHYvxZo5FFB4NA7C6v
4mN9EGe4yyexK/gy71R2dvdqROJHzfUDu4XJTsraiZ85xPAS4cYpTqSESxb2yo2Z
7anvvDpx30BMaPRkhYEcZ2AatyMQPO0ZlzYWuAzxG5A1EU/rRUdyaF/HnxZsCG4h
/ZHl4VTAWKhoY2cak1w9AeGD8joN8j5yCup+mNtGAKOdaE4E+ngLwcuiFuLp0AEC
AwEAAaMeMBwwGgYDVR0RBBMwEYcEfwAAAYIJbG9jYWxob3N0MA0GCSqGSIb3DQEB
CwUAA4IBAQAjTbdm0y73dnIXI/2MprHp+NvRzsDJ2pVMLiw2L6cfSTOEyC13aBDm
w4ssKG2P9H6Ezm/lWArQ3mFO2qzoan2OZID8zek7455ilUzP9VTNfWds5rh6qeN/
Yq4BsPC8rLhTHoWW2jBDktCjlPLtLxBOBapE3JA4POv3SuOYP95wgxnnlZBKMAx0
QyAEPYFlv2bfYxBka/6clEZpoFgfWWgFRNP67/trGRvdf+yTRkw/HSwE3vGrnv+k
nESRVOxqLBaAdDtVCvqqEoE54fCXPAmyOzH/Vh/vFKuBX16WnwPRfqh4C0E5J07c
vM6jjAQYMlejYh38X8R4yrFVbI4Plbqu
AwEAAaNvMG0wHQYDVR0OBBYEFEBUxV+r++fNBSKzZjHCCfBv6v9LMB8GA1UdIwQY
MBaAFEBUxV+r++fNBSKzZjHCCfBv6v9LMA8GA1UdEwEB/wQFMAMBAf8wGgYDVR0R
BBMwEYcEfwAAAYIJbG9jYWxob3N0MA0GCSqGSIb3DQEBCwUAA4IBAQDB+cew+WQq
sJoFxf2CJNUwYwi/dXGEydI8V55q28gjfpomQwHWqyFve5AjAt93YhRVKAceQJ7h
AksRuTzcFnh1K5Ck+U6TK78aec/FL1Q87GXC/nQoIlKuEDheUHq2fNfDNdssouyK
kJv3p2A14L6U60W3/2TLTzTwS3jeRmK0D08mE0VqOY/eIf3Q8OKQj1udreU9/lEp
C23ifWpJX3WKzdLzZ5voY8N981H6Ih7TXjjjf4AKjDYJXZqyBYjrIrEIiNjTWfxp
k4amKe8T9aObRy1ZAuR91sUy3qZX3Njj5mQTX+6RkVEPdsj4VTL3g1JgdU3Tq53P
m+kOsoKlxwA1
-----END CERTIFICATE-----
77 changes: 38 additions & 39 deletions tests/client.crt
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 3 (0x3)
Serial Number: 8 (0x8)
Signature Algorithm: sha256WithRSAEncryption
Issuer: C=RU, ST=Moscos, L=Moscow, O=FSI RSL, OU=rust-mysql-simple test ca, CN=rust_mysql_simple/[email protected]
Issuer: C=RU, ST=Mowcow, L=Moscow, O=FSI RSL, OU=rust-mysql-simple test ca, CN=rust_mysql_simple/[email protected]
Validity
Not Before: Oct 19 10:01:04 2021 GMT
Not After : Sep 25 10:01:04 2121 GMT
Subject: C=RU, ST=Moscow region, O=FSI RSL, OU=rust-mysql-simple test client cert, CN=localhost
Not Before: Nov 11 13:19:21 2022 GMT
Not After : Oct 18 13:19:21 2122 GMT
Subject: C=RU, ST=Moscow, O=FSI RSL, OU=rust-mysql-simple test ca, CN=rust_mysql_simple
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Expand Down Expand Up @@ -35,41 +35,40 @@ Certificate:
X509v3 Subject Alternative Name:
IP Address:127.0.0.1, DNS:localhost
Signature Algorithm: sha256WithRSAEncryption
4b:4b:2f:02:29:c5:32:32:6a:ce:3a:c6:fd:f4:b7:77:f9:59:
94:4d:35:21:01:dc:09:4d:ad:3d:ff:13:f3:23:4e:82:e6:07:
54:25:b3:f6:f9:83:80:d5:55:12:d1:7f:d6:21:f5:22:24:05:
3e:03:43:97:2b:81:bf:ce:01:54:5e:38:fa:fe:66:d2:4f:03:
bf:bd:e1:2c:50:5f:39:dc:5c:4f:bc:7b:5b:d1:2a:d1:dc:aa:
3b:e0:0c:9d:1b:6f:d4:5c:b8:ae:95:09:a1:6e:e2:f8:44:0f:
65:f1:a2:e0:be:fb:4e:bf:c7:3a:e5:70:9b:23:dd:54:99:01:
05:f0:15:a3:67:e2:cf:a5:1b:7a:44:76:f2:64:70:31:f0:ef:
34:40:6e:86:ef:be:81:a6:f7:34:46:ca:b9:76:8d:0c:dc:2c:
b0:50:81:7f:ba:cb:42:27:a3:15:c7:89:91:58:ea:39:74:32:
2c:7b:16:22:8e:14:8c:05:61:58:c7:9d:f6:9f:16:5a:df:1f:
fd:f9:1e:2b:68:73:1c:60:7b:c8:df:d3:e3:6a:d0:1f:29:74:
c4:98:a4:1d:5a:0d:4d:2f:0f:03:dd:5e:a8:03:da:4a:6e:12:
6b:65:e9:13:e0:c4:10:d1:85:c6:48:8e:eb:2e:52:c4:6f:ab:
c4:ce:b2:65
47:6e:41:a6:3e:49:fa:c7:03:a1:01:4c:98:27:19:6f:41:e1:
5b:a0:99:bc:de:af:91:12:7b:21:7f:9e:3e:6c:05:82:30:c3:
b9:22:52:a0:71:8d:bc:35:b5:8b:39:9b:f0:c6:5c:6f:ee:24:
db:49:22:17:c4:83:62:4a:40:68:fe:ee:e8:99:ec:f3:91:c1:
c2:1b:89:ac:e8:5c:7f:7d:fe:61:9a:fa:67:4b:79:0b:01:d5:
8f:6b:96:66:47:75:6c:28:7b:ea:3e:69:c7:11:c2:87:df:33:
0d:6c:35:a6:2e:c0:d4:e3:7d:2a:15:b9:eb:a0:7c:f7:bd:f8:
76:d4:ce:3f:2a:02:79:2b:8f:7f:33:b1:26:b4:d7:0d:3e:75:
41:e5:d5:3f:5e:25:a9:66:8f:4d:07:ca:d4:26:d5:17:6c:85:
7b:cc:e2:bc:03:18:9b:76:b4:78:4a:17:a5:5e:b4:58:fc:61:
df:b5:3d:d1:51:df:fb:65:14:1a:bb:49:70:d3:01:2e:fb:ef:
73:21:19:a7:d1:0c:82:56:92:70:00:68:6f:e0:76:c2:7a:29:
3c:21:6b:ac:4f:26:30:15:02:b2:5f:33:80:40:39:e4:97:e3:
b5:76:5b:f1:1a:19:59:fb:87:8e:f1:c6:3e:4d:a9:8e:bc:d3:
81:a9:1d:3a
-----BEGIN CERTIFICATE-----
MIIDvzCCAqegAwIBAgIBAzANBgkqhkiG9w0BAQsFADCBqzELMAkGA1UEBhMCUlUx
DzANBgNVBAgMBk1vc2NvczEPMA0GA1UEBwwGTW9zY293MRAwDgYDVQQKDAdGU0kg
MIIDtzCCAp+gAwIBAgIBCDANBgkqhkiG9w0BAQsFADCBqzELMAkGA1UEBhMCUlUx
DzANBgNVBAgMBk1vd2NvdzEPMA0GA1UEBwwGTW9zY293MRAwDgYDVQQKDAdGU0kg
UlNMMSIwIAYDVQQLDBlydXN0LW15c3FsLXNpbXBsZSB0ZXN0IGNhMRowGAYDVQQD
DBFydXN0X215c3FsX3NpbXBsZTEoMCYGCSqGSIb3DQEJARYZcm9vdF9lbWFpbEBy
b290LmxvY2FsaG9zdDAgFw0yMTEwMTkxMDAxMDRaGA8yMTIxMDkyNTEwMDEwNFow
eDELMAkGA1UEBhMCUlUxFjAUBgNVBAgMDU1vc2NvdyByZWdpb24xEDAOBgNVBAoM
B0ZTSSBSU0wxKzApBgNVBAsMInJ1c3QtbXlzcWwtc2ltcGxlIHRlc3QgY2xpZW50
IGNlcnQxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBAKBwhPKcIAb7nQuN5Q9z/kG6pR+ui6429TCfK5EvuCSBUmiiL1d9
hyHlxoZN6GkOghqPhPJ0ok6D+O7PRrzZPOgBhS6bzG0FUpYj8ZRBq5olXD8srJgv
RZh2hFuvF0CkjMbcH+PzQwtYLCMJ0+I35sxfFS2k0Aiw/Sj6/qP8GkZd3By9z9aj
J4LrWLBprJaWOV/UVvQtAMJD//nUl5rnBVuwWrivn/TpVzipaGSsNdwWNGo0968+
gyfiyv6mALwDNBY5ecI31URqqDkzc84sZmyi6nQHbfL815qgEJjMvoOluAtma/oK
EOauZj67z0nEuLrsIi2+6QlKj4Gvfa8okIsCAwEAAaMeMBwwGgYDVR0RBBMwEYcE
fwAAAYIJbG9jYWxob3N0MA0GCSqGSIb3DQEBCwUAA4IBAQBLSy8CKcUyMmrOOsb9
9Ld3+VmUTTUhAdwJTa09/xPzI06C5gdUJbP2+YOA1VUS0X/WIfUiJAU+A0OXK4G/
zgFUXjj6/mbSTwO/veEsUF853FxPvHtb0SrR3Ko74AydG2/UXLiulQmhbuL4RA9l
8aLgvvtOv8c65XCbI91UmQEF8BWjZ+LPpRt6RHbyZHAx8O80QG6G776Bpvc0Rsq5
do0M3CywUIF/ustCJ6MVx4mRWOo5dDIsexYijhSMBWFYx532nxZa3x/9+R4raHMc
YHvI39PjatAfKXTEmKQdWg1NLw8D3V6oA9pKbhJrZekT4MQQ0YXGSI7rLlLEb6vE
zrJl
b290LmxvY2FsaG9zdDAgFw0yMjExMTExMzE5MjFaGA8yMTIyMTAxODEzMTkyMVow
cDELMAkGA1UEBhMCUlUxDzANBgNVBAgMBk1vc2NvdzEQMA4GA1UECgwHRlNJIFJT
TDEiMCAGA1UECwwZcnVzdC1teXNxbC1zaW1wbGUgdGVzdCBjYTEaMBgGA1UEAwwR
cnVzdF9teXNxbF9zaW1wbGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
AQCgcITynCAG+50LjeUPc/5BuqUfrouuNvUwnyuRL7gkgVJooi9XfYch5caGTehp
DoIaj4TydKJOg/juz0a82TzoAYUum8xtBVKWI/GUQauaJVw/LKyYL0WYdoRbrxdA
pIzG3B/j80MLWCwjCdPiN+bMXxUtpNAIsP0o+v6j/BpGXdwcvc/WoyeC61iwaayW
ljlf1Fb0LQDCQ//51Jea5wVbsFq4r5/06Vc4qWhkrDXcFjRqNPevPoMn4sr+pgC8
AzQWOXnCN9VEaqg5M3POLGZsoup0B23y/NeaoBCYzL6DpbgLZmv6ChDmrmY+u89J
xLi67CItvukJSo+Br32vKJCLAgMBAAGjHjAcMBoGA1UdEQQTMBGHBH8AAAGCCWxv
Y2FsaG9zdDANBgkqhkiG9w0BAQsFAAOCAQEAR25Bpj5J+scDoQFMmCcZb0HhW6CZ
vN6vkRJ7IX+ePmwFgjDDuSJSoHGNvDW1izmb8MZcb+4k20kiF8SDYkpAaP7u6Jns
85HBwhuJrOhcf33+YZr6Z0t5CwHVj2uWZkd1bCh76j5pxxHCh98zDWw1pi7A1ON9
KhW566B89734dtTOPyoCeSuPfzOxJrTXDT51QeXVP14lqWaPTQfK1CbVF2yFe8zi
vAMYm3a0eEoXpV60WPxh37U90VHf+2UUGrtJcNMBLvvvcyEZp9EMglaScABob+B2
wnopPCFrrE8mMBUCsl8zgEA55JfjtXZb8RoZWfuHjvHGPk2pjrzTgakdOg==
-----END CERTIFICATE-----
Loading